Android开发学习

MVVM-live

2018-04-02  本文已影响168人  lbForce

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

关键点:

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);
    }

关键点

优点

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.

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.

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.

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

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
    }

}

需要明白的几点:

解释:

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
    }
在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与其他的逻辑的通信桥梁。

考虑以下情况:

使用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+)以上使用。

优点:

使用之前在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,运行截图

借鉴 & 运用

上一篇 下一篇

猜你喜欢

热点阅读