Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎知識(6)—數據持久化之數據存儲

Android基礎知識(6)—數據持久化之數據存儲

編輯:關於Android編程

首先,我們要知道什麼是數據持久化。

數據持久化就是指那些內存中的瞬時數據保存到存儲設備中,保證即使手機在關機的情況下,這些數據不會丟失。保存在內存中的數據是處於瞬時狀態,保存在存儲設備中的數據是處於持久狀態。持久化技術則是提供了一種機制可以讓數據在瞬時狀態和持久狀態之間進行轉換。

Android系統主要提供了三種方式用於簡單地實現數據持久化功能,即文件存儲、SharePreference存儲、SQLite數據庫存儲,最後還有一種就是SD卡存儲。

 

(一)文件存儲

文件存儲是Android中最基本的一種數據存儲方式,他不會對存儲的內容進行任何格式處理,所以數據都是原封不動的保存在文件中,因而他適合用於存儲一些比較簡單的文本或二進制數據。

 

寫入文件:

Context類中提供了一個openFileOutput方法,可以用於將數據存儲到指定的文件中,這個方法接收兩個參數:第一個參數是文件名;第二個是文件的操作模式;

主要有兩種模式:

MODE_PRIVATE:默認的操作模式,表示當指定同樣文件名的時候,所寫入的內容會覆蓋原有,而且只能被當前程序讀寫。
MODE_AOOEND:以追加方式打開該文件,應用程序可以向該文件中追加內容。

 

  FileOutputStream out = openFileOutput(file_name, MODE_PRIVATE);  //打開寫入文件
接著就可以將字節數據寫入文件中:
out.write(str.getBytes());
上述代碼使用write()方法將參數的字節數據寫入文件,字符串調用getByte()方法轉換成字節數組。最後調用close()方法關閉流。
 out.close();

讀取文件:

讀取文件使用FileInputStream對象:

FileInputStream in = openFileInput(file_name); //打開讀取文件

 

上述代碼使用繼承自Context類的openFileInput()方法打開FileInputStream文件流。參數是文件名字符串,然後我們需要自行建立讀取緩存區的byte[]數組以讀取文件內容。

 

       byte[] data = new byte[1024];
       in.read(data);
       String str = new String(data);
最後調用close()方法關閉流。
in.close();
【實例】存儲和讀取文件

 

布局文件中,EditText和兩個按鈕,還有TestView,代碼就不貼了

主要來看看java文件的代碼:

 

