2025-05-17

Android提供的數據持久化存儲方式有以下幾種。

1.Shared Preferences:以Key-Value形式存儲數據

2.Internal Storage:數據文件存儲在內存卡

3.External Storage:數據存儲在外部設備,如SD卡等

4.SQLite Databases:SQLite存儲方式

5.Network Connection:通過WebService等網絡通信方式存儲數據。

 

 

一、Shared Preferences

常用來存儲應用中的用戶偏好設置,例如應用的默認皮膚設置、記錄用戶上次登錄信息等。數據的存儲格式為Key-Value。

下面通過案例,記錄用戶信息來瞭解如何使用Shared Preferences。

介紹將使用到的Android SDK API:

SharedPreferences類:提供瞭一批讀取、遍歷數據的API。

Editor類:提供修改、保存數據API。
getSharedPreferences(String name, int mode):指定存儲文件的文件名,並設置訪問權限

getPreferences(int mode):如果你的Activity中隻需要一個喜好文件,則可以不提供存儲文件名,隻需要設置訪問權限

更多介紹可以訪問:http://android.toolib.net/guide/topics/data/data-storage.html#pref

1、新建Android項目

項目名稱Shared Preferences,主Activity名稱為MainActivity。

2、設計主界面XML描述

[html] <?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
<TextView   
    android:layout_width="fill_parent"  
    android:layout_height="wrap_content"  
    android:text="@string/name" 
    /> 
  
<EditText 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/name" 
    /> 
 
<TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/age"  
    /> 
     
<EditText 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/age" 
    /> 
 
<Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="@string/save"  
    android:onClick="save" 
    /> 
</LinearLayout> 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/name"
    />
 
<EditText
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:id="@+id/name"
 />

<TextView
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="@string/age"
 />
 
<EditText
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:id="@+id/age"
 />

<Button
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/save"
 android:onClick="save"
 />
</LinearLayout>界面效果:
 
 

 

3、定義“保存”按鈕的save事件處理方法

[java] package mr.jin.shared; 
 
import android.app.Activity; 
import android.content.Context; 
import android.content.SharedPreferences; 
import android.content.SharedPreferences.Editor; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
    private EditText nameEdit; 
    private EditText ageEdit; 
    private String USERINFO="userInfo"; 
     
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
         
        nameEdit = (EditText) findViewById(R.id.name);//應用打開後,即查找到姓名、年齡的文本框對象。  
        ageEdit = (EditText) findViewById(R.id.age); 
 
        init(); 
    } 
     
    public void save(View v){ 
        try{ 
            SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); 
            Editor editor = perference.edit(); 
            editor.putString("name", nameEdit.getText().toString()); 
            editor.putString("age", ageEdit.getText().toString()); 
            editor.commit();//未調用commit前,數據實際是沒有存儲進文件中的。 調用後,存儲存儲  
             
            Toast.makeText(this, R.string.success, Toast.LENGTH_LONG).show(); 
             
        }catch(Exception e){ 
            Toast.makeText(this, R.string.error, Toast.LENGTH_LONG).show(); 
        } 
    } 
     
    /*第一次打開應用時,讀取本地用戶信息設置*/ 
    public void init(){ 
        SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); 
        nameEdit.setText(perference.getString("name", "")); 
        ageEdit.setText(perference.getString("age", "")); 
    } 

package mr.jin.shared;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
 private EditText nameEdit;
 private EditText ageEdit;
 private String USERINFO="userInfo";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        nameEdit = (EditText) findViewById(R.id.name);//應用打開後,即查找到姓名、年齡的文本框對象。
        ageEdit = (EditText) findViewById(R.id.age);

        init();
    }
   
    public void save(View v){
     try{
      SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE);
      Editor editor = perference.edit();
      editor.putString("name", nameEdit.getText().toString());
      editor.putString("age", ageEdit.getText().toString());
      editor.commit();//未調用commit前,數據實際是沒有存儲進文件中的。 調用後,存儲存儲
      
      Toast.makeText(this, R.string.success, Toast.LENGTH_LONG).show();
         
     }catch(Exception e){
      Toast.makeText(this, R.string.error, Toast.LENGTH_LONG).show();
     }
    }
   
    /*第一次打開應用時,讀取本地用戶信息設置*/
    public void init(){
     SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE);
     nameEdit.setText(perference.getString("name", ""));
     ageEdit.setText(perference.getString("age", ""));
    }
}

4、部署應用

第一次打開應用,兩個輸入框都為空。在輸入信息後,點擊保存。退出應用,再次打開應用,將顯示之前保存的用戶信息。

 

二、Internal Storage

可以將文件存儲在內部存儲設備,默認文件訪問權限是私有的,除瞭當前應用,其他應用無法訪問。當用戶卸載您的應用程序,這些文件將被刪除。

來看看Android SDK提供的文件存儲權限:

Context.MODE_APPEND;//追加方式存儲
Context.MODE_PRIVATE;//私有方式存儲,其他應用無法訪問
Context.MODE_WORLD_READABLE;//允許其他應用讀取數據
Context.MODE_WORLD_WRITEABLE;//允許其他應用寫入、讀取數據

