有關Service的startService與bindService在各種情形下生命週期的變化
Activity模版:
public class MainActivity extends AppCompatActivity{
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
log("onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
log("onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
log("onCreate");
}
public void click1(View view) {
int id = view.getId();
switch (id) {
case R.id.bt_1_1:
log("click -> startService");
startService(new Intent(this,MyService.class));
break;
case R.id.bt_1_2:
log("click -> stopService" );
stopService(new Intent(this,MyService.class));
break;
case R.id.bt_1_3:
log("click -> bindService");
bindService(new Intent(this,MyService.class),connection,BIND_AUTO_CREATE);
break;
case R.id.bt_1_4:
log("click -> unbindService");
unbindService(connection);
break;
case R.id.bt_1_5:
log("click -> to next activity");
startActivity(new Intent(this,Main2Activity.class));
break;
default:
}
}
@Override
protected void onDestroy() {
super.onDestroy();
log("onDestroy");
}
private void log(String msg) {
Log.d("TAG-MainActivity", msg);
}
}
Service設定:
public class MyService extends Service {
private MyBinder binder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
log("onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
log("onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
log("onBind");
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
log("onUnbind");
return super.onUnbind(intent);
}
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
log("bindService");
return super.bindService(service, conn, flags);
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
log("unbindService");
}
@Override
public void onDestroy() {
super.onDestroy();
log("onDestroy");
}
@Override
public boolean stopService(Intent name) {
log("onDestroy");
return super.stopService(name);
}
private void log(String msg) {
Log.d("TAG-MyService", msg);
}
static class MyBinder extends Binder {
}
}
說明:有三個Activity,分別為MainActivity、Main2Activity、Main3Activity,這三個Activity 的實現完全複製於上述模版,只不過Main3Activity中跳轉到下一個Activity的點選事件實際的實現。
接下來,將會對各種情景進行實踐,觀察Service的生命週期變化。
(說明:紅色框代表第一個Activity,即MainActivity,黃色的代表Main2Activity,藍色代表Main3Activity,箭頭向下表示從當前Activity跳轉到下一個Activity,箭頭向上則表示把當前Activity 推出棧回到上一個Activity,框內的表示當前Activity對同一個Service的操作,空白表示不做任何操作。當然最後都會把第一個Activity推出棧並回到桌面)
情景:
1、
先有一個Activity startService(跳轉到後面當Activity時沒有被銷燬,只能被壓到了棧底),之後有多個Activity bindService,然後跳轉帶最後一個Activity時,先bindService,然後直接stopService,之後再依次將Activity推出棧,從上面的執行截圖可以看到,當Service被stopService,Service沒有立即被銷燬,然後一直等到了最初bindService的Activity被銷燬之後(從日誌可以看到先MainActivity被onDestory然後才是Service被onDestory),Service才被銷燬,此時也沒有對startService的Activity做任何操作。
2、
這次是在第一個Activity中bindService,在第二個中startService,再最後一箇中bindService,然後回退Activity的時候在最後一箇中unbindService,第二個不錯操作,回到第一個unbindService,最後把第一個也推出棧,然後從執行日誌中可以看到,在最後Service沒有執行onDestory方法,也就是表明Service還存在,沒有被銷燬,這一點從日誌畫紅圈的部分(重新進入第一個Activity並startService)也可以得以驗證。
3、
這一次只是單單在兩個Activity中執行bindService以及unbindService操作,可以看到,此時在第一個Activity銷燬前,Service已經在執行了unbindService操作後被銷燬了,與(1)存在些許區別。
4、
在這次的嘗試中,從輸出的日誌可以看到,當在第二個Activity中stopService之後,Service沒有被立即銷燬,而是一直等到第一個Activity被onDestory之後(也就是最後一個與其繫結的Context銷燬之後),它才自動被銷燬,情況和(1)類似。
5、
在這一次的嘗試中,可以看到,最後在第一個Activity中執行完unbindService之後,Service正常的被銷燬。
6、
根據執行流程與輸出的日誌可以看到,雖然在第二個Activity中沒有unbindService,但是當第二個Activity onDestory之後,其繫結到Service中的Context也就失效了,然後回到第一個Activity中執行unbindService之後,Service就立即被銷燬了。
7、
這次在第一個Activity中unbindService之後,Service也被正常銷燬了。
8、
這次,在第二個Activity中startService後沒有進行stopService,在第三個Activity中bindService後也沒有unbindService,只有在第一個Activity推出棧之前執行unbindService,從執行日誌可以看出,Service沒有被銷燬,還處於執行狀態(從畫圈部分的日誌可以得以驗證,再次進入程式,在第一個Activity中startService並沒有執行onCreate只執行了onStartCommand)。
9、
10、
如果只是在第一個Activity中bindService,然後在把Activity推出棧,在Activity執行onDestory之後,Service才自動執行unbindService然後被銷燬。
11、
根據上述的幾個情景的驗證,可以得出如下結論:
【1】當startService單獨使用時,即使對應的startService
時傳入的Context被銷燬,Service也還是會處於執行狀態。
【2】無論多少個Activity綁定了Service,但是onBind()
只會執行一次,也就是Service首次被繫結時會執行,onUnbind()
也是如此,即最後一個Context失效後,才會執行onUnbind()
(Activity主動呼叫unbindService
或者被onDestory
)。
而如果由於Activity沒有主動呼叫unbindService與Serivice解綁,這樣會造成記憶體洩漏。如截圖:
(這裡需要說明的是,只要Activity在bindService後,如果在銷燬前沒有主動呼叫unbindService,就會引發記憶體洩漏。)
而最後一個Context
的意思是所有Context中最後一個失效的Context,假設有兩個Activity,都綁定了Service,且在從第一個Activity跳轉帶第二個Activity,當在第二個Activity中bindService
後,藉助廣播或者其他途徑直接finish掉第一個Activity(可以在第一個Activity被銷燬前先unbindService
),這樣,在第二個Activity與Service繫結時傳入的Context就成了最後一個Context了。
【3】當只有一個Activity與Service進行bindService而沒有startService,則Activity在onDestory
前如果沒有主動呼叫unbindService
與Service解除繫結,或者只是直接呼叫stopService
,則需要等到Activity被銷燬,也就是與Service繫結的Context失效時,Service才會執行onUnbind()
,之後會自動呼叫onDestory()
進行銷燬。
【4】
如果是多個Activity都綁定了同一個Service繫結,且沒有執行過startService,當其中一個Activity onDestory
或者進行unbindService
之後,其與Service進行bindService
時的Context就會失效,而當最後與Service繫結的Contxet失效後,Service才會執行onUnbind()
,之後會自動呼叫onDestory()
進行銷燬。
【5】
如果是同時有多個Activity對Service進行了startService
和bindService
,如果沒有顯示呼叫過stopService
,則當所有與Service繫結的Context失效後,Service不會被銷燬,會一直在後臺執行,因為有主動呼叫了startService
,此時必須主動呼叫stopService
或者在Service中呼叫stopSelf才能將其銷燬;而如果在一個或者多個Context失效前主動呼叫了stopService
或者在Service中呼叫stopSelf
,則需要等到最後一個Context主動與Service進行unbindService
或者失效後,才會能使Service執行onDestory
。