前言
學(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)也更加方便和安全