教程地址:https://www.bilibili.com/video/av65180549
源码地址:https://github.com/longway777/Android-2019-Tutorial-RoomBasic-step-3
RecyclerView 是一个回收视图,当滚动出屏幕外面的内容会自动回收,回收系统资源
相同的内容,支持用不同的样式来呈现!
创建2个 Layout 资源文件
<?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.Guideline android:id="@+id/guideline2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.1" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.85" /> <TextView android:id="@+id/textViewNumber" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="1" /> <TextView android:id="@+id/textViewEnglish" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="TextView" android:textSize="18sp" app:layout_constraintBottom_toTopOf="@+id/textViewChinese" app:layout_constraintEnd_toStartOf="@+id/guideline3" app:layout_constraintHorizontal_bias="0.1" app:layout_constraintStart_toStartOf="@+id/guideline2" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textViewChinese" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/textViewEnglish" app:layout_constraintTop_toBottomOf="@+id/textViewEnglish" /> <ImageView android: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/guideline3" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/ic_chevron_right_black_24dp" /> </androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent" android:foreground="?selectableItemBackground" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.10948905" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.85" /> <TextView android:id="@+id/textViewNumber" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline4" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="1" /> <TextView android:id="@+id/textViewEnglish" 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/textViewChinese" app:layout_constraintEnd_toStartOf="@+id/guideline5" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="@+id/guideline4" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textViewChinese" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/textViewEnglish" app:layout_constraintTop_toBottomOf="@+id/textViewEnglish" /> <ImageView android: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/guideline5" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/ic_chevron_right_black_24dp" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> </LinearLayout>
2.创建 适配器 Adapter类 ,继承自 RecylerView.Adapter ,是 RecyclerView 的内容管理器
package com.example.roombasic;
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.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
//用来存放数据的列表
List<Word> allWords = new ArrayList<>();
boolean use_CellCard; //是否使用 cell_card 这个样式
public MyAdapter(boolean use_CellCard) {
this.use_CellCard = use_CellCard;
}
public void setAllWords(List<Word> allWords) {
this.allWords = allWords;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
//用开关控件,控制不同的样式
View itemView ;
if(use_CellCard)
itemView = layoutInflater.inflate(R.layout.cell_card,parent,false);
else
itemView = layoutInflater.inflate(R.layout.cell_normal,parent,false);
return new MyViewHolder(itemView);
}
//数据绑定
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
//数据绑定
final Word word = allWords.get(position); //通过位置找到内容
holder.textViewNumber.setText(String.valueOf(position + 1));
holder.textViewEnglish.setText(word.getWord());
holder.textViewChinese.setText(word.getChineseMeaning());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Uri uri = Uri.parse("http://m.youdao.com/dict?le=eng&q=" + holder.textViewEnglish.getText());
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
holder.itemView.getContext().startActivity(intent);
}
});
}
//返回列表数据的总个数
@Override
public int getItemCount() {
return allWords.size();
}
// 因为需要管理三个内容,左边的数字,右上英文,右下汉字,所以创建三个值来管理
// 创建一个属于 Adapter 自身的 ViewHolder
//加 static 防内存泄漏
static class MyViewHolder extends RecyclerView.ViewHolder{
TextView textViewNumber,textViewEnglish,textViewChinese;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textViewNumber = itemView.findViewById(R.id.textViewNumber);
textViewEnglish = itemView.findViewById(R.id.textViewEnglish);
textViewChinese = itemView.findViewById(R.id.textViewChinese);
}
}
}
3. MainActivity.java 类
package com.example.roombasic; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.SavedStateViewModelFactory; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class MainActivity extends AppCompatActivity { //WordDatabase wordDatabase; //WordDao wordDao; Button buttonInsert,buttonUpdate,buttonClear,buttonDelete; TextView textView; LiveData<List<Word>> allWordsLive; WordViewModel wordViewModel; RecyclerView recyclerView; MyAdapter myAdapter1; //cell_normal MyAdapter myAdapter2; //cell_card ,这里必须弄2个适配器,要不然一切换数据加载不出来!?? Switch aSwitch; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //wordDatabase = Room.databaseBuilder(this,WordDatabase.class,"word_database") //.allowMainThreadQueries() //allowMainThreadQueries() 强制允许在主线程运行 // .build(); //wordDao = wordDatabase.getWordDao(); //wordViewModel = ViewModelProviders recyclerView = findViewById(R.id.recyclerView); myAdapter1 = new MyAdapter(false); myAdapter2 = new MyAdapter(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(myAdapter1); wordViewModel = new ViewModelProvider(this,new SavedStateViewModelFactory(getApplication(),this)).get(WordViewModel.class); //allWordsLive = wordDao.getAllWordLive(); textView = findViewById(R.id.textViewNumber); buttonInsert = findViewById(R.id.buttonInsert); buttonUpdate = findViewById(R.id.buttonUpdate); buttonClear = findViewById(R.id.buttonClear); buttonDelete = findViewById(R.id.buttonDelete); aSwitch = findViewById(R.id.switch1); //开关监听,用的是哪种样式? aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(aSwitch.isChecked()){ recyclerView.setAdapter(myAdapter2); } else{ recyclerView.setAdapter(myAdapter1); } } }); //利用 LiveData<> 与 observe的onChanged配合,数据自动刷新 //allWordsLive.observe(this, new Observer<List<Word>>() { wordViewModel.getAllWordsLive().observe(this, new Observer<List<Word>>() { @Override public void onChanged(List<Word> words) { //当数据改变时会自动呼叫这个函数 //String text=""; /*StringBuilder text = new StringBuilder(); textView.setText(text); //先将 textView 清空 for(int i=0;i<words.size();i++){ Word word = words.get(i); text.append(word.getId() + ":" + word.getWord() + "=" + word.getChineseMeaning() + "\n"); textView.setText(text); }*/ myAdapter1.setAllWords(words); myAdapter1.notifyDataSetChanged(); myAdapter2.setAllWords(words); myAdapter2.notifyDataSetChanged(); } }); buttonInsert.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String[] english = new String[]{"Hello", "World", "Android", "Google", "Studio", "Project", "Database", "RecyclerView", "View", "Value" }; String[] chinese; chinese = new String[]{"你好", "世界", "安卓", "谷歌", "工作室", "项目", "数据库", "回收站", "视图", "数值" }; for(int i=0;i<english.length;i++){ wordViewModel.insertWords(new Word(english[i],chinese[i])); } } }); buttonUpdate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Word word = new Word("English","英语"); word.setId(76); //更新是用主键来更新的 wordViewModel.updateWords(word); //wordDao.updateWords(word); //new UpdateAsyncTask(wordDao).execute(word); //updateView(); } }); //删除所有的记录 buttonClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //wordDao.deleteAllWords(); //new DeleteAllAsyncTask(wordDao).execute(); //updateView(); wordViewModel.deleteAllWords(); } }); buttonDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Word word = new Word("English","英语"); word.setId(76); //删除也是用主键来更新的 wordViewModel.deleteWords(word); //wordDao.deleteWords(word); //new DeleteAsyncTask(wordDao).execute(word); //updateView(); } }); } /*void updateView(){ List<Word> list = wordDao.getAllWords(); String text=""; textView.setText(text); //先将 textView 清空 for(int i=0;i<list.size();i++){ Word word = list.get(i); text += word.getId() + ":" + word.getWord() + "=" + word.getChineseMeaning() + "\n"; textView.setText(text); } }*/ }
4.细节
项目每一行设置可点击,在cell_normal.xml 中 设置 android:clickable="true"
项目点击后,有一个背景, android:foreground="?selectableItemBackground"
Android Studio 之 ROM【3】,LiveData+ViewModel+AsyncTask+Repository+RecyclerView