Android Service 啟動方式,生命周期和應用場景詳解
備注:
Android Service 啟動方式,生命周期和應用場景詳解: https://www.cnblogs.com/finn21/p/11652482.html
ContentProvider1進程一代碼:https://github.com/zengyuan/ContentProvider1Mode
ContentProvider1進程二代碼:https://github.com/zengyuan/ContentProvider2Mode
iOS APP打包上傳審核和 客服咨詢流程(審核被拒,賬號問題等):https://www.cnblogs.com/finn21/p/11084272.html
startService 和 bindService 區別:
startService 特點:一旦服務開啟跟調用者(開啟者)就沒有任何關系了。開啟者退出了,開啟者掛了,服務還在后台長期的運行。開啟者不能調用服務里面的方法。
bindService 特點:bind的方式開啟服務,綁定服務,調用者掛了,服務也會跟着掛掉。綁定者可以調用服務里面的方法。(說白了就和小程序一樣,打開的時候使用,用完了就關閉拍屁股走人,一次性滴)注意:綁定服務不會調用onstart()
或者onstartcommand()
方法
一,Service 含義:
Service分為本地服務(LocalService)和遠程服務(RemoteService):
1、本地服務依附在主進程上而不是獨立的進程,這樣在一定程度上節約了資源,另外Local服務因為是在同一進程因此不需要IPC,
也不需要AIDL。相應bindService會方便很多。主進程被Kill后,服務便會終止。
2、遠程服務為獨立的進程,對應進程名格式為所在包名加上你指定的android:process字符串。由於是獨立的進程,因此在Activity所在進程被Kill的時候,該服務依然在運行,
不受其他進程影響,有利於為多個進程提供服務具有較高的靈活性。該服務是獨立的進程,會占用一定資源,並且使用AIDL進行IPC稍微麻煩一點。
Service啟動方式(主要是1,2兩種):
1、startService 啟動的服務:主要用於啟動一個服務執行后台任務,不進行通信。停止服務使用stopService;
2、bindService 啟動的服務:該方法啟動的服務可以進行通信。停止服務使用unbindService;
3、startService 同時也 bindService 啟動的服務:停止服務應同時使用stepService與unbindService
二. Service的生命周期(第一次啟動:onCreate()------》onStartCommand();第二次啟動:nStartCommand();關閉:onDestory();)