public class FileTest extends Activity {
    final String file_name = "songsong.txt";   //文件名
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_test);
    }

    public void Btn_Save(View view) {
        EditText edit = (EditText) findViewById(R.id.edit);
        String str = edit.getText().toString();
        try {
            FileOutputStream out = openFileOutput(file_name, MODE_PRIVATE);  //打開寫入文件
            out.write(str.getBytes());
            out.close();
            Toast.makeText(this, "成功寫入", Toast.LENGTH_SHORT).show();
            edit.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void Btn_Show(View view) {
        try {
            FileInputStream in = openFileInput(file_name); //打開讀取文件
            byte[] data = new byte[1024];
            in.read(data);
            String str = new String(data);
            in.close();
            Toast.makeText(this, "成功讀取", Toast.LENGTH_SHORT).show();
            TextView show = (TextView) findViewById(R.id.show);
            show.setText(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
其實主要的代碼都是兩個按鈕之間的存儲、讀取。還有捕獲異常吧 來看看效果:

 

\\

 

 


(二)使用SharePreferences

SharePreferences是使用鍵值對的方式來存儲數據的,也就是當保存一條數據的時候,需要給這條數據配對一個對應的鍵,這樣在讀取的時候就可以根據這個鍵來取出這個數據。而且SharePreferences還支持多種不同類型的的數據存儲,如果數據存儲是整型,那麼取出來的數據也是整型的。(使用在應用程序的各種配置信息,比如是否打開音效、振動、小游戲積分榜)

如何將數據存儲到SharePreferences中:

1、首先需要獲得SharePreferences對象。

 

 SharedPreferences preferences = getSharedPreferences("songsong", MODE_PRIVATE);

 

解釋一下,此方法接收會兩個參數:

第一個參數:用於指定SharePreferences文件的名稱(將”songsong"命名為文件名),如果指定的文件不存在則會新建一個。

第二個參數:用於指定操作模式MODE_PRIVATE、MODE_MULTI_PROCESS。

MODE_PRIVAT:是默認的操作模式,表示只有當前應用程序才可以對這個文件進行讀寫。MODE_MULTI_PROCESS:則是用於多個進程中對同一個文件進行讀寫。

2、調用SharePreferences對象的edit()方法來獲取一個SharePreferences.Editor對象

 

    SharedPreferences.Editor editor = preferences.edit();

 

3、向SharePreferences對象中添加數據,根據不同類型putXXX。

 

    editor.putString("name", "songsong");
    editor.putInt("age", 22);
    editor.putBoolean("married", false);
4、調用commit()方法將添加了的數據進行提交,從而完成數據存儲操作。
     editor.commit();

 

如何從SharePreferences中讀取數據:

從SharePreferences文件中讀取數據很簡單,SharePreferences對象中提供了一系列的get方法用於對存儲數據進行讀取。每種get方法都對應了之前存儲put方法。好比如,我putString,那麼就getString。這些get方法接收兩個參數,第一個是鍵,傳入存儲數據時使用的鍵就可以獲得相應的數據了。第二個參數是默認值,我個人稱為後備值,即表示當傳入的鍵找不到對應的值時,就會返回這個後備值。

 

      String name = preferences.getString("name", null);
      int age = preferences.getInt("age", 0);
      Boolean married = preferences.getBoolean("married", false);

【實例】接下來演示一個完整的代碼示例,布局文件裡只定義了兩個按鈕,一個是讀取,另一是寫入,十分簡單的界面。

public class SharePreferencesTest extends Activity {

    SharedPreferences preferences;
    SharedPreferences.Editor editor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_preferences_test);
        Button read = (Button) findViewById(R.id.read);
        Button write = (Button) findViewById(R.id.write);

        //獲取只能被本應用程序讀寫的SharedPreferences
        preferences = getSharedPreferences("songsong", MODE_PRIVATE);  
        editor = preferences.edit();

        write.setOnClickListener(new View.OnClickListener() {  //寫入事件
            @Override
            public void onClick(View v) {
                editor.putString("name", "songsong");
                editor.putInt("age", 22);
                editor.putBoolean("married", false);
                editor.commit();
            }
        });

        read.setOnClickListener(new View.OnClickListener() {  //讀取事件
            @Override
            public void onClick(View v) {
                String name = preferences.getString("name", null);
                int age = preferences.getInt("age", 0);
                Boolean married = preferences.getBoolean("married", false);
                Log.d("songsong", "name:" + name);
                Log.d("songsong", "age:" + age);
                Log.d("songsong", "married:" + married);
            }
        });
    }
}

運行一下程序,單擊寫入write按鈕,這時數據應該保持成功了。SharePreferences數據總是保存在/data/data//shared_prefs目錄下

\

SharePreferences數據總是以XML格式保存。借助File Explorer面板的導出文件,打開該XML文件可以看到如下內容:


  songsong      

 

接下來點擊讀取read按鈕,然後查看LogCat中打印的信息:

\

所有之前存儲的數據都成功讀取出來,在實際開發中偏好設置功能其實都使用到SharePreferences技術,接下來會做幾個實際應用會用到的功能。

-------------

【實例】記錄應用程序的使用次數

新建Activity,界面布局就保存最初始化。每次打開應用程序都會顯示Toast,而且count的次數都會遞增1。

 

public class UserCount extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_usercount);

       SharedPreferences preferences = getSharedPreferences("ueercount", MODE_PRIVATE);
        int count = preferences.getInt("count", 0);  //讀取sharepreferences裡的count數據
        Toast.makeText(this, "使用次數:" + count, Toast.LENGTH_SHORT).show();
        SharedPreferences.Editor editor = preferences.edit();
        editor.putInt("count", ++count);   //存入數據
        editor.commit();    //提交
    }
}

 

【實例】實現記住密碼功能

先寫一個Login登錄界面:(簡單為主)

 

    

    

    
接下來是Java代碼
public class LoginActivity extends Activity {
    SharedPreferences preferences;
    SharedPreferences.Editor editor;
    EditText accountEdit, passwordEdit;
    Button btnlogin;
    CheckBox cBox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        accountEdit = (EditText) findViewById(R.id.accountEdit);
        passwordEdit = (EditText) findViewById(R.id.passwordEdit);
        btnlogin = (Button) findViewById(R.id.btnlogin);
        cBox = (CheckBox) findViewById(R.id.cBox);

        preferences = PreferenceManager.getDefaultSharedPreferences(this); //打開默認的偏好文件

        boolean isRemember = preferences.getBoolean("remember_password", false);   //讀取isRemember

        if (isRemember) {   //將賬號密碼設置在文本框中
            String account = preferences.getString("account", "");
            String password = preferences.getString("password", "");
            accountEdit.setText(account);
            passwordEdit.setText(password);
            cBox.setChecked(true);
        }

        btnlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account = accountEdit.getText().toString();
                String password = passwordEdit.getText().toString();
                if (account != "" && password != "") {
                    editor = preferences.edit();
                    if (cBox.isChecked()) {
                        editor.putString("account", account);
                        editor.putString("password", password);
                        editor.putBoolean("remember_password", true);
                    } else {
                        editor.clear();//清空裡面所有數據
                    }
                    editor.commit();
                    Intent intent = new Intent(LoginActivity.this, LoginActivity.class);
                    startActivity(intent);
                    finish();
                } else
                    Toast.makeText(LoginActivity.this, "請輸入賬號或密碼", Toast.LENGTH_SHORT).show();
            }
        });
    }
} 

