大家豪~今天要來聊聊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

好啦廢話講完了開始吧!

上~~~功~~~能~~~


新增資料

sqlite新增

修改資料

sqlite修改

刪除資料

sqlite刪除

Github

https://github.com/thumbb13555/SQLiteExample


0.功能描述

  1. 在Android中建立SQLite資料表
  2. 新增四個欄位: 姓名\Name、電話\Phone、興趣\Hobby、其他\ElseInfo
  3. 完成新增資料功能
  4. 完成修改資料功能
  5. 完成刪除資料功能(RecyclerView向右滑即可刪除)

 

0.1 關於Stetho工具

Stetho工具是fackbook公司所發行的一套可以測試資料庫與網路傳輸的軟體

介紹在這:http://facebook.github.io/stetho/

並且,他除了能測試SQlite

他也可以測試Room資料庫喔!!!

好的接下來就來聊聊如何安裝

首先去他官網的Github

在這裡->https://github.com/facebook/stetho

然後找到這

截圖 2020-01-05 上午10.33.02

將這行複製起來(我知道你懶) (っ・∀・)っ

implementation 'com.facebook.stetho:stetho:1.5.1'

然後再專案中找到 build.grade

截圖 2019-12-29 上午1.27.38

然後找到dependencies(我做的時候還是用1.4.1...不過不影響)

截圖 2020-01-04 下午3.27.52

貼上去(●`・皿・)

然後按下Syne即完成

截圖 2019-12-29 上午1.30.39

最後一步,在MainActivity的onCreate內加入這行

Stetho.initializeWithDefaults(this);

截圖 2020-01-04 下午3.39.49

接著開啟這個網頁

chrome://inspect/#devices

稍微等候一下,就會出現你的裝置囉!(我是用實體手機測試)

截圖 2020-01-04 下午3.55.33

稍後測試時,按下inspect就可以看到你的資料庫囉~


1.建立Layout與新增類別框架:

首先本次有兩個類別(就是.java檔案)

截圖 2020-01-05 上午1.21.37

除了原廠的MainActivity外還有SQLiteDataBaseHelper

建立步驟:首先在資料夾處點右鍵

New->Java Class

截圖 2020-01-04 下午2.22.53

然後命名(名字可隨意)->按下OK

截圖 2020-01-04 下午2.23.30

接下來進入這個檔案,使它繼承SQLiteOpenHelper

截圖 2020-01-04 下午2.24.11

加入方法

截圖 2020-01-04 下午2.24.35

截圖 2020-01-04 下午2.24.46

最後加入建構子

截圖 2020-01-04 下午2.26.11

完成!(・ω・)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,再來設置介面

介面長這樣

截圖 2020-01-05 上午11.32.21

結構樹:

截圖 2020-01-05 上午11.50.09

最後是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.javaonCreate

@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語法

因此若有輸入錯誤不會提示

如果輸入正確的話顏色提示應該要是這樣

截圖 2020-01-05 下午12.36.12

還有就是逗號要記得打,以前剛學真的常常忘記,又沒有提示

除錯除了老半天...(´・д・`)

@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);

    }

截圖 2020-01-05 下午12.56.57

關於onUpgrade方法我承認我還了解不夠多

這裡有一篇範例比我介紹得更清楚

https://mrraybox.blogspot.com/2017/01/android-sqlite-onupgrade.html

簡單而言他就是一個針對資料庫改版的方法

假設去年我寫了一個資料庫

然後今年主管跟你說因為有新增功能,要改結構

但是我的舊程式已經上線多時了,用戶也存了很多資料了

怎麼辦?難道他們更新後他們存的資料都會死光光嗎?(´・_・`)

當然不是啊傻喔!ノಠ_ಠノ

於是這方法就是,如果你的資料庫版本有變(建構子中的 int verson)

截圖 2020-01-05 下午1.03.34

他就會被觸發。

詳細的上面給的網誌有寫,可以參考參考

然後回到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
}

這時候執行,就可以在測試工具中看到資料庫囉!

截圖 2020-01-04 下午4.28.00拷貝

ヾ(^-^)ノヾ(・ω・o) (・ωー)~☆(・ω・`)………..(´・д・`) (・ω・)b(´・д・`) (´・з・)(´・_・`)ノಠ_ಠノ(●`・皿・)(っ・∀・)っ

我突然發現我從開始寫到現在複製過的表情符號串起來好有戲.....XDDDDD

接下來是建立各種方法

回到SQLiteDataBaseHelper.java

https://github.com/thumbb13555/SQLiteExample/blob/master/app/src/main/java/com/jetec/sqliteexample/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要回傳的陣列內容,藍色部分是從資料庫中撈資料

後面跟的數字意思是欄位

截圖 2020-01-04 下午4.28.00拷貝2

//以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
}

然後回去看測試資料庫

截圖 2020-01-04 下午4.28.00

aymUm

(喂..真是夠了...)

再來試試看撈資料吧

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
}

這時候如果有多新增幾筆資料的話,就會出現這樣的結果喔~

截圖 2020-01-04 下午4.39.18

 

此外因為一些因緣際會,我也了解到了如何取得資料表資訊以及新增資料表

在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

供參考

Dogeza_SP1


4.總結:

Android 的 SQLite 是一個儲存大量設定很不錯的方法

他的生命週期是從這個APP被下載的那一天到你把它刪掉的那一天

因此這其中的操作就變得十分重要,並且須謹慎

否則很容易使APP莫名其妙地越來越肥...

而且通常操作上都會綁著陣列做使用

因此陣列觀念就變得十分重要

我為了做教學,通常是不會在另開一個類別寫setter & Getter(了解的就知道我在說什麼)

這週再決定要寫SQLite的時候也很擔心會寫不好

因為SQLite除了資料操作,還得完善UI的問題

所以說真的...又怕大家看不懂,但又不能忽略UI,實在很難辦

文長..希望大家能真的看懂今天的內容

最後有什麼問題,歡迎留言喔~

TK2

 
arrow
arrow

    碼農日常 發表在 痞客邦 留言(7) 人氣()