一、简介
Android Architecture Components 是谷歌在Google I/O 2017发布一套帮助开发者解决Android 架构设计的方案。使用Google 提供的处理数据持久化和管理组件生命周期的类,有助于应用开发者们构建更加鲁棒性,可测的,稳定可靠的应用。
二、Lifecycle
Lifecycle 组件指的是 android.arch.lifecycle 包下提供的各种类与接口,可以让开发者构建能感知其他组件(主要指Activity 、Fragment)生命周期(lifecycle-aware)的类。
1、为什么要使用Lifecycle
下面举一个常用的 MVP 例子,没引进 lifecycle 之前,我们需要在 Activity 或者 Fragment 销毁的时候,即 onDestroy 的时候手动调用 onDestroy 方法,这里会带来一些问题,每一次在 Activity 或者 Fragment 销毁的烧开后都要调用 presenter.destory() 方法,这样的代码枯燥,毫无意义。
class MainPresenter{
public MainPresenter() {
}
void onCreate() {
//do something
}
void onDestroy() {
//do something
}
}
在 MainActivity的生命周期方法中回调MainPresenter的生命周期方法:
class MainActivity extends AppCompatActivity {
private MainPresenter presenter;
public void onCreate(...) {
presenter= new MainPresenter ();
presenter.onCreate();
}
public void onDestroy() {
super.onDestroy();
presenter.onDestory();
}
}
上面这种方式有什么缺点呢?
1、不够灵活,假如除了 MainPresenter类,还有别的类要监听 Activity 生命周期变化,那也需要添加许多生命周期的回调方法,比较繁琐,导致Activity生命周期方法中有很多其他类的生命周期方法。
2、某些类需要在Activity的onDestroy()中调用自己的销毁方法,但是另一个开发者在Activity使用时可能对这个类不熟悉,就不会调用销毁方法。
使用lifecycle 就可以解决上面的问题。
2、使用Lifecycle
MainPresenter改造如下:
public class MainPresenter {
private static final String TAG = MainPresenter.class.getSimpleName();
private Lifecycle lifecycle;
public MainPresenter(Lifecycle lifecycle){
this.lifecycle = lifecycle;
lifecycle.addObserver(new GenericLifecycleObserver() {
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_CREATE) {
onCreate();
} else if (event == Lifecycle.Event.ON_DESTROY) {
onDestroy();
}
}
});
}
public void onCreate() {
Log.d(TAG, "onCreate:");
}
public void onDestroy() {
Log.d(TAG, "onDestroy:");
}
}
使用Lifecycle MainPresenter的逻辑都集中在MainPresenter中。避免了在Activity中多次调用。
Activity中调用如下:
public class LifecycleActivity extends AppCompatActivity {
private static final String TAG = LifecycleActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle);
Lifecycle lifecycle = getLifecycle();
MainPresenter presenter = new MainPresenter(lifecycle);
}
}
三、ViewModel
多数人都遇到过旋转手机并且应用程序崩溃或UI失去状态的问题。解决它最简单的办法就是配置Activity
为potrait
模式,但这是一个很糟糕的做法。幸运的是,Android团队在2017年Google I / O期间发布了ViewModel。
ViewModel不会因为Activity因配置改变销毁时被销毁(配置改变如旋转屏幕、设置中字体大小、粗细改变。Activity中配置改变会回调onRetainCustomNonConfigurationInstance和getLastNonConfigurationInstance)。ViewModelProviders.of(this).get(UserInfoViewModel.class)因配置改变时只是重连,不是新建。这就是使用ViewModel的好处。
ViewModel使用例子结合下节一起讲解。
四、LiveData
LiveData是google发布的lifecycle-aware components中的一个组件,它最大的特点就是具备生命周期感知功能。LiveData的优点:
1、解决内存泄露问题
由于LiveData会在Activity/Fragment等具有生命周期的lifecycleOwner组件调用onDestory的时候自动解绑,所以解决了可能存在的内存泄漏问题。之前我们为了避免这个问题,一般有注册绑定的地方都要解绑(即注册跟解绑要成对出现),而LiveData利用生命周期感知功能解决了这一问题,可以实现只需关心注册,而解绑会根据生命周期自动进行的功能。
2、不需要手动处理生命周期的变化
观察者并不需要手动处理生命周期变化对自身的逻辑的影响,只需要关心如何处理获取到的数据。LiveData能够感知Activity/Fragment等组件的生命周期变化,所以就完全不需要在代码中告诉LiveData组件的生命周期状态,当数据发生变化时,只在生命周期处于active下通知观察者,而在inactive下,不会通知观察者。(例如联网返回数据后弹出Dialog提示,联网时退出Activity,后台Http还在运行,这种情况返回数据后弹出Dialog提示就会崩溃)
1、如何注册观察者
1)、public void observe (LifecycleOwner owner, Observer<? super T> observer)
这个方法添加的observer会受到owner生命周期的影响,在owner处于active状态时,有数据变化会通知,当owner处于inactive状态,不会通知,并且当owner的生命周期状态时DESTROYED时,自动removeObserver。
2)、public void observeForever (Observer<? super T> observer)
这个方法添加的observer不存在生命周期概念,只要有数据变化,LiveData都会通知,并且不会自动remove。
2、如何设置LiveData的值
1)、protected void setValue (T value)
这个方法必须在主线程调用,子线程调用会抛异常。
2)、protected void postValue (T value)
这个方式主要用于在子线程调用。
3、下面结合ViewModel举一个例子
1)定义ViewModel
public class UserInfoViewModel extends ViewModel {
private static final String TAG = UserInfoViewModel.class.getSimpleName();
private MutableLiveData<UserInfo> ldUserInfo = new MutableLiveData<>();;
private int id;
public UserInfoViewModel(){
UserInfo userInfo = new UserInfo();
userInfo.name = "王羲之";
userInfo.id = "" + id;
ldUserInfo.setValue(userInfo);
}
public MutableLiveData<UserInfo> getData() {
return ldUserInfo;
}
public void changeData() {
UserInfo userInfo = new UserInfo();
userInfo.name = "王羲之";
id++;
userInfo.id = "" + id;
ldUserInfo.setValue(userInfo);
}
}
继承ViewModel,ViewModel没有抽象方法,所以我们在子类中也不用实现什么抽象方法,这样UserInfoViewModel就具有了ViewModel的功能。
LiveData是一个抽象类,所以我们使用其实现类MutableLiveData。泛型UserInfo是LiveData中对象的类型。
2)、Activity中的代码如下
public class LiveDataActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = LiveDataActivity.class.getSimpleName();
private TextView tvUserInfo;
private UserInfoViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data);
tvUserInfo = findViewById(R.id.tv_data);
initViewModel();
setLisenter();
}
/**
* 初始化ViewModel
*/
private void initViewModel() {
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())
).get(UserInfoViewModel.class);
Log.d(TAG, "viewModel>>" + viewModel.toString());
Log.d(TAG, "viewModel>>" + viewModel.getData().getValue().toString());
setDataChangeObserve();
}
/**
* 设置数据观察者
*/
private void setDataChangeObserve() {
viewModel.getData().observe(this, new Observer<UserInfo>() {
@Override
public void onChanged(@Nullable UserInfo userInfo) {
Log.d(TAG, "viewModel.getData().observe.onChanged>>" + viewModel.getData().getValue().toString());
// !!!UserInfo数据变化时统一在这里处理,避免多处处理,增加耦合
tvUserInfo.setText(viewModel.getData().getValue().toString());
}
});
}
private void setLisenter() {
findViewById(R.id.btn_change).setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_change:
viewModel.changeData();
break;
}
}
}
a、获取ViewModel的实例
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication());
b、为UserInfo的LiveData设置观察者,UserInfo数据改变时就会回调这里,然后处理更改UI的逻辑
viewModel.getData().observe(this, new Observer<UserInfo>() {
@Override
public void onChanged(@Nullable UserInfo userInfo) {
Log.d(TAG, "viewModel.getData().observe.onChanged>>" + viewModel.getData().getValue().toString());
// !!!UserInfo数据变化时统一在这里处理,避免多处处理,增加耦合
tvUserInfo.setText(viewModel.getData().getValue().toString());
}
});
3)、验证ViewModel的功能
竖屏时打印日志如下:
D/LiveDataActivity: viewModel>>com.demo.archcomponent.livedata.UserInfoViewModel@a0db0be
D/LiveDataActivity: viewModel>>UseInfo{id='2', name='王羲之'}
D/LiveDataActivity: viewModel.getData().observe.onChanged>>UseInfo{id='2', name='王羲之'}
切换横屏时打印日志如下:
D/LiveDataActivity: viewModel>>com.demo.archcomponent.livedata.UserInfoViewModel@a0db0be
D/LiveDataActivity: viewModel>>UseInfo{id='2', name='王羲之'}
D/LiveDataActivity: viewModel.getData().observe.onChanged>>UseInfo{id='2', name='王羲之'}
横竖屏切换时都会调用
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication());
但是日志中两次打印出的对象都是同一个,而且值也是一样的。这就证明了ViewModelProviders.of(this).get(UserInfoViewModel.class)因配置改变时只是重连,不是新建。
4)、验证LiveData的功能
在UserInfoViewModel中添加如下测试代码。
public void testLiveData(){
new Thread(){
@Override
public void run() {
super.run();
Log.d(TAG, "延时开始");
try {
sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "延时结束");
UserInfo userInfo = new UserInfo();
userInfo.name = "testLiveData";
userInfo.id = "999";
ldUserInfo.postValue(userInfo);
}
}.start();
}
上面代码延时了4秒再更新UserInfo的数据,调用该方法后我们就退出Activtiy,日志显示并没有回调onChange方法。证明LiveData会在Activity/Fragment等具有生命周期的lifecycleOwner组件调用onDestory的时候自动解绑。