1.建立項目

項目名稱InternalStorage,主Activity類名稱MainActivity。

2.定義界面及XML描述

  

 

print?<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
<TextView   
    android:layout_width="fill_parent"  
    android:layout_height="wrap_content"  
    android:text="輸入文字" 
    /> 
  
 <EditText 
    android:minLines="3" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/editText" 
    /> 
  
 <Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="保存" 
    android:onClick="save" 
    /> 
     
 <TextView 
    android:id="@+id/showText" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    /> 
     
 <Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="顯示保存的數據" 
    android:onClick="showData" 
    /> 
</LinearLayout> 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="輸入文字"
    />
 
 <EditText
  android:minLines="3"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:id="@+id/editText"
  />
 
 <Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="保存"
  android:onClick="save"
  />
  
 <TextView
  android:id="@+id/showText"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  />
  
 <Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="顯示保存的數據"
  android:onClick="showData"
  />
</LinearLayout>
3.定義“保存”按鈕的save、“顯示保存的數據”按鈕的事件處理

[java] package mr.jin.internal; 
 
import java.io.ByteArrayOutputStream; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
 
import android.app.Activity; 
import android.content.Context; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.TextView; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
    private EditText editText; 
    private TextView showText; 
     
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
         
        editText = (EditText) findViewById(R.id.editText); 
        showText = (TextView) findViewById(R.id.showText); 
    } 
     
    public void save(View v){ 
        String content = editText.getText().toString(); 
         
        try { 
            FileOutputStream outfile = openFileOutput("current_file", Context.MODE_PRIVATE); 
            outfile.write(content.getBytes()); 
            outfile.close(); 
            Toast.makeText(this, "保存成功", 3000).show(); 
        } catch (Exception e) { 
            Toast.makeText(this, "保存失敗", 3000).show(); 
            e.printStackTrace(); 
        } 
    } 
     
    public void showData(View v){ 
        try { 
            FileInputStream showfile = openFileInput("current_file"); 
            ByteArrayOutputStream out = new ByteArrayOutputStream(); 
            byte[] data = new byte[1024]; 
            int len = 0; 
             
            while( (len=showfile.read(data))  != -1){ 
                out.write(data, 0, len); 
            } 
             
            String content = new String(out.toByteArray()); 
             
            showText.setText(content); 
             
            Toast.makeText(this, "顯示成功", 3000).show(); 
        } catch (Exception e) { 
            Toast.makeText(this, "顯示失敗", 3000).show(); 
            e.printStackTrace(); 
        } 
    } 

package mr.jin.internal;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
    private EditText editText;
    private TextView showText;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        editText = (EditText) findViewById(R.id.editText);
        showText = (TextView) findViewById(R.id.showText);
    }
   
    public void save(View v){
     String content = editText.getText().toString();
     
     try {
   FileOutputStream outfile = openFileOutput("current_file", Context.MODE_PRIVATE);
   outfile.write(content.getBytes());
   outfile.close();
   Toast.makeText(this, "保存成功", 3000).show();
  } catch (Exception e) {
   Toast.makeText(this, "保存失敗", 3000).show();
   e.printStackTrace();
  }
    }
   
    public void showData(View v){
     try {
   FileInputStream showfile = openFileInput("current_file");
   ByteArrayOutputStream out = new ByteArrayOutputStream();
   byte[] data = new byte[1024];
   int len = 0;
   
   while( (len=showfile.read(data))  != -1){
    out.write(data, 0, len);
   }
   
   String content = new String(out.toByteArray());
   
   showText.setText(content);
   
   Toast.makeText(this, "顯示成功", 3000).show();
  } catch (Exception e) {
   Toast.makeText(this, "顯示失敗", 3000).show();
   e.printStackTrace();
  }
    }
}

 

4.部署測試。

 

三、External Storage

擴展存儲,例如常見擴展存儲有SD卡,可以將大容量的數據存儲在外部存儲中。

因為SD卡是可以由用戶自由裝載、卸載的,所以在使用SD卡上的文件之前,應該先檢測設備是否已經裝載成功。

通過判斷Environment.getExternalStorageState()的返回值,可以知道目前SD卡的狀態。

 

 

1、訪問SD卡上文件

a.如果使用API級別大於等於8,可以使用getExternalFilesDir(String type),參數要求提供一個子目錄名稱,若傳遞null即為根目錄,返回指定目錄路徑的File對象。

這裡手冊上建議使用有意義的子目錄名稱,便於Android媒體掃描器,正確的將文件分類。

