理解 Android 本地数据存储 API

利用首选项、SQLite 和内部及外部内存 API

对于需要跨应用程序执行期间或生命期而维护重要信息的应用程序来说,能够在移动设备上本地存储数据是一种非常关键的功能。作为一名开发人员,您经常需要存储诸如用户首选项或应用程序配置之类的信息。您还必须根据一些特征(比如访问可见性)决定是否需要涉及内部或外部存储器,或者是否需要处理更复杂的、结构化的数据类型。跟随本文学习 Android 数据存储 API,具体来讲就是首选项、SQLite 和内部及外部内存 API。

C. Enrique Ortiz, 开发人员兼作家, About Mobility Weblog

C. Enrique Ortiz 是一位经验丰富的移动技术专家、开发人员和作家。他在 About Mobility 上撰写博客,他是 Austin chapter of MobileMonday 的创始人。



2010 年 12 月 27 日

常用缩写词

  • ADT:Android 开发工具
  • API:应用程序编程接口
  • IDE:集成开发环境
  • JDK:Java 开发工具包
  • JSON:JavaScript 对象表示法
  • SDK:软件开发工具包
  • SQL:结构化查询语言
  • UI:用户界面
  • XML:可扩展标记语言

前提条件

要跟随本文,需要具备以下技能和工具:

  • 基本了解 Java™ 技术和如何使用 Eclipse(或者您喜欢的 IDE)
  • Java Development Kit(需要版本 5 或 6)
  • Eclipse(版本 3.4 或 3.5)
  • Android SDK 和 ADT 插件

关于下载和设置信息,请参见本文末尾的 参考资料


样例应用程序

为了突出 Android 应用程序开发的本地存储方面,我这里介绍一个样例应用程序,它允许您测试各种类型 API 的执行。有 源代码 可供下载。该应用程序支持 图 1 中的操作。

图 1. 用例
样例中的用例图

图 1 列出了以下用例:

  • 管理和存储首选项
  • 从应用程序资产加载信息
  • 将信息导出到内部内存、外部内存和本地数据库
  • 从内部内存和本地数据库读取数据
  • 清除已存储的信息
  • 在屏幕上查看信息

通篇文章中,详细介绍了在应用程序中使用本地存储,如下:

  • 从用户捕获首选项,本地存储起来,并在整个应用程序中加以使用。
  • 从内部应用程序资产检索一个用户图片,存储在本地内部内存和外部内存中,并呈现在屏幕上。
  • 从应用程序的资产检索一个 JSON 格式的好友列表。解析并存储在本地内部内存、外部内存和关系数据库中,再呈现在屏幕上。

样例应用程序定义了 表 1 中的类。

表 1. 样例应用程序中的类
说明
MainActivityMain Activity;大多数样例代码都驻留在这里
Friend描绘一个 Friend
AppPreferenceActivityPreferences Activity 和屏幕
DBHelper一个用于 SQLite 数据库管理的帮助器类

示例应用程序使用了两种类型的数据。第一种是应用程序首选项,存储为名-值对。对于首选项,定义了以下信息:

  • 一个 filename,用于加载和存储好友姓名列表
  • 一个 filename,用于加载和存储用户的一幅图片
  • 一个 flag,如果设置了,那么表示在应用程序启动时自动删除所有已存储的数据

第二种类型的数据是好友列表。好友列表最初表示为 Facebook Graph API JSON 格式,包含一组姓名和好友对象(参见 清单 1)。

清单 1. 好友列表(Facebook Graph API JSON 格式)
{
   "data": [
      {
         "name": "Edmund Troche",
         "id": "500067699"
      }
   ]
}

上面的简单格式使得 Friend 对象和数据库模式也简单。清单 2 展示了 Friend 类。

清单 2. Friend
package com.cenriqueortiz.tutorials.datastore;

import android.graphics.Bitmap;

/**
 * Represents a Friend
 */
public class Friend {
    public String id;
    public String name;
    public byte[] picture;
    public Bitmap pictureBitmap;;
}

除了 ID 和姓名之外,样例应用程序也保留了对好友图片的引用。尽管样例应用程序没有使用这些引用,但是您很容易扩展样例应用程序,以从 Facebook 检索图片并显示在主屏幕中。

