0%

JetPack中的LiveData、ViewModel、LifeCycle

2018年谷歌I/O 发布了一系列辅助android开发者的实用工具,合称Jetpack,以帮助开发者构建出色的 Android 应用。
这次发布的 Android Jetpack 组件覆盖以下 4 个方面:Architecture、Foundation、Behavior 以及 UI。
该系列博客介绍一下Jetpack中常用组件,本篇介绍LiveData、ViewModel、LifeCycle。最后借助于https://github.com/android/sunflower 来写一个完整的应用

lifecycle

原文:https://developer.android.google.cn/topic/libraries/architecture/lifecycle
说白了,就是一个接口回调,可以使用注解的方式来相应声明周期的回调,并且已经帮我们处理好了各种各样的意外状况(比如我们在onStart中做了比较多的操作,用户点了home键,导致onStop在OnStart完成之前被调用了)

Lifecycle是一个包含有关组件生命周期状态的信息(如Activity或Fragment)的类,允许其他对象观察此状态
Lifecycle使用两个枚举类EventState来追踪组件的生命周期
LifeCycler
代码如下
定义一个Observer实现LifecycleObserver接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MyLifecycleObserver implements LifecycleObserver {
private String tag;
public MyLifecycleObserver(String tag){
this.tag = tag;
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate(){
Log.e(tag,"ON_CREATE");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart(){
Log.e(tag,"ON_START");
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume(){
Log.e(tag,"ON_RESUME");
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause(){
Log.e(tag,"ON_PAUSE");
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop(){
Log.e(tag,"ON_STOP");
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy(){
Log.e(tag,"ON_DESTROY");
}
}

在Activity中

1
2
3
4
5
6
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle_observer);
getLifecycle().addObserver(new MyLifecycleObserver("Activity"));
}

这里要求Activity继承自实现了LifecycleOwner接口的类,比如AppCompatActivity等。
如果因为某些原因没有办法继承这种Activity,我们可以自己实现LifecycleOwner接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WithoutLifeCycleActivity extends Activity implements LifecycleOwner {

private LifecycleRegistry lifecycleRegistry;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_without_life_cycle);
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
getLifecycle().addObserver(new MyLifecycleObserver("lifecycleRegistry"));
}
@Override
protected void onStart() {
super.onStart();
lifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}

LiveData

原文:https://developer.android.google.cn/topic/libraries/architecture/livedata
LiveData和RxJava很像,但是LiveData可以和LifeCycle绑定,来防止内存泄漏。因为LiveData仅通知处于活动状态的观察者有关更新的信息,
注册观查LiveData对象的非活动观察者不会收到有关更改的通知(当然我们也可以声明任何状态下都能手打通知)。
如果Observer类表示的观察者生命周期处于STARTED或RESUMED状态,则LiveData会将其视为处于活动状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class LiveDataActivity extends AppCompatActivity {

private MutableLiveData<String> liveData;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data);
liveData = new MutableLiveData<>();
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.e("observe",s);
}
});
liveData.observeForever(new Observer<String>() {
@Override
public void onChanged(String s) {
Log.e("observeForever",s);
}
});
liveData.setValue("onCreate");
}

@Override
protected void onStart() {
super.onStart();
liveData.setValue("onStart");
}

@Override
protected void onResume() {
super.onResume();
liveData.setValue("onResume");
}

@Override
protected void onStop() {
super.onStop();
liveData.setValue("onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
liveData.setValue("onDestroy");
}
}

我们打开界面,按下home键,然后返回到界面,然后按返回键,可以发现如下log:
打开界面

E/observeForever: onCreate
E/observeForever: onStart
E/observe: onStart
E/observe: onResume
E/observeForever: onResume

按下home键

E/observeForever: onStop

返回界面

E/observeForever: onStart
E/observe: onStart
E/observe: onResume
E/observeForever: onResume

按下返回键

E/observeForever: onStop
E/observeForever: onDestroy

