Android Jetpack系列之Lifecycle組件(一篇文章掌握Lifecycle)

Lifecycle是什么咆爽?

Lifecycle是一個(gè)Android生命周期管理的組件挫酿,在Android中惨缆,activity和fragment都具有它們自己的生命周期辟灰,對(duì)于android開發(fā)來說,界面的生命周期對(duì)我們來說是很重要的凯旭,處理不好的話就會(huì)出現(xiàn)內(nèi)存泄漏的問題概耻。在android開發(fā)中,很多功能的實(shí)現(xiàn)都需要在不同的生命周期中進(jìn)行相應(yīng)操作的調(diào)用罐呼,比如說地圖鞠柄,定位需要在onStart中執(zhí)行start操作,在onStop中執(zhí)行stop操作嫉柴;還有播放器需要在onStart中的進(jìn)行連接厌杜,在onStop中進(jìn)行中斷連接的操作。如果我們忘記了在onStop或者onDestory中釋放資源计螺,那么就會(huì)導(dǎo)致內(nèi)存泄漏的問題夯尽。

為了更加清楚的了解Lifecycle和傳統(tǒng)生命周期管理的區(qū)別,我把Google中的示例代碼放上登馒,讓大家更好的理解Lifecycles

Kotlin代碼:

internal class MyLocationListener(
        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start() {
        // connect to system location service
    }

    fun stop() {
        // disconnect from system location service
    }
}

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        myLocationListener.start()
        // manage other components that need to respond
        // to the activity lifecycle
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

java代碼:

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // connect to system location service
    }

    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

這段代碼在Android開發(fā)中是標(biāo)準(zhǔn)的實(shí)例匙握,這樣的話在各個(gè)生命周期的方法中會(huì)有大量的代碼,例如onStart()和onStop()陈轿,這樣使他們難以維護(hù)圈纺。

Lifecycle介紹

Lifecycle組件包括LifecycleOwner秦忿、LifecycleObserver。LifeCyclerObserver是我們要實(shí)現(xiàn)的具有生命周期感知的類的需要實(shí)現(xiàn)的接口蛾娶,這個(gè)接口沒有任何方法灯谣。在這個(gè)類中我們通過注解來表明函數(shù)在LifeCycleOwner的哪個(gè)生命周期的時(shí)候執(zhí)行。實(shí)現(xiàn)了LifecycleObserver 接口的類蛔琅,可以在方法上添加注解來監(jiān)視其組件以來的UI界面的生命周期胎许,可以通過調(diào)用Lifecycle類的addObserver()方法傳遞觀察者實(shí)例來添加觀察者。

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener() {
        ...
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

看到這里揍愁,大家沒有理解不用急呐萨,后面會(huì)有一個(gè)完整的功能來演示使用Lifecycle杀饵。在上面說到了OnLifecycleEvent注解中(Lifecycle.Event的狀態(tài)莽囤,為了更好的理解,我用Google文檔中的一個(gè)圖片來說明

lifecycle-states.png

LifeCycleOwner也是一個(gè)接口切距,這個(gè)接口只有g(shù)etLifeCycle一個(gè)方法朽缎。用于標(biāo)志它的實(shí)現(xiàn)類是具有生命周期的類。在26.0.1版本后的support庫中的Activity谜悟、Fragment都實(shí)現(xiàn)了LifeCycleOwner接口话肖。所以通常的情況下我們不需要自己去實(shí)現(xiàn)LifecycleOwner,我們只要去實(shí)現(xiàn)lifecycleObserver就可以了葡幸。

Lifecycle如何使用

下面我們會(huì)用一個(gè)獲取定位的案例來演示Lifecycle如何使用最筒,首先我們先建立一個(gè)BoundLocationManager的類

public class BoundLocationManager {
    public static void bindLocationListenerIn(LifecycleOwner lifecycleOwner,
                                              LocationListener listener, Context context) {
        new BoundLocationListener(lifecycleOwner, listener, context);
    }

    @SuppressWarnings("MissingPermission")
    static class BoundLocationListener implements LifecycleObserver {
        private final Context mContext;
        private LocationManager mLocationManager;
        private final LocationListener mListener;

        public BoundLocationListener(LifecycleOwner lifecycleOwner,
                                     LocationListener listener, Context context) {
            mContext = context;
            mListener = listener;
            lifecycleOwner.getLifecycle().addObserver(this);
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        void addLocationListener() {
            mLocationManager =
                    (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mListener);
            Log.d("BoundLocationMgr", "Listener added");

            // Force an update with the last location, if available.
            Location lastLocation = mLocationManager.getLastKnownLocation(
                    LocationManager.GPS_PROVIDER);
            if (lastLocation != null) {
                mListener.onLocationChanged(lastLocation);
            }
        }


        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void removeLocationListener() {
            if (mLocationManager == null) {
                return;
            }
            mLocationManager.removeUpdates(mListener);
            mLocationManager = null;
            Log.d("BoundLocationMgr", "Listener removed");
        }
    }
}

BoundLocationListener實(shí)現(xiàn)了LifecycleObserver接口,并在構(gòu)造函數(shù)中需要傳入LifecycleOwner(調(diào)用BoundLocationManager的Activity或者fragment),LocationListener(定位改變的監(jiān)聽)蔚叨,Context(上下文床蜘,初始化定位的需要)。

addLocationListener()方法上面添加了注解@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)的意思是addLocationListener()只有在LifecycleOwner(即Activity或者fragment)的生命周期為onResume()的時(shí)候才會(huì)執(zhí)行蔑水。

removeLocationListener()方法上面添加了注解 @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)的意思是removeLocationListener()只有在LifecycleOwner(即Activity或者fragment)的生命周期為onPause()的時(shí)候才會(huì)執(zhí)行邢锯。

也就是BoundLocationListener這個(gè)類可以監(jiān)聽Activity或者fragment的生命周期并自動(dòng)執(zhí)行其生命周期鎖對(duì)應(yīng)的方法。

還有一點(diǎn)需要注意的:在BoundLocationListener構(gòu)造方法中 lifecycleOwner.getLifecycle().addObserver(this),只有加上這句代碼搀别,BoundLocationListener才會(huì)檢測(cè)其Activity或者fragmeng的生命周期丹擎。

那么我們?cè)贏ctivity中應(yīng)該如何使用呢?其實(shí)很簡(jiǎn)單歇父,只需要在Activity或者fragmeng中添加一句代碼就可以了