数据库模式包含单个表,用于存储 Friend 的信息。表有三列:

  • 惟一的 ID 或键
  • Facebook ID
  • Friend 的姓名

清单 3 展示了相应关系表声明的 SQL 语句。

清单 3. Friend 数据库表
db.execSQL("create table " + TABLE_NAME + " (_id integer primary key autoincrement, " 
+ " fid text not null, name text not null) ");

根据此信息,您可以在主屏幕上显示姓名;使用 ID,您可以检索所选用户的额外详细信息。在样例应用程序中,只显示了姓名。检索额外信息留给您去试验。注意,您很容易更改代码,以直接转向 Facebook。


存储应用程序首选项

本节介绍 Preferences API 和屏幕。Android API 提供很多方式处理首选项。其中一种方式是直接使用 SharedPreferences,并使用您自己的屏幕设计和首选项管理。第二种方法是使用 PreferenceActivityPreferenceActivity 自动负责首选项如何呈现在屏幕上(默认情况下,看起来跟系统首选项一样),并通过使用 SharedPreferences 在用户与每个首选项交互时自动存储或保存首选项。

为了简化样例应用程序,使用一个 PreferenceActivity 来管理首选项和首选项屏幕(参见 图 2)。首选项屏幕显示两个部分:Assets 和 Auto Settings。在 Assets 下,您可以为 Friends List 和 Picture 选项输入文件名。在 Auto Settings 下,您可以选中一个复选框,以便在启动时删除信息。

图 2. 实现的 Preferences 屏幕
实现的 Preferences 屏幕的屏幕截图

图 2 中,布局是用 XML 以声明式方法定义的(不是以编程方式);声明式 XML 是首选方法,因为它保持了源代码的清晰可读。清单 4 展示了 Preferences UI 的 XML 声明。

清单 4. Preferences 屏幕的 XML 声明
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/prefs_screen"
        android:key="preferencescreen"
    >
    <PreferenceCategory android:title="Assets">
        <EditTextPreference 
            android:key="@string/prefs_assetname_friendslist_key"
            android:title="Friends List" 
            android:summary="Please enter filename"
            android:defaultValue="friends.txt"
        />
        <EditTextPreference 
            android:key="@string/prefs_assetname_picture_key"
            android:title="Picture" 
            android:summary="Please enter filename"
            android:defaultValue="pict2.jpg"
        />
    </PreferenceCategory>

    <PreferenceCategory android:title="Auto Settings">
        <CheckBoxPreference
            android:key="@string/prefs_autodelete_key"
            android:title="Delete at Startup" 
            android:summary="Check to clear at startup"
            android:defaultValue="false"
        />
    </PreferenceCategory>
</PreferenceScreen>

PreferenceScreen 包含 EditTextPreference 的两个实例、一个 CheckBoxPreference 和两个由 PreferenceCategory 定义的类别组(一个用于 Asset,另一个用于 Auto Settings)。

在样例应用程序中,设计要求 Preference 屏幕使用菜单项进行调用。为此,使用一条 Intent 消息来调用叫做 AppPreferenceActivity 的 Preference Screen Activity(参见 清单 5)。注意,我没有详细介绍 Intent 如何工作。关于 Intent 的更多信息,请参见 参考资料

清单 5. AppPreferenceActivity
/*
 * AppPreferenceActivity is a basic PreferenceActivity
 * C. Enrique Ortiz | http://CEnriqueOrtiz.com
 */
package com.cenriqueortiz.tutorials.datastore;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class AppPreferenceActivity extends PreferenceActivity {

    /**
     * Default Constructor
     */
    public AppPreferenceActivity() {}

   /** 
    * Called when the activity is first created. 
    *   Inflate the Preferences Screen XML declaration.
    */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.prefs); // Inflate the XML declaration
    }   

}

在样例应用程序中,像 清单 6 中一样,从菜单项处理程序中调用 Intent。