通過startService啟動后,service會一直無限期運行下去,只有外部調用了stopService()或stopSelf()方法時,該Service才會停止運行並銷毀。
要創建一個這樣的Service,你需要讓該類繼承Service類,然后重寫以下方法:
-
onCreate()
1.如果service沒被創建過,調用startService()后會執行onCreate()回調;
2.如果service已處於運行中,調用startService()不會執行onCreate()方法。
也就是說,onCreate()只會在第一次創建service時候調用,多次執行startService()不會重復調用onCreate(),此方法適合完成一些初始化工作。 -
onStartCommand() ------》其中有四種int類型返回值的:
START_STICKY: 當Service因內存不足而被系統kill后,一段時間后內存再次空閑時,系統將會嘗試重新創建此Service,一旦創建成功后將回調onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個狀態下比較適用於不執行命令、但無限期運行並等待作業的媒體播放器或類似服務。
START_NOT_STICKY:當Service因內存不足而被系統kill后,即使系統內存再次空閑時,系統也不會嘗試重新創建此Service。除非程序中再次調用startService啟動此Service,這是最安全的選項,可以避免在不必要時以及應用能夠輕松重啟所有未完成的作業時運行服務。
START_REDELIVER_INTENT:當Service因內存不足而被系統kill后,則會重建服務,並通過傳遞給服務的最后一個 Intent 調用 onStartCommand(),任何掛起 Intent均依次傳遞。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill后一定能重啟。
如果多次執行了Context的startService()方法,那么Service的onStartCommand()方法也會相應的多次調用。
onStartCommand()方法很重要,我們在該方法中根據傳入的Intent參數進行實際的操作,比如會在此處創建一個線程用於下載數據或播放音樂等。 -
onBind()
Service中的onBind()方法是抽象方法,Service類本身就是抽象類,所以onBind()方法是必須重寫的,即使我們用不到。 -
onDestory()
在銷毀的時候會執行Service該方法。
這幾個方法都是Service的回調方法,且在主線程中執行。
用startService 方式啟動Service的時候重寫onStartCommand()的方法。每次用該方式啟動Service的時候都會調用改方法。
第二種方式:通過bindService啟動Service
bindService啟動服務特點:(和小程序一樣,一次性滴,進入頁面的時候綁定service,退出的時候關閉service)
1.bindService啟動的服務和調用者之間是典型的client-server模式。調用者是client,service則是server端。service只有一個,但綁定到service上面的client可以有一個或很多個。這里所提到的client指的是組件,比如某個Activity。
2.client可以通過IBinder接口獲取Service實例,從而實現在client端直接調用Service中的方法以實現靈活交互,這在通過startService方法啟動中是無法實現的。
3.bindService啟動服務的生命周期與其綁定的client息息相關。當client銷毀時,client會自動與Service解除綁定。當然,client也可以明確調用Context的unbindService()方法與Service解除綁定。
當沒有任何client與Service綁定時,Service會自行銷毀。
bindService代碼實例
1.創建一個FinnService繼承Service(Server)
/** * Created by Finn on 2019-10-10. */ public class bindServiceA extends Service{ //client 可以通過Binder獲取Service實例 public class MyBinder extends Binder { public bindService getService() { return bindServiceA .this; } } //通過binder實現調用者client與Service之間的通信 在onBind中返回該對象 private MyBinder binder = new MyBinder(); private final Random generator = new Random(); @Override public void onCreate() { Log.i("Finn","bindServiceA - onCreate - Thread = " + Thread.currentThread().getName()); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("Finn", "bindServiceA - onStartCommand - startId = " + startId + ", Thread = " + Thread.currentThread().getName()); return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { Log.i("Finn", "bindServiceA - onBind - Thread = " + Thread.currentThread().getName()); return binder; } @Override public boolean onUnbind(Intent intent) { Log.i("Finn", "bindService - onUnbind - from = " + intent.getStringExtra("from")); return false; } @Override public void onDestroy() { Log.i("Finn", "bindServiceA - onDestroy - Thread = " + Thread.currentThread().getName()); super.onDestroy(); } //getRandomNumber是Service暴露出去供client調用的公共方法 public int getRandomNumber() { return generator.nextInt(); }
2.創建ActivityA,可以通過bindService綁定服務(client)
public class ActivityA extends Activity { private bindServiceA service = null; private boolean isBind = false; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder binder) { isBind = true; bindService .MyBinder myBinder = (bindServiceA.MyBinder) binder; service = myBinder.getService();//通過ServiceConnection 中的IBinder獲取 綁定的service對象 Log.i("Finn", "ActivityA - onServiceConnected"); int num = service.getRandomNumber();//通過service對象可對 bindServiceA中的函數進行操作 Log.i("Kathy", "ActivityA - getRandomNumber = " + num); } @Override public void onServiceDisconnected(ComponentName name) { isBind = false; Log.i("Finn", "ActivityA - onServiceDisconnected"); } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); Log.i("Finn", "ActivityA - onCreate - Thread = " + Thread.currentThread().getName()); bindservice(); unbindservice(); } private void bindservice(){ Intent intent = new Intent(this, bindServiceA.class); intent.putExtra("from", "ActivityA"); Log.i("Finn", "ActivityA 執行 bindServiceA"); bindService(intent, conn, BIND_AUTO_CREATE);//通過該方法綁定服務(周期:onCreate()------》onbind()) } private void unbindservice(){ //單擊了“unbindService”按鈕 if (isBind) { Log.i("Finn", "ActivityA 執行 unbindService"); unbindService(conn);//通過該方法解除綁定服務 周期:----先執行 onunbind()---》onDestroy()
} } @Override protected void onDestroy() { super.onDestroy(); Log.i("Finn", "ActivityA - onDestroy"); } }
bindServices創建如下:
要想讓Service支持bindService調用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder類型的實例。
2.onBInd()方法返回的IBinder的實例需要能夠返回Service實例本身。通常,最簡單的方法就是在service中創建binder的內部類,加入類似getService()的方法返回Service,這樣綁定的client就可以通過getService()方法獲得Service實例了。