private void bindLocationListener() {
    BoundLocationManager.bindLocationListenerIn(this, mGpsListener, getApplicationContext());
}

看到這里蒂培,相信大家對(duì)Lifecycle的使用方式已經(jīng)有了自己的了解,使用Lifecyle可以讓我們更好的去管理Activity或者fragment的生命周期榜苫,而且極大簡(jiǎn)化了Activity或者fragment中的代碼护戳,并且使我們出現(xiàn)內(nèi)存泄漏的概率大大的降低了。下面我會(huì)放出Activity中的完整代碼

public class LocationActivity extends AppCompatActivity {

    private static final int REQUEST_LOCATION_PERMISSION_CODE = 1;

    private LocationListener mGpsListener = new MyLocationListener();

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED
                && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
            bindLocationListener();
        } else {
            Toast.makeText(this, "This sample requires Location access", Toast.LENGTH_LONG).show();
        }
    }

    private void bindLocationListener() {
        BoundLocationManager.bindLocationListenerIn(this, mGpsListener, getApplicationContext());
    }

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

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_LOCATION_PERMISSION_CODE);
        } else {
            bindLocationListener();
        }
    }

    private class MyLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            TextView textView = findViewById(R.id.location);
            textView.setText(location.getLatitude() + ", " + location.getLongitude());
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
            Toast.makeText(LocationActivity.this,
                    "Provider enabled: " + provider, Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    }
}

Activity的布局文件里面只有一個(gè)TextView单刁,具體的代碼就省略了灸异。

如何自定義LifecycleOwner府适?

在上文中說過在26.0.1版本后的support庫中的Activity、Fragment都實(shí)現(xiàn)了LifeCycleOwner接口肺樟,那么我們之前版本的Activity檐春、Fragment也想使用Lifecycle應(yīng)該怎么做?這樣的話就需要我們自定義LifecycleOwner么伯,其實(shí)自定義LifecycleOwner很簡(jiǎn)單疟暖,只需要讓你的類實(shí)現(xiàn)LifecycleOwner 接口并在其相應(yīng)的生命周期中添加幾句代碼就可以了。

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

以上就是Lifecycle的使用方式田柔,Lifecycle的使用方式很簡(jiǎn)單俐巴,相信大家看到這里也基本上掌握了Lifecycle,后面將會(huì)講解ViewModel和LiveData的使用硬爆,最后希望大家都能一起進(jìn)步欣舵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缀磕,隨后出現(xiàn)的幾起案子缘圈,更是在濱河造成了極大的恐慌,老刑警劉巖袜蚕,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糟把,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡牲剃,警方通過查閱死者的電腦和手機(jī)遣疯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凿傅,“玉大人缠犀,你說我怎么就攤上這事∠凉椋” “怎么了夭坪?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長过椎。 經(jīng)常有香客問我室梅,道長,這世上最難降的妖魔是什么疚宇? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任亡鼠,我火速辦了婚禮,結(jié)果婚禮上敷待,老公的妹妹穿的比我還像新娘间涵。我一直安慰自己,他們只是感情好榜揖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布勾哩。 她就那樣靜靜地躺著抗蠢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪思劳。 梳的紋絲不亂的頭發(fā)上迅矛,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音潜叛,去河邊找鬼秽褒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛威兜,可吹牛的內(nèi)容都是我干的销斟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼椒舵,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蚂踊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起逮栅,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤悴势,失蹤者是張志新(化名)和其女友劉穎窗宇,沒想到半個(gè)月后措伐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡军俊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年侥加,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粪躬。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡担败,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镰官,到底是詐尸還是另有隱情提前,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布泳唠,位于F島的核電站狈网,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏笨腥。R本人自食惡果不足惜拓哺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脖母。 院中可真熱鬧士鸥,春花似錦、人聲如沸谆级。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脚仔,卻和暖如春币砂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玻侥。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工决摧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凑兰。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓掌桩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姑食。 傳聞我的和親對(duì)象是個(gè)殘疾皇子波岛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359