1. 程式人生 > >資料繫結與MVVM

資料繫結與MVVM

本篇給出資料繫結及MVVM框架的總結,主要內容來自《Android程式設計權威指南》及網際網路博文。

MVVM:Model-View-ViewModel,將其中的View的狀態和行為抽象化,將檢視UI和業務邏輯分開。MVVM架構很好地把控制器裡的臃腫程式碼抽到佈局檔案裡,讓開發人員很容易看出哪些是動態介面。同時,它抽出部門動態控制器程式碼放入ViewModel類,方便開發測試和驗證。

 

DataBinding:一個幫助開發者處理檢視與資料互動的工具,即資料繫結。

gradle——Android新增

 dataBinding {
     enabled = true
}

把一般佈局改造為資料繫結佈局

<layout xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</layout>

<layout>標籤告訴資料繫結工具處理此類,資料繫結工具會自動生成一個繫結類,預設以佈局檔案命名,如fragment_beat_box.xml繫結類為FragmentBeatBoxBinding。例項化檢視層級結構時,例項化FragmentBeatBoxBinding,其getRoot()引著佈局檢視結構,該類也會引著佈局檔案裡以android:id標籤引用的其他檢視。

public class BeatBoxFragment extends Fragment {
    private BeatBox mBeatBox;

    public static BeatBoxFragment newInstance() {
        return new BeatBoxFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBeatBox 
= new BeatBox(getActivity()); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { FragmentBeatBoxBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_beat_box, container, false); binding.recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),3)); binding.recyclerView.setAdapter(new SoundAdapter(mBeatBox.getSounds())); return binding.getRoot(); } private class SoundHolder extends RecyclerView.ViewHolder { private ListItemSoundBinding mBinding; private SoundHolder(ListItemSoundBinding binding) { super(binding.getRoot()); mBinding = binding; mBinding.setViewModel(new SoundViewModel(mBeatBox)); } public void bind(Sound soud) { mBinding.getViewModel().setSound(soud); mBinding.executePendingBindings(); } } private class SoundAdapter extends RecyclerView.Adapter<SoundHolder> { private List<Sound> mSounds; public SoundAdapter(List<Sound> sounds) { mSounds = sounds; } @Override public SoundHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(getActivity()); ListItemSoundBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_item_sound, parent, false); return new SoundHolder(binding); } @Override public void onBindViewHolder(SoundHolder holder, int position) { Sound sound = mSounds.get(position); holder.bind(sound); } @Override public int getItemCount() { return mSounds.size(); } } }

檢視模型

public class SoundViewModel extends BaseObservable {
    private Sound mSound;
    private BeatBox mBeatBox;
    public SoundViewModel(BeatBox beatBox) {
        mBeatBox = beatBox;
    }

    @Bindable
    public String getTitle() {
        return mSound.getName();
    }

    public Sound getSound() {
        return mSound;
    }

    public void setSound(Sound sound) {
        mSound = sound;
        notifyChange();
    }
}

notifyChange()通知繫結類,檢視模型物件上所有可繫結屬性都已經更新,繫結類會再次執行繫結表示式更新檢視資料。setSound(sound)方法一被呼叫,ListItemSoundBinding就立即知道,並呼叫list_item_sound.xml佈局裡指定的Button.setText(String)方法。viewModel.title就是viewModel.getTitle()簡寫形式。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.bignerdranch.android.beatbox.SoundViewModel"/>
    </data>
    <Button
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:text="@{viewModel.title}"
        tools:text="Sound name"/>
</layout>

 完整專案Github地址