很赞的Android架构组件 Android Architecture Components

1、概述

打开 Google Android Developer 官网,你会看到,给你展示的是这个Android架构组件,可见这个架构组件是官方比较推荐使用的组件,且现在已经是1.0稳定版。

1.png

说到Android应用的架构,百家争鸣,各有各的思路,由比较认可的MVC,到后来发展的MVP、MVVM。这些架构都非常不错,但对于Android这个系统来说,似乎总有点不够完美。比较通俗的理解这些架构,就是代码应该写在哪里,以达到高内聚,低耦合的目的。

Google推出的Android架构组件 Android Architecture Components,就真的是从Android系统出发,个人感觉比较惊艳的是可以让数据具有感知生命周期的能力。我们在写代码的时候,应该多考虑下生命周期的问题,比如一个变量的生命周期,一个页面 Activity/Fragment 的生命周期,一个线程 Thread 的生命周期,一个服务 Service 的生命周期等等。当在开发一个功能模块的过程中,这些生命周期如果没有协同的工作,就会引起一系列的问题,比如内存泄漏、应用崩溃、资源浪费、响应卡顿等等。通常做Android的应用开发面对这样的问题,总得需要做很多操作来避免以上问题,而现在通过Google官方提供的架构组件就可以轻松解决这样的问题。

Android Architecture Components,这是一个帮助构建稳定,易于测试和易于维护的App架构的库。

imgac_architecture.png

下面分别介绍下该组件所提供的几个库

2.png
  • 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,使用了聚合数据 提供的 头条新闻 接口获取新闻数据。

1514799795538.jpg

先看看目录结构


1514795179283.jpg

这里有一个 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<List<News>> newsLiveData;

    public LiveData<List<News>> 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<WebResponse> newsCall = service.getNews(Url.TYPE_TOP, Url.APPKEY);

        Log.i(TAG, "start to send network message");

        // 3、利用OkHttp执行网络请求
        newsCall.enqueue(new Callback<WebResponse>() {
            @Override
            public void onResponse(Call<WebResponse> call, Response<WebResponse> 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<WebResponse> 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<List<News>>() {
            @Override
            public void onChanged(@Nullable List<News> 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();
}
1514796897495.jpg
1514789083458.jpg

看看 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容