Android Architecture Components架构下的高效开发

概述

Android Architecture Components是一系列库集合,能帮助你设计出健壮的,可测试的,可维护的应用。使用几个类,来管理UI组件的生命周期和处理数据持久化。

  • 管理app的生命周期很轻松。新的lifecycle-aware components组件,能帮助你管理activity/fragment的生命周期。保存配置更改,避免内存泄漏并轻松加载数据。

  • 使用LiveData构建数据对象,在底层数据库更改时通知视图。

  • ViewModel存储UI相关数据,这些数据不会在应用旋转中被销毁。

  • Room是一个SQLite对象映射库。使用它避免样板代码,并容易地将SQLite表数据转换为Java对象。提供SQLite语句的编译时检查,并可以返回RxJava,Flowable和LiveData可观察对象。

架构图

推荐使用官方架构,模块的交互方式如下:

Picture

生命周期感知组件

感知生命周期的组件执行动作,以响应其他组件(如Activity和Fragment)的生命周期状态的变化。这些组件有助于产生更好的组织性和更轻的重量代码,这更易于维护。

一种常见的模式是在Activity和Fragment的生命周期方法中实现依赖组件的动作。然而,这种模式导致代码的组织和错误扩散。通过使用生命周期感知组件,可以将依赖组件的代码从生命周期方法中移出并移入组件本身。

生命周期包提供了允许您构建生命周期感知组件的类和接口,这些组件可以根据Activity和Fragment的当前生命周期状态自动调整它们的行为。

Lifecycle-Aware Components,主要包含三个基本接口:

  • LifecycleOwner

interface LifecycleOwner {
getLifecycle();
}
在FragmentActivity和Fragment实现,返回Lifecycle对象,用来给外部管理生命周期状态。

  • Lifecycle

Lifecycle对象,能观察LifecycleObserver对象,并返回当前LifecycleOwner的生命周期状态(started,created)。

  • LifecycleObserver

实现LifecycleObserver的类,能通过注解的方式,接收到状态变化的通知。如:

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(LifecycleOwner lifecycleOwner) {
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume(LifecycleOwner lifecycleOwner) {
}

比如,ViewModel类实现了LifecycleObserver接口,在Activity里添加getLifecycle().addObserver(viewModel);
那ViewModel就有了生命周期感知功能。

在Android框架中定义的大多数应用程序组件都有生命周期。生命周期是由操作系统或运行在您的进程中的框架代码管理的。它们是Android工作的核心,你的应用程序必须尊重它们。不这样做可能触发内存泄漏或甚至应用崩溃。

想象一下,我们有一个Activity显示屏幕上的设备位置。一个常见的实现方式可能如下:

class MyActivity extends AppCompatActivity {

private MyLocationListener myLocationListener;

public void onCreate(...) {
    myLocationListener = new MyLocationListener(this, location -> {
        // update UI
    });
}

@Override
public void onStart() {
    super.onStart();
    Util.checkUserStatus(result -> {
        // what if this callback is invoked AFTER activity is stopped?
        if (result) {
            myLocationListener.start();
        }
    });
}

@Override
public void onStop() {
    super.onStop();
    myLocationListener.stop();
}
}

用了Lifecycle,还可以这样:

public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
    ...
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
    ...
}
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

是不是清晰很多。

LiveData

LiveData是一个可观测的数据保持类。与常规观察不同,LiveData是生命周期感知的,这意味着它尊重其他应用程序组件(如Activity、Fragment或Service)的生命周期。这种感知确保LiveData只更新处于活跃生命周期状态的应用程序组件观察者。

