Android 为你提供了几种保存持久应用程序数据方式。你所选择的方法取决于你的特定需求,例如数据是否是你的应用程序私有的或者允许其他程序(和用户)访问,和你的数据需要多大的存储空间。
你的数据存储方式如下:
Shared Preference
以键值对的形式存储简单私有的数据。
Internal Storage
在设备的内存中存储私有数据。
External Storage
在共享的外部存储上存储共有的数据。
SQLite Storage
在私有数据中存储结构化数据。
Network Connection
在自己的网络服务器的web上存储数据。
Android为你提供了一种向其他的程序暴露你私有数据的方式---使用content provider。content provider是一个可选的组件,它暴露你的程序数据的读写权限,不受任何限制。关于更多使用content providerde的信息,请阅读Content Providers文档。
——————————————————————————————————————————————————————————————————
Android 为你提供了几种保存持久应用程序数据方式。你所选择的方法取决于你的特定需求,例如数据是否是你的应用程序私有的或者允许其他程序(和用户)访问,和你的数据需要多大的存储空间。
你的数据存储方式如下:
Shared Preference
以键值对的形式存储简单私有的数据。
Internal Storage
在设备的内存中存储私有数据。
External Storage
在共享的外部存储上存储共有的数据。
SQLite Storage
在私有数据中存储结构化数据。
Network Connection
在自己的网络服务器的web上存储数据。
Android为你提供了一种向其他的程序暴露你私有数据的方式---使用content provider。content provider是一个可选的组件,它暴露你的程序数据的读写权限,不受任何限制。关于更多使用content providerde的信息,请阅读Content Providers文档。
———————————————————————————————————————————————————————————————————
SharedPreferences类提供了一个通用的框架,它允许你保存和获取原始数据类型的持久化键值对。你可以使用SharedPreferences去保存任何原始数据:booleans,floats,ints,longs,和strings。这些数据将会跨越用户会话保存(即使你的程序被杀死)。
你的程序为了获取SharedPreferences对象,使用以下两个方法中的任意一个:
getSharedPreferences() - 如果你需要多个preferences文件的时候就使用它。你使用第一个参数指定它们的名字来加以区分。
getPreferences() - 如果你仅仅需要一个preference文件的时候使用它,该文件与你的Activity关联。因为这种方法仅仅有一个与你Activity关联的preference文件,你不需要提供名字。
写数据:
1.调用edit()获取SharedPreferences.Editor对象。
2.使用例如putBoolean()和putString()等方法添加值。
3.使用commit()方法提交新的值。
读数据,使用例如getBoolean()和getString()等SharedPreferences的方法。
用户偏好:Shared preferences不仅仅保存“用户偏好”,例如用户选择了什么手机铃声。如果你对为你的应用程序创建用户偏好感兴趣,查阅PreferenceActivity,它为你提供了一个Activity框架,来创建用户偏好,它将会自动存储(使用Shared preferences)。
以下是一个实例,它在计算器中保存一个silent keypress模式的共享参数:
public class Calc extends Activity { public static final String PREFS_NAME = "MyPrefsFile"; @Override protected void onCreate(Bundle state){ super.onCreate(state); . . . // Restore preferences SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); boolean silent = settings.getBoolean("silentMode", false); setSilent(silent); } @Override protected void onStop(){ super.onStop(); // We need an Editor object to make preference changes. // All objects are from android.context.Context SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean("silentMode", mSilentMode); // Commit the edits! editor.commit(); } }使用内部存储器
———————————————————————————————————————————————————————————————————
你可以将文件直接保存在设备的内部存储器中。默认情况下,保存在内部存储器中的文件是你的程序私有的,并且其他的程序无法访问(用户也一样)。当用户卸载你的程序的时候,文件也被移除。
向内部存储器创建和写一个私有文件:
1.传入文件名称和操作模式参数调用openFileOutput()方法,返回一个FileOutputStream对象。
2.调用write()方法写文件。
3.调用close()方法关闭文件流。
例如:
String FILENAME = "hello_file"; String string = "hello world!"; FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close();MODE_PRIVATE创建一个新的文件(或替换一个同名的文件),它是你的程序私有的。其它可用的模式有:MODE_APPEND,MODE_WORLD_READABLE,和MODE_WORLD_WRITEABLE。
从内部存储器中读取文件:
1. 传递需要读取的文件名称为参数调用openFileInput()。然会一个FileInputStream对象。
2.调用read()方法从文件中读取字节。
3.调用close()方法关闭文件流。
提示:如果你想在程序编译的时候保存一个静态的文件,将它保存在你的项目res/raw/ 目录下。你能调用openRawResource()方法打开它,传入资源IDR.raw.<filename>为参数。这个方法返回一个InputStream对象,它可以使你能够读取文件[一般为音频、视频等文件、Html、APK文件等](但是你不能写这个文件)。
保存缓存
如果你想缓存一些数据,而不是持久化存储,你可以调用getCacheDir()方法打开一个File对象,它代表了你的应用程序存储临时缓存文件的内部路径。当设备在内存空间稀缺的时候,Android可能会删除这个缓存文件去回收存储空间。然而,你不能依靠系统去为你清除这个文件。你应该常常自己维护这个文件,并且保持在一个合理的大小限制以内,例如1MB。当用户卸载应用程序的时候,这个文件被移除。
getFileDir():获取你的内部文件存储的文件系统目录的绝对路径。
getDir():在你的内部存储空间创建(或者打开一个已存在)的目录。
deleteFile():删除一个存储在内部空间的文件。
fileList():返回你的应用程序当前存储文件的数组。
——————————————————————————————————————————————————————————————————
每个兼容Android的设备都支持一个共享“外部存储”,你能使用它来保存文件。它可以是一个可移除的存储媒介(例如一个SD卡)或者一个内在的(不可移除)存储。当它们从USB大量存储传输到电脑中的时候,存储在外部存储的文件都是任何人可读的,并且可以被用户修改。
一台设备使用部分内部存储用于外部存储是可能的,也会提供一个SD卡槽。如果这样,SD卡不是外部存储的一部分,并且你的应用部不能访问它(系统无法检测)(外部存储被定义仅仅为用户提供的系统扫描到的媒介)。
当心:如果用户在一台电脑挂载或者移除媒介,外部存储会变得不不可用,并且你存储在外部存储的文件没有安全保障。所有的程序都能读写在外部存储上的文件,并且用户可以删除它。
在你使用外部存储做任何工作之前,你必须调用getExternalStorageState()去检查这个媒介是否可用。这么媒介可能被挂载在一台电脑,丢失,只读,或者在别的某种状态。例如,以下是你如何检查可用性的案例:
boolean mExternalStorageAvailable = false; boolean mExternalStorageWriteable = false; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // We can read and write the media mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // We can only read the media mExternalStorageAvailable = true; mExternalStorageWriteable = false; } else { // Something else is wrong. It may be one of many other states, but all we need // to know is we can neither read nor write mExternalStorageAvailable = mExternalStorageWriteable = false; }这个案例是检查外部存储是否可以读写。getExternalStroageState()方法返回一个你检测到的状态,例如媒介是否共享(连接到一台电脑),完全丢失(已经移除)等。当你的应用程序需要访问这个媒介的时候,你可以使用这些信息通知用户。
如果你使用API Level 8以及以上的版本,使用getExternalFilesDir()去打开一个File对象,它代表了你存储你的文件的外部存储的路径。这个方法使用一个类型参数,它指定了你想操作的子目录的类型,例如DIRECTORY_MUSIC和DIRECTORY_RINGTONES(传递Null,则返回你的应用程序的文件目录的根)。如果有必要,这个方法将创建一个合适的路径。通过指定目录的类型,你确保了Android的媒体扫描器在系统中能正确的将你的文件分类(例如,铃声被定义为铃声而不是音乐)。如果用户卸载你的应用程序,该目录和所有的内容将被删除。
如果你使用API Level 7或者更低的版本,使用getExternalStorageDirectory(),去打开一个File对象,它代表了外部存储的根目录。那么你将要把你的数据写在如下目录中:
/android/data/<package_name>/files/
<package_name>是你的java包名,例如”com.example.android.app”。如果这个设备正在运行的是API Level 8以及以上的版本,那么他们卸载你的应用程序的时候,这个目录以及所有的内容都将被删除(API Level 8之前不会被删除?)。
如果你想保存文件,他们不仅仅特定于你的程序,并且当你的程序被卸载时不被删除,将它们保存在外部存储上的一个公共目录中。这些目录在放在外部存储的根,例如Music/,Pictures/,Ringtones/,和其他。
如果你使用API Level7或更低的版本,使用getExternalStorageDirectory()方法获取一个File对象,它代表了外部存储的根,然后将你的共享文件存储在以下的目录之一:
Music/ -媒体扫描器将所有从这里找到的文件视为音乐
Podcasts/ -媒体扫描器将所有从这里找到文件视为播客
Ringtones/ -媒体扫描器将所有从这里找到文件视为铃声
Alarms/ -媒体扫描器将所有从这里找到文件视为警告
Notifications/ -媒体扫描器将所有从这里的找到的文件视为通知铃声
Pictures/ -所有的照片(包括照相机拍摄的)
Movies/ -所有的电影(包括录像机录制的)
Download/ -其它的下载
对媒体扫描器隐藏你的文件
在你的外部文件目录中包含一个被命名为.nomedia的空文件(注意在文件名中的点)。这将阻止Android的媒体扫描器读取你的媒体文件,和在如Gallery或者Music的应用中包含它们。
如果你使用API Level 8或者更高的版本,使用getExternalCacheDir()打开一个File对象,它代表了你保存缓存文件的外部存储的路径。如果用户卸载你的应用程序,这些文件将会被自动删除。然而,在你的程序的生命周期,你应该管理这些缓存文件,并且为了维护文件空间,在它们不需要的时候删除它们。
如果你使用API Level 7或者更低的版本,使用getExternalStroageDirectory()代开一个File对象,它代表了外部存储的根目录,然后你在这个目录里面写你的缓存数据:
/Android/data/<package_name>/cache/
<package_name>是你的包名,如”com.example.android.app”。
——————————————————————————————————————————————————————————————————
Android为SQLite数据库提供了完美的支持。任何你创建的数据库都能被你程序中所有类通过名字访问,但是不包括其他程序的类。
创建一个SQLite数据库的推荐方法是创建一个SQLiteOpenHelper的子类,并且重写onCreate()方法,你可以再这个方法里执行一条SQLite命令去创建一个数据库中的一个表。
例如:
public class DictionaryOpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 2; private static final String DICTIONARY_TABLE_NAME = "dictionary"; private static final String DICTIONARY_TABLE_CREATE = "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" + KEY_WORD + " TEXT, " + KEY_DEFINITION + " TEXT);"; DictionaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DICTIONARY_TABLE_CREATE); } }然后,你使用你定义的构造方法获取一个你的SQLiteOpenHelper实例。分别 调用getWritableDatabase()和getReadableDatabase()方法去从数据库中进行读和写操作 。 它们都返回一个SQLiteDatabase对象,它代表数据库并且提供了操作数据库的方法。
你可以使用SQLiteDatabase的query()方法执行数据库的查询操作,它接受各种各样的查询参数,例如表查询,选择查询,行查询,组查询和其他。对于更复杂的查询,例如需要列别名的查询,你需要使用SQLiteQueryBuilder,它提供了几个方便查询的方法。
所有的SQLite查询都返回一个Cursor,它查询到的所有的行。Cursor是一种操纵机制,它负责操作你从数据库查询的结果,如读取行和列。
查看Note Pad和Searchable Dictionary示例程序,它们演示了在Android中如实使用SQLite数据库。
Android SDK提供了包括sqlite3数据库工具,它使你能够浏览表的内容,运行SQL命令,和运行在SQLite数据中其它重要的功能。查看Examining sqlite3 data frome shell去学习如何使用这个工具。
———————————————————————————————————————————————————————————————————
你可以使用网络(当它可用的时候)在自己的web服务器上存储和获取数据。执行网络操作,使用下面包中的类:
java.net.*;
android.net.*