数据绑定与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地址

猜你喜欢

转载自www.cnblogs.com/kyun/p/10108249.html
今日推荐