今天要來聊聊Android JetPack 中的 Room DataBase的部分
以及配合Stetho監視 Room資料庫內容這回事(・ωー)~☆
之前我曾經發過一個講述使用SQLite DataBase的部分
在這裡->碼農日常-『Android studio』SQLite資料庫建立、資料表建立與操作以及Stetho工具
2021/3/20更新
如果有需要知道Room資料庫遷移(新增資料欄位)的方法的話,請參考這篇
->碼農日常-『Android studio』Room database Migrate 資料庫版本遷移
此外目前本篇提供的Git連結已更新為遷移後的狀態,如果要看本篇的內容,也請點這篇文章,並拉到第4大段
文章有教學如何看到Github內舊的程式碼哦
當時在寫這篇的時候,就想說總有一天一定要寫一篇Room資料庫的部分
於是...我就寫了(´・з・)
關於這篇閒聊一下~因為我想說喔之前寫了一篇SQLite的文章
所以這次我想就直接用那篇的介面以及那篇的功能直接用Room框架實現
呃...當然啦,也不是說要看懂這篇文章就一定得回去看我那篇文章
介面以及載入Library都會重講哦(`・ω・´)+
OK,那就來看看今天要做的內容吧d(>_・ )
介面
新增資料
修改資料
刪除資料
GitHub
→https://github.com/thumbb13555/RoomDataBaseExample
1.載入相關的庫
統整一下今天要使用的庫
1.Room本身要用的庫->Room資料庫官方
2.Facebook的Stetho 資料庫監視庫->Facebook stetho
3.lifecycle庫->Lifecycle官方
因為今天要載入的東西多,我就直接給你需要的內容就好(但是版本要自己去注意哦(・ωー)~☆)
def room_version = "2.2.5"
def lifecycle_version = "2.2.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
androidTestImplementation "androidx.room:room-testing:$room_version"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation 'com.facebook.stetho:stetho:1.5.1'
載入方法
打開build.gradle(Module: app)
將上述內容全部載入至此(dependencies)
按下Sync Now即完成
2.建立畫面
這次想存入的內容跟前篇一樣,我預計存入
1.姓名(String)
2.電話(String)
3.興趣(String)
4.其他(String)
四個欄位
請原諒我都使用String變數QQ,做完才發現
我直接PO介面Xml給各位,直接複製吧!
3.建立需要的類別
完成了以上的功能之後,可以先試著執行一下,看看有沒有什麼奇怪的毛病(´・д・`)
這時候應該是可以順利執行,但畫面不會有東西就是
再來我們先建立需要的類別
除了原廠給的MainActivity.java之外
還要建立三個類別
分別為
1.連接主介面與DB的抽象類別
2.設置操作資料庫SQL語法的DAO-Interface
3.Getter-Setter的類別
關於使用Getter-Setter的基本觀念可以參照我這篇文章
->碼農日常-『Java』List<GetterSetter> 如何在陣列中使用Getter Setter
先PO建立起來會長怎麼樣
那一個一個建立,先從資料夾開始吧(笑)
通常第二層資料夾如果在做大型專案時,是肯定會加入的東西
為了方便分類....
如果客倌是學生的話,我是不知道現在的學生會不會資料夾分類啦...至少我遇過的學生普遍沒這習慣
通常因為Room在製作時最少都要三個類別,因此我會建議放一個資料夾包起來
資料夾建立
在你要建立資料夾的那一層點右鍵->New->Package
就完成建立囉!
建立類別檔大家可能沒什麼問題,建立抽象類別的話可能有些人比較陌生
首先一樣按照建立新的類別的方法到這個介面為止(右鍵->New->Java Class)
然後注意⚠️在底下Modifiers的部分
點擊Abstract(抽象的),按下OK
這樣就完成一個抽象類別了
再來是DAO 的Interface的部分
一樣是到這個畫面
然後點擊Kind的下拉式選單
選擇Interface就完成囉
最後在建立一個一般的類別,請直接建立吧
完成後就如同這個圖
4.撰寫需要的內容
首先先建立Getter-Setter的檔案好了
基本上設置方法請參照Getter-Setter的作法
這邊我的類別檔取名為MyData.java,大家自由取名就好
直接PO程式
再來是抽象類別的部分
一樣PO全部
最後是Interface內容
Interface基本上就是用來設置SQL語法的地方,跟SQLite大同小異
但是他提供了更簡單的方法來設置在SQLite中操作的各種語法
我已經將常用的新增、修改、刪除、撈取等四種常用方法都寫進去了,請自由使用(・ω・)b
5.寫功能
OK接下來是重頭戲
在剛剛上面的內容因為我覺得沒什麼特別好說的,所以我就只放註解沒特別解釋
接下來的內容將會一段一段講,當然沒興趣看我說的話直接跳去最後面複製就好(・∀・)
((其實如果不需要知道我程式在講什麼的話可以直接從我的Git將專案複製到自己的編輯器內就好....
將整個重點來到Main.Activity.java
製作步驟大致如下
1.連接所有的介面元件及載入資料庫監視軟體Stetho
2.製作RecyclerView的適配器Adapter以及內容方法
3.新增資料
4.撈取資料顯示於介面上
5.修改資料
6.製作左右滑動刪除
7.刪除資料
ㄎㄅ..七個步驟,會寫死我自己_(:3」∠)_←我說網誌
首先是連接介面...老掉牙的東西不再解釋
紅字的全域變數記得加入~
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
MyData nowSelectedData;//取得在畫面上顯示中的資料內容
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);//設置資料庫監視
Button btCreate = findViewById(R.id.button_Create);
Button btModify = findViewById(R.id.button_Modify);
Button btClear = findViewById(R.id.button_Clear);
EditText edName = findViewById(R.id.editText_Name);
EditText edPhone = findViewById(R.id.editText_Phone);
EditText edHobby = findViewById(R.id.editText_Hobby);
EditText edElseInfo = findViewById(R.id.editText_else);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
.
.
.
}
}
製作RecyclerView的適配器(Adapter)
再來製作RecyclerView要用的Adapter
private static class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<MyData> myData;
private Activity activity;
private OnItemClickListener onItemClickListener;
public MyAdapter(Activity activity, List<MyData> myData) {
this.activity = activity;
this.myData = myData;
}
/**建立對外接口*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
View view;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvTitle = itemView.findViewById(android.R.id.text1);
view = itemView;
}
}
/**更新資料*/
public void refreshView() {
new Thread(()->{
List<MyData> data = DataBase.getInstance(activity).getDataUao().displayAll();
this.myData = data;
activity.runOnUiThread(() -> {
notifyDataSetChanged();
});
}).start();
}
/**刪除資料*/
public void deleteData(int position){
new Thread(()->{
DataBase.getInstance(activity).getDataUao().deleteData(myData.get(position).getId());
activity.runOnUiThread(()->{
notifyItemRemoved(position);
refreshView();
});
}).start();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_1, null);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.tvTitle.setText(myData.get(position).getName());
holder.view.setOnClickListener((v)->{
onItemClickListener.onItemClick(myData.get(position));
});
}
@Override
public int getItemCount() {
return myData.size();
}
/**建立對外接口*/
public interface OnItemClickListener {
void onItemClick(MyData myData);
}
}
為了程式美觀(自認為XD)我將所有跟資料庫操作的方法都寫在Adapter內
主要就是重新撈資料與刪除資料的部分
refreshView()
的這一支副程式,他的重點就是重新抓取資料庫內所有資料並顯示
藍色部分則是建立一個內部的InterFace方法,將點擊選取到的資料傳出去(Adapter)外面
新增資料
因為沒有資料沒辦法驗證撈取( ´_ゝ`)所以先新增一筆資料
我把它寫在btCreate的按鈕內
/**新增資料*/
btCreate.setOnClickListener((v -> {
new Thread(() -> {
String name = edName.getText().toString();
String phone = edPhone.getText().toString();
String hobby = edHobby.getText().toString();
String elseInfo = edElseInfo.getText().toString();
if (name.length() == 0) return;//如果名字欄沒填入任何東西,則不執行下面的程序
MyData data = new MyData(name, phone, hobby, elseInfo);
DataBase.getInstance(this).getDataUao().insertData(data);
runOnUiThread(() -> {
myAdapter.refreshView();
edName.setText("");
edPhone.setText("");
edHobby.setText("");
edElseInfo.setText("");
});
}).start();
}));
這左一按鈕的點擊事件
抓取四個EditText內容,存入MyData類別,最後在統一輸入到資料庫
綠色部分是更新資料,因為目前還沒寫Adapter,所以暫時先註解掉
((不然閃退的話不要來幹我.....(`Д´*)
另外紅字部分,這很重點~~~~
這是在Room操作最有名的一句話
凡是所有Room的操作都要寫在子執行緒!
凡是所有Room的操作都要寫在子執行緒!!
凡是所有Room的操作都要寫在子執行緒!!!
子執行緒是什麼?就是背景執行啦
因為撈資料的行為本身是耗時操作,所以一定得寫(其實是不寫會閃退....
這部分的話看你要用Handler、Thread、AsyneTask都可以,看你熟悉哪個,我示範用Thread
這時候可以打開Stetho,看看資料有沒有進去
↓
看到這個畫面就是資料已輸入囉(・ωー)~☆
撈取資料並顯示
這時候可以先把剛才綠色註解取消掉,因為要來處理建立Adapter了XD
請在onCreate內的recyclerview下方加入這些
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
MyData nowSelectedData;//取得在畫面上顯示中的資料內容
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);//設置資料庫監視
Button btCreate = findViewById(R.id.button_Create);
Button btModify = findViewById(R.id.button_Modify);
Button btClear = findViewById(R.id.button_Clear);
EditText edName = findViewById(R.id.editText_Name);
EditText edPhone = findViewById(R.id.editText_Phone);
EditText edHobby = findViewById(R.id.editText_Hobby);
EditText edElseInfo = findViewById(R.id.editText_else);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//設置分隔線
setRecyclerFunction(recyclerView);//設置RecyclerView左滑刪除
new Thread(() -> {
List<MyData> data = DataBase.getInstance(this).getDataUao().displayAll();
myAdapter = new MyAdapter(this, data);
runOnUiThread(() -> {
recyclerView.setAdapter(myAdapter);
});
}).start();
/**新增資料*/
btCreate.setOnClickListener((v -> {
new Thread(() -> {
String name = edName.getText().toString();
String phone = edPhone.getText().toString();
String hobby = edHobby.getText().toString();
String elseInfo = edElseInfo.getText().toString();
if (name.length() == 0) return;//如果名字欄沒填入任何東西,則不執行下面的程序
MyData data = new MyData(name, phone, hobby, elseInfo);
DataBase.getInstance(this).getDataUao().insertData(data);
runOnUiThread(() -> {
myAdapter.refreshView();
edName.setText("");
edPhone.setText("");
edHobby.setText("");
edElseInfo.setText("");
});
}).start();
}));
}//onCreate
.
.
.
}
綠色部分是設置RecyclerView的部分,紅色是撈取資料庫;最後藍色是設置Adapter(別忘了他有全域變數在最頂!)
這時候在執行一次,就會有資料囉!而新增一筆資料後畫面也會同步顯示資料~
修改資料
修改資料有兩個部分
1.點擊RecyclerView內容取得資料
2.修改後並更新
首先是點擊RecyclerView後取得資料
最早在Adapter內已經寫一個如何取得資料的方法了
在上方製作RecyclerView的適配器(Adapter)內的藍字部分...請跳回去參考
接著我們再onCreate中初始化RecyclerView Adapter內寫入該點擊事件
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
MyData nowSelectedData;//取得在畫面上顯示中的資料內容
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);//設置資料庫監視
(略)
/**=======================================================================================*/
/**設置修改資料的事件*/
btModify.setOnClickListener((v) -> {
new Thread(() -> {
if(nowSelectedData ==null) return;//如果目前沒前台沒有資料,則以下程序不執行
String name = edName.getText().toString();
String phone = edPhone.getText().toString();
String hobby = edHobby.getText().toString();
String elseInfo = edElseInfo.getText().toString();
MyData data = new MyData(nowSelectedData.getId(), name, phone, hobby, elseInfo);
DataBase.getInstance(this).getDataUao().updateData(data);
runOnUiThread(() -> {
edName.setText("");
edPhone.setText("");
edHobby.setText("");
edElseInfo.setText("");
nowSelectedData = null;
myAdapter.refreshView();
Toast.makeText(this, "已更新資訊!", Toast.LENGTH_LONG).show();
});
}).start();
});
/**新增資料*/
(略)
/**=======================================================================================*/
/**初始化RecyclerView*/
new Thread(() -> {
List<MyData> data = DataBase.getInstance(this).getDataUao().displayAll();
myAdapter = new MyAdapter(this, data);
runOnUiThread(() -> {
recyclerView.setAdapter(myAdapter);
/**===============================================================================*/
myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {//原本的樣貌
@Override
public void onItemClick(MyData myData) {}
});
/**===============================================================================*/
/**取得被選中的資料,並顯示於畫面*/
myAdapter.setOnItemClickListener((myData)-> {//匿名函式(原貌在上方)
nowSelectedData = myData;
edName.setText(myData.getName());
edPhone.setText(myData.getPhone());
edHobby.setText(myData.getHobby());
edElseInfo.setText(myData.getElseInfo());
});
/**===============================================================================*/
});
}).start();
/**=======================================================================================*/
}
這時候執行看看,就會出現想要的效果囉!
撰寫左右滑動刪除
這個我就不多解釋,詳細請參考這篇...
->碼農日常-『Android studio』基本RecyclerView 用法-3 RecyclerView上下滑動排序與側滑刪除(RecyclerView Swipe)
我直接貼副程式
/**設置RecyclerView的左滑刪除行為*/
private void setRecyclerFunction(RecyclerView recyclerView){
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {//設置RecyclerView手勢功能
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0,ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
switch (direction){
case ItemTouchHelper.LEFT:
case ItemTouchHelper.RIGHT:
myAdapter.deleteData(position);
break;
}
}
});
helper.attachToRecyclerView(recyclerView);
}
直接複製貼上在onCreate外部就好
然後在onCreate內的RecyclerView底下綁定給RecyclerView
setRecyclerFunction(recyclerView);//設置RecyclerView左滑刪除
紅字部分就是刪除資料的方法囉~之前已經把副程式寫在Adapter中了,直接引用就好!
這時候按下執行,就會有功能了!
也記得觀察一下資料庫有沒有動靜哦!(以我的程式而言如果刪沒成功這筆資料會再跑出來...)
最後是MainActivity.java的全部程式
另外我還有在程式內加入一點防錯機制跟清除所選中的資料顯示,再麻煩細心去加入囉!
結語
好累...總算打完了( ´_ゝ`)
我最近是因為覺得自己都發一些太簡單的東西,所以才想說這週來發比較麻煩的東西XD
原本像這種的我都會挑連假寫...不過事實證明一個普通假日也寫得完...
這篇文章我星期六完成程式碼,週日我從早上寫到下午六點,整整花了整個下午QQ
ok,不過這是我個人問題,也許之後能再寫更快也說不定(・∀・)
總之希望大家能在這裡學習到Room DataBase的基本使用方法
如果在這邊會了Room卻還不會SQLite的話,可以再跳回去這篇參考哦
->碼農日常-『Android studio』SQLite資料庫建立、資料表建立與操作以及Stetho工具
那這篇到這邊,希望文章有幫助到大家~
留言列表