Room,数据库框架学习二(使用RecyclerView和databinding)

前言

Room,数据库框架学习一
上一篇中我们简单的搭建了一个用Room数据库框架完成的demo,这一篇我们将结合RecyclerView和databinding的形式实现数据的加载,进一步完成项目。关于项目的搭建可以参照前一篇文章。
①首先把上一篇布局中的TextView去掉,换成RecyclerView,然后增加一个switch开关按钮。
activity_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="data"
            type="com.mrlove.roombasic2.MyViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@+id/guideline3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.7" />

        <Button
            android:id="@+id/buttoninsert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/buttoninsert"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/buttonupdate"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline3"
            app:layout_constraintVertical_bias="0.151" />

        <Button
            android:id="@+id/buttonupdate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/buttonupdate"
            app:layout_constraintBottom_toBottomOf="@+id/buttoninsert"
            app:layout_constraintEnd_toStartOf="@+id/buttondelete"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/buttoninsert" />

        <Button
            android:id="@+id/buttondelete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/buttondelete"
            app:layout_constraintBottom_toBottomOf="@+id/buttonupdate"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/buttonupdate" />

        <Switch
            android:id="@+id/switch1"
            android:layout_width="wrap_content"
            android:layout_height="27dp"
            android:text="@string/text_switch"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="@+id/buttondelete"
            app:layout_constraintTop_toBottomOf="@+id/buttondelete"
            app:layout_constraintVertical_bias="0.601" />

        <Button
            android:id="@+id/buttonclear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="60dp"
            android:text="@string/buttonclear"
            app:layout_constraintStart_toStartOf="@+id/buttonupdate"
            app:layout_constraintTop_toBottomOf="@+id/buttonupdate" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

②然后为RecyclerView创建两个不同的内容布局文件,一个是常见的内容布局文件,一个是用CardView实现的内容布局文件。
cell_normal.xml

<?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="data"
           type="com.mrlove.roombasic2.MyViewModel" />
    </data>
    <!--android:clickable="true" 实现元素的可点击-->
    <!-- android:foreground="?attr/selectableItemBackground" 为点击创建点击效果-->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackground"
        android:clickable="true"
        android:orientation="vertical">

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.08" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.9" />

        <TextView
            android:id="@+id/textNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/textnumber"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/guideline"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textEnglish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/textEnglish"
            android:textSize="24sp"
            app:layout_constraintBottom_toTopOf="@+id/textChinese"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="@+id/guideline"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textChinese"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/textChinese"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="@+id/textEnglish"
            app:layout_constraintTop_toBottomOf="@+id/textEnglish" />

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/Imgarrow"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="@+id/guideline2"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_arrow_forward_black_24dp" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

cell_card.xml

<?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="data"
            type="com.mrlove.roombasic2.MyViewModel" />
    </data>
    <!--android:clickable="true" 实现元素的可点击-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:orientation="vertical">
        <!-- android:foreground="?attr/selectableItemBackground" 为点击创建点击效果-->
        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:foreground="?attr/selectableItemBackground">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <androidx.constraintlayout.widget.Guideline
                    android:id="@+id/guideline"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    app:layout_constraintGuide_percent="0.08" />

                <androidx.constraintlayout.widget.Guideline
                    android:id="@+id/guideline2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    app:layout_constraintGuide_percent="0.9" />

                <TextView
                    android:id="@+id/textNumber"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/textnumber"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toStartOf="@+id/guideline"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

                <TextView
                    android:id="@+id/textEnglish"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:text="@string/textEnglish"
                    android:textSize="24sp"
                    app:layout_constraintBottom_toTopOf="@+id/textChinese"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.0"
                    app:layout_constraintStart_toStartOf="@+id/guideline"
                    app:layout_constraintTop_toTopOf="parent" />

                <TextView
                    android:id="@+id/textChinese"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="8dp"
                    android:text="@string/textChinese"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintStart_toStartOf="@+id/textEnglish"
                    app:layout_constraintTop_toBottomOf="@+id/textEnglish" />

                <ImageView
                    android:id="@+id/imageView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:contentDescription="@string/Imgarrow"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="@+id/guideline2"
                    app:layout_constraintTop_toTopOf="parent"
                    app:srcCompat="@drawable/ic_arrow_forward_black_24dp" />

            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>
    </LinearLayout>
</layout>

③为RecyclerView创建一个适配器Adapter,首先当适配器创建时会先执行onCreateViewHolder()方法,这时可以在此方法中绑定不同布局,获取binding实例。然后把不同的binding作为参数,返回一个自定义的MyViewHolder。接着当执行onBindViewHolder()方法时,通过我们已经初始化的holder,来为布局UI绑定数据。
MyAdapter.java

package com.mrlove.roombasic2;

import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;

import com.mrlove.roombasic2.databinding.CellCardBinding;
import com.mrlove.roombasic2.databinding.CellNormalBinding;
import com.mrlove.roombasic2.domain.Word;

import java.util.ArrayList;
import java.util.List;

