教程地址:https://www.bilibili.com/video/av65180549html
源碼地址:https://github.com/longway777/Android-2019-Tutorial-RoomBasic-step-3java
RecyclerView 是一個回收視圖,當滾動出屏幕外面的內容會自動回收,回收系統資源android
相同的內容,支持用不一樣的樣式來呈現!git
建立2個 Layout 資源文件github
<?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 類app
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.細節ide
項目每一行設置可點擊,在cell_normal.xml 中 設置 android:clickable="true"函數
項目點擊後,有一個背景, android:foreground="?selectableItemBackground"ui