szs 发表于 2016-12-2 06:43:39

理解 Android 本地数据存储 API 利用首选项、SQLite 和内部及外部内存 API

  http://www.ibm.com/developerworks/cn/xml/x-androidstorage/


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

  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)。


使用 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 voidprefsSetAutoDelete(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();
}

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();
}
});         
}
MainActivity Select 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();
}
});
}   
 从本地私有存储器读取数据   

/**
* 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();
}
}
 从内部私有存储器读取数据


/**
* 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;
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;
}

从本地私有存储器删除数据

/**
* 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 测试外部存储器是否可用。


测试外部存储器是否可用   

/**
* 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;
}

 测试外部存储器是否只可读

/**
* 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;
}
 写到外部内存

/**
* 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();
}
}
}
 从外部内存读取数据

/**
* 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;
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;
}
外部内存删除文件

/**
* 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 请求得到


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


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


检索到内部内存高速缓存的路径

/**
* 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;      
}
检索到外部内存高速缓存的路径

/**
* 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;   
}
页: [1]
查看完整版本: 理解 Android 本地数据存储 API 利用首选项、SQLite 和内部及外部内存 API