清单 6. 使用 Intent 调用 Preference Activity
/**
 * Invoked when a menu item has been selected
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        // Case: Bring up the Preferences Screen
        case R.id.menu_prefs: // Preferences
            // Launch the Preference Activity
            Intent i = new Intent(this, AppPreferenceActivity.class);
            startActivity(i);
            break;

        case R.id.menu...:
            :
            break;

    }
    return true;
}

此外,您必须在 AndroidManifest XML 文件中定义所有的 Intent,如 清单 7 所示。

清单 7. 在 AndroidManifest.xml 中定义 Intent
:

<application android:icon="@drawable/icon" android:label="@string/app_name">

    :
    :
    
    <activity 
        android:name="AppPreferenceActivity" 
        android:label="Preferences">
    </activity>  

     :

</application>

回想一下,PreferenceActivity 使用 SharedPreferences 在用户与首选项屏幕交互时自动存储首选项。然后应用程序在执行各种任务时使用这些首选项。清单 8 展示了如何直接使用 SharedPreferences 来加载存储的首选项;关于加载的首选项在整个样例代码中是如何被使用的,您可以参考相应的样例代码。此外,清单 8 也展示了如何利用 SharedPreferences 直接存储首选项,以防您喜欢自己管理首选项(不是通过 PrefenceActivity),使用了一个 Editor

清单 8 展示了如何使用 SharedPreferences 加载已存储的首选项,以及如何使用 Editor 更改已存储的首选项。

清单 8. 使用 SharedPreferences
/////////////////////////////////////////////////////////////
// The following methods show how to use the SharedPreferences
/////////////////////////////////////////////////////////////

/**
 * Retrieves the Auto delete preference
 * @return the value of auto delete
 */
public boolean prefsGetAutoDelete() {
    boolean v = false;
    SharedPreferences sprefs = 
       PreferenceManager.getDefaultSharedPreferences(appContext); 
    String key = appContext.getString(R.string.prefs_autodelete_key);
    try {
        v = sprefs.getBoolean(key, false);
    } catch (ClassCastException e) {
    }
    return v;
}   

/**
 * Sets the auto delete preference
 * @param v the value to set
 */
public void  prefsSetAutoDelete(boolean v) {
    SharedPreferences sprefs = 
    PreferenceManager.getDefaultSharedPreferences(appContext); 
    Editor e = sprefs.edit();
    String key = appContext.getString(R.string.prefs_autodelete_key);               
    e.putBoolean(key, v);
    e.commit();
}

接下来,将介绍如何使用数据库来存储数据。


使用 SQLite 数据库

Android 通过 SQLite 提供对本地关系数据库的支持。表中(定义在以下代码清单中)汇总了样例应用程序中使用的重要数据库类。

样例应用程序使用了一个 DBHelper 类来封装一些数据库操作(参见 清单 9)。

清单 9. DBHelper
package com.cenriqueortiz.tutorials.datastore;

import java.util.ArrayList;

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

public class DBHelper extends SQLiteOpenHelper {

为数据库版本、数据库名称和表名称定义了很多常量(参见 清单 10)。

清单 10. 初始化 DBHelper
    private SQLiteDatabase db;
    private static final int DATABASE_VERSION = 1;
    private static final String DB_NAME = "sample.db";
    private static final String TABLE_NAME = "friends";

