Android的SQLite資料庫
SQLite是一套開放原始碼的資料庫函式庫,並遵循ACID關聯式資料標準,使用標準的SQL語法,提供單機、無需連線環境的資料庫的管理系統。它被廣泛地使用在嵌入式系統、瀏覽器、作業系統內部。
Android支援SQLite資料庫,每個應用程式都可選擇建立自己的資料庫,將資料儲存在SQLite資料庫檔案中,開發人員使用Android提供的API類別庫即可在應用程式中存取資料庫中資料,包括查詢、新增、刪除與更新等標準的SQL存取語法。它亦提供應用程式訂定資料庫版本,可在新版應用程式一併進行資料庫版本的複製、轉移等工作。
一開始在Atm專案中建立一個具實感設計的活動,再進行必要的元件與畫面配置,待活動與畫面架構成形後,再進行SQLite資料庫的介紹與實作。因為,使用到資料庫的情境都需要使用者介面,筆者希望在設計操作資料庫的程式碼時,能與使用者的介面互動,並在練習過程中認識各個元件的角色與使用方法,單純地認識片段的資料庫操作程式碼,並不足以在設計應用程式時派上用場。
準備活動
建立一個新活動FinanceActivity進行範例與操作說明,這是一個簡單的記帳功能,可新增並顯示所有消費記錄,請在Atm專案中建立一個「Basic Activity」名稱為「FinanceActivity」,目的是顯示消費清單可在主畫面中按下「投資理財」功能時開啟這個活動,一開始是無任何內容,如下圖。
第二個活動是簡易的「Empty Activity」空白活動,名稱為「AddActivity」在此活動中設計新增消費記錄的使用者介面,供使用者輸入消費記錄,如下圖:
第一個消費清單為FinanceActivity,第二個新增消費為AddActivity,請先依以下步驟建立活動。
1. 建立活動
請使用功能表的「File/New/Activity/Basic Activity」建立具實感設計的基本活動,名稱為FinanceActivity,如下圖:
上述動作會產生一個FinanceActivity類別與兩個版面配置檔「activity_finance.xml」與「content_finance.xml」。
完成後,再使用功能表的「File/New/Activity/Empty Activity」新增另一個空白活動,名稱為AddActivity,如下圖:
上述動作產生一個AddActivity類別與一個版面配置檔「activity_add.xml」,如下:
2. 畫面配置
再打開產生的「res/layout/activity_add.xml」版面配置檔,加入必要的元件,預覽與元件結構如下圖:
配置檔activity_add.xml原始碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.tom.atm.AddActivity" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="日期" android:id="@+id/textView" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ed_date" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="說明" android:id="@+id/textView2" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ed_info" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="金額" android:id="@+id/textView3" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:ems="10" android:id="@+id/ed_amount" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新增" android:id="@+id/button" android:onClick="add" /> </LinearLayout> |
三個輸入方塊的id值為「ed_date」、「ed_info」與「ed_amount」,分別代表日期、消費說明與消費金額的輸入方塊,再為按鈕設定onClick屬性為「add」。
3, 實作必要程式碼
請再開啟AddActivity,設計以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.tom.atm; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class AddActivity extends AppCompatActivity { private EditText edDate; private EditText edInfo; private EditText edAmount; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add); findViews(); } private void findViews() { edDate = (EditText) findViewById(R.id.ed_date); edInfo = (EditText) findViewById(R.id.ed_info); edAmount = (EditText) findViewById(R.id.ed_amount); } public void add(View v){ } } |
上述程式使用前面章節介紹的方法,取得畫面中三項輸入元件,並將元件設定為屬性,最後加入新增按鈕的事件處理方法「add」。
AddActivity準備完成後,請開啟FinanceActivity,修改原本「onCreate」方法內浮動鈕的事件程式碼,將SnackBar產生程式碼換成
1 2 3 4 5 6 7 8 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity( new Intent(FinanceActivity.this, AddActivity.class)); } }); |
完成後,按下浮動鈕將開啟AddActivity活動畫面。
最後為了能在主功能畫面中按下「投資理財」功能時,可啟動FinanceActivity活動,請在MainActivity的onItemClick方法內的switch…case敍述中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public void onItemClick(AdapterView<?> parent, View view, int position, long id) { switch (position){ case 0: break; case 1: break; case 2: break; case 3: startActivity(new Intent(this, FinanceActivity.class)); break; case 4: finish(); break; } } |
SQLiteOpenHelper類別
存取資料庫需要瞭解對檔案格式、協定與規範,以程式實作這些功能更是複雜,請不用擔心,Android提供一個已經實作好的-SQLiteOpenHelper類別,它的package是android.datatbase.sqlite。當應用程式需要使用SQLite資料庫時,只需要設計一個新類別並繼承SQLiteOpenHelper,這個類別即具有存取資料庫的能力。
建立應用程式的SQLiteOpenHelper類別
請展開專案「app/java/com.tom.atm」,在com.tom.atm套件上按右鍵選擇「New/Java Class」,名稱輸入「MyDBHelper」產生類別,再加入繼承「extends SQLiteOpenHelper」語法,如下:
1. 實作方法
由於SQLiteOpenHelper是抽象類別,其子類別必須實作必要的方法,請將游標停在出現錯誤的類別定義該行,按下「Alt+Enter」選擇「Implement methods」,如下圖:
對話框中已自動選擇onCreate與onUpgrade兩個方法,按下Enter即可,如下:
2. 實作建構子
因父類別SQLiteOpenHelper中並未實作無參數的建構子,因此MyDBHelper必須設計建構子,可將游標停在出現錯誤的類別定義該行,按下「Alt+Enter」選擇「Create constructor matching super class」建立與父類別相同參數的建構子,如下圖:
再選擇第一個即可,最後完成程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.tom.atm; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDBHelper extends SQLiteOpenHelper{ public MyDBHelper(Context context, String name, 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) { } } |
SQLiteDatabase類別
SQLiteDatabase類別的用途存取SQLite資料庫,提供許多能夠存取資料庫的方法,如query查詢、insert新增、update更新與關閉資料庫等方法,在這些方法中使用SQL語法並執行。
在SQLiteOpenHelper類別中可呼叫以下方法得到SQLiteDatabase物件:
- getReadableDatabase()方法
讀取資料庫的SQLiteDatabase物件,可用在查詢。
- getWritableDatabase()方法
擁有更新能力的SQLiteDatabase物件,用途為新增、修改或刪除。
請依實際開發時的用途,選擇呼叫上述兩個方法取得適合的SQLiteDatabase物件。
建立資料表格的時機-onCreate
當應用程式中執行到有關任何存取資料庫的指令時,假如資料庫檔案不存在,則會立即執行本方法。因此,在此撰寫建立資料庫表格的程式碼,若表格中需要初始資料時,在建立表格完成後可繼續撰寫新增資料記錄的程式碼。
在本例中每一筆消費記錄包括以下欄位:
- 消費日期
- 說明
- 金額
在表格中的辨識ID,請使用「_id」為欄位名稱,使其成為自動產生的主鍵(Primary key) ,表格欄位與資料型態如下表:
表格名稱:exp
欄位名稱 | 資料型態 | 備註 |
_id | INTEGER | PRIMARY KEY |
cdate | DATETIME | NOT NULL |
info | VARCHAR(20) | |
amount | INTEGER |
建立exp表格的SQL語法為:
1 | CREATE TABLE "main"."exp" ("_id" INTEGER PRIMARY KEY NOT NULL , "cdate" DATETIME NOT NULL , "info" VARCHAR, "amount" INTEGER) |
在onCreate方法中,取得可寫入SQLiteDatabase物件後,呼叫execSQL方法建立exp表格,如下:
老師好:
因照著做有發現報錯,在onCreate那邊的getWritableDatabase().execSQL ,我把它改成db.execSQL才能建立,再麻煩你確認一下,謝謝~
您好,這是個問題,應使用方法中的db物件去執行才對,這是內容的錯誤,謝謝。
02-09 07:56:33.369 2584-2584/com.example.user.atm D/ADD: -1
請問我的是-1是什麼意思?
新增失敗
請問如果都照打,但是新增失敗 怎麼辦? 要怎麼修改?
請參考logcat資訊判斷失敗原因
請問為什麼 table_name要用 main.exp? 不能直接用 exp就好了嗎
每個DBMS都會有Database後,才有Tables,main就是SQLite中使用的預設Database名稱,有加沒加都可以
老師,我照著做 發現回傳的是-1,於是我把下面這行
values.put(“into”, info);
改成
values.put(“info”, info);
就正常了,不知道是不是內容錯誤
是排版誤打了,應把into換為info,已修正,謝謝您。
老師好:
因照著做,發現到好像多打了一個 . 在db.execSQL();這句裡面
感謝提醒,已修正
請問如果要刪除資料要怎麼做
刪除資料請參考 sql delete 語句
https://www.tutorialspoint.com/sqlite/sqlite_delete_query.htm