學(xué)習(xí)記錄(2) - LifeCycle

前言

學(xué)習(xí)記錄系列是通過(guò)閱讀學(xué)習(xí)《Android Jetpack應(yīng)用指南》對(duì)書中內(nèi)容學(xué)習(xí)記錄的Blog,《Android Jetpack應(yīng)用指南》京東天貓有售,本文是學(xué)習(xí)記錄的第二篇。


誕生

在 Android 應(yīng)用程序開發(fā)中,解耦很大程序上表現(xiàn)為系統(tǒng)組件的生命周期與普通組件之間的解耦。普通組件在使用過(guò)程中通常需要依賴于系統(tǒng)組件的生命周期。有時(shí)候,我們不得不在系統(tǒng)組件的生命周期回調(diào)方法中,主動(dòng)對(duì)普通組件進(jìn)行調(diào)用或控制。因?yàn)槠胀ńM件無(wú)法主動(dòng)獲知系統(tǒng)組件的生命周期事件。

系統(tǒng)組件:指的是 Activity/Fragment、Service 和 Application
普通組件:為了讓代碼更容易管理和維護(hù),通常會(huì)將代碼按照功能或作用封裝成組件

舉例:我們經(jīng)常需要在頁(yè)面的 onCreate()方法中對(duì)組件初始化,在 onPause()方法中停止組件,而在頁(yè)面的 onDestroy()方法中對(duì)組件進(jìn)行資源回收工作。這樣的工作非常煩瑣,會(huì)讓頁(yè)面與組件之間的耦合度變高。但這些工作又不得不做,因?yàn)檫@可能會(huì)引發(fā)內(nèi)存泄漏。
我們希望對(duì)自定義組件的管理,不依賴于頁(yè)面生命周期的回調(diào)方法。同時(shí),在頁(yè)面周期發(fā)生變化時(shí),也能及時(shí)收到通知。

簡(jiǎn)介

LifeCycle 可以幫助開發(fā)者創(chuàng)建可以感知生命周期的組件。這樣,組件便能夠在其內(nèi)部管理自己的生命周期,從而降低模塊間的耦合度,并降低內(nèi)存泄漏發(fā)生的可能性。LifeCycle不只對(duì) Activity/Fragment 有用,在 Service 和 Application 中也能大顯身手。

使用LifeCycle解耦頁(yè)面與組件

1.案例分析

需求:在用戶打開某個(gè)頁(yè)面時(shí),獲取用戶當(dāng)前的地理位置。
代碼實(shí)現(xiàn):

public class LifeCycleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);

        // 初始化位置管理器
        initLocationManager();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 開始獲取用戶的地理位置
        startGetLocation();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 停止獲取用戶的地理位置
        stopGetLocation();
    }
}

從以上代碼可以看出,獲取地理位置這個(gè)需求的實(shí)現(xiàn),與頁(yè)面的生命周期息息相關(guān)。如果要將獲取地理位置這一功能獨(dú)立成一個(gè)組件,那么生命周期是必須考慮在內(nèi)的。我們不得不在頁(yè)面生命周期的各個(gè)回調(diào)方法中,對(duì)組件進(jìn)行通知,因?yàn)榻M件不能主動(dòng)感知生命周期的變化。

2.LifeCycle的原理

Jetpack 提供了兩個(gè)類:LifecycleOwner(被觀察者)和 LifecycleObserver(觀察者)。即通過(guò)觀察者模式,實(shí)現(xiàn)對(duì)頁(yè)面生命周期的監(jiān)聽。

在新版本的SDK包中,Activity已經(jīng)默認(rèn)實(shí)現(xiàn)了 LifecycleOwner 接口。LifecycleOwner 接口中只有一個(gè)getLifecycle(LifecycleObserver observer)方法,LifecycleOwner 正是通過(guò)該方法實(shí)現(xiàn)觀察者模式的,

3.解決方案

利用LifecyCycle改寫需求,將該功能從Activity中獨(dú)立出去,在減少耦合度的同時(shí),又不影響對(duì)生命周期的監(jiān)聽。

/**
 * 自定義組件,讓組件實(shí)現(xiàn)LifecycleObserver接口。
 * 與獲取地理位置相關(guān)的代碼在該類中完成
 * 對(duì)于組件中那些需要在頁(yè)面周期發(fā)生變化時(shí)得到通知的方法,我們需要在這些方法上使用@OnLifecycleEvent(Lifecycle.Event.On_XXX)標(biāo)簽進(jìn)行標(biāo)識(shí)。
 * 這樣,當(dāng)頁(yè)面生命周期發(fā)生變化時(shí),這些被標(biāo)識(shí)過(guò)的方法便會(huì)被自動(dòng)調(diào)用
 *
 * @author JinXin 2020/7/26
 */
public class MyLocationListener implements LifecycleObserver {

    private static final String TAG = "MyLocationListener";

    private OnLocationChangedListener onLocationChangedListener;

    public MyLocationListener(Context context, OnLocationChangedListener onLocationChangedListener) {
        this.onLocationChangedListener = onLocationChangedListener;

        // 初始化操作
        initLocationManager();
    }

