1、概述
打开 Google Android Developer 官网,你会看到,给你展示的是这个Android架构组件,可见这个架构组件是官方比较推荐使用的组件,且现在已经是1.0稳定版。
说到Android应用的架构,百家争鸣,各有各的思路,由比较认可的MVC,到后来发展的MVP、MVVM。这些架构都非常不错,但对于Android这个系统来说,似乎总有点不够完美。比较通俗的理解这些架构,就是代码应该写在哪里,以达到 高内聚,低耦合的目的。
Google推出的Android架构组件 Android Architecture Components,就真的是从Android系统出发,个人感觉比较惊艳的是可以让数据具有感知生命周期的能力。我们在写代码的时候,应该多考虑下生命周期的问题,比如一个变量的生命周期,一个页面 Activity/Fragment 的生命周期,一个线程 Thread 的生命周期,一个服务 Service 的生命周期等等。当在开发一个功能模块的过程中,这些生命周期如果没有协同的工作,就会引起一系列的问题,比如内存泄漏、应用崩溃、资源浪费、响应卡顿等等。通常做Android的应用开发面对这样的问题,总得需要做很多操作来避免以上问题,而现在通过Google官方提供的架构组件就可以轻松解决这样的问题。
Android Architecture Components,这是一个帮助构建稳定,易于测试和易于维护的App架构的库。
下面分别介绍下该组件所提供的几个库
- Lifecycle
提供的类和接口,便于我们构建能够感知生命周期的能力的类。能够根据 Activity/Fragment 的生命周期响应相应的状态、生命周期事件。
- LiveData
通过观察者模式,持有的数据可以被观察响应事件,另外还具备感知生命周期的能力。可以在 Activity/Fragment 活跃状态时响应观察者事件,在页面销毁时也会被移除观察者。
- ViewModel
ViewModel 用于存储和处理 UI 相关的数据,是连接数据和 UI 的层。在数据缓存方面非常出色,也不会因为系统配置(屏幕旋转、系统回收组件)发生变化而需要重新初始化数据。
- Room
是基于 SQLite 的一个 ORM 库。使得数据持久化非常方便。对比与 Ormlite、GreenDao 等有了 Google 官方支持的优势。通过 Room 对数据的持久化,大大改善用户在 App 离线场景的使用体验。
2、如何使用
首先引入 android.arch.lifecycle 相关的包
implementation "android.arch.lifecycle:runtime:1.0.3"
implementation "android.arch.lifecycle:extensions:1.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
本文介绍的是使用了 ViewModel + LiveData 重构了以前一个基于MVP架构的小项目 News,使用了聚合数据 提供的 头条新闻 接口获取新闻数据。
先看看目录结构
这里有一个 NewsViewModel 类继承于 ViewModel,里面有一个持有新闻列表 NewsList 的 LiveData,网络请求是用了 OkHttp + Retrofit 。
/**
* 新闻类
* Created by lex on 2018/1/1.
*/
public class NewsViewModel extends ViewModel {
private static final String TAG = NewsViewModel.class.getSimpleName();
private MutableLiveData> newsLiveData;
public LiveData> getNewsLiveData() {
if (newsLiveData == null) {
newsLiveData = new MutableLiveData<>();
}
remoteGetNews();
return newsLiveData;
}
/**
* 远程获取消息列表
*/
private void remoteGetNews() {
// 1、初始化Retrofit,得到INews动态代理对象
INews service = NetworkService.getInstance().getRetrofit().create(INews.class);
// 2、动态代理,生成OkHttpCall
Call newsCall = service.getNews(Url.TYPE_TOP, Url.APPKEY);
Log.i(TAG, "start to send network message");
// 3、利用OkHttp执行网络请求
newsCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response == null || response.body() == null || response.body().result == null) return;
newsLiveData.postValue(response.body().result.data);
Log.i(TAG, "return: " + response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
if (t == null) return;
Log.e(TAG, "failed: " + t.toString());
}
});
}
然后在UI层(Activity/Fragment)对 LiveData 持有的数据进行观察
public class HomeFragment extends BaseFragment {
private static final String TAG = HomeFragment.class.getSimpleName();
@BindView(R.id.recycler_news)
RecyclerView recyclerNews;
private BaseAdapter mAdapter;
@Override
protected int getLayoutId() {
return R.layout.content_home;
}
/**
* 初始化view
*/
@Override
protected void initView() {
mAdapter = new NewsAdapter();
recyclerNews.setAdapter(mAdapter);
recyclerNews.setLayoutManager(new LinearLayoutManager(getActivity()));
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
NewsViewModel newsViewModel = ViewModelProviders.of(this).get(NewsViewModel.class);
newsViewModel.getNewsLiveData().observe(this, new Observer>() {
@Override
public void onChanged(@Nullable List news) {
mAdapter.refreshData(news);
}
});
}
}
3、这样做的好处
- 代码简洁
保持UI(Activity/Fragment)中的代码足够简洁。不需要写业务逻辑相关的代码,数据跟UI完全分离。
- 避免内存泄漏或者应用崩溃
通过观察者模式,被绑定到组件的生命周期上,也会随着被绑定的组件的销毁而注销观察者。
- 实时数据刷新问题
当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据且不需要重新加载网络数据库。
- 解决屏幕旋转 Configuration Change 问题
在屏幕发生旋转或者被回收,再次启动时,立刻就能收到最新的数据且不需要重新加载网络数据库。
4、原理
看到 appcompat-v7:26.1.0 中的 Activity/Fragment 中已经实现了 LifecycleOwner 接口
/**
* A class that has an Android lifecycle. These events can be used by custom components to
* handle lifecycle changes without implementing any code inside the Activity or the Fragment.
*
* @see Lifecycle
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
@NonNull
Lifecycle getLifecycle();
}
看看 Activity/Fragment 对这个方法的实现
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
这个LifecycleRegistry 是什么呢?
public class LifecycleRegistry extends Lifecycle {
public LifecycleRegistry(@NonNull LifecycleOwner provider) {
mLifecycleOwner = new WeakReference<>(provider);
mState = INITIALIZED;
}
}
实现对 LifecycleOwner 也就是 Activity/Fragment 进行注册、注销、状态管理、生命周期事件的发送。
再看看 Lifecycle
public abstract class Lifecycle {
public abstract void addObserver(@NonNull LifecycleObserver observer);
public abstract void removeObserver(@NonNull LifecycleObserver observer);
public abstract State getCurrentState();
public enum Event {
ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY
}
public enum State {
DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
}
这是一个抽象类,拥有着跟 Activity/Fragment 生命周期相关的 Event 事件,State 状态。实现对 LifecycleObserver 的注册与注销。可见这是一个通过观察者模式来响应 Activity/Fragment 的生命周期,使得相关的类具有感知生命周期的能力。具体实现可以详细阅读下源码。
5、Lifecycle 与 Room
这是只是使用了 ViewModel + LiveData 解决了一些生命周期相关的问题。另外还有比如 Lifecycle ,也能够给数据赋予生命周期的能力,为什么不使用 LiveData 来做?在官方 Lifecycle 文档中有个定位的Demo,因为考虑到需要取消定位的需求,使用 Lifecycle 就更合适,所以 LifeCycle 比较适用于能感知生命周期,且在生命周期前后需要做处理的场景。Room 使得对数据的持久化更轻松,这是针对原生 SQLite 的一个 ORM 框架,使用起来也比较简单。
6、总结
当这 Lifecycle + LiveData + ViewModel + Room 四者结合起来使用,开发Android应用程序如虎添翼。当再结合使用 DataBinding、RxJava、Dragger、ButterKnife 等这些优秀的开源库的话,那么Android App的架构也变得越来越强大了。
Demo源码已上传至 GitHub