Android Architecture Components

Android Architecture Components是Google为开发者提供的架构设计方案,里面包含若干内容:

  • Lifecycle
  • ViewModel
  • LiveData
  • Room
  • Paging

具体介绍和教程见官网,暂时项目用得上是前三个,重点吹吹ViewModel和LiveData。Room是官方提供的对SQLite的抽象,知道它的存在就好,没有找到取代greenDAO或者realm的理由。Paging支持对RecyclerView分页加载,可以期待,但现在版本还是1.0.0rc,先放一边。

现在最新的版本:android.arch.lifecycle:extensions:1.1.1

Lifecycle

向上找Activity的父类,在SupportActivity里实现了LifecycleOwner,里面只有一个方法getLifecycle。(某个版本api添加的哈,人懒没有去查是几)

在onCreate可以将Activity的生命周期委托给LifecycleObserver:

lifecycle.addObserver(MyLifecycleObserver())

LifecycleObserver是一个接口,我们使用@OnLifecycleEvent绑定生命周期和具体的函数。除了ON_CREATE等基本的,还添加了ON_ANY。

class MyLifecycleObserver : LifecycleObserver {
    companion object {
        val LIFECYCLE_TAG = TAG + "lifecycle"
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        LogUtils.d("$LIFECYCLE_TAG-onCreate")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        LogUtils.d("$LIFECYCLE_TAG-onStart")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    fun onAny() {
        //LogUtils.d("$LIFECYCLE_TAG-onAny")
    }
}

使用Lifecycle好处显而易见,Activity生命周期的函数不用散落到各处,可以统一在一个地方处理好。

ViewModel和LiveData

ViewModel就是MVVM模式中的VM,默认你认识MVVM和databinding,写个demo。

photo

Activity里有两个Fragment(红色是Fragment1、蓝色是Fragment2),通过“上一页”、“下一页”切换。有一个持久化的user对象,包括“name”和“age”两个属性,点击按钮“更新user”,变更user对象的属性并显示在两个Fragment中。

功能很简单,但是需要处理常见的Fragment间通信。假如使用MVP模式,每个Fragment对应一个Presenter。两个Fragment之间的通信,要不使用Activity传递参数,要不使用RxBus之类的事件总线,ViewModel提供更简单的方法。

首先介绍LiveData,可以包装任意类型的对象,它有三个特点:

  • 供观察者订阅
  • 感知组件(Activity、Fragment、Service)生命周期
  • 提供活跃状态,活跃的才通知观察者

在ViewModel自定义一个init函数,创建User对象的LiveData:

private lateinit var userData: LiveData<User>

fun init() {
    val user = createUser()
    this.userData = userRepository.getUser(user.userId)
}

userRepository是M层的对象,我这里使用了ROOM,它可以直接返回对象的LiveData。如果是其他持久化库,返回的user对象可以手动setValue进MutableLiveData。MutableLiveData是LiveData的子类,可以修改值,还有一个子类MediatorLiveData,可以观测一个或多个LiveData的变化,用到再说了。

更新值有两个方法,一个是postValue,一个是setValue。前者可以在任意线程,后者只能在主线程。


在Activity里获取ViewModel:

val viewModel = ViewModelProviders.of(this).get(PersonalDetailViewModel::class.java)

在Fragment里获取ViewModel:

val viewModel = ViewModelProviders.of(activity!!).get(PersonalDetailViewModel::class.java)

两者非常相似,要注意of函数传入的参数,无论是Activity还是Fragment,都是传入activity对象,这样保证它们获取同一个ViewModel。(Activity里有个Map保存ViewModel)


viewModel.getUserData().observe(this, Observer<User> { user ->
    user?.let {
        tv_name.text = user.name
        tv_age.text = user.age.toString()
    }
})

在Fragment2中通过observe订阅LiveData变化,当Fragment1修改User属性,Fragment2触发Observer的onChanged函数,我们对应修改ui显示。只要订阅了LiveData,任意地方都可以即时知道。

既然有订阅观察,为什么没有写对应的解绑订阅?这就是LiveData的第二个特点,注意到observe传入的参数是LifecycleOwner,它是可以感知组件的生命周期。当生命周期是DESTORY时,自动解绑订阅,具体后面分析源码就知道了。

也有另外一个observeForever函数,不需要传入LifecycleOwner,但是需要手动使用remove,和普通的观察者模式一样。

还有第三个特点,活跃状态。这个很好理解,组件处于某些状态时,才通知观察者变化。

LiveData源码分析

知其然知其所以然,顺手看看ViewModel和LiveData的实现方式。

LiveData是典型的观察者模式,使用自定义的SafeIterableMap保存所有观察者。

private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

键值对类型<Observer<T>, ObserverWrapper>,Observer是观察者对象,ObserverWrapper是什么东西,观察者的包装类?

private abstract class ObserverWrapper {
    final Observer<T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    //...
}

果然ObserverWrapper包装了Observer,增加了active和version。LifecycleBoundObserver是ObserverWrapper的抽象实现类,包含了生命周期LifecycleOwner。他们的联系很清楚了,对Observer的管理叠加了生命周期,看LifecycleBoundObserver其中两个函数:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull final LifecycleOwner mOwner;

