大家豪~今天要來聊聊SQlite資料庫ヾ(・ω・o)
在2020年的現在,不知道還有多少人還在用SQLite呢XD
因為Google在2018年的I/O大會上,發表了Android Jetpack
並且這個套件中,也針對SQLite做了改善
於是這個解決方案的結果就是Room資料庫
當然,有機會也會做一套Room的介紹(・ωー)~☆
關於Room,可參考官網:https://developer.android.com/reference/androidx/room/package-summary
2020/04/19更新
如果想了解Android Room Database的朋友,請往這邊走~
碼農日常-『Android studio』使用Room資料庫以及資料庫監視工具Stetho
OK,雖然SQLite或許算比較舊的寫法了,不過有些開發需求或許會用到
像我來說我也是使用Room的玩家
但有一次繼承了別人寫的專案,好死不死這個專案又是4年前寫的
裡面就有一套SQLite的功能 (・ω・`)………..
好吧,沒辦法,只能上了(´・д・`)
因此才有了今天的撰文XD
好啦廢話講完了開始吧!
上~~~功~~~能~~~
新增資料
修改資料
刪除資料
Github
https://github.com/thumbb13555/SQLiteExample
0.功能描述
- 在Android中建立SQLite資料表
- 新增四個欄位: 姓名\Name、電話\Phone、興趣\Hobby、其他\ElseInfo
- 完成新增資料功能
- 完成修改資料功能
- 完成刪除資料功能(RecyclerView向右滑即可刪除)
0.1 關於Stetho工具
Stetho工具是fackbook公司所發行的一套可以測試資料庫與網路傳輸的軟體
介紹在這:http://facebook.github.io/stetho/
並且,他除了能測試SQlite
他也可以測試Room資料庫喔!!!
好的接下來就來聊聊如何安裝
首先去他官網的Github
在這裡->https://github.com/facebook/stetho
然後找到這
將這行複製起來(我知道你懶) (っ・∀・)っ
implementation 'com.facebook.stetho:stetho:1.5.1'
然後再專案中找到 build.grade
然後找到dependencies(我做的時候還是用1.4.1...不過不影響)
貼上去(●`・皿・)
然後按下Syne即完成
最後一步,在MainActivity的onCreate內加入這行
Stetho.initializeWithDefaults(this);
接著開啟這個網頁
稍微等候一下,就會出現你的裝置囉!(我是用實體手機測試)
稍後測試時,按下inspect就可以看到你的資料庫囉~
1.建立Layout與新增類別框架:
首先本次有兩個類別(就是.java檔案)
除了原廠的MainActivity外還有SQLiteDataBaseHelper
建立步驟:首先在資料夾處點右鍵
New->Java Class
然後命名(名字可隨意)->按下OK
接下來進入這個檔案,使它繼承SQLiteOpenHelper
加入方法
最後加入建構子
完成!(・ω・)b
在SQLiteDataBaseHelper.java內目前框架長這樣(可直接複製)
//SQLiteDataBaseHelper.java
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper;public class SQLiteDataBaseHelper extends SQLiteOpenHelper { public SQLiteDataBaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
OK,再來設置介面
介面長這樣
結構樹:
最後是xml
https://github.com/thumbb13555/SQLiteExample/blob/master/app/src/main/res/layout/activity_main.xml
2.在SQLiteDataBaseHelper.java中建立需要的方法:
開始之前,因為操作資料庫的方法可以說是以SQLite語法載入Java
因此在開始建議可以了解一下各種SQL語法
https://www.1keydata.com/tw/sql/sql.html
再來,把焦點放到SQLiteDataBaseHelper.java中
我的習慣是把所有方法全部放到這邊操作,這樣之後會比較好管理
首先是建立建構子內的物件
public class SQLiteDataBaseHelper extends SQLiteOpenHelper {
String TAG = SQLiteDataBaseHelper.class.getSimpleName();
String TableName;
public SQLiteDataBaseHelper(@Nullable Context context
, @Nullable String dataBaseName
, @Nullable SQLiteDatabase.CursorFactory factory, int version, String TableName) {
super(context, dataBaseName, factory, version);
this.TableName = TableName;
}
.
.
.
}
因為希望資料表的名稱可以從外部控制
故在建構子內加入紅色的部分
而其中建構子的內容會影響建立資料庫,請特別注意
再來是要建立資料表
首先看到SQLiteDataBaseHelper.java的onCreate
@Override
public void onCreate(SQLiteDatabase db) {
String SQLTable = "CREATE TABLE IF NOT EXISTS " + TableName + "( " +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"Name TEXT, " +
"Phone TEXT," +
"Hobby TEXT," +
"ElseInfo TEXT" +
");";
db.execSQL(SQLTable);
}
鍵入紅色的內容
在建立時請注意,因為是以字串輸入SQL語法
因此若有輸入錯誤不會提示
如果輸入正確的話顏色提示應該要是這樣
還有就是逗號要記得打,以前剛學真的常常忘記,又沒有提示
除錯除了老半天...(´・д・`)
@Override
public void onCreate(SQLiteDatabase db) {
String SQLTable = "CREATE TABLE IF NOT EXISTS " + TableName + "( " +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"Name TEXT, " +
"Phone TEXT," +
"Hobby TEXT," +
"ElseInfo TEXT" + //最後一個沒有逗號!!
");";
db.execSQL(SQLTable);
}
剛開始學的時候,建議先直接複製我的run一次
確定沒有問題後再來改~可以降低犯錯的機會
另外就是,欄位為TEXT的話就是一般字串格式
其他還有
- INTEGER : 整數,對應Java 的byte、short、int 和long
- REAL : 小數,對應Java 的float 和double
另外經過實測
TEXT欄位可以放JSON陣列!!!!!
我在其他的專案中蠻常用的,一樣有機會會獨立寫一篇(´・з・)
然後在onUpgrade的方法中填入
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
final String SQL = "DROP TABLE " + TableName;
db.execSQL(SQL);
}
關於onUpgrade方法我承認我還了解不夠多
這裡有一篇範例比我介紹得更清楚
https://mrraybox.blogspot.com/2017/01/android-sqlite-onupgrade.html
簡單而言他就是一個針對資料庫改版的方法
假設去年我寫了一個資料庫
然後今年主管跟你說因為有新增功能,要改結構
但是我的舊程式已經上線多時了,用戶也存了很多資料了
怎麼辦?難道他們更新後他們存的資料都會死光光嗎?(´・_・`)
當然不是啊傻喔!ノಠ_ಠノ
於是這方法就是,如果你的資料庫版本有變(建構子中的 int verson)
他就會被觸發。
詳細的上面給的網誌有寫,可以參考參考
然後回到MainActivity.java
先在全域變數內輸入這些東西
private final String DB_NAME = "MyList.db";
private String TABLE_NAME = "MyTable";
private final int DB_VERSION = 1;
SQLiteDataBaseHelper mDBHelper;
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();//取得所有資料
ArrayList<HashMap<String, String>> getNowArray = new ArrayList<>();//取得被選中的項目資料
最後在onCreate內輸入這個
mDBHelper = new SQLiteDataBaseHelper(this, DB_NAME
, null, DB_VERSION, TABLE_NAME);//初始化資料庫
到目前為止結果會這樣
public class MainActivity extends AppCompatActivity {
private final String DB_NAME = "MyList.db";
private String TABLE_NAME = "MyTable";
private final int DB_VERSION = 1;
SQLiteDataBaseHelper mDBHelper;
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();//取得所有資料
ArrayList<HashMap<String, String>> getNowArray = new ArrayList<>();//取得被選中的項目資料
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
mDBHelper = new SQLiteDataBaseHelper(this, DB_NAME
, null, DB_VERSION, TABLE_NAME);//初始化資料庫
}//onCreate End
}
這時候執行,就可以在測試工具中看到資料庫囉!
ヾ(^-^)ノヾ(・ω・o) (・ωー)~☆(・ω・`)………..(´・д・`) (・ω・)b(´・д・`) (´・з・)(´・_・`)ノಠ_ಠノ(●`・皿・)(っ・∀・)っ
我突然發現我從開始寫到現在複製過的表情符號串起來好有戲.....XDDDDD
接下來是建立各種方法
回到SQLiteDataBaseHelper.java
我在程式中有特別標注所有方法了,各位可自行參考
我在這邊只列出圖鑑給大家看~
//檢查資料表狀態,若無指定資料表則新增
public void chickTable(){
Cursor cursor = getWritableDatabase().rawQuery(
"select DISTINCT tbl_name from sqlite_master where tbl_name = '" + TableName + "'", null);
if (cursor != null) {
if (cursor.getCount() == 0)
getWritableDatabase().execSQL("CREATE TABLE IF NOT EXISTS " + TableName + "( " +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"Name TEXT, " +
"Phone TEXT," +
"Hobby TEXT," +
"ElseInfo TEXT" +
");");
cursor.close();
}
}
//取得有多少資料表,並以陣列回傳
public ArrayList<String> getTables(){
Cursor cursor = getWritableDatabase().rawQuery(
"select DISTINCT tbl_name from sqlite_master", null);
ArrayList<String> tables = new ArrayList<>();
while (cursor.moveToNext()){
String getTab = new String (cursor.getBlob(0));
if (getTab.contains("android_metadata")){}
else if (getTab.contains("sqlite_sequence")){}
else tables.add(getTab.substring(0,getTab.length()-1));
}
return tables;
}
//新增資料
public void addData(String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("Name", name);
values.put("Phone", phone);
values.put("Hobby", hobby);
values.put("ElseInfo", elseInfo);
db.insert(TableName, null, values);
}
//顯示所有資料
public ArrayList<HashMap<String, String>> showAll() {
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(" SELECT * FROM " + TableName, null);
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();
while (c.moveToNext()) {
HashMap<String, String> hashMap = new HashMap<>();
String id = c.getString(0);
String name = c.getString(1);
String phone = c.getString(2);
String hobby = c.getString(3);
String elseInfo = c.getString(4);
hashMap.put("id", id);
hashMap.put("name", name);
hashMap.put("phone", phone);
hashMap.put("hobby", hobby);
hashMap.put("elseInfo", elseInfo);
arrayList.add(hashMap);
}
return arrayList;
}
↑紅字部分是規定HashMap要回傳的陣列內容,藍色部分是從資料庫中撈資料
後面跟的數字意思是欄位
//以id搜尋特定資料
public ArrayList<HashMap<String,String>> searchById(String getId){
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(" SELECT * FROM " + TableName
+ " WHERE _id =" + "'" + getId + "'", null);
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();
while (c.moveToNext()) {
HashMap<String, String> hashMap = new HashMap<>();
String id = c.getString(0);
String name = c.getString(1);
String phone = c.getString(2);
String hobby = c.getString(3);
String elseInfo = c.getString(4);
hashMap.put("id", id);
hashMap.put("name", name);
hashMap.put("phone", phone);
hashMap.put("hobby", hobby);
hashMap.put("elseInfo", elseInfo);
arrayList.add(hashMap);
}
return arrayList;
}
//以興趣篩選資料
public ArrayList<HashMap<String, String>> searchByHobby(String getHobby) {
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(" SELECT * FROM " + TableName
+ " WHERE Hobby =" + "'" + getHobby + "'", null);
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();
while (c.moveToNext()) {
HashMap<String, String> hashMap = new HashMap<>();
String id = c.getString(0);
String name = c.getString(1);
String phone = c.getString(2);
String hobby = c.getString(3);
String elseInfo = c.getString(4);
hashMap.put("id", id);
hashMap.put("name", name);
hashMap.put("phone", phone);
hashMap.put("hobby", hobby);
hashMap.put("elseInfo", elseInfo);
arrayList.add(hashMap);
}
return arrayList;
}
//修改資料(麻煩)
public void modify(String id, String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL(" UPDATE " + TableName
+ " SET Name=" + "'" + name + "',"
+ "Phone=" + "'" + phone + "',"
+ "Hobby=" + "'" + hobby + "',"
+ "ElseInfo=" + "'" + elseInfo + "'"
+ " WHERE _id=" + "'" + id + "'");
}
//修改資料(簡單)
public void modifyEZ(String id, String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("Name", name);
values.put("Phone", phone);
values.put("Hobby", hobby);
values.put("ElseInfo", elseInfo);
db.update(TableName, values, "_id = " + id, null);
}
//刪除全部資料
public void deleteAll(){
SQLiteDatabase db = getWritableDatabase();
db.execSQL("DELETE FROM"+TableName);
}
//以id刪除資料(簡單)
public void deleteByIdEZ(String id){
SQLiteDatabase db = getWritableDatabase();
db.delete(TableName,"_id = " + id,null);
}
從上面這些副程式中可以發現,其實主體上存在兩種形式的做法
當然這兩種做法都是用
SQLiteDatabase db = getWritableDatabase();
或
SQLiteDatabase db = getReadableDatabase();
中取得方法,並直接實踐
像是insert, update, delete等因為常用,因此有被寫入
就舉addData這個副程式來說
//新增資料
public void addData(String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("Name", name);
values.put("Phone", phone);
values.put("Hobby", hobby);
values.put("ElseInfo", elseInfo);
db.insert(TableName, null, values);
}
insert方法必須回傳(資料表名稱,nullColumnHack,值)
那我們必須用ContentValues將所有值包起來,然後送給資料庫
方法基礎就是HashMap的做法
可參照橘色字部分
另外種做法就是自己寫SQL語法
而其中套用的就是
getWritableDatabase().execSQL();
方法
實際操作是這樣
SQLiteDatabase db = getWritableDatabase();
db.execSQL("");//這邊寫入SQL語法
最後再告訴各位一個坑
在輸入SQL語法的時候,一定要特別注意
舉個像是這個例子
//修改資料(麻煩)(這會閃退)
public void modify(String id, String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL(" UPDATE " + TableName
+ " SET Name=" + name + ","
+ "Phone=" + "'" + phone + "',"
+ "Hobby=" + "'" + hobby + "',"
+ "ElseInfo=" + "'" + elseInfo + "'"
+ " WHERE _id=" + "'" + id + "'");
}
這是修改的範例
大家來找碴看看跟這個有哪裡不一樣
//修改資料(麻煩)
public void modify(String id, String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL(" UPDATE " + TableName
+ " SET Name=" + "'" + name + "',"
+ "Phone=" + "'" + phone + "',"
+ "Hobby=" + "'" + hobby + "',"
+ "ElseInfo=" + "'" + elseInfo + "'"
+ " WHERE _id=" + "'" + id + "'");
}
先講~這兩句放在編譯器裡都不會紅字喔!但上面的那個會閃退報錯
報錯內容如下
--------- beginning of crash
2020-01-05 14:10:11.420 E: FATAL EXCEPTION: main
Process: com.jetec.sqliteexample, PID: 22756
android.database.sqlite.SQLiteException: no such column: 劉 (code 1 SQLITE_ERROR[1]): , while compiling: UPDATE MyTable SET Name=劉,Phone='0934676485',Hobby='桌球',ElseInfo='無' WHERE _id='10'
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1229)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:703)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:59)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2227)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:2155)
at com.jetec.sqliteexample.SQLiteDataBaseHelper.modify(SQLiteDataBaseHelper.java:174)
at com.jetec.sqliteexample.MainActivity.lambda$buttonFunction$2$MainActivity(MainActivity.java:71)
at com.jetec.sqliteexample.-$$Lambda$MainActivity$bPc7AhXOnDKOD5eCZOAQUkNUzLs.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7339)
at android.widget.TextView.performClick(TextView.java:14222)
at android.view.View.performClickInternal(View.java:7305)
at android.view.View.access$3200(View.java:846)
at android.view.View$PerformClick.run(View.java:27787)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7078)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
2020-01-05 14:10:11.449 I: Sending signal. PID: 22756 SIG: 9
.
.
.
.
.
公佈答案~
//修改資料(麻煩)
public void modify(String id, String name, String phone, String hobby, String elseInfo) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL(" UPDATE " + TableName
+ " SET Name=" + "'" + name + "',"
+ "Phone=" + "'" + phone + "',"
+ "Hobby=" + "'" + hobby + "',"
+ "ElseInfo=" + "'" + elseInfo + "'"
+ " WHERE _id=" + "'" + id + "'");
}
底加啦┐(´д`)┌
概念其實很簡單,在SQL語法內
只要是牽涉到字串,都必須加一個小引號
像是這樣
UPDATE TableName SET Sales = 500 WHERE Store_Name = 'Los Angeles' AND Txn_Date = 'Jan-08-1999';
(這是其他網站的範例)
注意到了嗎?他的字串有加小引號喔
所以說,在寫資料庫時,記得要加小引號才不會出錯(b^_^)b
寫到這邊,所有的工具都取得了
剩下的就是運用這些工作完成我們的功能
我們來做個測試吧!
回到空空如也的MainActivity.java
這時候可以在onCreate底下加入一個新增資料
public class MainActivity extends AppCompatActivity {
String TAG = MainActivity.class.getSimpleName() + "My";
private final String DB_NAME = "MyList.db";
private String TABLE_NAME = "MyTable";
private final int DB_VERSION = 1;
SQLiteDataBaseHelper mDBHelper;
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();//取得所有資料
ArrayList<HashMap<String, String>> getNowArray = new ArrayList<>();//取得被選中的項目資料
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
mDBHelper = new SQLiteDataBaseHelper(this, DB_NAME
, null, DB_VERSION, TABLE_NAME);//初始化資料庫
mDBHelper.addData("Sam","0912-345678","爬山","none");
}//onCreate End
}
然後回去看測試資料庫
(喂..真是夠了...)
再來試試看撈資料吧
public class MainActivity extends AppCompatActivity {
String TAG = MainActivity.class.getSimpleName() + "My";
private final String DB_NAME = "MyList.db";
private String TABLE_NAME = "MyTable";
private final int DB_VERSION = 1;
SQLiteDataBaseHelper mDBHelper;
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();//取得所有資料
ArrayList<HashMap<String, String>> getNowArray = new ArrayList<>();//取得被選中的項目資料
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
mDBHelper = new SQLiteDataBaseHelper(this, DB_NAME
, null, DB_VERSION, TABLE_NAME);//初始化資料庫
mDBHelper.addData("Sam","0912-345678","爬山","none");
Log.d(TAG, "onCreate: "+mDBHelper.showAll());
}//onCreate End
}
這時候如果有多新增幾筆資料的話,就會出現這樣的結果喔~
此外因為一些因緣際會,我也了解到了如何取得資料表資訊以及新增資料表
在Android內,因為SQLite通常不會存放巨量資料
因此這種操作相對少見
我在這邊放他的副程式給大家看(其實上面有)
//檢查資料表狀態,若無指定資料表則新增
public void chickTable(){
Cursor cursor = getWritableDatabase().rawQuery(
"select DISTINCT tbl_name from sqlite_master where tbl_name = '" + TableName + "'", null);
if (cursor != null) {
if (cursor.getCount() == 0)
getWritableDatabase().execSQL("CREATE TABLE IF NOT EXISTS " + TableName + "( " +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"Name TEXT, " +
"Phone TEXT," +
"Hobby TEXT," +
"ElseInfo TEXT" +
");");
cursor.close();
}
}
//取得有多少資料表
public ArrayList<String> getTables(){
Cursor cursor = getWritableDatabase().rawQuery(
"select DISTINCT tbl_name from sqlite_master", null);
ArrayList<String> tables = new ArrayList<>();
while (cursor.moveToNext()){
String getTab = new String (cursor.getBlob(0));
if (getTab.contains("android_metadata")){}
else if (getTab.contains("sqlite_sequence")){}
else tables.add(getTab.substring(0,getTab.length()-1));
}
return tables;
}
副程式貼上去,然後在MainActivity.java新增
mDBHelper.chickTable();//確認是否存在資料表,沒有則新增
mDBHelper.getTables();//取得所有的資料表(Table名稱)
搞定!(・ωー)~☆
OK,如果只是想了解操作資料庫的話,到這邊你就可以開始動手做你的專案了
因為剩下的內容就是收拾殘局處理UI互動的部分了
3.收拾殘局處理UI互動與資料庫操作:
接下來的內容基本就跟這個單元無關了
主要操作都在MainActivity.java內
這個部分的話我就直接貼程式,並標示我有改的部分
很省了...但是仍有186行
public class MainActivity extends AppCompatActivity {
String TAG = MainActivity.class.getSimpleName() + "My";
private final String DB_NAME = "MyList.db";
private String TABLE_NAME = "MyTable";
private final int DB_VERSION = 1;
SQLiteDataBaseHelper mDBHelper;
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();//取得所有資料
ArrayList<HashMap<String, String>> getNowArray = new ArrayList<>();//取得被選中的項目資料
EditText edName, edPhone, edHobby, edElse;
Button btCreate, btModify, btClear;
MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
mDBHelper = new SQLiteDataBaseHelper(this, DB_NAME
, null, DB_VERSION, TABLE_NAME);//初始化資料庫
mDBHelper.chickTable();//確認是否存在資料表,沒有則新增
arrayList = mDBHelper.showAll();//撈取資料表內所有資料
itemSetting();//連接所有元件
recyclerViewSetting();//設置RecyclerView
buttonFunction();//設置按鈕功能
}//onCreate End
private void buttonFunction() {//設置按鈕功能
btClear.setOnClickListener(v -> {
clearAll();//清空目前所選以及所有editText
});
btCreate.setOnClickListener(v -> {
mDBHelper.addData(edName.getText().toString()
,edPhone.getText().toString()
,edHobby.getText().toString()
,edElse.getText().toString());
arrayList = mDBHelper.showAll();
myAdapter.notifyDataSetChanged();
clearAll();
});
btModify.setOnClickListener(v -> {
mDBHelper.modify(getNowArray.get(0).get("id")
,edName.getText().toString()
,edPhone.getText().toString()
,edHobby.getText().toString()
,edElse.getText().toString());
arrayList = mDBHelper.showAll();
myAdapter.notifyDataSetChanged();
clearAll();//清空目前所選以及所有editText
});
}
private void clearAll() {//清空目前所選以及所有editText
edName.setText("");
edElse.setText("");
edHobby.setText("");
edPhone.setText("");
getNowArray.clear();
}
private void recyclerViewSetting() {//設置RecyclerView
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
myAdapter = new MyAdapter();
recyclerView.setAdapter(myAdapter);
setRecyclerFunction(recyclerView);//設置RecyclerView手勢功能
}
private void itemSetting() {//連接所有元件
btCreate = findViewById(R.id.button_Create);
btModify = findViewById(R.id.button_Modify);
btClear = findViewById(R.id.button_Clear);
edName = findViewById(R.id.editText_Name);
edPhone = findViewById(R.id.editText_Phone);
edHobby = findViewById(R.id.editText_Hobby);
edElse = findViewById(R.id.editText_else);
}
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {//設置Adapter
@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(arrayList.get(position).get("name"));
holder.itemView.setOnClickListener((v) -> {
getNowArray.clear();
getNowArray = mDBHelper.searchById(arrayList.get(position).get("id"));
try {
edName.setText(getNowArray.get(0).get("name"));
edPhone.setText(getNowArray.get(0).get("phone"));
edHobby.setText(getNowArray.get(0).get("hobby"));
edElse.setText(getNowArray.get(0).get("elseInfo"));
} catch (Exception e) {
Log.d(TAG, "onBindViewHolder: " + e.getMessage());
}
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvTitle = itemView.findViewById(android.R.id.text1);
}
}
}
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:
mDBHelper.deleteByIdEZ(arrayList.get(position).get("id"));
arrayList.remove(position);
arrayList = mDBHelper.showAll();
myAdapter.notifyItemRemoved(position);
break;
}
}
});
helper.attachToRecyclerView(recyclerView);
}
}
顏色區分:
紅色是跟介面控件有關的內容
紫色是跟RecyclerView有關的功能
棕色則是跟SQLite有關的操作功能
此外關於RecyclerView相關系列
基本RecyclerView用法: http://thumbb13555.pixnet.net/blog/post/311803031
RecyclerView點擊事件: http://thumbb13555.pixnet.net/blog/post/312844960-android-studio-%e4%b9%8b%e5%9f%ba%e6%9c%acrecycleview-%e7%94%a8%e6%b3%95-2--%e5%9f%ba%e6%9c%ac%e7%89%88%e4%b8%8b
RecyclerView滑動事件: http://thumbb13555.pixnet.net/blog/post/316420566-recyclerview-swipe
供參考
4.總結:
Android 的 SQLite 是一個儲存大量設定很不錯的方法
他的生命週期是從這個APP被下載的那一天到你把它刪掉的那一天
因此這其中的操作就變得十分重要,並且須謹慎
否則很容易使APP莫名其妙地越來越肥...
而且通常操作上都會綁著陣列做使用
因此陣列觀念就變得十分重要
我為了做教學,通常是不會在另開一個類別寫setter & Getter(了解的就知道我在說什麼)
這週再決定要寫SQLite的時候也很擔心會寫不好
因為SQLite除了資料操作,還得完善UI的問題
所以說真的...又怕大家看不懂,但又不能忽略UI,實在很難辦
文長..希望大家能真的看懂今天的內容
最後有什麼問題,歡迎留言喔~
留言列表