1. 用到的组件 Room,ViewModel,LiveData,Repository,AsyncTack
2. Module 中 build.gradle 文件中添加
dependencies {def room_version = "2.4.3"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"
}
3. 数据操作
3.1 Word 实体类, Word.java
@Entity
public class Word {@PrimaryKey(autoGenerate = true)private int id; //主键@ColumnInfo(name = "english_word")private String word;@ColumnInfo(name = "chinese_meaning")private String chineseMeaning;public Word(String word, String chineseMeaning) {this.word = word;this.chineseMeaning = chineseMeaning;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getWord() {return word;}public void setWord(String word) {this.word = word;}public String getChineseMeaning() {return chineseMeaning;}public void setChineseMeaning(String chineseMeaning) {this.chineseMeaning = chineseMeaning;}
}
3.2 实现 Database 接口, WordDao.java
@Dao //Database access object
public interface WordDao {@Insertvoid insertWords(Word... words);@Updatevoid updateWords(Word... words);@Deletevoid deleteWords(Word... words);@Query("DELETE FROM WORD")void deleteAllWords();@Query("SELECT * FROM WORD ORDER BY ID DESC")LiveData<List<Word>> getAllWordsLive();//List<Word> getAllWords();
}
3.3 Database 管理操作数据库, WordDatabase.java
//singleton 只允许生成一个实例
@Database(entities = {Word.class}, version = 1, exportSchema = false)
public abstract class WordDatabase extends RoomDatabase {private static WordDatabase INSTANCE;//synchronized: 解决多个线程下调用,创建多个实例问题static synchronized WordDatabase getDatabase(Context context) {if (INSTANCE == null) {INSTANCE = Room.databaseBuilder(context.getApplicationContext(), WordDatabase.class, "word_database").build();}return INSTANCE;}public abstract WordDao getWordDao();
}
3.4 Repository 操作数据库, WordRepository.java
//Repository 仓库 获取数据的意思
class WordRepository {private WordDao wordDao;private LiveData<List<Word>> allWordsLive;WordRepository(Context context) {WordDatabase wordDatabase = WordDatabase.getDatabase(context);wordDao = wordDatabase.getWordDao();allWordsLive = wordDao.getAllWordsLive();}LiveData<List<Word>> getAllWordsLive() {return allWordsLive;}void insertWords(Word... words) {new InsertAsyncTask(wordDao).execute(words);}void updateWords(Word... words) {new UpdateAsyncTask(wordDao).execute(words);}void deleteWords(Word... words) {new DeleteAsyncTask(wordDao).execute(words);}void deleteAllWords() {new DeleteAllAsyncTask(wordDao).execute();}static class InsertAsyncTask extends AsyncTask<Word, Void, Void> {private WordDao wordDao;InsertAsyncTask(WordDao wordDao) {this.wordDao = wordDao;}@Overrideprotected Void doInBackground(Word... words) {wordDao.insertWords(words);return null;}}static class UpdateAsyncTask extends AsyncTask<Word, Void, Void> {private WordDao wordDao;UpdateAsyncTask(WordDao wordDao) {this.wordDao = wordDao;}@Overrideprotected Void doInBackground(Word... words) {wordDao.updateWords(words);return null;}}static class DeleteAsyncTask extends AsyncTask<Word, Void, Void> {private WordDao wordDao;DeleteAsyncTask(WordDao wordDao) {this.wordDao = wordDao;}@Overrideprotected Void doInBackground(Word... words) {wordDao.deleteWords(words);return null;}}static class DeleteAllAsyncTask extends AsyncTask<Void, Void, Void> {private WordDao wordDao;DeleteAllAsyncTask(WordDao wordDao) {this.wordDao = wordDao;}@Overrideprotected Void doInBackground(Void... voids) {this.wordDao.deleteAllWords();return null;}}
}
4. 实现 ViewModel, WordViewModel.java
public class WordViewModel extends AndroidViewModel {private WordRepository wordRepository;public WordViewModel(@NonNull Application application) {super(application);wordRepository = new WordRepository(application);}public LiveData<List<Word>> getAllWordsLive() {return wordRepository.getAllWordsLive();}void insertWords(Word... words) {wordRepository.insertWords(words);}void updateWords(Word... words) {wordRepository.updateWords(words);}void deleteWords(Word... words) {wordRepository.deleteWords(words);}void deleteAllWords() {wordRepository.deleteAllWords();}
}
5. RecyclerView 的实现
5.1 资源文件进入页面提示标志 ic_baseline_chevron_right_24.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:tint="@android:color/secondary_text_dark_nodisable"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="@android:color/white"android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z" />
</vector>
5.2 列表子布局常规 item, cell_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="?attr/selectableItemBackground"android:clickable="true"><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.1" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.85" /><TextViewandroid:id="@+id/tv_number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="TextView"android:textSize="16sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/guideline3"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:text="1" /><TextViewandroid:id="@+id/tv_english"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:text="TextView"android:textSize="24sp"app:layout_constraintBottom_toTopOf="@+id/tv_chinese"app:layout_constraintStart_toStartOf="@+id/tv_chinese"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/tv_chinese"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:text="TextView"android:textSize="18sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/guideline4"app:layout_constraintHorizontal_bias="0.02"app:layout_constraintStart_toStartOf="@+id/guideline3"app:layout_constraintTop_toBottomOf="@+id/tv_english" /><ImageViewandroid:id="@+id/imageView2"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="@+id/guideline4"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/ic_baseline_chevron_right_24" />
</androidx.constraintlayout.widget.ConstraintLayout>
5.3 列表子布局 cardView item, cell_card.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"android:layout_width="match_parent"android:layout_height="wrap_content"android:clickable="true"><androidx.cardview.widget.CardViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:foreground="?attr/selectableItemBackground"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:ignore="MissingConstraints"><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/tv_number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="TextView"android:textSize="16sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/guideline5"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:text="1" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.1" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline6"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.85" /><TextViewandroid:id="@+id/tv_english"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:text="TextView"android:textSize="24sp"app:layout_constraintBottom_toTopOf="@+id/tv_chinese"app:layout_constraintEnd_toStartOf="@+id/guideline6"app:layout_constraintHorizontal_bias="0.02"app:layout_constraintStart_toStartOf="@+id/guideline5"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/tv_chinese"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:text="TextView"android:textSize="18sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="@+id/tv_english"app:layout_constraintTop_toBottomOf="@+id/tv_english" /><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="@+id/guideline6"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/ic_baseline_chevron_right_24" /></androidx.constraintlayout.widget.ConstraintLayout></androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
5.4 RecyclerView 内容管理器 Adapter, MyAdapter.java
//内容管理器
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {private List<Word> allWords = new ArrayList<>();private boolean useCardView;public void setAllWords(List<Word> allWords) {this.allWords = allWords;}public MyAdapter(boolean useCardView) {this.useCardView = useCardView;}@NonNull@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());View itemView;if (useCardView) {itemView = layoutInflater.inflate(R.layout.cell_card, parent, false);} else {itemView = layoutInflater.inflate(R.layout.cell_normal, parent, false);}return new MyViewHolder(itemView);}@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {Word word = allWords.get(position);holder.tvNumber.setText(String.valueOf(position + 1));holder.tvEnglish.setText(word.getWord());holder.tvChinese.setText(word.getChineseMeaning());holder.itemView.setOnClickListener(view -> {Uri uri = Uri.parse("https://m.youdao.com/m/result?lang=en&word=" + word.getWord());Intent intent = new Intent(Intent.ACTION_VIEW);intent.setData(uri);holder.itemView.getContext().startActivity(intent);});}@Overridepublic int getItemCount() {return allWords.size();}static class MyViewHolder extends RecyclerView.ViewHolder {TextView tvNumber, tvEnglish, tvChinese;public MyViewHolder(@NonNull View itemView) {super(itemView);tvNumber = itemView.findViewById(R.id.tv_number);tvEnglish = itemView.findViewById(R.id.tv_english);tvChinese = itemView.findViewById(R.id.tv_chinese);}}
}
6. 测试调用
6.1 布局文件,activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.85" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintBottom_toTopOf="@+id/guideline2"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><Buttonandroid:id="@+id/bt_clear"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Clear"app:layout_constraintBottom_toBottomOf="@+id/switch1"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.5"app:layout_constraintStart_toEndOf="@+id/switch1"app:layout_constraintTop_toTopOf="@+id/switch1" /><Buttonandroid:id="@+id/bt_insert"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="insert"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/switch1"app:layout_constraintHorizontal_bias="0.5"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="@+id/guideline2" /><Switchandroid:id="@+id/switch1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:minHeight="48dp"android:text="CardView"app:layout_constraintBottom_toBottomOf="@+id/bt_insert"app:layout_constraintEnd_toStartOf="@+id/bt_clear"app:layout_constraintHorizontal_bias="0.5"app:layout_constraintStart_toEndOf="@+id/bt_insert"app:layout_constraintTop_toTopOf="@+id/bt_insert" /></androidx.constraintlayout.widget.ConstraintLayout>
6.2 测试文件,MainActivity. java
public class MainActivity extends AppCompatActivity {Button btInsert, btClear;Switch aSwitch;WordViewModel viewModel;RecyclerView recyclerView;MyAdapter myAdapter1, myAdapter2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myAdapter1 = new MyAdapter(false);myAdapter2 = new MyAdapter(true);recyclerView = findViewById(R.id.recyclerView);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(myAdapter1);aSwitch = findViewById(R.id.switch1);aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton compoundButton, boolean isChanged) {if (isChanged) {recyclerView.setAdapter(myAdapter2);} else {recyclerView.setAdapter(myAdapter1);}}});viewModel = new ViewModelProvider(this).get(WordViewModel.class);viewModel.getAllWordsLive().observe(this, new Observer<List<Word>>() {@Overridepublic void onChanged(List<Word> words) {myAdapter1.setAllWords(words);myAdapter1.notifyDataSetChanged();myAdapter2.setAllWords(words);myAdapter2.notifyDataSetChanged();}});View.OnClickListener listener = new View.OnClickListener() {@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.bt_insert:String[] english = {"Hello","World","Android","Google","Studio","Project","Database","Recycler","View","String","Value","Integer"};String[] chinese = {"你好","世界","安卓","谷歌","工作室","项目","数据库","回收站","视图","字符串","值","整数类型"};for (int i = 0; i < english.length; i++) {viewModel.insertWords(new Word(english[i], chinese[i]));}break;case R.id.bt_clear:viewModel.deleteAllWords();break;}}};btInsert = findViewById(R.id.bt_insert);btClear = findViewById(R.id.bt_clear);btInsert.setOnClickListener(listener);btClear.setOnClickListener(listener);}
}
7.效果图