05 Jetpack-ViewModel & LiveData&

作者: 凤邪摩羯 | 来源:发表于2021-11-25 09:24 被阅读0次

    Android Jetpack组件推荐的使用项目架构

    image

    上面架构组件的功能如下:

    • Activity和Fragment负责产品与用户的交互
    • ViewModel作为数据的存储和驱动
    • Resposity负责调度数据的获取(Room储存本地序列化的数据,Retrofit获取远程数据的数据)

    ViewModel+ LiveData

    ViewModel的优点:
    • 解决了运行中断和界面重建时的数据保存问题 (横竖屏切换,导致Activity销毁并重新创建时,ViewMode仍然可以保留之前读取到的数据不会因为Activity的销毁而丢失,这样我们无需额外再浪费资源去再次请求数据)
    • 配合LiveData实时获取最新数据
    • 实现Activity中Fragment之间的数据交互(数据共享)
    • 数据和界面的分离,使数据驱动界面 (ViewModel类被设计为通过lifecycle感知的方式存储和管理UI相关数据)
    ViewModel的生命周期:
    • ViewModel对象的范围是在获取ViewModel时传递给ViewModelProvider的Lifecycle生命周期
    • ViewModel在内存中直到Activity销毁或Fragment被移除
    • 系统首次调用活动对象的onCreate()方法时,通常会请求ViewModel
    • 系统可能会在整个活动的整个生命周期中多次调用onCreate(),例如当设备屏幕旋转时
    • ViewModel从第一次请求ViewModel直到活动完成并销毁时存在

    ViewMode在其生命周期的范围内会一直保存在内存中,所以横竖屏切换 当切换手机横竖屏后,Activity会destroy并重新onCreate来重构当前界面,生命周期再次重新触发onCreate,但是ViewMode 并没有重新执行获取数据的操作。

    由于 ViewModel 生命周期可能长与 activity 生命周期,所以为了避免内存泄漏 Google 禁止在 ViewModel 中持有 Context 或 activity 或 view 的引用。
    如果有些请求数据的情况必须用到Context,在继承ViewMode的时候,可以改为继承AndroidViewMode,这个类会返回一个带有Context的构造函数。

    ViewMode执行onCleared操作,这个是ViewMode的一个回调,表明当前Activity要彻底关闭,ViewMode需要做一些回收清理的操作

    image
    LiveData

    优点:

    • 确保UI界面的数据状态
    • 没有内存泄漏,不会因为Activity的不可见导致Crash
    • 一个存放可被观察的数据持有类,但与一般的被观察者不同的是,它是有生命周期感知功能,解决了android开发者需要去手动处理生命周期的痛点。
    • 共享资源
     viewMode.getUserLiveData().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String users) {
                    fragment2.setText("fragment2==\n" + users);
                }
            });
    
    

    LiveData是一个observable数据持有类,LiveData是生命周期感知的,这意味着它跟随其他应用程序组件(如activities, fragments, or services)的生命周期。这种感知能力确保LiveData只更新处于活跃生命周期状态的应用程序组件
    LiveData与一个Observer关联,如果观察者的生命周期处于STARTED或RESUMED状态,则表示观察者处于活动状态。LiveData只通知活跃的观察者做更新。注册到LiveData对象中的不活跃的观察者则得不到数据更新的通知。

    注册一个observer并与实现了LifecycleOwner接口的对象配对。这种关系允许当相应的Lifecycle对象的状态改变为DESTROYED时,观察者被移除

    利用ViewMode(配合LiveData实时获取最新数据)进行Fragment之间的数据交互
    public class OneFragment extends BaseFragment {
        @BindView(R2.id.fragment2)
        TextView fragment2;
        @Override
        protected int initLayout() {
            return R.layout.fragment_detail;
    
        }
        @Override
        protected void initView(View view) {
            //绑定ViewMode的selected的值,当有更新时通知DetailFragment
            SharedViewModel viewMode = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            viewMode.getUserLiveData().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String users) {
                    fragment2.setText("fragment2==\n" + users);
                }
            });
    
        }
    
    }
    
    public class TwoFragment extends BaseFragment {
        @BindView(R2.id.fragment1)
        TextView fragment1;
    
        SharedViewModel viewMode;
    
        @Override
        protected void initView(View view) {
            //注意:这里ViewModelProviders.of(getActivity())这里的参数需要是Activity,而不能是Fragment,否则收不到监听
            viewMode = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    
            fragment1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //当点击某一个item的时候,更新viewmode中的selected的值
                    viewMode.select("fragment1点击后,更新viewmode中的值,fragment2 里面的数据同步更新");
                }
            });
        }
    
        @Override
        protected void initData() {
            viewMode.getUserLiveData().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String users) {
                    Log.w("TAG", "====" + users);
                }
            });
    
        }
    
        @Override
        protected int initLayout() {
            return R.layout.fragment_master;
        }
    }
    
    public class SharedViewModel extends AndroidViewModel {
        //userLiveData保存的是被选中的item的状态或者数据
        private MutableLiveData<String> userLiveData;
    
        public MutableLiveData<String> getUserLiveData() {
            if (userLiveData == null) {
                Log.w("TAG", "SharedViewModel-getUserLiveData");
                userLiveData = new MutableLiveData<>();
    
            }
            return userLiveData;
        }
    
        //主要通过masterFragment进行调用交互,用来更新selected中的值
        public void select(String item) {
            userLiveData.setValue(item);
        }
    
        public SharedViewModel(@NonNull Application application) {
            super(application);
        }
    
        /**
         * 这里可以执行一些资源释放、数据清理的操作
         * ViewMode会执行onCleared操作,这个是ViewMode的一个回调,
         * 表明当前Activity要彻底关闭,ViewMode需要做一些回收清理的操作,如下代码:
         */
        @Override
        protected void onCleared() {
            super.onCleared();
    
        }
    }
    
    

    上述代码的逻辑很简单,OneFragment与TwoFragment并不直接进行交互,而是各自与ViewMode进行交互,OneFragment用来更新维护ViewMode中的数据,TwoFragment可以收到来自ViewMode中数据更新的通知。这样便达到了两个frangment之间的数据通信。

    LifeCycles原理

    Lifecycles是生命周期管理组件 另一组件的生命周期状态(随着Activity和Fragment)的变化而执行动作,support 26 以上的兼容包中的AppCompatActivity与Fragment中默认已实现了LifeCycleOwner接口,保证了LiveData及ViewModel具备了生命周期感知与内存缓存的能力。

    场景使用:在平时的开发过程中,我们难免有些逻辑的执行是和UI的生命周期相结合的,需要在特定的生命周期中执行相应的方法,我们平时做的可能就是在View中的每个周期调用Present中获取数据的方法,然后在调用View的回调接口更新UI,但现在使用Lifecycles可以使用注解和观察的模式自动调用Observe中定义好的方法。

         //谁观察生命周期  就注册谁  两个角色定义好后,需要让他们之间建立联系
            //获取Lifecycle
            getLifecycle().addObserver(new LocationListener());
    
    public class LocationListener implements LifecycleObserver {
        private static final String TAG = "TAG";
    
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        public void onActivityCreate(LifecycleOwner owner) {
            Log.w(TAG, "onActivityCreate");
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        public void onActivityDestroy(LifecycleOwner owner) {
            Log.w(TAG, "onActivityDestroy");
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        public void onActivityPause(LifecycleOwner owner) {
            Log.w(TAG, "onActivityPause");
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        public void onActivityResume(LifecycleOwner owner) {
            Log.w(TAG, "onActivityResume");
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        public void onActivityStart(LifecycleOwner owner) {
            Log.w(TAG, "onActivityStart");
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        public void onActivityStop(LifecycleOwner owner) {
            Log.w(TAG, "onActivityStop");
        }
    
    }
    
    

    Lifecycle 原理 如何感知 activity 或 fragment 生命周期

    1、activity 和 fragment 已经实现了 LifecycleOwner
    2、出现了一个LifecycleRegistry,是 Lifecycle 的一个实现类。通过markState方法在onSaveInstanceState把 Lifecycle 状态标记为Lifecycle.State.CREATED。
    3、onCreate 方法里有个ReportFragment,
    4、利用 fragment 的特性,绑定了一个 fragment 然后在其生命周期dispatch()方法中调用了LifecycleRegistry的handleLifecycleEvent,此方法便是通知观察者的地方。Lifecycle.Event,判断执行事件后下一个到达的状态,然后使用moveToState()中修改活动的生命周期
    5、通知观察者addObserver 后,把observer维护到ObserverWithState然后装到 map 里。
    然后通过handleLifecycleEvent方法最终遍历map 通知 observer。

    伪代码
    public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner{
    
     private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    
     @CallSuper
        @Override
        protected void onSaveInstanceState(@NonNull Bundle outState) {
            mLifecycleRegistry.markState(Lifecycle.State.CREATED);
            super.onSaveInstanceState(outState);
        }
    
     @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mSavedStateRegistryController.performRestore(savedInstanceState);
            ReportFragment.injectIfNeededIn(this);
            if (mContentLayoutId != 0) {
                setContentView(mContentLayoutId);
            }
        }
    
      public void addObserver(@NonNull LifecycleObserver observer) {
            State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
            ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
            ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
    
    }
    
    

    ViewModel 原理

        getLifecycle().addObserver(new LifecycleEventObserver() {
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source,
                        @NonNull Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        if (!isChangingConfigurations()) {
                            getViewModelStore().clear();
                        }
                    }
                }
            });
    
    

    ViewModel 和 onSaveInstaceState方法区别在于:ViewModel只能保存因为配置更改导致重建的数据,但是它能保存大量和复杂的数据;onSaveInstaceState能保存配置更改导致重建和资源限制导致重建的数据,但是它只能保存少量简单的数据。ViewModel使用SavedStateHandle能够保存资源限制导致重建的数据。

    根据传入的Activity获取、创建、添加并以键值对保存Fragment,从VIewStore的Map中或Factory的create()中获取ViewMode
    1、获取ViewProvider:
    2、获取ViewModelStore:由前面的源码可以知道创建ViewProvider时传入两个参数:ViewModelStore 和 Factory;显然从名字就可以看出他们的作用,Factory负责创建,ViewModelStore负责存储

    ViewModelStore内部维护者一个Map集合保存者ViewModel对象的键值对

    ViewModel的生命周期要比Activity长一点。因为在ComponentActivity 实现了的getViewModelStore ,ViewModelStore在Activity重建前后能保持同一个对象就是通过NonConfigurationInstances实现的。

    ActivityThread 里面performLaunchActivity方法里面,启动Activity 调用了Activity的attach方法,在这个方法,将已有的NonConfigurationInstances赋值给了新的Activity对象。所以Activity 获取到的ViewMode是同一个,
    这样NonConfigurationInstances能保证ViewModelStore在Activity重建前后是同一个对象,同时也知道为啥ViewModel的生命周期比Activity的生命周期要长一点

    LiveData 原理,如何做到生命周期感知:

    涉及到LifecycleOwner属于另一个架构组件 lifecycle,lifecycle原理上面已经讲述

    伪代码
       //LiveData数据可以再通过observe方法进行数据回调的返回,如上代码中的onChanged回调。
        //  从Livedata添加观察者的方法 observe 开始:
            viewMode.getUsers().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String users) {
                    viewmode_text.setText("viewMode获取到的数据--" + users);
                }
            });
    
     public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            assertMainThread("observe");
            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);
        }
    
    

    第一个参数为LifecycleOwner用于提供当前的生命周期状态,DESTROYED的时候不做任何操作。
    第二个为观察者observer,首先把observer包装成了LifecycleBoundObserver,然后把LifecycleBoundObserver维护到mObservers里
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    mObservers是一个LinkedList结构的容器 通过putIfAbsent方法判断,容器中此观察者是不是已经存在,如果存在且LifecycleOwner不同的话则抛异常,LifecycleOwner相同则 return 不重复添加。
    LifecycleBoundObserver实现了LifecycleObserver,为lifecycle 的观察者,通过上文的 observe方法添加到了lifecycle观察中,

    接下来主要看LifecycleBoundObserver
    通过此类持有 Livedata 的观察者observer,当 生命周期发生变化时 会回调onStateChanged方法,然后 Livedata 的观察者在onStateChanged中执行相应的逻辑。

      @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                    removeObserver(mObserver);
                    return;
                }
                activeStateChanged(shouldBeActive());
            }
        //接着执行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);
                }
            }
    
    

    通过巧妙的设计实现了:
    1、状态没有变化,什么也不做。
    2、变为活(active)就是调用onActive(),非活(inactive)就调用onInactive().
    3、另外,变为活的话就调用dispatchingValue方法,此方法为回调观察者的方法

    事件的通知
    LiveData通过 setValue 或 postValue 方法去改变持有的数据,并通知观察者,最终都是调用dispatchingValue()方法:

     void dispatchingValue(@Nullable ObserverWrapper initiator) {
       ........................................
    //遍历之前注册的观察者
                    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                            mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                        considerNotify(iterator.next().getValue());
                        if (mDispatchInvalidated) {
                            break;
                        }
                    }
                }
            } while (mDispatchInvalidated);
            mDispatchingValue = false;
        }
    
     private void considerNotify(ObserverWrapper observer) {
       ................................
            if (observer.mLastVersion >= mVersion) {
                return;
            }
            observer.mLastVersion = mVersion;
         //开始通知了
            observer.mObserver.onChanged((T) mData);
        }
    

    相关文章

      网友评论

        本文标题:05 Jetpack-ViewModel & LiveData&

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