    //...

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }

    //...
}

当生命周期变为DESTROYED时,自动移除观察者,实现上节所讲感知组件生命周期。当组件处于活跃时,观察才是有效的,这里需要生命周期至少是STARTED。最后调用ObserverWrapper.activeStateChanged处理生命周期变化。

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        onInactive();
    }
    if (mActive) {
        dispatchingValue(this);
    }
}

onActive和onInactive是两个空函数,可以让LiveData的子类额外处理活跃变化。处于活跃时,调用dispatchingValue通知观察者。具体的通知过程路过,不外乎是循环所有观察者,根据条件调用onChange函数。

最后看回LiveData的订阅函数observe,有了上面的分析,都不用讲了。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    owner.getLifecycle().addObserver(wrapper);
}

ViewModel源码分析

ViewModel是一个抽象类,里面只有一个clear函数,需要时可以重写做些清理。

public abstract class ViewModel {
    protected void onCleared() {
    }
}

使用ViewModel的入口函数在ViewModelProviders,核心是函数of,区分入参Fragment和Activity两个版本。

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
    Application application = checkApplication(checkActivity(fragment));
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}

of返回的对象是ViewModelProvider,和ViewModelProviders差了个s。

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    this.mViewModelStore = store;
}

创建ViewModelProvider需要两个对象:

  • ViewModelStore
  • Factory
Factory
public interface Factory {
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

Factory接口,只有一个函数create,传入class,创建ViewModel。AndroidViewModelFactory是它的实现类:

//AndroidViewModelFactory
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
        //noinspection TryWithIdenticalCatches
        try {
            return modelClass.getConstructor(Application.class).newInstance(mApplication);
        } 
       //catch...
    }
    return super.create(modelClass);
}

通过isAssignableFrom判断class类型是不是AndroidViewModel,是的话创建带Application实例的AndroidViewModel。不是的话,创建工作交给父类NewInstanceFactory,对应的create函数创建无参构造函数的普通ViewModel。

//NewInstanceFactory
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    //noinspection TryWithIdenticalCatches
    try {
        return modelClass.newInstance();
    } 
    //catch...
}
ViewModelStore
private final HashMap<String, ViewModel> mMap = new HashMap<>();

ViewModelStore很简单,里面有一个HashMap,保存key和ViewModel。很明显它是ViewModel的缓存,可以使用get和put操作。

@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
    if (activity instanceof ViewModelStoreOwner) {
        return ((ViewModelStoreOwner) activity).getViewModelStore();
    }
    return holderFragmentFor(activity).getViewModelStore();
}

ViewModelStore通过调用ViewModelStores.of获取,有两种获取来源:

  • 第一种,ViewModelStore对象保存在Activity和Fragment,它们都实现了ViewModelStoreOwner接口。因此,可以很轻松在Activity或Fragment得到我们需要的ViewModel对象。
  • 第二种,ViewModelStoreOwner接口是某个时候加入Activity的,如果之前的没有实现接口又怎样办?

大神们弄了个HolderFragment承载ViewModelStore:

HolderFragment holderFragmentFor(FragmentActivity activity) {
    FragmentManager fm = activity.getSupportFragmentManager();
    HolderFragment holder = findHolderFragment(fm);
    if (holder != null) {
        return holder;
    }
    holder = mNotCommittedActivityHolders.get(activity);
    if (holder != null) {
        return holder;
    }

    if (!mActivityCallbacksIsAdded) {
        mActivityCallbacksIsAdded = true;
        activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
    }
    holder = createHolderFragment(fm);
    mNotCommittedActivityHolders.put(activity, holder);
    return holder;
}

就是这个方法createHolderFragment,动态将HolderFragment添加进Activity,然后就可以获取ViewModelStore了。

private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
    HolderFragment holder = new HolderFragment();
    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
    return holder;
}

Fragment里添加HolderFragment类似,用的是ChildFragmentManager。

ViewModelProvider.get()

最后一步,从ViewModelProvider获取ViewModel的get函数:

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        //noinspection unchecked
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }

    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    //noinspection unchecked
    return (T) viewModel;
}

ViewModel存在于ViewModelStore时直接获取,否则创建并加入ViewModelStore,key的构成是固定字符串加上类的canonicalName。

总结

可以用

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

推荐阅读更多精彩内容