1. 程式人生 > >有關Service的startService與bindService在各種情形下生命週期的變化

有關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進行了startServicebindService,如果沒有顯示呼叫過stopService,則當所有與Service繫結的Context失效後,Service不會被銷燬,會一直在後臺執行,因為有主動呼叫了startService,此時必須主動呼叫stopService或者在Service中呼叫stopSelf才能將其銷燬;而如果在一個或者多個Context失效前主動呼叫了stopService或者在Service中呼叫stopSelf,則需要等到最後一個Context主動與Service進行unbindService或者失效後,才會能使Service執行onDestory