    private void initLocationManager() {

    }

    /**
     * 當(dāng)Activity執(zhí)行onResume()方法時(shí),該方法會(huì)被自動(dòng)調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation: ");
        if (onLocationChangedListener != null) {
            onLocationChangedListener.onChanged(0,0);
        }
    }

    /**
     * 當(dāng)Activity執(zhí)行onPause()方法時(shí),該方法會(huì)被自動(dòng)調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void stopGetLocation() {
        Log.d(TAG, "stopGetLocation: ");
        if (onLocationChangedListener != null) {
            onLocationChangedListener.onChanged(0,0);
        }
    }

    /**
     * 當(dāng)?shù)乩砦恢冒l(fā)生變化時(shí),通過(guò)該接口通知調(diào)用者
     */
    public interface OnLocationChangedListener {

        /**
         * 地理位置發(fā)生變化
         * @param latitude 緯度
         * @param longitude 經(jīng)度
         */
        void onChanged(double latitude, double longitude);

    }
}

在LifeCycleActivity中,只需要引用 MyLocationListener 即可,不再關(guān)心 Activity 生命周期變化對(duì)組件所帶來(lái)的影響。生命周期的管理完全交給 MyLocationListener 內(nèi)部自行處理。在 Activity 中要做的只是通過(guò) getLifecycle().addObserver()方法,將觀察者和被觀察者綁定起來(lái)

public class LifeCycleActivity extends AppCompatActivity {

    private static final String TAG = "LifeCycleActivity";

    private MyLocationListener myLocationListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);
        // 使用Lifecycle感知生命周期
        // 自定義組件MyLocationListener,該組件實(shí)現(xiàn)LifeCycleObserver接口。
        // 獲取地理位置相關(guān)的代碼在該組件中完成
        myLocationListener = new MyLocationListener(this, (latitude, longitude) -> {

            // 展示收到的位置信息
            Log.d(TAG, "onChanged: " + latitude + " " + longitude);
        });

        // 將觀察者與被觀察者綁定
        getLifecycle().addObserver(myLocationListener);
    }
}


使用LifecycleService 解耦Service組件

1.LifecycleService 基本介紹

為了便于對(duì) Service 生命周期的監(jiān)聽,達(dá)到解耦 Service 與組件的目的, Android 提供了一個(gè)名為 LifecycleService 的類。該類繼承自 Service,并實(shí)現(xiàn)了 LifecycleOwner 接口。

2.LifecycleService 的具體使用方法

1.首先,需要在 app 的 build.gradle 文件中添加相關(guān)依賴