如果我们将LiveData和LifeCycle绑定后,在界面处于非活动状态是收不到通知的。
LiveData经常和Room及ViewModel一块使用

ViewModel

原文:https://developer.android.google.cn/topic/libraries/architecture/viewmodel
ViewModel是以关联生命周期的方式来存储和管理UI相关的数据的类,即使configuration发生改变(比如旋转屏幕),数据仍然可以存在不会销毁。并且我们还可以通过ViewModelProviders在不同的Fragment之间共享数据。
实现ViewModel,这里省略掉了getter和setter方法。其实我们可以把每个属性都用MutableLiveData包装一下,这样当属性发生变化的时候,我们就可以立刻知道。

1
2
3
4
5
6
7
8
9
10
11

public class UserViewModel extends AndroidViewModel {
public UserViewModel(@NonNull Application application) {
super(application);
}
private String name;
private int age;
private String sex;
private MutableLiveData<Integer> valueChanged = new MutableLiveData<>();

}

在Activity中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

public class ViewModelActivity extends AppCompatActivity {

ActivityViewModelBinding binding;
private UserViewModel userViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_view_model);
userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getValueChanged().observeForever(new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
binding.setUser(userViewModel);
}
});


binding.save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userViewModel.setSex(binding.sex.getText().toString());
userViewModel.setName(binding.name.getText().toString());
userViewModel.setAge(Integer.valueOf(binding.age.getText().toString()));
userViewModel.getValueChanged().postValue(1);
}
});

binding.reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userViewModel.setAge(11);
userViewModel.setName("aa");
userViewModel.setSex("M");
userViewModel.getValueChanged().postValue(1);
binding.setUser(userViewModel);
}
});
binding.setUser(userViewModel);

ArrayList<Fragment> pages = new ArrayList<>();
pages.add(new ViewModelFragmentA());
pages.add(new ViewModelFragmentB());
PagerAdapter adapter=new ViewAdapter(getSupportFragmentManager(), pages);
binding.viewPager.setAdapter(adapter);

}

class ViewAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> list;
public ViewAdapter(FragmentManager fm,ArrayList<Fragment> list) {
super(fm);
this.list=list;
}

@Override
public Fragment getItem(int arg0) {
return list.get(arg0);
}

@Override
public int getCount() {
return list.size();
}
}
}

FragmentA和FragmentB是一样的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class ViewModelFragmentA extends Fragment implements View.OnClickListener {

private EditText name;
private EditText age;
private EditText sex;

private UserViewModel user;

public ViewModelFragmentA() {
// Required empty public constructor
}

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

user = ViewModelProviders.of(getActivity()).get(UserViewModel.class);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_view_model, container, false);
name = view.findViewById(R.id.name);
age = view.findViewById(R.id.age);
sex = view.findViewById(R.id.sex);

view.findViewById(R.id.save).setOnClickListener(this);
view.findViewById(R.id.reset).setOnClickListener(this);
view.findViewById(R.id.show).setOnClickListener(this);
user.getValueChanged().observeForever(new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
show();
}
});

show();
return view;
}


private void show() {
sex.setText(user.getSex());
age.setText(String.valueOf(user.getAge()));
name.setText(user.getName());
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.save:
user.setSex(sex.getText().toString());
user.setName(name.getText().toString());
user.setAge(Integer.valueOf(age.getText().toString()));
user.getValueChanged().postValue(1);
break;
case R.id.reset:
user.setAge(11);
user.setName("aa");
user.setSex("M");
user.getValueChanged().postValue(1);
break;
case R.id.show:
show();
break;
}

}
}

Activity中显示名字、年龄、性别。两个按钮save和reset。 在Fragment中多一个show按钮。
我们获取ViewModel都是通过ViewModelProviders.of(getActivity()).get(UserViewModel.class)来获取,得到是同一个对象。
当我们在任意一个地方修改数据并保存之后,会通过valueChanged属性来通知观察者来刷新界面。前面也提到过,我们可以把每个属性都用MutableLiveData
包装一下,观察者就可以在每个属性改变的时候得到通知了。


以上