MVVM-live

作者: lbForce | 来源:发表于2018-04-02 19:23 被阅读168次

    MVVM-live

    Google的项目: https://github.com/googlesamples/android-architecture/tree/mastertodo‑mvvm

    官方解释:

    Uses ViewModels and LiveData from Architecture Components and the Data Binding library with an MVVM architecture.

    This version of the app is called todo-mvvm-live, and it uses some Architecture Components like ViewModel, LiveData, and other lifecycle-aware classes. It's based on the todo-mvvm-databinding sample, which uses the Data Binding Library to display data and bind UI elements to actions.

    总结:MVVM就包含了ViewModels及Data Binding,所以mvvm‑live = mvvm + LiveData

    需要了解的概念有 Lifecycle-aware组件、MVVM、LiveData、ViewModel、Data binding library。

    以下是翻译Google的文档 + 源码解释。

    Lifecycle-aware组件

    lifecycle-aware组件能够对其他组件(比如activity和fragment)发生生命周期改变时做出反应,这样的组件显然很容易使用,轻量且易维护。

    举个例子:在UI上显示定位信息

    传统做法是:

    定义获取位置的接口:
    public class MyLocationListener {
        public MyLocationListener(Context context, LocCallback callback) {
            // ...
        }
    
        void start() {
            // connect to system location service
        }
    
        void stop() {
            // disconnect from system location service
        }
    
        public interface LocCallback {
            void loc(long lat, long lag);
        }
    }
    
    在activity里显示位置信息,并在生命周期里控制接口:
    public class MyActivity extends AppCompatActivity {
    
        MyLocationListener myLocationListener;
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
    
            myLocationListener = new MyLocationListener(this, new MyLocationListener.LocCallback() {
                @Override
                public void loc(long lat, long lag) {
                    // update ui
                }
            });
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            myLocationListener.start();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            myLocationListener.stop();
        }
    }
    

    这么做的问题:

    1. 需要在生命周期方法里正确去回调接口方法,如果没有正确回调有可能导致内存泄漏。
    2. 并且可能在生命周期方法里有很多类似调用,导致代码很难维护,丑陋。
    3. 甚至有可能myLocationListener.stop()在start()之后调用,导致myLocationListener周期异常,例如:
    @Override
    protected void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start();
            }
        });
    }
        
        @Override
        protected void onStop() {
            super.onStop();
            myLocationListener.stop();
        }
    

    android.arch.lifecycle组件包能帮助避免这些问题。

    下面详细介绍。

    Lifecycle

    Lifecycle是一个类维护了组件(像activity或fragment)的生命周期信息,并且允许这些信息被观察者获取。内部使用2个enum类Event和State来跟踪与之关联的组件状态:

    Event :从关联的组件(activities 或 fragments)里发送过来的,表明组件已经到了哪个生命周期了(如ON_CREATE、ON_START等)

    State :Lifecycle对象跟踪的关联组件的状态。

    官方event与state关系图

    lifecycle_frag_activity图

    定义可以观察组件生命周期的observer,用annotation方式:

    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()) 让MyObserver观察组件的生命周期。

    那什么是LifecycleOwner?

    LifecycleOwner

    定义:

    public interface LifecycleOwner {
        /**
         * Returns the Lifecycle of the provider.
         *
         * @return The lifecycle of the provider.
         */
        @NonNull
        Lifecycle getLifecycle();
    }
    

    只是一个接口,表明实现者有Lifecycle。v4包里的fragemnt和activity都实现了这个,也可以实现自己的LifecycleOwner。
    前面显示定位信息的例子可以改为:

    public class MyLocationListener2 implements LifecycleObserver {
        private boolean enabled = false;
        private Lifecycle lifecycle;
        private WeakReference<LocCallback> callbackWeakReference;  // 弱引用
    
        public MyLocationListener2(Context context, Lifecycle lifecycle, LocCallback callback) {
           // ...
           callbackWeakReference = new WeakReference<LocCallback>(callback);
        }
    
        public void enable() {  // 提供enable方法,更安全
            enabled = true;
            if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
                // connect if not connected
            }
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        void start() {
            if (enabled) {
                // connect
            }
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        void stop() {
            // disconnect if connected
        }
    
        public interface LocCallback {
            void onLoc(long lat, long lag);
        }
    }
    
    public class MyActivity2 extends AppCompatActivity {
    
        MyLocationListener2 myLocationListener;
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
    
            myLocationListener = new MyLocationListener2(this, getLifecycle(), new MyLocationListener2.LocCallback() {
                @Override
                public void onLoc(long lat, long lag) {
                    // update ui
                }
            });
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Util.checkUserStatus(result -> {
                if (result) {
                    myLocationListener.enable();
                }
            });
        }
    }
    

    这个MyLocationListener2就是一个lifecycle-aware的组件。

    这么做的好处是:

    1. 让MyLocationListener2自己观察生命周期的变化,不需要外部组件回调,外部组件需需要初始化它就好。
    2. 避免了潜在的泄漏问题
    3. MyLocationListener2非常独立,很好复用。

    Google官方的建议:

    If a library provides classes that need to work with the Android lifecycle, we recommend that you use lifecycle-aware components. Your library clients can easily integrate those components without manual lifecycle management on the client side.

    就是说如果你的library需要跟生命周期有关系,那就实现成lifecycle-aware的组件,这样外部就很容易集成而不用管理它的生命周期。

    自定义LifecycleOwner

    V4包的Support Library 26.1.0版本及以上的Fragment与Activitie已经实现了LifecycleOwner,也可以自己实现,同样借助LifecycleRegistry。

    public class MyActivity extends Activity implements LifecycleOwner {
        private LifecycleRegistry mLifecycleRegistry;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mLifecycleRegistry = new LifecycleRegistry(this);
            mLifecycleRegistry.markState(Lifecycle.State.CREATED);
        }
    
        @Override
        public void onStart() {
            super.onStart();
            mLifecycleRegistry.markState(Lifecycle.State.STARTED);
        }
    
        @NonNull
        @Override
        public Lifecycle getLifecycle() {
            return mLifecycleRegistry;
        }
    }
    

    MVVM

    维基百科的解释: mvvm

    关键点:

    • Model 代表domain model或者数据访问层。
    • View 代表用户在界面上能看到的UI,如layout,fragment,各种组件。(我认为activity也是,在MVVM框架里,activity被弱化了,只作为view的承载着和生命周期的体现者)。
    • View model 是view的抽象,暴露公开的属性和命令。MVVM有binder。在view model里,binder协调着view和data binder,view model可以被看成是model层数据的一种状态。
    • Binder 把view model里的数据绑定到view上的库。

    LiveData

    参考google官方解释: architecture-livedata
    源码里LiveData的解释很棒!

    其实LiveData就是lifecycle-aware组件的增强版,其内部实现了LifecycleObserver。(LifecycleBoundObserver实现的)

        @MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            ... ...
            LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
            ... ...
            owner.getLifecycle().addObserver(wrapper);
        }
    

    关键点

    • 是可被观察的data holder
    • 是lifecycle-aware的,就是说它可感知组件(如activities, fragments, services)的生命周期。并且它只更新处于active状态的观察者组件。
    • active状态是指生命周期处于 STARTED 或者 RESUMED 状态,LiveData只通知active的观察者,非active的观察者得不到通知。
    • STARTED的解释RESUMED的解释

    优点

    • 确保UI跟数据状态匹配

    LiveData notifies Observer objects when the lifecycle state changes. You can consolidate your code to update the UI in these Observer objects。LiveData notifies Observer objects when the lifecycle state changes.

    • 没有内存泄漏

    Observers are bound to Lifecycle objects and clean up after themselves when their associated lifecycle is destroyed.

    • 不会因为activity stop掉而crash

    If the observer's lifecycle is inactive, such as in the case of an activity in the back stack, then it doesn’t receive any LiveData events.

    • 自动处理由于生命周期改变的影响

    UI components just observe relevant data and don’t stop or resume observation. LiveData automatically manages all of this since it’s aware of the relevant lifecycle status changes while observing.

    • 在active时,observer总是收到最新的数据

    If a lifecycle becomes inactive, it receives the latest data upon becoming active again. For example, an activity that was in the background receives the latest data right after it returns to the foreground.

    • 对configuration change的处理

    If an activity or fragment is recreated due to a configuration change, like device rotation, it immediately receives the latest available data.

    • 在app内共享资源

    You can extend a LiveData object using the singleton pattern to wrap system services so that they can be shared in your app. The LiveData object connects to the system service once, and then any observer that needs the resource can just watch the LiveData object. For more information, see Extend LiveData 。通过下面的ViewModel也可以做到。

    怎么使用LiveData:

    1. 在ViewModel里创建LiveData
    public class NameViewModel extends AndroidViewModel {
    
        // Create a LiveData with a String
        private MutableLiveData<String> curName; // LiveData是data的封装,LiveData通常是放在ViewModel里,通过getter被获取
    
        public NameViewModel(@NonNull Application application) {
            super(application);
        }
    
        public MutableLiveData<String> getCurName() {
            if (curName == null) {
                curName = new MutableLiveData();
            }
            return curName;
        }
    
        public void requestFromServer(String params) {
            // make the request
    
            // set the response data
            curName.setValue("LiBo");// setValue()需要再主线程调用
    //        curName.postValue("liBo");// postValue()可以在子线程调用
        }
    }
    
    1. 在lifecycle owner的组件(比如activity、fragment)里observe live data
    public class MvvmTestActivity extends AppCompatActivity {
    
        private TextView nameTv;
    
        private NameViewModel nameViewModel;
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
    
            // Get the ViewModel.
            nameViewModel = 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 String s) {
                    // Update the UI
                    nameTv.setText(s);
                }
            };
    
            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            nameViewModel.getCurName().observe(this, nameObserver);// 第一个参数是 LifecycleOwner对象
    //        nameViewModel.getCurName().observeForever(nameObserver); // observer is considered to be always active and is therefore always notified about modifications
        }
    
    }
    

    需要明白的几点:

    • 在viewmodel里而不是fragment或activity管理livadata对象,因为(避免fragment或activitydiamante臃肿,避免congiguration change销毁livadata)。解释-1
    • 当更新LiveData里的value时,会触发所有活着的observer(其所关联的LifecycleOwner在active状态)。 解释-2
    • 如果observer从inactione变成active状态,也会受到推送的数据。 解释-3
    • 调用observe(this, nameObserver)就意味着nameObserver跟MvvmTestActivity这个lifecycle owner产生关联,其实是跟activity关联的lifecycle对象LifecycleRegistry关联的。当lifecycle对象不是active状态时,nameObserver 不会接收到更新,当lifecycle对象被销毁时,nameObserver自动从livedata里移除。

    解释:

    • 1
      见下面 ' ViewModel为什么能够保活?'
    • 2
    LiveData.java
    
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;   // 记录数据版本,很重要
        mData = value;
        dispatchingValue(null);  // 会调用 considerNotify()
    }
    
    private void considerNotify(ObserverWrapper observer) {
            if (!observer.mActive) {
                return;
            }
            // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
            //
            // we still first check observer.active to keep it as the entrance for events. So even if
            // the observer moved to an active state, if we've not received that event, we better not
            // notify for a more predictable notification order.
            if (!observer.shouldBeActive()) {
                observer.activeStateChanged(false); 
                return;
            }
            // 如果observer接受的数据版本大于等于目前版本,就不用通知observer了。
            if (observer.mLastVersion >= mVersion) {
                return;
            }
            observer.mLastVersion = mVersion;
            //noinspection unchecked
            observer.mObserver.onChanged((T) mData); // 通知obserser
        }
    
    • 3
    在LiveData.observe()里调用了owner.getLifecycle().addObserver(wrapper) 把obserser关联到了owner的lifecycle。
    当owner即activity或fragment state状态发生改变时,会调用LifecycleRegistry.markState()或handleLifecycleEvent(),
    再调用sync(),最后会遍历所有关联的observer,并调用其 onStateChanged(),
    
    在LiveData.java
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);   // 如果lifecycle owner已经是DESTROYED状态,就移除该observer
            return;
        }
        activeStateChanged(shouldBeActive()); // 
    }
    
    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;  // mActiveCount记录活着的observer个数
        if (wasInactive && mActive) {
            onActive();
        }
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }
        if (mActive) {
            dispatchingValue(this); // 上面解释过
        }
    }
    

    Transform LiveData

    一些高级的用法,待更新

    Merge multiple LiveData sources

    一些高级的用法,待更新

    ViewModel

    参考官方 ViewModel
    源码里ViewModel的解释很棒!

    设计ViewModel的目的是存储及管理UI相关的数据同时关注其生命周期,能保证数据在configuration change(比如切屏)时存活,还有作为fragment,activity与其他的逻辑的通信桥梁。

    考虑以下情况:

    • 当configuration change时,activity被销毁并重建,虽然可以通过onSaveInstanceState()保存数据,但是只可以保存少量的可序列化的数据;

    • 还有ui controller(activity、fragment等)需要管理一些异步调用并保证在适当时清理掉 以避免内存泄漏,这些管理工作很麻烦;

    • UI controller应该只是显示数据到UI、相应用户操作、处理系统的交互如处理permission请求。

    使用ViewModel可以把数据及处理从Ui controller分离。

    怎么使用ViewModel

    继承ViewModel,ViewModel的对象可以在configuration change时自动保活,其保存的数据可以立即被下一个activity或fragment实例使用。
    public class MyViewModel extends ViewModel {
        private MutableLiveData<List<User>> users;
        public LiveData<List<User>> getUsers() {
            if (users == null) {
                users = new MutableLiveData<List<User>>();
                loadUsers();
            }
            return users;
        }
    
        private void loadUsers() {
            // Do an asynchronous operation to fetch users.
        }
    }
    
    class User {
    
    }
    

    注意:ViewModel一定不要引用一个view、lifecycle或任何会引用activity context的类。 ViewModel被设计用来独立与view或LifecycleOwner而保活数据的。ViewModel可以维护LifecycleObserver例如LiveData,但是不能observe lifecycle-aware的被观察者例如LiveData。如果需要application context,可以继承AndroidViewModel。

    ViewModel的生命周期

    ViewModel对象一直存活直到关联的lifecycle永远失效,例如 activity 被finish掉(注意不是onDestroy()被调用)或者fragment被detatched了。生命周期图
    验证一下:

    public class MainViewModel extends AndroidViewModel {
        private int count = 0; // 只是用于activity更新以在某时做finish操作
    
        public MainViewModel(@NonNull Application application) {
            super(application);
        }
    
        @Override
        protected void onCleared() {
            super.onCleared();
            Log.i("lbtest", "MainViewModel onCleared");
        }
    
        public void updateCount() {
            count++;
        }
    
        public int getCount() {
            return count;
        }
    }
    
    private MainViewModel obtainViewModel() {
            MainViewModel vm = ViewModelProviders.of(this)
                    .get(MainViewModel.class);
            return vm;
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.i("lbtest", "onCreate this="+this+", vm="+obtainViewModel());
        }
    
        @Override
        public void onResume() {
            super.onResume();
            MainViewModel viewModel = obtainViewModel();
            Log.i("lbtest", "onResume this="+this+", vm="+viewModel);
            viewModel.updateCount();
            if (viewModel.getCount() == 2) {
                Log.i("lbtest", "onResume finish this="+this);
                finish();
            }
        }
    
        @Override
        public void onPause() {
            super.onPause();
            Log.i("lbtest", "onPause this="+this+", vm="+obtainViewModel());
        }
    
        @Override
        public void onStop() {
            super.onStop();
            Log.i("lbtest", "onStop this="+this+", vm="+obtainViewModel());
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("lbtest", "onDestroy this="+this/*+", vm="+obtainViewModel()*/);
        }
    
    运行结果:
    
    04-03 14:33:50.828 30546-30546/? I/lbtest: onCreate this=com.lb.legor.MainActivity@50deb83, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:50.832 30546-30546/? I/lbtest: onResume this=com.lb.legor.MainActivity@50deb83, vm=com.lb.legor.MainViewModel@e6d758a
    // 切屏操作
    04-03 14:33:57.558 30546-30546/com.lb.legor I/lbtest: onPause this=com.lb.legor.MainActivity@50deb83, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.560 30546-30546/com.lb.legor I/lbtest: onStop this=com.lb.legor.MainActivity@50deb83, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.560 30546-30546/com.lb.legor I/lbtest: onDestroy this=com.lb.legor.MainActivity@50deb83
    // 新的activity对象创建了,viewmodel对象不变
    04-03 14:33:57.577 30546-30546/com.lb.legor I/lbtest: onCreate this=com.lb.legor.MainActivity@390bb73, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.582 30546-30546/com.lb.legor I/lbtest: onResume this=com.lb.legor.MainActivity@390bb73, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.582 30546-30546/com.lb.legor I/lbtest: onResume finish this=com.lb.legor.MainActivity@390bb73 // 主动去finish()
    04-03 14:33:57.589 30546-30546/com.lb.legor I/lbtest: onPause this=com.lb.legor.MainActivity@390bb73, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.658 30546-30546/com.lb.legor I/lbtest: onStop this=com.lb.legor.MainActivity@390bb73, vm=com.lb.legor.MainViewModel@e6d758a
    04-03 14:33:57.658 30546-30546/com.lb.legor I/lbtest: MainViewModel onCleared // viewmodel对象被清
    04-03 14:33:57.659 30546-30546/com.lb.legor I/lbtest: onDestroy this=com.lb.legor.MainActivity@390bb73
    // 重新进入app,肯定都是新的对象
    04-03 14:36:28.277 30546-30546/com.lb.legor I/lbtest: onCreate this=com.lb.legor.MainActivity@c0db1d, vm=com.lb.legor.MainViewModel@34e80ea
    04-03 14:36:28.280 30546-30546/com.lb.legor I/lbtest: onResume this=com.lb.legor.MainActivity@c0db1d, vm=com.lb.legor.MainViewModel@34e80ea
    

    在fragment间共享ViewModel:

    public class SharedViewModel extends ViewModel {
        private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
    
        public void select(Item item) {
            selected.setValue(item);
        }
    
        public LiveData<Item> getSelected() {
            return selected;
        }
    }
    
    public class MasterFragment extends Fragment {
        private SharedViewModel model;
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            itemSelector.setOnClickListener(item -> {
                model.select(item);
            });
        }
    }
    
    public class DetailFragment extends Fragment {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            model.getSelected().observe(this, { item ->
               // Update the UI.
            });
        }
    }
    

    注意,2个fragment里用getActivity()获取到相同的ViewModel对象。

    这样共享ViewModel的好处是:

    activity不需要知道fragment之间通信的细节,fragment之间也不需要知道对方,一个fragemnt的存活与否也不影响另一个fragment使用viewmodle。

    原理分析

    ViewModel架构图

    ViewModel为什么能够保活?

    ViewModelProviders.java:
        @MainThread
        public static ViewModelProvider of(@NonNull FragmentActivity activity,
                @NonNull Factory factory) {
            checkApplication(activity);
            return new ViewModelProvider(ViewModelStores.of(activity), factory);
        }
        
    ViewModelStores.java:
        @MainThread
        public static ViewModelStore of(@NonNull FragmentActivity activity) {
            return holderFragmentFor(activity).getViewModelStore();
        }
        
    HolderFragment.java:
        private ViewModelStore mViewModelStore = new ViewModelStore();
        public HolderFragment() {
            setRetainInstance(true); // Control whether a fragment instance is retained across
            // Activity re-creation (such as from a configuration change).
        }
    
        .HolderFragmentManager (内部类):
                private ActivityLifecycleCallbacks mActivityCallbacks =
                    new EmptyActivityLifecycleCallbacks() {
                        @Override
                        public void onActivityDestroyed(Activity activity) {
                            // activity被destroyed了才移除对应的fragment,所以其维护的mViewModelStore也没了。
                            HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                            if (fragment != null) {
                                Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                            }
                        }
                    };
    
            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); // 观察activity的生命周期
                }
                holder = createHolderFragment(fm);
                mNotCommittedActivityHolders.put(activity, holder);
                return holder;
            }
        
            private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
                HolderFragment holder = new HolderFragment(); // 创建时会setRetainInstance(true)让该fragment保活。
                // 创建一个HolderFragment对象,add进activity或者fragment关联的FragmentManager,但不显示,没有UI。
                fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
                return holder;
            }
    
    ViewModelProvider of(@NonNull Fragment fragment)逻辑类似。
    

    ViewModel为什么可以share?

    因为通过ViewModelProvider of(FragmentActivity)获得的ViewModelProvider对象里是相同的ViewModelStore对象
    从这个对象里用相同的key获取viewmodel就是一个model对象。
    
    ViewModelProvider.java:
        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;
        }
    

    AndroidViewModel 与ViewModel,该用哪个?
    ViewModel是不支持任何context的,如果在ViewModel里需要使用context就用AndroidViewModel,因为可以通过getApplication()得到app context,也不会造成内存泄漏。

    Data Binding Library

    参考 官方解释

    Data Binding Library具有高度可扩展性和易用性,是一个支持库,可以在Android 2.1 (API level 7+)以上使用。

    优点:

    • 不用再findViewById()了,code也不会出现自动生成的控件标签
    • 可以自动绑定数据
    • 可以优雅的处理事件(如click或自定义方法等)
    • 更多高级用法,如表达式及转换等

    使用之前在app module的build.gradle file 里添加

    android {
        ....
        dataBinding {
            enabled = true
        }
    }
    

    Android Gradle Plugin 3.1.0 Canary 6使用了新的bindding编译器,在gradle.properties里添加
    android.databinding.enableV2=true 就可以激活它。

    使用data binding,首先从layout文件开始,在java文件里通过DataBinding实例或DataBindingUtil来inflate一个layout,之后就可以通过DataBinding实例来操作layout。

    写个简单的demo演示下前2个优点,用mvvm-live模式,显示一个person的简单信息:

    1. 主layout:
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
            <import type="com.lb.legor.mvvm_live.databinding.Person"/>
            <variable
                name="person"
                type="Person"/>
        </data>
    
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <include layout="@layout/simple_textview"
                android:id="@+id/simpleTextView"/>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#000000"
                android:text="@{person.id}"/>
    
            <com.lb.legor.mvvm_live.databinding.DataBindingLayout1
                android:id="@+id/dataBindingLayout1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    
            <com.lb.legor.mvvm_live.databinding.DataBindingLayout2
                android:id="@+id/dataBindingLayout2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
        </LinearLayout>
    </layout>
    
    1. 主activity:
    public class DataBindingActivity extends FragmentActivity {
        ActivityDatabindingBinding binding;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            binding = DataBindingUtil.setContentView(this, R.layout.activity_databinding);
            observeData();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            obtainViewModel().requestAPerson();
        }
    
        private void observeData() {
            obtainViewModel().getPersonLiveData().observe(this, new Observer<Person>() {
                @Override
                public void onChanged(@Nullable Person person) {
                    if (person == null) {
                        return;
                    }
                    binding.simpleTextView.textView.setText("A person's simple info:");
                    binding.setPerson(person);
                    binding.dataBindingLayout1.updateData(person.name);
                    binding.dataBindingLayout2.updateData(person.basic);
                    binding.recyclerView.setLayoutManager(new LinearLayoutManager(DataBindingActivity.this));
                    binding.recyclerView.setAdapter(new CompanyAdapter(DataBindingActivity.this, person.companyList));
                }
            });
        }
    
        private DataBindingViewModel obtainViewModel() {
            return ViewModelProviders.of(this).get(DataBindingViewModel.class);
        }
    }
    
    1. DataBindingLayout1类
    public class DataBindingLayout1 extends LinearLayout {
        private LayoutDatabinding1Binding binding;
    
        public DataBindingLayout1(Context context) {
            this(context, null);
        }
    
        public DataBindingLayout1(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public DataBindingLayout1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // 有2种写法,用编译生成的LayoutDatabinding1Binding或DataBindingUtil
            binding = LayoutDatabinding1Binding.inflate(LayoutInflater.from(context), this, true);
    //        binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.layout_databinding_1, this, true);
        }
    
        public void updateData(Person.Name name) {
            binding.setName(name);
        }
    }
    
    1. DataBindingLayout1类的layout:
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        
        <data>
            <variable
                name="name"
                type="com.lb.legor.mvvm_live.databinding.Person.Name"/>
        </data>
        
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{name.firstName}"/>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="2dp"
                android:text="@{name.lastName}"/>
    
        </LinearLayout>
    </layout>
    

    DataBindingLayout2类似

    1. CompanyAdapter类:
    public class CompanyAdapter extends RecyclerView.Adapter<CompanyAdapter.MyViewHolder> {
    
        private Context context;
        private List<Person.Company> data;
    
        public CompanyAdapter(Context context, List<Person.Company> data) {
            this.context = context;
            this.data = data;
        }
    
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            SimpleTextviewBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.simple_textview,
                    parent, false);
            return new MyViewHolder(binding.getRoot(), binding);
        }
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.binding.textView.setText(data.get(position).name);
        }
    
        @Override
        public int getItemCount() {
            return data.size();
        }
    
        static class MyViewHolder extends RecyclerView.ViewHolder {
            SimpleTextviewBinding binding;
    
            public MyViewHolder(View itemView, SimpleTextviewBinding binding) {
                super(itemView);
                this.binding = binding;
            }
        }
    }
    
    1. DataBindingViewModel类:
    public class DataBindingViewModel extends AndroidViewModel {
        private MutableLiveData<Person> personLiveData = new MutableLiveData<>();
    
        public DataBindingViewModel(@NonNull Application application) {
            super(application);
        }
    
        public void requestAPerson() {
            //...
            Person person = new Person();
            person.id = "340811199001011234";
            Person.Name name = new Person.Name();
            name.firstName = "Paul";
            name.lastName = "Li";
            person.name = name;
            Person.Basic basic = new Person.Basic();
            basic.age = 18;
            basic.sex = "Male";
            person.basic = basic;
            List<Person.Company> companyList = new ArrayList<>();
            Person.Company company1 = new Person.Company();
            company1.name = "Rong";
            companyList.add(company1);
            Person.Company company2 = new Person.Company();
            company2.name = "Le";
            companyList.add(company2);
            Person.Company company3 = new Person.Company();
            company3.name = "Sony";
            companyList.add(company3);
            person.companyList = companyList;
            personLiveData.setValue(person);
        }
    
        public MutableLiveData<Person> getPersonLiveData() {
            return personLiveData;
        }
    }
    

    done,运行截图

    借鉴 & 运用

    相关文章

      网友评论

        本文标题:MVVM-live

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