[java] public class Environment { 
    public static String DIRECTORY_MUSIC = "Music"; //音頻文件  
    public static String DIRECTORY_PODCASTS = "Podcasts";   //廣播  
    public static String DIRECTORY_RINGTONES = "Ringtones"; //鈴聲  
    public static String DIRECTORY_ALARMS = "Alarms";   //警報  
    public static String DIRECTORY_NOTIFICATIONS = "Notifications"; //通知  
    public static String DIRECTORY_PICTURES = "Pictures";   //圖片  
    public static String DIRECTORY_MOVIES = "Movies";   //電影  
    public static String DIRECTORY_DOWNLOADS = "Download";  //下載  
    public static String DIRECTORY_DCIM = "DCIM";   //照片  
    //…不完整的Environment類內容  

public class Environment {
 public static String DIRECTORY_MUSIC = "Music"; //音頻文件
 public static String DIRECTORY_PODCASTS = "Podcasts"; //廣播
 public static String DIRECTORY_RINGTONES = "Ringtones"; //鈴聲
 public static String DIRECTORY_ALARMS = "Alarms"; //警報
 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; //通知
 public static String DIRECTORY_PICTURES = "Pictures"; //圖片
 public static String DIRECTORY_MOVIES = "Movies"; //電影
 public static String DIRECTORY_DOWNLOADS = "Download"; //下載
 public static String DIRECTORY_DCIM = "DCIM"; //照片
 //…不完整的Environment類內容
}

 

b.API級別小於等於7,可以使用getExternalStorageDirectory(),將返回文件路徑為/Android/data/<package_name>/files/的File對象,這裡的<package_name>就是
AndroidManifest.xml中<manifest>標簽中定義package。

這兩種方法創建的文件,在應用被卸載時,文件也隨之刪除。

 

2、如果不希望創建的文件在應用卸載後被刪除,可以使用下面的方法

以共享文件的方式存儲,任何應用都將可以訪問這些文件。

a.API大於等於8,getExternalStoragePublicDirectory (String type),參數與getExternalFilesDir(String type)中的參數一樣,指定子目錄。

b.API小於等於7,getExternalStorageDirectory(),返回外部存儲的根目錄的File對象。然後將文件存儲在:

Music/ – 媒體掃描儀劃分為用戶的音樂在這裡發現的所有媒體。
Podcasts/ – 媒體掃描儀的分類在這裡找到一個podcast的所有媒體。
Ringtones/ – 媒體掃描器分類作為鈴聲,在這裡發現所有的媒體。
Alarms/ – 媒體掃描儀發出報警聲,這裡發現的所有媒體分類。
Notifications/ – 媒體掃描儀的分類作為通知的聲音在這裡發現的所有媒體。
Pictures/ – 所有照片(不包括那些用相機拍攝)。
Movies/ – 所有電影(不包括用攝像機拍攝的)。
Download/ – 雜項下載。

 

 

四、SQLite存儲

Android提供瞭對SQLite全面支持,無需考慮數據庫連接、連接池等問題。

隻需要集成SQLiteOpenHelper類,它提供瞭訪問數據庫、事務等API。

[java] package mr.jin.service; 
 
import android.content.Context; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 
 
public class DBOpenHelper extends SQLiteOpenHelper { 
 
    public DBOpenHelper(Context context) { 
        //第一個參數:傳遞上下文對象  
        //第二個參數:數據庫保存的文件名  
        //第三個參數:null使用默認的創建遊標對象工廠  
        //第四個參數:最重要,表示數據庫版本號,最小值1。每次運行應用前  
        //      會與當前應用的數據庫版本做比較,如果大於當前版本號  
        //      將調用onUpgrade方法。  
        super(context, "dbfile.db", null, 1); 
    } 
 
    @Override 
    public void onCreate(SQLiteDatabase db) {//隻在第一次運行應用時調用,這裡可以運行創建數據庫結構的代碼  
        db.execSQL("CREATE TABLE person(personid integer primary key autoincrement, name varchar(20))"); 
    } 
 
    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//隻在數據庫版本發生改變時調用  
        db.execSQL("ALTER TABLE person ADD amount integer NULL"); 
    } 
 

package mr.jin.service;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBOpenHelper extends SQLiteOpenHelper {

 public DBOpenHelper(Context context) {
  //第一個參數:傳遞上下文對象
  //第二個參數:數據庫保存的文件名
  //第三個參數:null使用默認的創建遊標對象工廠
  //第四個參數:最重要,表示數據庫版本號,最小值1。每次運行應用前
  //  會與當前應用的數據庫版本做比較,如果大於當前版本號
  //  將調用onUpgrade方法。
  super(context, "dbfile.db", null, 1);
 }

 @Override
 public void onCreate(SQLiteDatabase db) {//隻在第一次運行應用時調用,這裡可以運行創建數據庫結構的代碼
  db.execSQL("CREATE TABLE person(personid integer primary key autoincrement, name varchar(20))");
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//隻在數據庫版本發生改變時調用
  db.execSQL("ALTER TABLE person ADD amount integer NULL");
 }

}
SQLiteOpenHelper提供瞭兩個API來獲得數據庫連接對象SQLiteDatabase:

getWritableDatabase():返回可讀、寫對象

getReadableDatabase():返回可讀、寫對象。僅當無法寫時,返回隻讀對象。

具體一些操作數據庫的方法,可以參看SQLiteDatabase API手冊,提供的方法已經足夠多瞭。http://android.toolib.net/reference/android/database/sqlite/SQLiteDatabase.html

 

摘自  God's blog
 

發佈留言

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