先來看看效果:
\

 


(三)SQLite數據庫存儲

 

創建數據庫:

 

Android為了讓我們能夠更充分方便地使用管理數據庫,專門提供了一個SQLiteOpenHelper幫助類,借助這個類就可以非常簡單地對數據庫進行創建和升級。首先我們要知道這個類是一個抽象類,這意味如果我們要使用它的話,就需要創建一個自己的幫助類去繼承它。SQLiteOpenHelper中有兩個抽象方法分別是onCreate()onUpgrade(),我們必須在自己的幫助類裡面重寫這兩個方法,然後分別在這兩個方法中去實現創建升級數據庫的邏輯。

SQLiteOpenHelper中還有兩個非常重要的實例方法,getReadableDatabase()和getWritableDatabase()。這兩個方法共同點是:都可以創建或打開一個現有的數據庫(如果數據庫不存在則會創建新的),並返回一個可對數據庫進行讀寫操作的對象。不同點是:如果磁盤空間已滿,getReadableDatabase()方法返回的對象將以只讀的方式去打開數據庫,而getWritableDatabase()方法則將會出現異常。

SQLiteOpenHelper中有兩個構造方法可供重寫,一般使用參數少一點的那個構造方法即可,這個構造方法中接收四個參數:

 

 public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

 

第一個參數是Context,這個沒什麼好說,必須要有它才能對數據庫進行操作。第二個參數是數據庫名,創建數據庫時使用的就是這裡指定的名稱。第三個參數是允許我們在查詢數據時候返回一個自定義的Cursor,一般傳入null。第四個參數是表示當前數據庫版本號,可用於對數據庫進行升級操作。

【實例】創建數據庫

創建一個命名為BookStore.db的數據庫,然後在這個數據庫裡面新建一張Book表,表裡有id(唯一主鍵)、作者、價格、頁數、書名。
新建MyDatabaseHelper類繼承自SQLiteOpenHelper,代碼如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {
    public static final String CREATE_BOOK = "create table Book("
            + "id integer primary key autoincrement,"
            + "author text,"
            + " price real,"
            + "pages integer,"
            + "name text)";
    private Context mcontext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mcontext = context;
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mcontext, "創建成功", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
布局文件很簡單,只有一個按鈕,用於創建數據庫:
在onCreate方法中構建一個MyDatabaseHelper對象,並通過構建函數的參數將數據庫名指定為BookStore.db,版本號指定為1,然後在按鈕點擊事件裡調用了getWritableDatabase方法,當第一次點擊按鈕時,就會檢測到沒有BookStore.db這個數據庫,於是就去創建該數據庫並調用onCreate方法,這樣一來Book表也創建成功。

 

public class SQLiteTest extends Activity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_test);

        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);  //命名為BookStore,版本為1

        findViewById(R.id.create_database).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();//第一次點擊按鈕時,就會檢查到當前程序中並沒有這數據庫,接著就調用onCreate
            }
        });
    }
}

升級數據庫:

