Android高效入門—SQLite資料庫

By | 2016-05-09

Android的SQLite資料庫

A4958

SQLite是一套開放原始碼的資料庫函式庫,並遵循ACID關聯式資料標準,使用標準的SQL語法,提供單機、無需連線環境的資料庫的管理系統。它被廣泛地使用在嵌入式系統、瀏覽器、作業系統內部。

Android支援SQLite資料庫,每個應用程式都可選擇建立自己的資料庫,將資料儲存在SQLite資料庫檔案中,開發人員使用Android提供的API類別庫即可在應用程式中存取資料庫中資料,包括查詢、新增、刪除與更新等標準的SQL存取語法。它亦提供應用程式訂定資料庫版本,可在新版應用程式一併進行資料庫版本的複製、轉移等工作。

一開始在Atm專案中建立一個具實感設計的活動,再進行必要的元件與畫面配置,待活動與畫面架構成形後,再進行SQLite資料庫的介紹與實作。因為,使用到資料庫的情境都需要使用者介面,筆者希望在設計操作資料庫的程式碼時,能與使用者的介面互動,並在練習過程中認識各個元件的角色與使用方法,單純地認識片段的資料庫操作程式碼,並不足以在設計應用程式時派上用場。

準備活動

建立一個新活動FinanceActivity進行範例與操作說明,這是一個簡單的記帳功能,可新增並顯示所有消費記錄,請在Atm專案中建立一個「Basic Activity」名稱為「FinanceActivity」,目的是顯示消費清單可在主畫面中按下「投資理財」功能時開啟這個活動,一開始是無任何內容,如下圖。

A4952

第二個活動是簡易的「Empty Activity」空白活動,名稱為「AddActivity」在此活動中設計新增消費記錄的使用者介面,供使用者輸入消費記錄,如下圖:

A4951

第一個消費清單為FinanceActivity,第二個新增消費為AddActivity,請先依以下步驟建立活動。

1.  建立活動

請使用功能表的「File/New/Activity/Basic Activity」建立具實感設計的基本活動,名稱為FinanceActivity,如下圖:

A4942

上述動作會產生一個FinanceActivity類別與兩個版面配置檔「activity_finance.xml」與「content_finance.xml」。

A4943

完成後,再使用功能表的「File/New/Activity/Empty Activity」新增另一個空白活動,名稱為AddActivity,如下圖:

A4944

上述動作產生一個AddActivity類別與一個版面配置檔「activity_add.xml」,如下:

A4945

2. 畫面配置

再打開產生的「res/layout/activity_add.xml」版面配置檔,加入必要的元件,預覽與元件結構如下圖:

A4946

配置檔activity_add.xml原始碼如下:

<?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,設計以下程式碼:

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產生程式碼換成

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敍述中加入:

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」語法,如下:

A4377

1. 實作方法

由於SQLiteOpenHelper是抽象類別,其子類別必須實作必要的方法,請將游標停在出現錯誤的類別定義該行,按下「Alt+Enter」選擇「Implement methods」,如下圖:

A4378

對話框中已自動選擇onCreate與onUpgrade兩個方法,按下Enter即可,如下:

A4379

2. 實作建構子

因父類別SQLiteOpenHelper中並未實作無參數的建構子,因此MyDBHelper必須設計建構子,可將游標停在出現錯誤的類別定義該行,按下「Alt+Enter」選擇「Create constructor matching super class」建立與父類別相同參數的建構子,如下圖:

A4380

再選擇第一個即可,最後完成程式碼如下:

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

當應用程式中執行到有關任何存取資料庫的指令時,假如資料庫檔案不存在,則會立即執行本方法。因此,在此撰寫建立資料庫表格的程式碼,若表格中需要初始資料時,在建立表格完成後可繼續撰寫新增資料記錄的程式碼。

在本例中每一筆消費記錄包括以下欄位:

  1. 消費日期
  2. 說明
  3. 金額

在表格中的辨識ID,請使用「_id」為欄位名稱,使其成為自動產生的主鍵(Primary key) ,表格欄位與資料型態如下表:

表格名稱:exp

欄位名稱 資料型態 備註
_id INTEGER PRIMARY KEY
cdate DATETIME NOT NULL
info VARCHAR(20)
amount INTEGER

建立exp表格的SQL語法為:

CREATE  TABLE "main"."exp" ("_id" INTEGER PRIMARY KEY  NOT NULL , "cdate" DATETIME NOT NULL , "info" VARCHAR, "amount" INTEGER)

在onCreate方法中,取得可寫入SQLiteDatabase物件後,呼叫execSQL方法建立exp表格,如下:

請參考 Android APP 高效入門

14 thoughts on “Android高效入門—SQLite資料庫

  1. AvatarMorton

    老師好:
    因照著做有發現報錯,在onCreate那邊的getWritableDatabase().execSQL ,我把它改成db.execSQL才能建立,再麻煩你確認一下,謝謝~

    Reply
    1. AvatarHank Tom Post author

      您好,這是個問題,應使用方法中的db物件去執行才對,這是內容的錯誤,謝謝。

      Reply
  2. Avataryuren

    02-09 07:56:33.369 2584-2584/com.example.user.atm D/ADD: -1
    請問我的是-1是什麼意思?

    Reply
      1. Avatar000

        請問如果都照打,但是新增失敗 怎麼辦? 要怎麼修改?

        Reply
  3. AvatarKuang

    請問為什麼 table_name要用 main.exp? 不能直接用 exp就好了嗎

    Reply
    1. AvatarHank Tom Post author

      每個DBMS都會有Database後,才有Tables,main就是SQLite中使用的預設Database名稱,有加沒加都可以

      Reply
  4. AvatarCode

    老師,我照著做 發現回傳的是-1,於是我把下面這行
    values.put(“into”, info);
    改成
    values.put(“info”, info);
    就正常了,不知道是不是內容錯誤

    Reply
  5. AvatarSoar

    老師好:
    因照著做,發現到好像多打了一個 . 在db.execSQL();這句裡面

    Reply

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *