資料繫結與MVVM
阿新 • • 發佈:2018-12-12
本篇給出資料繫結及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地址