//RecyclerView内容管理器类 泛型参数指定为自己的
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private List<Word> allWords = new ArrayList<>();
    private boolean useCardView;
    private CellNormalBinding normalBinding;
    private CellCardBinding cardBinding;

    //返回所有的数据
    void setAllWords(List<Word> allWords) {
        this.allWords = allWords;
    }

    //初始化布局标志位
    public MyAdapter(boolean useCardView) {
        this.useCardView = useCardView;
    }

    //当适配器创建的时候调用
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //RecyclerView中调用Databinding,绑定布局,获取binding实例
        //根据标识位初始化获取不同的binding
        if (useCardView) {
            cardBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.cell_card, parent, false);
            //把binding作为参数,返回一个自定义的MyViewHolder
            return new MyViewHolder(cardBinding);
        } else {
            normalBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.cell_normal, parent, false);
            return new MyViewHolder(normalBinding);
        }
    }

    //当调用ViewHolder时响应
    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
        //获取当前位置的一行数据
        Word word = allWords.get(position);
        //设置数据
        holder.textNumber.setText(String.valueOf(position + 1)); //让页面显示从1开始,而不用显示word.getId数据库中实际的位置
        holder.textEnglish.setText(word.getWord());
        holder.textChinese.setText(word.getChineseMeaning());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri uri = Uri.parse("https://m.youdao.com/dict?le=eng&q=" + holder.textEnglish.getText());
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(uri);
                holder.itemView.getContext().startActivity(intent);
            }
        });
    }

    @Override
    public int getItemCount() {
        //返回一个数据的容量
        return allWords.size();
    }

    //把onCreateViewHolder方法中的binding存起来,可以下次再用。这样做的好处就是不必每次都到布局文件中去拿到你的View,提高了效率。
    static class MyViewHolder extends RecyclerView.ViewHolder {
        private CellNormalBinding normalBinding;
        private CellCardBinding cardBinding;
        private TextView textNumber, textEnglish, textChinese;
        //两种参数不同的构造函数初始化不同的布局控件
        MyViewHolder(CellNormalBinding binding) {
            super(binding.getRoot());
            normalBinding = binding;
            textNumber = normalBinding.textNumber;
            textEnglish = normalBinding.textEnglish;
            textChinese = normalBinding.textChinese;
        }

        MyViewHolder(CellCardBinding binding) {
            super(binding.getRoot());
            cardBinding = binding;
            textNumber = cardBinding.textNumber;
            textEnglish = cardBinding.textEnglish;
            textChinese = cardBinding.textChinese;
        }
    }
}

④在mainactivity中,首先创建两个不同类型的适配器,然后为RecyclerView给个默认初始化的适配器,通过switch按钮的点击事件为RecyclerView设置不同的适配器,然后为两种不同的适配器都要实现其数据的填充,并且通过notifyDataSetChanged()方法,进行适配器数据的刷新。
MainActivity.java

package com.mrlove.roombasic2;

import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.Observer;
import androidx.lifecycle.SavedStateViewModelFactory;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.mrlove.roombasic2.databinding.ActivityMainBinding;
import com.mrlove.roombasic2.domain.Word;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    MyViewModel myViewModel;
    //DatabindingBinding 由框架编译时生成,负责通知界面同步更新(命名方式:xml文件名 + Binding);
    ActivityMainBinding binding;
    MyAdapter myAdaptercard, myAdapternormal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //DataBindingUtil 将布局文件与Activity关联,生成DatabindingBinding实例binding;
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        //获取ViewModel实例
        myViewModel = new ViewModelProvider(this, new SavedStateViewModelFactory(getApplication(), this)).get(MyViewModel.class);
        //为布局文件设置源数据
        binding.setData(myViewModel);
        myAdapternormal = new MyAdapter(false);
        myAdaptercard = new MyAdapter(true);
        binding.recyclerview.setLayoutManager(new LinearLayoutManager(this));
        binding.recyclerview.setAdapter(myAdapternormal);

        binding.switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if (b) {
                    binding.recyclerview.setAdapter(myAdaptercard);
                } else {
                    binding.recyclerview.setAdapter(myAdapternormal);
                }
            }
        });

        //为实现LiveData的数据设置观察者,以便当数据改变时通知UI更新数据
        myViewModel.getAllWordsLive().observe(this, new Observer<List<Word>>() {
            @Override
            public void onChanged(List<Word> words) {
                myAdaptercard.setAllWords(words);
                myAdaptercard.notifyDataSetChanged();
                myAdapternormal.setAllWords(words);
                myAdapternormal.notifyDataSetChanged();
            }
        });
        //添加
        binding.buttoninsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Word word1 = new Word("hello", "你好");
                Word word2 = new Word("world", "世界");
                myViewModel.insertWords(word1, word2);

            }
        });
        //删除所有
        binding.buttonclear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.clearWords();

            }
        });
        //更新
        binding.buttonupdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Word word = new Word("haha", "哈哈");
                word.setId(40);
                myViewModel.updateWords(word);
            }
        });
        //删除某一项
        binding.buttondelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Word word = new Word("haha", "哈哈");
                word.setId(40);
                myViewModel.deleteWords(word);
            }
        });
    }
}

至此,一个通过RecyclerView和Databinding实现的Room已经完成。
github参考代码:https://github.com/Mrlove133481/RoomBasic2

你可能感兴趣的:(Android)