    /**
     * Constructor
     * @param context the application context
     */
    public DBHelper(Context context) {
        super(context, DB_NAME, null, DATABASE_VERSION);
        db = getWritableDatabase();
    }

在准备好创建数据库时,会调用 onCreate() 方法。在该方法中,创建表(参见 清单 11)。

清单 11. 创建数据库表
    /**
     * Called at the time to create the DB.
     * The create DB statement
     * @param the SQLite DB
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(
                "create table " + TABLE_NAME + " (_id integer primary key autoincrement, 
" + " fid text not null, name text not null) ");
    }

insert() 方法在信息导出到数据库时由 MainActivity 调用(参见 清单 12)。

清单 12. 插入一行
    /**
     * The Insert DB statement
     * @param id the friends id to insert
     * @param name the friend's name to insert
     */
    public void insert(String id, String name) {
        db.execSQL("INSERT INTO friends('fid', 'name') values ('"
                + id + "', '"
                + name + "')");
    }

deleteAll() 方法在清理数据库时由 MainActivity 调用。它删除表(参见 清单 13)。

清单 13. 删除数据库表
    /**
     * Wipe out the DB
     */
    public void clearAll() {
        db.delete(TABLE_NAME, null, null);
    }

提供了两个 SELECT ALL 方法:cursorSelectAll()listSelectAll(),前者返回一个游标,后者返回一个 Friend 对象 ArrayList。这些方法在从数据库加载信息时由 MainActivity 调用(参见 清单 14)。

清单 14. 运行返回 ArrayListSelect All
    /**
     * Select All returns a cursor
     * @return the cursor for the DB selection
     */
    public Cursor cursorSelectAll() {
        Cursor cursor = this.db.query(
                TABLE_NAME, // Table Name
                new String[] { "fid", "name" }, // Columns to return
                null,       // SQL WHERE
                null,       // Selection Args
                null,       // SQL GROUP BY 
                null,       // SQL HAVING
                "name");    // SQL ORDER BY
        return cursor;
    }

listSelectAll() 方法返回 ArrayList 容器中选定的行,该容器由 MainActivity 用来将它绑定到 MainScreen ListView(参见 清单 15)。

清单 15. 运行返回游标的 Select All
    /**
     * Select All that returns an ArrayList
     * @return the ArrayList for the DB selection
     */
    public ArrayList<Friend> listSelectAll() {
        ArrayList<Friend> list = new ArrayList<Friend>();
        Cursor cursor = this.db.query(TABLE_NAME, new String[] { "fid", "name" }, 
null, null, null, null, "name");
        if (cursor.moveToFirst()) {
            do {
                Friend f = new Friend();
                f.id = cursor.getString(0);
                f.name = cursor.getString(1);
                list.add(f);
            } while (cursor.moveToNext());
        }
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        return list;
    }

如果检测到数据库版本更改,就会调用 onUpgrade() 方法(参见 清单 16)。

清单 16. 检测数据库版本是否更改
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, 
       int oldVersion, int newVersion) {
        // Here add any steps needed due to version upgrade
        // for example, data format conversions, old tables 
        // no longer needed, etc
    }
}

整个 MainActivity 中,当您将信息导出到数据库、从数据库加载信息以及清理数据库时,都会使用 DBHelper。第一件事是在创建 MainActivity 时实例化 DBHelper。在 onCreate() 时执行的其他任务包括初始化不同的屏幕视图(参见 清单 17)。

清单 17. MainActivity onCreate() 初始化数据库
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    appContext = this;
    setContentView(R.layout.main);
    dbHelper = new DBHelper(this);
    listView = (ListView) findViewById(R.id.friendsview);
    friendsArrayAdapter = new FriendsArrayAdapter(
       this, R.layout.rowlayout, friends);
    listView.setAdapter(friendsArrayAdapter);
    :
    :
}

清单 18 展示了如何从资产加载好友列表以及如何将之解析并插入数据库中。

清单 18. MainActivity 插入到数据库中
String fname = prefsGetFilename();
if (fname != null && fname.length() > 0) {
    buffer = getAsset(fname);
    // Parse the JSON file
    String friendslist = new String(buffer);
    final JSONObject json = new JSONObject(friendslist);
    JSONArray d = json.getJSONArray("data");
    int l = d.length();
    for (int i2=0; i2<l; i2++) {
        JSONObject o = d.getJSONObject(i2);
        String n = o.getString("name");
        String id = o.getString("id");
        dbHelper.insert(id, n);
    }
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            friendsArrayAdapter.notifyDataSetChanged();
        }
    });         
}

清单 19 展示了如何执行 SELECT ALL 以及如何将数据绑定到主屏幕 ListView

清单 19. MainActivitySelect All 和将数据绑定到 ListView
final ArrayList<Friend> dbFriends = dbHelper.listSelectAll();
if (dbFriends != null) {
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            friendsArrayAdapter = 
            new FriendsArrayAdapter(
                MainActivity.this, R.layout.rowlayout, dbFriends);
            listView.setAdapter(friendsArrayAdapter);
            friendsArrayAdapter.notifyDataSetChanged();
        }
    });
}

接下来,了解一下在示例应用程序中使用 Internal Storage API。


为私有数据使用设备的内部存储器

有了数据存储 API,您可以使用内部存储器存储数据。信息可以是私有的,您可以有选择地让其他应用程序对之具有读或写的访问权限。本节介绍这个存储私有数据的 API,它使用 android.content.Context.openFileInputopenFileOutputgetCacheDir() 来高速缓存数据,而不是永久地存储。

