美文网首页Android开发经验谈
Android Architecture Components

Android Architecture Components

作者: 展翅而飞 | 来源:发表于2018-05-29 14:40 被阅读6次

    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。

    未命名_meitu_0.jpg

    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。

    总结

    可以用

    相关文章

      网友评论

      • ManningZhang:默认的我都不会 kotlin还看不懂 我还是不要搞Android了

      本文标题:Android Architecture Components

      本文链接:https://www.haomeiwen.com/subject/ugqbjftx.html