您可以注册一个与实现 LifecycleOwner 接口的对象配对的观察者。这种关系允许当相应 ([https://developer.android.google.cn/reference/android/arch/lifecycle/Lifecycle.html)[|](https://developer.android.google.cn/reference/android/arch/lifecycle/Lifecycle.html)[%7C)60d8d77e15b1b69c7a3cfbc6b952b9393 |]对象的状态改变为([https://developer.android.google.cn/reference/android/arch/lifecycle/Lifecycle.State.html#DESTROYED)[|](https://developer.android.google.cn/reference/android/arch/lifecycle/Lifecycle.State.html#DESTROYED)[|) 60d8d77e15b1b69c7a3cfbc6b952b9394 |]时观察者被移除。这对于Activity和Fragment尤其有用,因为它们可以安全地观察 ([https://developer.android.google.cn/reference/android/arch/lifecycle/LiveData.html)|[%7C)60d8d77e15b1b69c7a3cfbc6b952b9395 |]对象,而不用担心泄漏——当Activity或Fragment的生命周期被销毁时,它们会立即取消订阅。
有关如何使用LiveData的更多信息,请参见使用LiveData对象

使用LiveData的优势

  • 确保UI与数据状态匹配
    LiveData遵循观察者模式。当生命周期状态改变时,LiveData通知观察者对象。您可以合并代码来更新这些观察对象中的UI。每次应用程序数据更改时,都不更新UI,观察者可以每次更改时更新UI。

  • 没有内存泄漏
    观察者绑定到生命周期对象,并在其关联的生命周期被销毁后自行清理。

  • 停止Activity时的崩溃
    如果观察者的生命周期是不活动的,比如在后堆栈中的活动,那么它不接收任何LiveData事件。

  • 无需手动处理生命周期
    UI组件只是观察相关数据,不停止或恢复观察。LiveData自动管理所有这一切,因为它意识到相关的生命周期状态变化,同时观察。

  • 始终保持最新数据
    如果生命周期变得不活动,则在再次激活时接收最新数据。例如,后台中的Activity在返回到前台后立即接收最新数据。

  • 正确的配置改变
    如果由于配置改变而重新生成Activity或Fragment,例如设备旋转,则它立即接收最新可用数据。

  • 资源共享
    您可以使用Sigelon模式扩展LiveData对象来包装系统服务,以便它们可以在您的应用程序中共享。LiveData对象连接到系统服务一次,然后需要该资源的任何观察者都可以只观察LiveData对象。有关更多信息,请参见扩展LiveData

如何使用LiveData

按照以下步骤使用LiveData对象:

  • 创建一个LiveData实例来保存某种类型的数据。这通常是在ViewModel类中完成的。

  • 创建一个Observer对象,该对象定义onChanged()方法,该方法控制LiveData对象保存的数据更改时发生的情况。通常在UI控制器,例如Activity或Fragment中,创建一个Observer对象。

  • 使用 observe()60d8d77e15b1b69c7a3cfbc6b952b93910 |]方法传入([https://developer.android.google.cn/reference/android/arch/lifecycle/LifecycleOwner.html)|[%7C)60d8d77e15b1b69c7a3cfbc6b952b93911 |]对象。这将观察对象向LiveData对象订阅,以便通知其更改。通常将观察者对象附加在UI控制器中,例如Activity或Fragment。

  • 当更新LiveData对象中存储的值时,只要所附的LifecycleOwner处于活动状态,就会触发所有已注册的观察器。
    LiveData允许UI控制器观察员订阅更新。当LiveData对象保存的数据发生变化时,UI会自动响应更新。

创建LiveData

public class NameViewModel extends ViewModel {

// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;

public MutableLiveData<String> getCurrentName() {
    if (mCurrentName == null) {
        mCurrentName = new MutableLiveData<String>();
    }
    return mCurrentName;
}

// Rest of the ViewModel...
}

观察LiveData

public class NameActivity extends AppCompatActivity {

private NameViewModel mModel;

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

    // Other code to setup the activity...

    // Get the ViewModel.
    mModel = ViewModelProviders.of(this).get(NameViewModel.class);

    // Create the observer which updates the UI.
    final Observer<String> nameObserver = new Observer<String>() {
        @Override
        public void onChanged(@Nullable final String newName) {
            // Update the UI, in this case, a TextView.
            mNameTextView.setText(newName);
        }
    };

    // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
    mModel.getCurrentName().observe(this, nameObserver);
}
}

扩展LiveData

LiveData认为观察者必须在有效状态,无论是在STARTED或([https://developer.android.google.cn/reference/android/arch/lifecycle/Lifecycle.State.html#RESUMED)|[|) 60d8d77e15b1b69c7a3cfbc6b952b93914 |]状态,可以用来做全局数据共享,
下面的示例代码说明如何扩展LiveData类:

public class StockLiveData extends LiveData<BigDecimal> {
private StockManager mStockManager;

private SimplePriceListener mListener = new SimplePriceListener() {
    @Override
    public void onPriceChanged(BigDecimal price) {
        setValue(price);
    }
};

public StockLiveData(String symbol) {
    mStockManager = new StockManager(symbol);
}

@Override
protected void onActive() {
    mStockManager.requestPriceUpdates(mListener);
}

@Override
protected void onInactive() {
    mStockManager.removeUpdates(mListener);
}
}

多种场景下的使用

Activity/Fragment
最基本的UI场景,只需要在Activity/Fragment调用observe()方法关注LiveData数据,即可。
需要注意的是,使用Activity/Fragment都是LifecycleOwner对象,需要哪个LifecycleOwner就看业务需要。

ViewHolder
比如在RecyclerView的ViewHolder里面观察LiveData,因为ViewHolder有缓存机制,所以Observer跟item并不一对一。一般可以在初始化ViewHolder时,观察LiveData,然后接收到数据变更,则修改item数据,并重修刷新ui。这样才能做到兼容ViewHolder机制。

View/ViewGroup
如果View不涉及到销毁(重建)的情况,也不需要理会Observer,否则,也要管理Observer的观察和取消观察。

UI组件以外
UI组件以外,需要用到observeForever()方法,此方法没有生命周期感知,需要手动管理取消观察。

ViewModel管理LiveData和全局LiveData的区别
本质上没有不同,主要在于数据本身生命周期的需要和共享的需要。
比如ViewModel的LiveData会随着Activity/Fragment产生、共享和销毁,而全局的LiveData是跟随进程或手动管理的。

LiveData的创建场景和观察场景
LiveData能在任何地方,任何情况创建。
观察场景可以在UI组件使用observe()/observeForever()方法,或其他非UI场景只能用observeForever()方法。

附言
以上为个人的经验总结,不当之处欢迎讨论,并持续优化。

image

image

+qq群:853967238。获取以上高清技术思维图,以及相关技术的免费视频学习资料

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

推荐阅读更多精彩内容