清单 20 中的代码片段展示了如何从内部私有存储器读取数据。使得存储器为私有的方法是对 openFileOutput() 使用 MODE_PRIVATE

清单 20. 从本地私有存储器读取数据
/**
 * Writes content to internal storage making the content private to 
 * the application. The method can be easily changed to take the MODE 
 * as argument and let the caller dictate the visibility: 
 * MODE_PRIVATE, MODE_WORLD_WRITEABLE, MODE_WORLD_READABLE, etc.
 * 
 * @param filename - the name of the file to create
 * @param content - the content to write
 */
public void writeInternalStoragePrivate(
        String filename, byte[] content) {
    try {
        //MODE_PRIVATE creates/replaces a file and makes 
        //  it private to your application. Other modes:
        //    MODE_WORLD_WRITEABLE
        //    MODE_WORLD_READABLE
        //    MODE_APPEND
        FileOutputStream fos = 
           openFileOutput(filename, Context.MODE_PRIVATE);
        fos.write(content);
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

清单 21 中的代码片段展示了如何从内部私有存储器读取数据;注意 openFileInput() 的使用。

清单 21. 从内部私有存储器读取数据
/**
 * Reads a file from internal storage
 * @param filename the file to read from
 * @return the file content
 */
public byte[] readInternalStoragePrivate(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    try {
        FileInputStream fis = openFileInput(filename);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int nrb = fis.read(buffer, 0, len); // read up to len bytes
        while (nrb != -1) {
            baos.write(buffer, 0, nrb);
            nrb = fis.read(buffer, 0, len);
        }
        buffer = baos.toByteArray();
        fis.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return buffer;
}

清单 22 展示了如何从内部私有存储器删除数据。

清单 22. 从本地私有存储器删除数据
/**
 * Delete internal private file 
 * @param filename - the filename to delete
 */
public void deleteInternalStoragePrivate(String filename) {
    File file = getFileStreamPath(filename);
    if (file != null) {
        file.delete();
    }
}

现在可以来看为公共数据使用外部存储器了。


为公共数据使用设备的外部存储器

有了数据存储 API,您可以使用外部存储器存储数据。信息可以是私有的,您可以有选择地让其他应用程序对之具有读或写的访问权限。本节您将对此 API 进行编程,以便使用包括 getExternalStorageState()getExternalFilesDir()getExternalStorageDirectory()getExternalStoragePublicDirectory() 在内的很多 API 来存储公共数据。您为公共数据使用下面的路径:/Android/data/<package_name>/files/

在使用外部存储器之前,必须看看它是否可用,是否可写。下面两个代码片段展示了测试这些条件的帮助器方法。清单 23 测试外部存储器是否可用。

清单 23. 测试外部存储器是否可用
/**
 * Helper Method to Test if external Storage is Available
 */
public boolean isExternalStorageAvailable() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        state = true;
    }
    return state;
}

清单 24 测试外部存储器是否只可读。

清单 24. 测试外部存储器是否只可读
/**
 * Helper Method to Test if external Storage is read only
 */
public boolean isExternalStorageReadOnly() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        state = true;
    }
    return state;
}

清单 25 展示了如何写到外部存储器,以存储公共数据。

清单 25. 写到外部内存
/**
 * Write to external public directory
 * @param filename - the filename to write to
 * @param content - the content to write 
 */
