Android的多种数据存储方法
扫描二维码
随时随地手机看文章
Android为你提供了若干选项用于存储应用程序数据。选择何种方案时情况而定。比如,数据仅为你的应用所使用,或是可是为其他应用(以及用户)所共享。又比如,你的数据需要多少空间。
数据存储有以下几个选择:
Data_Storage#.E4.BD.BF.E7.94.A8.E5.85.B1.E4.BA.AB.E7.9A.84.E9.85.8D.E7.BD.AE_-_Using_Shared_Preferences|Shared Preferences|公共配置-Shared Preferences
通过键值对的方式存储私有的原始数据。
Data_Storage#.E4.BD.BF.E7.94.A8.E5.86.85.E9.83.A8.E5.AD.98.E5.82.A8_-_Using_the_Internal_Storage|Internal Storage|内部存储-Internal Storage
在存储器上存储私有的数据。
Data_Storage#.E4.BD.BF.E7.94.A8.E5.86.85.E9.83.A8.E5.AD.98.E5.82.A8_-_Using_the_Internal_Storage|External Storage | 外部存储 - External Storage
在外部存储器上存储公开的数据。
Data_Storage#.E4.BD.BF.E7.94.A8.E6.95.B0.E6.8D.AE.E5.BA.93_-_Using_Databases|SQLite Database | SQLite数据库 - SQLite Database
在私有的数据库中存储结构化的数据。
Data_Storage#.E4.BD.BF.E7.94.A8.E7.BD.91.E7.BB.9C.E8.BF.9E.E6.8E.A5_-_Using_a_Network_Connection|Network Connection | 网络连接 - Network Connection
使用你的网络服务器存储数据。
Android提供了暴露私有数据给其他应用的方法——使用一个内容提供器(content provider)。内容提供器是一个可选的组件,为你的应用程序数据提供读/写权限,并受制于你给定的限制。关于使用内容提供器的更多细节,请查看Content Providers的文档。
使用共享的配置 - Using Shared Preferences
SharedPreferences类提供了一个通用的框架,用于保存和检索以持久化的键值对形式存储的原始数据类型。你可以使用SharedPreferences保存任意类型的原始数据:布尔(boolean),浮点,(float),整型(int),长整型(long)和字符串(string)。这些数据将会存放在用户会话中(即使你的应用程序已经退出)。
* 用户配置*
共享的配置并非一定要保存"用户配置",例如用户选择和哪个铃声。如果你有兴趣为你的应用创建用户配置,请参考PreferenceActivity。它提供了一个Activity的框架,可以用来创建持久化的用户配置(使用共享的配置)。
在应用程序中取得SharedPreferences对象,使用以下两种方法之一:
* int) getSharedPreferences() getPreferences()](http://developer.android.com/reference/android/content/Context.html#getSharedPreferencesjava.lang.String,)( - 当你仅需要一个配置文件。由于这是你的Activity的唯一一个配置文件,所以不必提供名称。
向SharedPreferences写入值的步骤:
1、调用edit(),取得一个SharedPreferences.Editor。
2、使用形如boolean) putBoolean() putString()](http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#putStringjava.lang.String,)这样的方法添加值。(
3、使用commit()提交新值。
从SharedPreferences读取值,使用它的方法,例如boolean) getBoolean() getString()](http://developer.android.com/reference/android/content/SharedPreferences.html#getStringjava.lang.String,)即可。(
这是一个例子,在一个计算器中使用无声的按键保存一个配置:
class extends { static String PREFS_NAME ; protected (){ .onCreate); . // Restore preferences "color:#660">(PREFS_NAME0boolean silent settings(, ); setSilent); @Override void onStopsuper(); // All objects are from android.context.Context "color:#660">(PREFS_NAME0SharedPreferencesEditor editor settings(); editor(, mSilentMode// Commit the edits! editor(); }
使用内部存储 - Using the Internal Storage
你可以直接将文件保存在设备上的内部存储中。缺省情况下,存放于内部存储的文件为你的应用程序所私有,其他应用程序不能够访问它们(其他用户亦然)。当用户卸载你的应用,这些文件也被删除。
在内部存储中创建并写入一个私有文件:
1、调用openFileOutput(),传入文件名和操作模式。方法返回一个FileOutputStream对象。
2、使用write()写文件。
3、使用close()关闭文件流。
例如:
"color:#080">"hello_file"String "color:#080">"hello world!"FileOutputStream fos openFileOutput, .MODE_PRIVATE.writestring());fos();
MODE_PRIVATE创建文件(或以同名文件替换),并为你的应用所私有。其他可用的模式有:MODE_APPEND, MODE_WORLD_READABLE, 和MODE_WORLD_WRITEABLE。
从内部存储中读一个文件:
1、调用openFileInput(),并传递需要读取的文件的名称。这个方法返回一个FileInputStream。
2、使用read()从文件中读取数据。
3、使用close()关闭文件流。
提示:如果你想在编译时往你的应用中存入一个静态文件,就得把文件保存到项目的res/raw目录下。你可以调用openRawResource()并传递资源的ID(R.raw.)来打开它。这个方法返回一个InputStream,你可以使用它读取文件,但不能够写入这个原始文件。
保存缓存文件
如果你想要缓存一些数据,而不是保存它们,你应该调用getCacheDir()打开一个File对象,它表示你的应用应当保存临时缓存文件的内部目录。
其他有用的方法
getFilesDir() 取得内部文件在文件系统中保存位置的绝对路径。
getDir() 创建(或者打开已存在的)内部存储空间所在的目录。
deleteFile() 删除内部存储的一个文件。
fileList() 返回当前由你的应用保存的文件的列表。
使用外部存储 - Using the External Storage
所有兼容Android的设备都支持一个可共享的“外部存储(external storage)”,可用来保存文件。这可以使一个可移动的存储设备(比如SD卡)或者一个内部的(不可移动的)存储。保存在外部存储的文件是可读的。并且当用于传输数据的USB大容量存储选项启用时,用户能够在计算机上修改它们。
注意:* 如果用户挂载外部存储到计算机上,或者移除媒体,外部文件将会消失不见。并且对于这些保存在外部存储的文件,没有强制的安全措施。所有的应用都可以读/写这些文件。用户也能够删除它们。
检测媒体可用性
在你对外部存储做任何事情之前,你总是应当调用getExternalStorageState()以检测媒体是否可用。媒体可能被计算机挂载,可能丢失,可能只读,或者处于某些其他状态。比如,这是示例代码:
"color:#008">falseboolean mExternalStorageWriteable ;"color:#606">Environment();(.MEDIA_MOUNTED(state{ "color:#660">"color:#008">true} if Environment.equals)) // We can only read the media mExternalStorageAvailable ; mExternalStorageWriteable ;else // Something else is wrong. It may be one of many other states, but all we need "color:#660">"color:#008">false}
这个例子检测了外部存储是否可读或可写。getExternalStorageState()方法返回你想要检测的其他状态。比如,媒体是否被共享(已连接到一台计算机),是否完全丢失,是否被移除等等。当你的应用需要访问媒体时,你可以依据这些以更详细的信息通知用户。
访问位于外部存储的文件
如果你正在使用API Level 8或者更高版本,使用getExternalFilesDir()打开一个文件对象,它表示你的应用应当保存文件所在的外部存储目录。这个方法需要一个类型参数,指定你需要的子目录类型,比如DIRECTORY_MUSIC或者DIRECTORY_RINGTONES(传递null表示你的应用程序的目录所在的根目录)。如有必要,这个方法将会创建一个目录。通过指定目录的类型,你确信Android的媒体扫描器会将系统中的文件正确分类(例如,铃声将被归类为铃声而不是音乐)。如果用户卸载了你的应用,这个目录以及它的内容将会被删除。
如果你正在使用API Level 7或者更低版本,使用getExternalStorageDirectory()打开一个文件对象,它表示外部存储的根目录。接下来,你应当写入你的数据在一下目录:
/Android/data//files/
"com.example.android.app"。如果用户的设备正在运行API Level 8或者更高版本,且用户卸载了你的应用,这个目录和它的内容将会被删除。
保存应当共享的文件
在媒体扫描器下隐藏你的文件
在你的外部文件目录中放置包括一个空的文件,命名为.nomedia(注意文件名前缀的点)。这会阻止Android的媒体扫描器读取你的媒体文件,并并在类似Gallery或者Music这样的应用中包括它们。
如果你想要保存与你的应用没有关联的文件,并且这些文件不应在应用卸载时被删除,把他们保存在外部存储的一个公共目录上即可。这些目录位于外部存储的根目录下,比如Music/, Pictures/, Ringtones/,以及其它目录。
在API Level 8或者更高版本,调用getExternalStoragePublicDirectory(),传递你需要的公共目录的类型,比如DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES或者其它。如有必要,这个方法会创建新目录。
如果你正在使用API Level 7或者更低版本,调用getExternalStorageDirectory()打开一个File,它表示外部存储的根目录。接着保存你的共享文件在以下文件夹之一:
Music/ - 媒体扫描器把所有在此发现的媒体归类为用户的音乐。
Podcasts/ - 媒体扫描器把所有在此发现的媒体归类为播客。
Ringtones/ - 媒体扫描器把所有在此发现的媒体归类为铃声。
Alarms/ - 媒体扫描器把所有在此发现的媒体归类为闹铃。
Notifications/ - 媒体扫描器把所有在此发现的媒体归类为提示音。
Pictures/ - 所有照片(相机拍摄的除外)。
Movies/ - 所有影片(摄像机拍摄的除外)。
Download/ - 各类下载。
保存缓存文件
如果你正在使用API Level 8或者更高版本,调用getExternalCacheDir()打开一个File,它表示你的应用应当保存文件所在的外部存储目录。如果用户卸载了你的应用,这些文件会被自动删除。然而,在你的应用的生命周期中,你应当管理这些缓存文件以及删除其中过期的部分以保证文件空间。
如果你正在使用API Level 7或者更低版本,使用getExternalStorageDirectory()打开一个File,它表示外部存储的根目录。接下来,你应当写入你的数据在一下目录:
/Android/data//files/
"com.example.android.app"。
使用数据库 - Using Databases
Android提供了对SQLite数据库的完整支持。你创建的任何数据库都能被应用程序中的任意类通过数据库名访问。但是不能够在应用程序以外访问。
推荐的创建新的SQLite数据库的方法是,在你执行SQLite命令在数据库中创建表的时候,创建一个SQLiteOpenHelper的子类,并重写onCreate()方法。例如:
class extends { static int DATABASE_VERSION ; static String DICTIONARY_TABLE_NAME ; static String DICTIONARY_TABLE_CREATE + DICTIONARY_TABLE_NAME " (" + + KEY_DEFINITION " TEXT);"DictionaryOpenHelperContext context{ (context, , DATABASE_VERSION} public () .execSQL); }
接着,你可以使用构造方法取得你实现的SQLiteOpenHelper的一个实例。分别使用getWritableDatabase()和getReadableDatabase()读写数据库。两者都会返回一个SQLiteDatabase对象,代表那个数据库,并提供操作SQLite的方法。
Android没有在标准SQLite概念之外加以任何限制。我们建议包含一个自增值的主键字段,能够作为一个唯一的ID,以便快速定位一条记录。这对私有数据来说不是必须的。但如果你实现了一个content provider,就必须包含一个唯一的ID,它使用BaseColumns._ID常量。
你可以使用SQLiteDatabase.query()方法执行SQLite查询,这个方法接受各种查询参数,例如待查询的表、投影、选择、列、组,或者其他。对于复杂查询,比如一些需要用到列的别名的,你应当使用SQLiteQueryBuilder,它能提供一些合适的方法以创建查询。
每一个SQLite查询都会返回一个Cursor对象,指向查询得到的所有行。Cursor对象总是你用来取得数据库查询或者读取行或列的结果的途径。
关于示例应用中演示如何在Android中使用SQLite数据库,见Node Pad和Searchable Dictionary这两个应用。
数据库调试
Android SDK包含了一个sqlite3的数据库工具,允许你浏览表内容,运行SQL命令,以及执行其他SQLite数据库中有用的功能。想要了解如何运行这个工具,请查看Examining sqlite3 databases from a remote shell这个例子。
使用网络连接 - Using a Network Connection
你可以使用网络连接(当可用时)通过基于web的服务存储或取得数据。需要执行网络操作时,使用以下包中的类:
java.net.*
android.net.*