美文网首页Android Databind
Android MVVM实战Demo --- 基于DataBin

Android MVVM实战Demo --- 基于DataBin

作者: Android_Jian | 来源:发表于2018-12-28 00:16 被阅读67次

    提到Android的架构,大家肯定会想到MVC、MVP、MVVM;今天我们就来一起学习下基于DataBinding的MVVM。在这里你也许会问,DataBinding和MVVM之间有什么关系吗?首先你需要明确下DataBinding是做什么的,DataBinding是实现数据和UI双向绑定的框架。其实两者的关系很简单,MVVM是一种设计思想,而DataBinding只是实现MVVM模式的一种方式而已,除此之外,实现MVVM还有另一种方式,那就是ViewModel+LiveData+Repository;在看本小节之前,希望您对DataBinding的基础知识有所了解。我们先来看下实例Demo最后实现的效果:


    截图

    很简单,界面主要分为上下两部分,上部分为FrameLayout,下部分为一个RecyclerView。话不多说,直接上代码:

    首先是我们的数据Bean类:

    public class HallListBean implements Serializable{
    
        public int iRet;
    
        public String info;
    
        public HallListData data;
    
        public static class HallListData implements Serializable{
    
            public int total;
    
            public ArrayList<HallItem> list;
    
            public PackageInfo package_info;
        }
    
        public static class HallItem implements Serializable{
    
            public String id;
    
            public String hotel_name;
    
            public String cate_name;
    
            public String hall_name;
    
            public String cover;
    
            public String table_num;
    
            public String price;
    
            public String pillar_name;
    
            public String icon;
        }
    
        public static class PackageInfo implements Serializable{
    
            public String id;
    
            public String price;
    
            public String background;
    
            public String color;
    
            public String title;
        }
    
    }
    

    我们的主界面为 HallListActivity,对应的ViewModel为 HallListViewModel,我们先来看下HallListActivity的布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <data>
            <import type="android.view.View"/>
            <variable
                name="hallListViewModel"
                type="com.example.databindingtest.viewmodel.HallListViewModel"/>
        </data>
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="180dp">
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:scaleType="fitXY"
                        app:imageUrl="@{hallListViewModel.packageData.background}"/>
    
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">
    
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="85dp"
                            android:orientation="horizontal">
    
                            <TextView
                                android:id="@+id/tv_price"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginLeft="20dp"
                                android:includeFontPadding="false"
                                android:text="@{hallListViewModel.packageData.price}"
                                android:textColor="@color/white"
                                android:textSize="26dp"
                                android:textStyle="bold" />
    
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginBottom="1dp"
                                android:includeFontPadding="false"
                                android:text="元起全包/桌"
                                android:textColor="@color/white"
                                android:textSize="26dp"
                                android:textStyle="bold" />
    
                        </LinearLayout>
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginLeft="20dp"
                            android:layout_marginTop="5dp"
                            android:layout_marginBottom="20dp"
                            android:includeFontPadding="false"
                            android:text="@{hallListViewModel.packageData.title}"
                            android:textColor="@color/white"
                            android:textSize="13dp" />
    
                        <View
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:background="@drawable/bg_hall_top"/>
    
                    </LinearLayout>
    
                </FrameLayout>
    
                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recycler_view"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:overScrollMode="never"
                    app:items="@{hallListViewModel.listItems}"/>
    
            </LinearLayout>
    
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginTop="15dp"
                android:visibility="@{hallListViewModel.dataLoading ? View.VISIBLE : View.GONE}" />
    
        </FrameLayout>
    
    </layout>
    

    接着看下HallListViewModel:

    package com.example.databindingtest.viewmodel;
    
    import android.content.Context;
    import android.databinding.ObservableArrayList;
    import android.databinding.ObservableBoolean;
    import android.databinding.ObservableField;
    
    import com.example.databindingtest.model.HallListBean;
    import com.example.databindingtest.utils.ResponseResult;
    import com.google.gson.Gson;
    
    public class HallListViewModel{
    
        private Context mContext;
        public ObservableArrayList<HallListBean.HallItem> listItems = new ObservableArrayList<>();
        public ObservableField<HallListBean.PackageInfo> packageData = new ObservableField<>();
        public ObservableBoolean dataLoading = new ObservableBoolean(true);
    
        public HallListViewModel(Context context) {
            this.mContext = context.getApplicationContext();
        }
    
        public void getHallListData(){
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(500);
                        //模拟网络拉取数据
                        HallListBean testBean = new Gson().fromJson(ResponseResult.response, HallListBean.class);
                        packageData.set(testBean.data.package_info);
                        listItems.addAll(testBean.data.list);
                        dataLoading.set(false);
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    

    为了简单起见,笔者没有进行网络请求,而是直接把Json数据写入到ResponseResult.response,开启一个线程来模拟网络请求操作。接着我们看下HallListActivity中的代码,HallListActivity(xml)作为MVVM中的View,肯定只做和UI操作相关的事情啦:

    package com.example.databindingtest;
    
    import android.databinding.DataBindingUtil;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v7.widget.LinearLayoutManager;
    
    import com.example.databindingtest.utils.DividerItemDecoration;
    import com.example.databindingtest.databinding.ActivityHallListBinding;
    import com.example.databindingtest.viewmodel.HallListViewModel;
    
    public class HallListActivity extends AppCompatActivity {
    
        private HallListViewModel viewModel;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            ActivityHallListBinding hallListBinding = DataBindingUtil.setContentView(this, R.layout.activity_hall_list);
            viewModel = new HallListViewModel(this);
            hallListBinding.setVariable(BR.hallListViewModel, viewModel);
    
            hallListBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
            hallListBinding.recyclerView.addItemDecoration(new DividerItemDecoration(this));
            hallListBinding.recyclerView.setAdapter(new HallListAdapter(this));
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            viewModel.getHallListData();
        }
    }
    

    由HallListActivity中的代码可以看到,recyclerview对应的adapter为HallListAdapter,我们还是先来看下 item_hall的布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <layout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <data>
            <variable
                name="itemHall"
                type="com.example.databindingtest.model.HallListBean.HallItem"/>
        </data>
    
        <LinearLayout
            android:id="@+id/ll_hall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="20dp">
    
            <ImageView
                android:layout_width="110dp"
                android:layout_height="83dp"
                android:scaleType="centerCrop"
                app:imageUrl="@{itemHall.cover}"/>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="15dp"
                android:layout_toRightOf="@+id/card_left"
                android:orientation="vertical">
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:maxLines="1"
                    android:text="@{itemHall.hotel_name}"
                    android:textColor="#323038"
                    android:textSize="14dp" />
    
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_marginTop="2dp">
    
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:ellipsize="end"
                        android:maxLines="1"
                        android:text="@{itemHall.hall_name}"
                        android:textColor="#323038"
                        android:textSize="15dp"
                        android:textStyle="bold" />
    
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@{itemHall.price}"
                            android:textColor="#FF1D41"
                            android:textSize="16dp"
                            android:textStyle="bold" />
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="元全包/桌"
                            android:textColor="#FF1D41"
                            android:textSize="11dp" />
    
                    </LinearLayout>
    
                </LinearLayout>
                
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="1dp"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:maxLines="1"
                        android:text="@{itemHall.cate_name}"
                        android:textColor="#95949D"
                        android:textSize="11sp" />
    
                    <View
                        android:layout_width="1dp"
                        android:layout_height="10dp"
                        android:layout_gravity="center_vertical"
                        android:layout_marginLeft="7dp"
                        android:layout_marginRight="7dp"
                        android:background="#DFDFDF" />
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:maxLines="1"
                        android:text="@{itemHall.table_num}"
                        android:textColor="#95949D"
                        android:textSize="11sp" />
    
                    <View
                        android:layout_width="1dp"
                        android:layout_height="10dp"
                        android:layout_gravity="center_vertical"
                        android:layout_marginLeft="7dp"
                        android:layout_marginRight="7dp"
                        android:background="#DFDFDF" />
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:maxLines="1"
                        android:text="@{itemHall.pillar_name}"
                        android:textColor="#95949D"
                        android:textSize="11sp" />
    
                </LinearLayout>
    
            </LinearLayout>
    
        </LinearLayout>
    
    </layout>
    

    接着看下HallListAdapter中的代码:

    package com.example.databindingtest;
    
    import android.content.Context;
    import android.databinding.DataBindingUtil;
    import android.support.annotation.NonNull;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Toast;
    
    import com.example.databindingtest.databinding.ItemHallBinding;
    import com.example.databindingtest.model.HallListBean;
    import com.example.databindingtest.utils.BindingViewHolder;
    
    import java.util.ArrayList;
    
    public class HallListAdapter extends RecyclerView.Adapter<BindingViewHolder>{
    
        private Context context;
        private final LayoutInflater mLayoutInflater;
        private ArrayList<HallListBean.HallItem> hallList = new ArrayList<>();
    
        public HallListAdapter(Context context) {
            this.context = context;
            mLayoutInflater = (LayoutInflater)
                    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }
    
        @NonNull
        @Override
        public BindingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
            ItemHallBinding itemHallBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.item_hall, parent, false);
            return new BindingViewHolder(itemHallBinding);
        }
    
        @Override
        public void onBindViewHolder(@NonNull BindingViewHolder bindingViewHolder, final int position) {
    
            ItemHallBinding binding = (ItemHallBinding)bindingViewHolder.getBinding();
            binding.setVariable(BR.itemHall, hallList.get(position));
            binding.executePendingBindings();
    
            binding.llHall.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, hallList.get(position).hotel_name, Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        @Override
        public int getItemCount() {
            return hallList.size();
        }
    
        public void replaceData(ArrayList<HallListBean.HallItem> datas){
    
            hallList.clear();
            hallList.addAll(datas);
            notifyDataSetChanged();
        }
    }
    

    对应的ViewHolder为:

    package com.example.databindingtest.utils;
    
    import android.databinding.ViewDataBinding;
    import android.support.v7.widget.RecyclerView;
    
    public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder{
    
        private T mBinding;
    
        public BindingViewHolder(T mBinding) {
            super(mBinding.getRoot());
            this.mBinding = mBinding;
        }
    
        public T getBinding(){
            return mBinding;
        }
    
    }
    

    最后附上Demo中使用到的BindingAdapter:

    package com.example.databindingtest.utils;
    
    import android.databinding.BindingAdapter;
    import android.widget.ImageView;
    
    import com.bumptech.glide.Glide;
    
    public class ImageBinding {
    
        @BindingAdapter({"imageUrl"})
        public static void loadImageFromUrl(ImageView view,
                                            String url) {
            Glide.with(view.getContext())
                    .load(url)
                    .into(view);
        }
    }
    
    
    package com.example.databindingtest.utils;
    
    import android.databinding.BindingAdapter;
    import android.support.v7.widget.RecyclerView;
    
    import com.example.databindingtest.HallListAdapter;
    import com.example.databindingtest.model.HallListBean;
    
    import java.util.ArrayList;
    
    public class RecyclerItemBinding {
    
        @BindingAdapter("app:items")
        public static void setItems(RecyclerView recyclerView, ArrayList<HallListBean.HallItem> items) {
            HallListAdapter adapter = (HallListAdapter) recyclerView.getAdapter();
            if (adapter != null)
            {
                adapter.replaceData(items);
            }
        }
    }
    

    上述就是示例Demo的所有代码,如果大家有不同的观点,欢迎一起交流啊。

    相关文章

      网友评论

        本文标题:Android MVVM实战Demo --- 基于DataBin

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