public void writeToExternalStoragePublic(String filename, byte[] content) {

    // API Level 7 or lower, use getExternalStorageDirectory() 
    //  to open a File that represents the root of the external 
    // storage, but writing to root is not recommended, and instead 
    // application should write to application-specific directory, as shown below.

    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (isExternalStorageAvailable() && 
       !isExternalStorageReadOnly()) {
        try {
            File file = new File(path, filename);
            file.mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(content);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

清单 26 展示了如何从外部存储器读取数据。

清单 26. 从外部内存读取数据
/**
 * Reads a file from internal storage
 * @param filename - the filename to read from
 * @return the file contents
 */
public byte[] readExternallStoragePublic(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (!isExternalStorageReadOnly()) {     
        try {
            File file = new File(path, filename);            
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int nrb = fis.read(buffer, 0, len); //read up to len bytes
            while (nrb != -1) {
                baos.write(buffer, 0, nrb);
                nrb = fis.read(buffer, 0, len);
            }
            buffer = baos.toByteArray();
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return buffer;
}

清单 27 中的代码片段展示了如何从外部内存删除文件。

清单 27. 从外部内存删除文件
/**
 * Delete external public file 
 * @param filename - the filename to write to
 */
void deleteExternalStoragePublicFile(String filename) {
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/"+filename;
    File file = new File(path, filename);
    if (file != null) {
        file.delete();
    }
}

处理外部存储器需要特殊的权限 WRITE_EXTERNAL_STORAGE,它通过 AndroidManifest.xml 请求得到(参见 清单 28)。

清单 28. WRITE_EXTERNAL_STORAGE
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

外部存储 API 通过根据文件类型(比如 Pictures、Ringtones)将文件存储在预先确定的目录中,允许您公共地存储文件。本文没有介绍这种方法,但是您应该熟悉它。此外,记住外部存储器中的文件任何时候都可能消失。


相关的方法

如果您具有不需要长期永久保存的临时文件,那么可以将这些文件存储在高速缓存中。高速缓存是一种特殊的内存,可以用于存储中小型数据(少于兆字节),但是您一定要知道,取决于有多少内存可用,高速缓存的内容任何时候都可能被清除。

清单 29 展示了一个帮助器方法,它返回到内部内存中高速缓存的路径。

清单 29. 检索到内部内存高速缓存的路径
/**
 * Helper method to retrieve the absolute path to the application 
 * specific internal cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getInternalCacheDirectory() {
    String cacheDirPath = null;
    File cacheDir = getCacheDir();
    if (cacheDir != null) {
        cacheDirPath = cacheDir.getPath();
    }
    return cacheDirPath;        
}

清单 30 展示了一个帮助器方法,它返回到外部内存中高速缓存的路径。

清单 30. 检索到外部内存高速缓存的路径
/**
 * Helper method to retrieve the absolute path to the application 
 * specific external cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getExternalCacheDirectory() {
    String extCacheDirPath = null;
    File cacheDir = getExternalCacheDir();
    if (cacheDir != null) {
        extCacheDirPath = cacheDir.getPath();
    }
    return extCacheDirPath;     
}

通过使用示例应用程序,您现在应该很好地理解了如何为公共数据使用设备的外部存储器。


结束语

本文介绍了几个 Android 存储 API,从首选项到使用 SQLite 和内部及外部内存。利用首选项 API,您可以让自己的应用程序收集和存储简单的首选项信息。使用 SQLite API,您可以存储更复杂的数据,利用内部和外部存储器,您可以存储对应用程序是私有的或者对其他应用程序公共可用的文件。跨多个会话持久存储的已存储数据让您的应用程序甚至在与网络断开连接时仍然能够工作。您现在应该掌握了在开发 Android 应用程序时利用所有这些类型的存储器。


下载

描述名字大小
本文源代码android.storage.source.zip38KB

参考资料

学习

获得产品和技术

  • Facebook Android SDK(当前是 Alpha 版本):利用这个库将 Facebook 集成到您的 Android 移动应用程序中。
  • Facebook Platform:扩展您在 Facebook 和 web 上构建社会应用程序的能力。
  • Facebook Old Rest API(Graph API 的前一版本):通过简单的 HTTP 请求以编程方式与 Facebook 网站交互。
  • Facebook Graph API(当前版本):深入研究这个核心的 Facebook Platform API。
  • OAuth 2.0 Protocol 规范(2010 年 7 月):处理 OAuth 身份认证,受 Facebook Platform 支持。
  • Android SDK:从官方 Android 开发人员网站下载 SDK、访问 API 参考资料以及获得关于 Android 的最新新闻。版本 1.5 及更新版本可以工作。
  • Android Open Source Project:找到构建 Android 兼容的设备所需的开源信息和源代码。
  • JDK 6 Update 21:获得 Java Platform, Standard Edition。
  • Eclipse:获得最新的 Eclipse IDE。
  • IBM 产品评估试用版软件:下载或 在线试用 IBM SOA Sandbox,并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source
ArticleID=605158
ArticleTitle=理解 Android 本地数据存储 API
publish-date=12272010