在MyDatabaseHelper中還有onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 方法是用於升級軟件時更新數據庫表結構,此方法在數據庫的版本發生變化時被調用,oldVersion代表數據庫之前版本號,newVersion代表數據庫當前版本號。當程序創建SQLiteOpenHelper對象時,第四個參數就必須指定version參數,該參數就決定了使用數據庫的版本號。

 dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

只要某次創建SQLiteOpenHelper時指定的數據庫版本號高於之前指定的版本號,系統就會自動觸發onUpgrade()方法。(注意:在實際上當應用程序升級表結構時,完全可能因為已有的數據導致升級失敗,所以可能需要先對數據進行轉儲,清空數據表中記錄,再更新,再把數據保存回來)

 

使用insert方法插入數據:

由於開發者水平總是參差不齊,所以在Android中,專門提供了一種輔助性方法,使得在Android中即使不去編寫SQL語句也能夠輕松完成CRUD操作。SQLiteDatadase提供了一個insert(String table, String nullColumnHack, ContentValues values)方法,這個方法專門用於添加數據,它接收三個參數:

第一個參數table:代表想插入數據的表名;
第二個參數nullColumnHack:用於在未指定添加數據的情況下給某些可以為空的列自動賦值NULL,一般填NULL即可;第三個參數values:是一個ContentValues對象,提供一系列的put()方法重載,用於向ContentValues中添加數據,只需將表中每個列名對應的內容添加數據傳入即可。

【實例】插入數據

 


    ...
   
添加了個Add按鈕,在添加數據Add按鈕的點擊事件裡面,先獲取到SQLiteDatabase對象,然後使用ContentValues來對要添加的數據進行組裝。因為Book表的id列設置了自動增長,所以只組裝了4個值。

 

 

  findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("name", "The one");
                values.put("author", "junlin");
                values.put("pages", 444);
                values.put("price", 14.44);
                db.insert("Book", null, values);
                values.clear();
                
                values.put("name", "The two");
                values.put("author", "songsong");
                values.put("pages", 555);
                values.put("price", 15.55);
                db.insert("Book", null, values);
            }
        });
將數據庫導出到桌面,然後用SQLite Database Browser 2.0 b1.exe打開文件。(這個軟件非常小而且簡單,可以在百度上面搜搜,我也會寫一篇文章來介紹這個 我老師傳給我的應用)

 

\

\

剛剛添加進去的兩條數據都顯示出來了,所以我們成功了!

 

 

使用update方法更新數據:

SQLiteDatadase提供了一個update方法,update(String table, ContentValues values, String whereClause, String[] whereArgs),這個更新方法的參數說明如下:

第一個參數table:代表想更新數據的表名。
第二個參數values:代表想更新的數據。
第三個參數whereClause:滿足該whereClause子句的記錄將會被更新,不指定的話就是默認所有行。
第四個參數whereArgs:用於為whereClause子句傳入參數。

例如,我們想更新書名為“the one”的價格為9.99,可調用如下方法:

首先修改xml文件內容,為其添加個按鈕updata:

 

布局文件的代碼十分簡單,然後為updata按鈕添加事件:
  //更新數據
        findViewById(R.id.updata).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 9.99);
                db.update("Book", values, "name=?", new String[]{"The one"});
            }
        });
來查看下結果:

\

 

使用delete方法刪除數據:

SQLiteDatadase提供了一個delete方法,delete(String table, StringwhereClause, String[] whereArgs),這個刪除方法的參數說明如下:

 

第一個參數table:代表想更新數據的表名。
第二個參數whereClause:滿足該whereClause子句的記錄將會被刪除。
第三個參數whereArgs:用於為whereClause子句傳入參數。 例如,我們想刪除頁數超過500頁的書籍,可調用如下方法:

 

在布局文件中添加delete按鈕:

 

為delete按鈕添加事件:
 //刪除數據
        findViewById(R.id.delete_data).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages>?", new String[]{"500"});
            }
        });
效果如下:

\

 

 

使用query方法查詢數據:

SQLiteDatadase提供了一個query方法,query(boolean distinct, String table, String[]columns, String whereClause, String selectionArgs, String groupBy, String having, String orderBy, String limit),這個query方法的參數說明如下:

distinct:指定是否去除重復記錄;table:執行查詢數據的表名;columns:要查詢出來的列名,相當於select語句select關鍵字後面的部分。whereClause:查詢條件子句,相當於select語句where關鍵字後面的部分,在條件子句中允許使用占位符“?”。selectionArgs:用於為whereClause子句中的占位符傳入參數值。groupBy:用於控制分組。相當於select語句group by關鍵字後面的部分。having:用於對分組進行過濾。
orderBy:用於對記錄進行排序。limit:用於進行分頁。

 

我們舉個例子:我們想查詢the開頭的書籍,那麼我們就可以這樣寫:

 

   Cursor cursor = db.query("Book", new String[]{"name,author,price,pages"}, "name like ? ", new String[]{"the%"}, null, null, null);

 

接下來做個案例,為程序添加一個按鈕,並為按鈕添加事件:

   //查詢數據
        findViewById(R.id.query_data).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                Cursor cursor = db.query("Book", null, null, null, null, null, null);
                if (cursor.moveToFirst())
                {
                    do {
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        String price = cursor.getString(cursor.getColumnIndex("price"));
                        String pages = cursor.getString(cursor.getColumnIndex("pages"));
                        String name = cursor.getString(cursor.getColumnIndex("name"));

                        Log.d("SQLiteTest", "name=" + name + ",author=" + author + ",pages=" + pages + ",price=" + price);
                    } while (cursor.moveToNext());
                    cursor.close();
                }
            }
        });

 

\

 

當我們點擊按鈕的時候,調用了SQLiteDatadase的query()方法去查詢數據,通過第一個參數book,其他全部為null,表示想查詢表裡所有數據。

補充說明:Cursor提供了如下方法來移動查詢結果的記錄指針:

move(int offset):將記錄指針向上或向下移動指定的行數,offset正數就是向下移動,為負數就是向上。boolean moveToFirst():將記錄指針移動到第一行,如果移動成功則返回true;
boolean moveToLast():將記錄指針移動到最後一行,如果移動成功則返回true;boolean moveToNext():將記錄指針移動到下一行,如果移動成功則返回true;
boolean moveToPosition(int position):將記錄指針移動到指定行,如果移動成功則返回true;boolean moveToPrevious():將記錄指針移動到上一行,如果移動成功則返回true;

 

 

使用SQL操作數據庫:

 

其實作為一個開發者,無論工作是使用哪種開發語言的,多多少少都會對SQL語句有了解。好比如我,在校的時候學C++,ASP.NET,PHP和Java,都會用到SQL語句,所以很多時候我會比較喜歡用SQL語句來對數據進行操作。而且很多android的書籍也是推薦使用SQL語句進行編程,但是這些輔助性的方法肯定有它存在的價值,作為Android初級開發者的我們,當然也要去了解、學習。

  那麼接下來也要懂得直接通過SQL來操作數據庫,下面就簡略演示用SQL來完成之前幾個小實例:

插入:

   db.execSQL("insert into Book(name,author,pages,price)values(?,?,?,?)", new String[]{"the love", "安德魯", "777", "29.5"});
更新:
 db.execSQL("update Book set price = ? where price > ?", new String[]{"25", "25"});
刪除:
 db.execSQL("delete from Book   where pages > ?", new String[]{"700"});
查詢:
  db.rawQuery("select * from Book", null);
上面說講到的內容是十分基礎的,真正到了實際開發環境中,就不是那麼簡單的,如果想真正了解SQL可以在網上搜索更多相關資料。

 

 

使用事務:

 

所謂事務是用戶定義的一個數據庫操作序列,這些操作要麼全做要麼全不做,是一個不可分割的工作單位。

beginTransaction():開始事務
setTransactionSuccessful():事務已經執行成功,如果沒調用此方法,endTransaction()將回滾事務。
endTransaction():由事務的標志決定是提交事務還是回滾事務。

 

接下來實例演示,將book表的所有數據刪除然後插入一句。如果刪除失敗,那麼插入也會失敗。

 

findViewById(R.id.Transaction_id).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.beginTransaction();//開啟事務
                try {
                    db.execSQL("delete from Book ");
                    db.execSQL("insert into Book(name,author,pages,price)values(?,?,?,?)", new String[]{"the love", "安德魯", "777", "29.5"});
                    db.setTransactionSuccessful();//事務執行完畢
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    db.endTransaction();//結束事務
                }
            }
        });


希望本文內容對你有幫助,謝謝!

如果有什麼問題可以在欄目下方評論以及交流。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved