Room提供更簡潔的方法將資料儲存於本機資料庫中,將SQL語法的INSERT、UPDATE、DELETE等指令包裝成註解,大大降低建立資料庫的時間,在使用上更加便利。
今天實作一個簡易的電話簿程式,使用到Rxjava與RecyclerView來協助撰寫,如果對RecyclerView較為不熟,可以往前看教學文章。
<?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">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Name"
android:textSize="20sp"/>
<EditText
android:id="@+id/edit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Phone"
android:textSize="20sp"/>
<EditText
android:id="@+id/edit_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName" />
</LinearLayout>
<Button
android:id="@+id/button_insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="50dp"
android:layout_marginTop="50dp"
android:text="新增"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<Button
android:id="@+id/button_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_marginEnd="50dp"
android:text="刪除"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_insert" />
</androidx.constraintlayout.widget.ConstraintLayout>
Room由三層架構組合而成:
//設定表格名稱
@Entity(tableName = "UserTable")
public class UserData {
//設置自動累加id
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String phone;
public UserData(String name, String phone) {
this.name = name;
this.phone = phone;
}
//建立getter and setter方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
@Entity標註後方須給表格名稱,使用@PrimaryKey標註則表示此變數會自動補上最新的數值,主要用於區分各筆資料。
@androidx.room.Dao
public interface Dao {
//資料表名稱
String tableName = "UserTable";
//新增資料的方法
@Insert(onConflict = OnConflictStrategy.REPLACE)
Completable insertData(UserData userData);
//撈取資料的方法
@Query("SELECT * FROM " + tableName)
Maybe<List<UserData>> selectAllData();
//刪除資料的方法
@Query("DELETE FROM "+tableName)
Completable deleteAllData();
}
這層架構提供我們使用標註及少量的SQL語法操作資料庫,提升資料庫的建構效率。
@Database(entities = {UserData.class},version = 1,exportSchema = false)
public abstract class DataBase extends RoomDatabase {
//資料庫名稱
public static final String DB = "UserData.db";
private static volatile DataBase instance;
public static DataBase getInstance(Context context){
//確認是否存在,避免重複消耗資源
//fallbackToDestructiveMigration(),會直接把table重建
if (instance==null){
instance = Room.databaseBuilder(context,DataBase.class,DB)
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
abstract public Dao getDao();
}
以上三層建構好後,我們開始來撰寫我們的主程式:
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
RecyclerViewAdapter recyclerViewAdapter;
Button button_insert, button_delete;
EditText edit_name, edit_phone;
UserData userData;
List<UserData> userDataResponse = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//設置資料庫監視工具
Stetho.initializeWithDefaults(this);
button_insert = findViewById(R.id.button_insert);
button_delete = findViewById(R.id.button_delete);
edit_name = findViewById(R.id.edit_name);
edit_phone = findViewById(R.id.edit_phone);
recyclerView = findViewById(R.id.recyclerview);
//設定 recyclerView 的 Adapter 和 Manager
recyclerViewAdapter = new RecyclerViewAdapter();
recyclerView.setAdapter(recyclerViewAdapter);
//設置布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//添加底線樣式
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
//onCreate時先抓取本機資料
getRoomData();
//新增按鈕點擊事件
button_insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userData = new UserData(edit_name.getText().toString(), edit_phone.getText().toString());
if(edit_name.getText().toString().matches("") != true && edit_phone.getText().toString().matches("") != true){
insertRoomData(userData);
}
}
});
//刪除按鈕點擊事件
button_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
deleteRoomData();
}
});
}
//新增資料
public void insertRoomData(UserData userData) {
DataBase.getInstance(MainActivity.this).getDao().insertData(userData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
//新增資料成功
//新增成功後清空輸入框
edit_name.setText("");
edit_phone.setText("");
//重新獲取資料
getRoomData();
}
@Override
public void onError(Throwable e) {
//新增資料失敗
}
});
}
//刪除資料
public void deleteRoomData() {
DataBase.getInstance(MainActivity.this).getDao().deleteAllData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
//刪除資料成功
//重新獲取資料
getRoomData();
}
@Override
public void onError(Throwable e) {
//刪除資料失敗
}
});
}
//獲取資料
public void getRoomData() {
DataBase.getInstance(MainActivity.this).getDao().selectAllData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MaybeObserver<List<UserData>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(List<UserData> userDataList) {
//獲取資料成功
userDataResponse = userDataList;
//將userDataList傳入recyclerViewAdapter
recyclerViewAdapter.setRoomDataList(userDataList);
//刷新RecyclerView資料
recyclerViewAdapter.notifyDataSetChanged();
}
@Override
public void onError(Throwable e) {
//獲取資料失敗
}
@Override
public void onComplete() {
}
});
}
}
這邊附上RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
List<UserData>mDataList = new ArrayList<>();
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_Num,tv_Name,tv_Phone;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tv_Num = itemView.findViewById(R.id.tv_Num);
tv_Name = itemView.findViewById(R.id.tv_Name);
tv_Phone = itemView.findViewById(R.id.tv_Phone);
}
void setShowData(int position){
//設定顯示資料
tv_Num.setText(String.valueOf(mDataList.get(position).getId()));
tv_Name.setText(mDataList.get(position).getName());
tv_Phone.setText(mDataList.get(position).getPhone());
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
//設定顯示資料
holder.setShowData(position);
}
@Override
public int getItemCount() {
return mDataList.size();
}
//傳入MainActivity中的userDataList
public void setRoomDataList(List<UserData>userDataList){
mDataList = userDataList;
notifyDataSetChanged();
}
}