每 个兼容Android的设备都支持一个共享的"外部存储器",你可以用它来储存文件。这可以是可被移除的存储媒介(例如一个SD卡)或是一个内部存储器 (不可被移除)。储存在外部存储器中的文件都是world-readable属性并且可以被用户修改(当他们允许USB大储存器在电脑上转移文件时)。
警告 :里面的这些外部文件是会消失不可见的——如果用户把外部存储器挂在到一台电脑上或移除该媒介(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; }
这个例子检测外部存储器是否可用于读和写。你可能希望检测getExternalStorageState() 函数返回的其他状态,例如媒介是否被共享了(连接到了电脑)、是否完全遗失了、被意外移除了等等。当你的应用需要访问媒介的时候,你可以使用这些(携带更多的信息)来提示用户。
访问外部存储器上的文件 (Accessing files on external storage)
如果你使用的是API Level 8或更高版本,使用getExternalFilesDir() 函数来打开一个代表外部存储器目录(你最终储存文件的地方)的File 对象。该函数使用一个type 参数来指定你希望的子目录的类型,例如 DIRECTORY_MUSIC 和 DIRECTORY_RINGTONES (传null 值,会返回你应用文件目录的根目录)。该函数会在需要时创建合适的目录。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函数来打开一个代表外部存储器根目录的File 对象。然后,你应该将你的数据写入到以下的目录:
/Android/data/<package_name> /files/
<package_name> 是你的Java风格的包名,比如"com.example.android.app "。如果用户的设备正在运行的是API Level 8或更高的版本,那么在你的应用被卸载后,该目录及其中的所有内容都将被删除掉。
保存可被共享的文件 (Saving files that should be shared)
如果你希望保存的文件并不特定于你的应用并且不会在应用卸载时被删除,请将他们保存到外部存储器上的一个公有目录。这些目录放置在外部存储器的根目录下,比如 Music/ , Pictures/
, Ringtones/
及其他。
在API Level 8或更高版本中,使用 getExternalStoragePublicDirectory() 函数,传给它一个你希望的公有目录类型,比如 DIRECTORY_MUSIC , DIRECTORY_PICTURES
, DIRECTORY_RINGTONES
或其他。该函数将在必要的时候创建合适的目录。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函数来打开一个代表外部存储器根目录的File 对象。然后,储存你的共享文件到以下目录中的一个里面:
Music/
- Media scanner classifies all media found here as user music.Podcasts/
- Media scanner classifies all media found here as a podcast.Ringtones/
- Media scanner classifies all media found here as a ringtone.Alarms/
- Media scanner classifies all media found here as an alarm sound.Notifications/
- Media scanner classifies all media found here as a notification sound.Pictures/
- All photos (excluding those taken with the camera).Movies/
- All movies (excluding those taken with the camcorder).Download/
- Miscellaneous downloads.如果你使用的是API Level 8或更高的版本,使用getExternalCacheDir() 函数来打开一个代表外部存储器中你将储存缓存文件的目录的File 对象。如果用户卸载你的应用,这些文件将会被自动删除。无论如何,在你应用的生命中,你应该管理这些缓存文件并在不再需要的时候移除它们以便保存文件空间。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函数来打开一个代表外部存储器根目录的File 对象,然后将你的缓存数据写入到下面的目录:
/Android/data/<package_name> /cache/
<package_name> 是你的Java风格的包名,比如"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 对象,并为SQLite的操作提供了函数。
Android没有在标准的SQLite概念上添加任何限制。我们推荐包含一个自动增量数值键字段来被用于作为一个唯一的ID,以便快速找到一个记录。这不需要是一个私有数据,但如果你实现了一个 content provider ,你就必须使用BaseColumns._ID 常量来包含一个唯一的ID。
你可以使用SQLiteDatabase 的query() 函数来执行SQLite的查询,query() 函数支持各种查询参数,例如查询表时就有projection, selection, columns, grouping等参数可配置。对于复杂的查询,例如那些需要列别名的,你应该使用SQLiteQueryBuilder ,它提供了多个便捷的函数可用于构建查询。
每个SQLite查询都会返回一个Cursor 对象,它指向查询所找到的所有的行。Cursor 永远是你操纵数据库查询结果及读取行和列的途径。
Android SDK包含了一个数据库工具来允许你浏览表格的内容,在SQLite数据库上运行SQL命令,并执行其他有用的方法。查阅Examining sqlite3 databases from a remote shell 学习如何运行该工具。
你可以在你自己的基于网络的服务器上使用网络(当它可用的时候)来储存和接收数据。要执行网络操作,使用下面的包中的类:
android.net.* java.net.*