dependencies {
    // 添加lifecycle相關(guān)依賴
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

2.創(chuàng)建 MyService 類并繼承自 LifecycleService ,LifecycleService 是 Service 的直接子類,使用和普通 Service 沒有差別

public class MyService extends LifecycleService {

    private MyServiceObserver myServiceObserver;

    public MyService() {

        myServiceObserver = new MyServiceObserver();
        // 將觀察者和被觀察者綁定
        getLifecycle().addObserver(myServiceObserver);
    }
}

Service 記得要在 AndroidManifest.xml 中注冊(cè)<service android:name=".service.MyService" />

3.創(chuàng)建 MyServiceObserver 類,該類需要實(shí)現(xiàn) LifecycleObserver 接口

public class MyServiceObserver implements LifecycleObserver {

    private static final String TAG = "MyServiceObserver";

    /**
     * 當(dāng)Service的onCreate()方法被調(diào)用時(shí),該方法會(huì)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation: 開始獲取地理位置");
    }

    /**
     *  當(dāng)Service的onDestroy()方法被調(diào)用時(shí),該方法會(huì)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void stopGetLocation() {
        Log.d(TAG, "stopGetLocation: 停止獲取地理位置");
    }
}

4.在 Activity 中控制 Service 的啟動(dòng)和停止

public class LifecycleServiceActivity extends AppCompatActivity {

    private static final String TAG = "LifecycleServiceActivit";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle_service);

        findViewById(R.id.btn_start_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 啟動(dòng)服務(wù)
                Intent intent = new Intent(LifecycleServiceActivity.this, MyService.class);
                startService(intent);
            }
        });

        findViewById(R.id.btn_stop_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 停止服務(wù)
                Intent intent = new Intent(LifecycleServiceActivity.this, MyService.class);
                stopService(intent);
            }
        });
    }
}

5.通過(guò) LogCat 中的日志可以看出,隨著 Service 生命周期的變化,MyServiceObserver 中帶有 @onLifecycleEvent 標(biāo)簽的方法被自動(dòng)調(diào)用了。這樣便實(shí)現(xiàn)了組件對(duì) Service 生命周期的監(jiān)聽。

2020-10-21 22:52:25.471 20670-20670/com.jinxin.jetpacktest D/MyServiceObserver: startGetLocation: 開始獲取地理位置
2020-10-21 22:52:26.925 20670-20670/com.jinxin.jetpacktest D/MyServiceObserver: stopGetLocation: 停止獲取地理位置

6.總結(jié)

當(dāng) Service 的生命周期發(fā)生變化時(shí),不再需要主動(dòng)對(duì)組件對(duì)組件進(jìn)行通知,組件能夠在其內(nèi)部自動(dòng)管理好生命周期所帶來(lái)的變化。LifecycleService 很好地實(shí)現(xiàn)了組件與 Service 之間的解耦。


使用 ProcessLifecycleOwner 監(jiān)聽?wèi)?yīng)用程序的生命周期

1.ProcessLifecycleOwner 存在的意義

監(jiān)聽整個(gè)應(yīng)用程序的生命周期情況

2.ProcessLifecycleOwner 的具體使用方法

1.首先,需要在 app 的 build.gradle 文件中添加相關(guān)依賴

dependencies {
    // 添加lifecycle相關(guān)依賴
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

2.ProcessLifecycleOwner 的本質(zhì)也是觀察者模式。由于觀察的是整個(gè)應(yīng)用程序,因此,需要在 Application 中進(jìn)行相關(guān)代碼的編寫。

public class MyApplication extends Application{

    @Override
    public void onCreate() {
        super.onCreate();

        // ProcessLifecycleOwner是針對(duì)整個(gè)應(yīng)用程序的監(jiān)聽,與Activity數(shù)量無(wú)關(guān)
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationObserver());
    }
}

3.定義一個(gè)名為 ApplicationObserver 的類,讓該類實(shí)現(xiàn) LifecycleObserver 接口,已負(fù)責(zé)對(duì)應(yīng)用程序生命周期的監(jiān)聽

/**
 * 負(fù)責(zé)對(duì)應(yīng)用程序生命周期的監(jiān)聽
 *
 * Lifecycle.Event.ON_CREATE 只會(huì)被調(diào)用一次,而Lifecycle.Event.ON_DESTROY永遠(yuǎn)不會(huì)被調(diào)用
 * 當(dāng)應(yīng)用程序從后臺(tái)回到前臺(tái),或者應(yīng)用程序被首次打開時(shí),會(huì)依次調(diào)用Lifecycle.Event.ON_START和Lifecycle.Event.ON_RESUME
 * 當(dāng)應(yīng)用程序從前臺(tái)回到后臺(tái)(用戶按下Home鍵或任務(wù)菜單鍵),會(huì)依次調(diào)用Lifecycle.Event.ON_PAUSE和Lifecycle.Event.ON_STOP
 * 
 * 需要注意的是,Lifecycle.Event.ON_START 和 Lifecycle.Event.ON_RESUME,這兩個(gè)方法的調(diào)用會(huì)有一定的延后。
 * 這是因?yàn)橄到y(tǒng)需要為 “屏幕旋轉(zhuǎn),由于配置發(fā)生變化而導(dǎo)致 Activity 重新創(chuàng)建” 的情況預(yù)留一些時(shí)間。也就是說(shuō),系統(tǒng)需要保證當(dāng)設(shè)備出現(xiàn)這種情況時(shí),
 * 這兩個(gè)事件不會(huì)被調(diào)用,因?yàn)楫?dāng)旋轉(zhuǎn)屏幕時(shí),你的應(yīng)用程序并沒有推到后臺(tái),它只是進(jìn)入了橫/豎屏模式而已
 * @author JinXin 2020/7/27
 */
class ApplicationObserver implements LifecycleObserver {

    private static final String TAG = "ApplicationObserver";

    /**
     * 在應(yīng)用程序的整個(gè)生命周期中只會(huì)被調(diào)用一次
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void onCreate() {
        Log.d(TAG, "onCreate: ");
    }

    /**
     * 當(dāng)應(yīng)用程序在前臺(tái)出現(xiàn)時(shí)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onStart() {
        Log.d(TAG, "onStart: ");
    }

    /**
     * 當(dāng)應(yīng)用程序在前臺(tái)出現(xiàn)時(shí)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void onResume() {
        Log.d(TAG, "onResume: ");
    }

    /**
     * 當(dāng)應(yīng)用程序退出到后臺(tái)時(shí)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    private void onPause() {
        Log.d(TAG, "onPause: ");
    }

    /**
     * 當(dāng)應(yīng)用程序退出到后臺(tái)時(shí)被調(diào)用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onStop() {
        Log.d(TAG, "onStop: ");
    }

    /**
     * 永遠(yuǎn)不會(huì)被調(diào)用,系統(tǒng)不會(huì)分發(fā)調(diào)用ON_DESTROY
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void onDestroy() {
        Log.d(TAG, "onDestroy: ");
    }
}


總結(jié)

Lifecycle 組件存在的主要意義是幫助我們解耦,讓自定義組件也能感受到生命周期的變化。有了 Lifecycle 之后,在自定義組件內(nèi)部便可以管理好其生命周期,不再需要擔(dān)心組件的內(nèi)存泄漏等問(wèn)題了,組件使用起來(lái)也更加方便和安全

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容