zoukankan      html  css  js  c++  java
  • Android Jetpack组件

    本文涉及的源码版本如下:

    • com.android.support:appcompat-v7:27.1.1
    • android.arch.lifecycle:extensions:1.1.1
    • android.arch.lifecycle:viewmodel:1.1.1
    • android.arch.lifecycle:livedata:1.1.1

    什么是ViewModel, 以及工作原理

    ViewModel用于存储和管理UI相关的数据,ViewModel有自己生命周期,会根据fragment,activity的生命周期销毁。当配置发生改变时, ViewModel存储的数据还是存在的,不会被销毁。(例如旋转屏幕,旋转屏幕通常会导致activity重建)

    ViewModel 相关类结构


    ViewModel:抽象类,onCleared方法用于释放资源

    AndroidViewModel: 继承了ViewModel, 没什么区别, 构造可以传入一个application

    ViewModelStore: ViewModel存储器, 内部Map存储

    ViewModelStoreOwner: 一个接口, ViewModelStore拥有者。 Fragment和FragmentActivity实现了接口

    Factory: 一个工厂接口,用于创建ViewModel。是ViewModelProvider的内部接口

    NewInstanceFactory: 继承Factory, 通过反射class.newInstance()产生一个ViewModel。所以使用这个Factory,ViewModel需要有空参构造器。

    AndroidViewModelFactory: 继承Factory, 也是通过反射产生一个AndroidViewModel, 而且这个AndroidViewModel构造器必须只有一个application参数, 如何反射创建失败会调用NewInstanceFactory去创建。

    ViewModelProvider: 是一个帮助类,构造器可以传入ViewModelStore和Factory, 会根据Factory产生一个ViewModel, 并存储到ViewModelStore里。

    ViewModel的生命周期

    ViewModel的生命周期是跟fragment, activity生命周期关联的。只有fragment, activity销毁时才会调用ViewModel.onCleared() (配置改成导致销毁,不会调用onCleared)

    ViewModel存储在ViewModelStore, ViewModel的onCleared方法在ViewModelStore的clear方法时被调用, ViewModelStore源码如下:

    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    /**
         *  Clears internal storage and notifies ViewModels that they are no longer used.
         */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
    复制代码

    下面看看Fragment, 和FragmentActivity的实现,先看Fragment的实现:

    public ViewModelStore getViewModelStore() {
        if (getContext() == null) {
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        // new一个ViewModelStore, 一个Fragment只有一个ViewModelStore
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
        return mViewModelStore;
    }
    
    public void onDestroy() {
        mCalled = true;
        // Use mStateSaved instead of isStateSaved() since we're past onStop()
        if (mViewModelStore != null && !mHost.mFragmentManager.mStateSaved) {
            mViewModelStore.clear(); // mStateSaved用于判读是否由于配置改变导致Fragment重建
        }
    }
    复制代码

    再看FragmentActivity的实现

        public ViewModelStore getViewModelStore() {
            if (getApplication() == null) {
                throw new IllegalStateException("Your activity is not yet attached to the "
                        + "Application instance. You can't request ViewModel before onCreate call.");
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
            return mViewModelStore;
        }
    
        protected void onDestroy() {
            super.onDestroy();
    		....
            if (mViewModelStore != null && !mRetaining) { 
                // mRetaining用于判读是否由于配置改变导致Fragment重建
                mViewModelStore.clear();
            }
        }
    复制代码

    ViewModel存储的数据不会在配置改变时而销毁, ViewModel是怎样保存的呢,看前面的分析在Fragment, FragmentActivity都有一个mViewModelStore的成员变量,只要保存好这个mViewModelStore这个就可以啦。当配置改变时,在onSaveInstanceState里保存数据,然后在onRestoreInstanceState恢复数据,但是这两个方法存储数据只能放在Bundle, 只能存小量数据, 过大会抛TransactionTooLargeException异常。所以不合适,看源码发现是利用Activity的onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()。

       // FragmentActivity关键代码
    	public final Object onRetainNonConfigurationInstance() {
            Object custom = onRetainCustomNonConfigurationInstance();
            // 这方法继承自Activty, 且把方法定义成final,不让子类实现,但是提供onRetainCustomNonConfigurationInstance方法
            FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
            //fragments是当前activity所有fragment需要保存的数据
            if (fragments == null && mViewModelStore == null && custom == null) {
                return null;
            }
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = mViewModelStore;
            nci.fragments = fragments;
            // mViewModelStore 和 fragments 就存在NonConfigurationInstances里
            return nci;
        }
    
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            ...
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            // 调用getLastNonConfigurationInstance方法获取NonConfigurationInstances恢复数据
            if (nc != null) {
                mViewModelStore = nc.viewModelStore;
            }
            if (savedInstanceState != null) {
                Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
                mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
                //nc.fragments通过mFragments.restoreAllState()恢复
            }    
            ...
        }    
    复制代码

    这里onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法就不深入啦,配置改变时还想保存一些自定义object数据可以重写onRetainCustomNonConfigurationInstance去实现。那Fragment的mViewModelStore呢,就是mFragments.retainNestedNonConfig() 和 mFragments.restoreAllState() 这两个方法啦。 mFragments是FragmentController实例,最后是调用到FragmentManager, 而FragmentManager真正实现是FragmentManagerImpl。下面截取部分FragmentManagerImpl的关键代码。

    // 这个方法就Activity里mFragments.retainNestedNonConfig()最终调用的方法
    FragmentManagerNonConfig retainNonConfig() {
        setRetaining(mSavedNonConfig); // 由于篇幅的原因, 这个方法本文不展开了
        return mSavedNonConfig;
    }
    //来看mSavedNonConfig这个实例是在哪里创建的,回到FragmentActivity.onSaveInstanceState方法里发现调用mFragments.saveAllState()保存状态,最终来到FragmentManagerImpl的saveAllState()
    Parcelable saveAllState() {
        mSavedNonConfig = null;
        saveNonConfig();
    }    
    
    void saveNonConfig() {
        ArrayList<Fragment> fragments = null;
        ArrayList<FragmentManagerNonConfig> childFragments = null;
        ArrayList<ViewModelStore> viewModelStores = null;
        if (mActive != null) {
            //mActive是SparseArray<Fragment>, 代表fragment栈, 遍历mActive, 
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.valueAt(i);
                if (f != null) {
                    ...
                    if (viewModelStores != null) {
                         // 把fragment的成员变量mViewModelStore添加到list中
                        viewModelStores.add(f.mViewModelStore);
                    }
                }
            }
        }
        if (fragments == null && childFragments == null && viewModelStores == null) {
            mSavedNonConfig = null;
        } else {
            //viewModelStores存储到FragmentManagerNonConfig里
            mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments,
                                                           viewModelStores);
        }
    }
    //mFragments.restoreAllState() 最终调用FragmentManagerImpl的restoreAllState()
    void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
        if (state == null) return;
        FragmentManagerState fms = (FragmentManagerState)state;
        //fms是保存状态时存储在Parcelable的,现在拿出来恢复状态
        if (fms.mActive == null) return; 
        //这里有很多种情况,这里大概分析常见的恢复过程
        ...
        mActive = new SparseArray<>(fms.mActive.length);
        //遍历FragmentState
        for (int i=0; i<fms.mActive.length; i++) { 
            FragmentState fs = fms.mActive[i];
            if (fs != null) {
                ...
                ViewModelStore viewModelStore = null;
                if (viewModelStores != null && i < viewModelStores.size()) {
                    viewModelStore = viewModelStores.get(i);
                }
                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig,
                                            viewModelStore);
                // 传入viewModelStore, 调用instantiate方法重新生成Fragment
                if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                mActive.put(f.mIndex, f);
            }
        }
    } 
    复制代码

    什么是LiveData, 以及工作原理

    LiveData是一个可观察数据的持有者, 但是不像普通的可观察数据, LiveData是绑定了生命周期,例如activitie, fragment的生命周期。有点抽象, 还是先了解一下关键的类。

    //Observer是一个接口,观察者。当数据改变时就回调onChanged
    public interface Observer<T> {
        void onChanged(@Nullable T t);
    }
    
    //LiveData类是个抽象类,这里先看看有什么暴露出去的方法
    public abstract class LiveData<T> {
        //添加观察者观察, 传入LifecycleOwner,用于来绑定生命周期
        public void observe(LifecycleOwner owner, Observer<T> observer)
        //添加观察者观察, 但是是没有LifecycleOwner
        public void observeForever(Observer<T> observer) 
        //移除观察者   
        public void removeObserver(Observer<T> observer) 
        //移除某个LifecycleOwner里所有的观察者    
        public void removeObservers(final LifecycleOwner owner)
        //是否有观察者    
        public boolean hasObservers()    
        //是否有活的观察者    
        public boolean hasActiveObservers()
    }    
    //MutableLiveData继承LiveData, 多开放2个方法。
    public class MutableLiveData<T> extends LiveData<T> {
        public void postValue(T value) //post一个数据 
        public void setValue(T value)  //设置一个数据
        //postValue和setValue的区别是:post可以在子线程用,而setValue只能在UI线程调用
    }
    复制代码

    介绍完了主要的类,下面举个例子:

    // 这段代码通常在Activity或者Fragment中, 用liveData去添加一个观察者
    // AppCompatActivity或者Fragment已经LifecycleOwner,通常传this即可
    // 当User数据有变化时,onChanged方法会被调用, 用于更新UI
    liveData.observe(this, new Observer<User>() {
        @Override
        public void onChanged(@Nullable User user) {
        	//更新UI
        }
    });
    
    //下面这段代码通常在ViewModel中,这里liveData和上面代码的liveData是同一个
    //可以通过postValue或者setValue去改成user数据, 有数据改变时, onChanged方法会被回调
    //假如一个场景, 在ViewModel中,通过网络请求去拿user数据,然后postValue就会去通知UI层onChanged去更新UI
    //liveData大概就是这个流程
    liveData = new MutableLiveData<User>()
    liveData.postValue(user)// 或者setValue(user)
    复制代码

    下面还是看看LiveData源码去了解一下原理

    LiveData工作原理

    这里以observe(LifecycleOwner owner, Observer observer) 和 postValue之间数据的通讯为例分析。对LifecycleOwner不熟悉的可以看我的上一篇文章:LifecycleOwner, 下面看LiveData.observe源码:

    
    	@MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            //判断当前生命周期是DESTROYED, 立马return, 都销毁了,添加观察者没意义
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                // ignore
                return;
            }
            
            
            LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
            ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
            //LifecycleBoundObserver继承ObserverWrapper, LifecycleBoundObserver实现LifecycleOwner
            //mObservers这是一个Map, key是observer, value是ObserverWrapper
            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);
        }
    复制代码

    接着看LifecycleBoundObserver和ObserverWrapper片段:

        class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
            @NonNull final LifecycleOwner mOwner;
            
            @Override
            boolean shouldBeActive() {
                //至少是STARTED状态
                return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
            }
    
            //GenericLifecycleObserver继承自LifecycleObserver, 当生命周期改变时onStateChanged会被回调
            @Override
            public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
                //生命周期处于DESTROYED时, 移除观察者,mObserver是livedata.observe时传进来
                if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                    removeObserver(mObserver);
                    return;
                }
                //shouldBeActive()方法实现在当前类, 调用isAtLeast(STARTED), 至少是STARTED状态才是true
                //就是生命周期在STARTED和RESUME状态时, 才是true
                //接着调用了父类的activeStateChanged
                activeStateChanged(shouldBeActive());
            }
        }
    
        private abstract class ObserverWrapper {
            
            void activeStateChanged(boolean newActive) {
                // mActive状态相同立即返回
                if (newActive == mActive) {
                    return;
                }
                // immediately set active state, so we'd never dispatch anything to inactive
                // owner
                mActive = newActive;
                //就是生命周期在STARTED和RESUME时, mActive为true, 其他为false
                boolean wasInactive = LiveData.this.mActiveCount == 0;
                LiveData.this.mActiveCount += mActive ? 1 : -1;
                //当mActive=true时, mActiveCount会加1, 当mActive=false时, mActiveCount会减1。
                //这里为什么要加1和减1呢,结合Activity生命周期去考虑,当Activity.onCreate -> Activity.onStart -> Activity.onResume, State由CREATED->STARTED->RESUMED,这个过程当到STARTED时mActive为true,mActiveCount加1后为1, 接着RESUMED, mActive还是true, 这方法第一句(newActive == mActive)条件成立直接return, mActiveCount此时还是1。
                //当Activity.onResume->Activity.onPause->Activity.onStop,State由RESUMED->STARTED->CREATED, Activity.onStop后State为CREATED, isAtLeast(STARTED)就为false, 此时mActive=false, mActiveCount减1,mActiveCount为0啦。
                //当Activity.onStop->Activity.onStart->Activity.onResume, State由CREATED->STARTED->RESUMED, mActive为true,mActiveCount加1后为1, mActiveCount此时为1。
                if (wasInactive && mActive) {
                    //根据上面一大段分析后,onActive会在Activity首次显示UI调用,从后台返回或者从另一个Activity回退后又调用一次。(打开透明Activity不走onStop,这种情况除外)
                    onActive();
                }
                if (LiveData.this.mActiveCount == 0 && !mActive) {
                    // Activity.onStop后调用
                    onInactive();
                }
                if (mActive) {
                    //分发数据, 跟踪dispatchingValue方法,会到LiveData.considerNotify方法
                    dispatchingValue(this);
                }
            }
        }
    
        private void considerNotify(ObserverWrapper observer) {
            if (!observer.mActive) { 
                //mActive可以知道是否处于onStop状态, 是Stop状态就不要分发数据
                return;
            }
            if (!observer.shouldBeActive()) {
                //shouldBeActive()再次检查是否observer活着
                //ObserverWrapper的实现类不止LifecycleBoundObserver, 这里暂时没看懂为什么再次检查
                observer.activeStateChanged(false);
                return;
            }
            if (observer.mLastVersion >= mVersion) {
                //mVersion会在调用postValue()或者setValue()处+1
                return;
            }
            observer.mLastVersion = mVersion;
            observer.mObserver.onChanged((T) mData);
            调用onChanged分发改变的数据
        }
    复制代码

    接着看postValue方法是是如果把值传到onChanged里:

     
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) { 
            // 一开始看到这里有点疑问,1. 为什么加锁, 1. 为什么要一个NOT_SET变量(NOT_SET是一个Obj对象)
            // 先带着疑问往下看
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) { // 先往下看,和加锁问题一起解释
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
        // mPostValueRunnable运行在主线程
    }
    
    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {  //加锁, 和postValue里的锁是一样的
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };  
    
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++; // 版本号加1,保证mVersion>mLastVersion
        mData = value; // 赋值给mData, 数据会分发到mObserver.onChanged
        dispatchingValue(null);
        
        //到这里很清晰啦,现在回头看看postValue和mPostValueRunnable里的锁,和NOT_SET的作用
        //1. postValue方法可能会被很多条线程调用
        //2. mPostValueRunnable异步运行在主线程, 主线程是串联执行的,一次执行一个runnable
        //3. 不加锁很明显不行, 多线程调用时, value从postValue方法赋值给mPendingData, 
        //在mPostValueRunnable主线程里把mPendingData赋值给mData, 
        //mPendingData和mData都是指向同一个对象, mData在主线程都是指向了最新的对象。
        //在主线程队列的里mPostValueRunnable每次运行都是拿了最新的数据,有点多余
        //4. 假如去掉NOT_SET, value从postValue方法赋值给mPendingData, 
        // 再到setValue的mData, mPendingData和mData都是指向同一个对象,
        // 虽然加了锁也没用。但有了NOT_SET就不同啦, mPendingData地址给mData,NOT_SET地址给mPendingData, 
        // 在postValue方法的子线程里新进来的value地址又赋值给mPendingData。
        //5.看回postValue方法里 if (!postTask) { return } 这个地方,
        // 假如A线程调用了postValue, 把value赋值给mPendingData并释放了锁, 
        // 把A.mPostValueRunnable放到主线程的Message中, 
        // 但这时之前的B.mPostValueRunnable还没运行完,运行到setValue方法,也没有持有锁。
        // 这时B线程也调用了postValue, 这时A.mPostValueRunnable还没运行,没有把mPendingData=NOT_SET,
        // B线程postTask就为false了, 接着又把value赋值给mPendingData, 接着就直接return。
        // 等A.mPostValueRunnable运行时, mPendingData又被B线程更新啦。
        // if (!postTask) { return } 这个判断能减少主线程没必要mPostValueRunnable运行, 
        // 而且能更新到最新的数据。
        
    }
    
    private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        // initiator是null , 下面是遍历mObservers存储ObserverWrapper通知所有观察者
        ...
        for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
             mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
            considerNotify(iterator.next().getValue()); 
            // considerNotify前面分析过了,看回LiveData.observe的过程, 最终分发数据Observer.onChanged
        }
    }
    复制代码

    ViewModel和LiveData结合使用

    先说说使用ViewModel和LiveData时注意事项:

    • ViewModel不要持有生命周期的对象,例如activity, fragment。最好context也不要持有
    • 可以使用AndroidViewModel具有application对象
    • activity, fragment不要拥有LiveData对象,LiveData最好保存在ViewModel里,ViewModel不会由于配置改变而销毁
    • activity, fragment也不要拥有数据对象,在Observer.onChange更新UI时,不要把数据存在activity, fragment中
    public class UserActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...
            findViewById(R.id.btn_logout).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mViewModel.onLogout(); // 点击按钮退出登录
                }
            });
            mViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
            //ViewModelProviders是一个工具类,默认包含AndroidViewModelFactory把UserViewModel.class通过反射创建ViewModel并存储在Activity中
            mViewModel.getUserLiveData().observe(this, new Observer<User>() {
                @Override
                public void onChanged(@Nullable User user) {
                	//在观察者中更新UI
                    if(user != null){
                        mTvName.setText(user.name);
                    }else {
                        //没有登录的状态
                        mTvName.setText("用户还没登录!!!!!");
                    }
                }
            });
            mViewModel.loadUserInfo();
        }
    }
    
    public class UserViewModel extends ViewModel {
    	//userLiveData存储在UserViewModel
        private final MutableLiveData<User> userLiveData = new MutableLiveData<User>();
        public MutableLiveData<User> getUserLiveData() {
            return userLiveData;
        }
        @Override
        protected void onCleared() {
        	//释放资源
        }
    
        public void loadUserInfo() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ignored) {
                    }
                    //开启一个线程,异步操作,建议使用线程池,这里演示就直接new Thread
                    User user = new User();
                    user.name = "Albert";
                    userLiveData.postValue(user); // 通知数据观察者
                }
            }).start();
        }
    
        public void onLogout() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ignored) {
                    }
                    /开启一个线程,异步操作
                    userLiveData.postValue(null); // 通知数据观察者
                }
            }).start();
        }
    }
    复制代码

    介绍完例子,下面说说优点:

    • 数据更新通知UI更新,数据的更新关联了生命周期,可以避免onStop时去更新UI.
    • 不需要手动处理生命周期
    • 没有内存泄漏
    • 配置更改,之前加载数据还能使用
    • 可以共享资源, 主要体现在同一个Activity里fragments可以共享viewmodel,livedata等(这里不展开,后面有空再分享)

    参考:

  • 相关阅读:
    MOSS中的User的Title, LoginName, DisplayName, SID之间的关系
    如何在Network Monitor中高亮间隔时间过长的帧?
    SharePoint服务器如果需要安装杀毒软件, 需要注意什么?
    如何查看SQL Profiler? 如何查看SQL死锁?
    什么是Telnet
    The name or security ID (SID) of the domain specified is inconsistent with the trust information for that domain.
    Windows SharePoint Service 3.0的某个Web Application无搜索结果
    网络连接不上, 有TCP错误, 如果操作系统是Windows Server 2003, 请尝试一下这里
    在WinDBG中查看内存的命令
    The virtual machine could not be started because the hypervisor is not running
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/11496622.html
Copyright © 2011-2022 走看看