Android提供了以下5种存储数据的方式:
【1】Shared Preferences:以key-value的形式保存一些基本数据类型的数据。
【2】Internal Storage:内部存储一些应用私有数据到设备内存中。
【3】External Storage:存储一些公开数据到外部存储设备中,如SD卡等。
【4】SQLite Databases:存储一些结构化的数据到自己的私有数据库中。
【5】Network Connection:将数据保存到自己的服务器上。
另外,Android还提供了content provider来让你将自己应用的私有数据暴露给其它的应用。
一、Shared Preferences
SharedPreferences类提供了一些API方法帮忙我们存储基本数据类型数据,如booleans, floats, ints, longs, and strings。使用Shared Preferences方法存储数据,主要有四个步骤:
【1】通过调用getSharedPreferences()方法或getPreferences()方法获取SharedPreferences对象
【2】SharedPreferences对象的edit()方法获取SharedPreferences.Editor对象
【3】调用SharedPreferences.Editor对象的如putBoolean()等方法,存储数据。
【4】调用SharedPreferences.Editor对象的commit()方法提交数据。
其中关于获取SharedPreferences对象的两个方法间的区别如下:
getSharedPreferences():如果你需要使用到多个SharedPreferences文件,那么你可以通过该方法去获取SharedPreferences对象,这些对象通过name来加以标识。
getPreferences():如果你只需要对单个Activity使用SharedPreferences文件,那么你可以使用该方法去获取SharedPreferences对象,它返回的是一个以(当前Activity的完整类名 - 项目包路径)后的字符串作为name的SharedPreferences对象。
最后你可以通过使用SharedPreferences对象的如getBoolean()等方法获取到之前保存的数据。使用例子:
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();
}
}
二、Internal Storage
内部存储的数据对于其它应用和用户而言,是不可见的,它保存在当前应用的私有文件夹下。当用户卸载APP时,这些数据也会被删除。
2.1 创建并写入数据到内部存储
1.你可以通过openFileOutput()方法传入一个fileName和fileMode打开一个文件的输出流,这个方法返回一个FileOutputStream对象。
2.然后调用FileOutputStream对象的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会给你创建一个专属于你APP的文件(或者替代当前存在的同名的文件),其它还有诸如MODE_APPEND(在当前文件的内容后面增加内容),MODE_WORLD_READABLE(其它应用可用读取该文件)和MODE_WORLD_WRITEABLE(其它应用可以写数据到这个文件)三种可用的文件权限。
1.调用openFileInput()方法,并且传入一个文件名fileName,这个方法会返回一个FileInputStream对象。
2.使用FileInputStream对象的read()方法读取数据。
3.在读取完数据后,记得调用close()方法关闭流。
PS:如果你希望保存一些静态文件到APP中,那么可以将它们放置到res/raw/目录下,然后通过openRawResource()方法并传递一个R.raw.
上面的openFileInput()方法或openFileOutput()方法打开的是/data/data/appPackageName/files路径下的文件。
2.3 保存缓存文件
如果你希望保存一些不用持久保存的临时文件,你可以使用getCacheDir()方法打开/data/data/appPackageName/cache的File对象。当系统内存不足时,这个路径下的文件会首先被删除,你不应该依赖系统去帮你清除这些文件,你可以自己给这个文件设置一个合理的大小空间,比如1M。当用户卸载APP时,这个文件会被移除。
getFilesDir():返回/data/data/appPackageName/files路径下的文件
getDir():创建或打开一个存在的/data/data/appPackageName/files路径下的文件
deleteFile():删除/data/data/appPackageName/files路径下的文件
fileList():返回/data/data/appPackageName/files路径下的文件列表
三、External Storage
外部存储器(如SD卡)中的文件对于所有的应用都是可读的,而且用户还能删除这个文件,所以存储在外部存储器上的文件是没有安全保障的。
3.1 获取外部存储器权限
如果你希望对外部存储设备进行读写操作,你需要向系统申请对应的READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。如:
...
如果你需要读和写的权限,你仅仅需要申请 WRITE_EXTERNAL_STORAGE权限,因为它会隐式地调用读权限。
PS:从Android 4.4(API level 18)开始,当读取当前APP在外部存储设备上的私有文件时,可以不申请权限。
3.2 检查设备是否可用
在你对外部存储设备进行读写操作之前,你需要先调用getExternalStorageState()方法来检查外部存储设备的状态,外部设备可能正挂载在电脑上或找不到,只可读等其他状态。比如说,你可以使用下面两个方法去检查存储设备的状态:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
3.3 保存和其它APP共享的数据文件
有时候,我们创建的文件可能需要提供给其它的APP也能使用,这个时候我们应该将这个文件放置到一个公共的路径下面。为了实现这个功能,我们可以使用getExternalStoragePublicDirectory()方法,并且传递如DIRECTORY_MUSIC,DIRECTORY_PICTURES,DIRECTORY_RINGTONES等,这样其它APP在浏览这些文件路径的时候,就能轻易地获取到你创建的文件。比如使用下面的方法去获取你创建的图片文件夹:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
3.4 保存当前APP私有的数据文件
如果你希望在外部存储设备上将文件保存为当前APP的私有文件,你可以使用getExternalFilesDir()方法获取到SD卡上APP私有文件路径,如:/storage/emulated/0/Android/data/appPackageName/files。这个方法同样接收一个type类型,如DIRECTORY_MUSIC,DIRECTORY_PICTURES,DIRECTORY_RINGTONES等。如果你不需要这些文件类型,你也可以传递一个null来获取到App私有文件夹的根路径。
从Android4.4(API level = 18)开始,读写外部存储器的私有路径文件不再需要READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE权限,所以在声明这个读写外部设备的权限时,你可以加上maxSdkVersion属性。如下:
...
注意:当用户卸载我们的APP时,外部存储设备的APP私有文件也会被删除,同时,系统的媒体浏览器也不会去浏览我们APP私有文件夹。所以一些属于用户的文件需要保存到公共的文件夹下,比如通过你的APP拍摄的照片等。
有时候,一个将一部分内部存储划分为外部存储的设备有可能提供一个SD卡的插槽,这个时候,当你的APP运行在4.3或者4.3以下版本的时候,getExternalFilesDir()方法返回的File是内部存储作为外部存储的那个路径,你的APP不能对SD卡进行读写操作,从Android4.4起,你可以使用getExternalFilesDirs()来获取这两个存储区,它返回的是一个File数组。这个数组中的第一个值就是内部私有文件区,一般情况下,你需要将文件读写到这个目录下,除非它不可用或者存储空间满了。如果你希望在4.3及其以下版本使用这个两个路径,你需要使用支持包中的方法:ContextCompat.getExternalFilesDirs()。它同样返回一个File数组,不过在4.3及以下时,一般只有一个值。
注意:虽然getExternalFilesDir()和getExternalFilesDirs()获取的文件区对于系统的媒体MediaStore Content Provider不可见,但是其它APP只要声明了READ_EXTERNAL_STORAGE权限,它就能查看到外部存储设备中的所有内容,包括这个文件区的内容;所以,如果你希望完全限制其它APP对文件的访问,你需要将文件保存在内部存储设备中,即data/data/appPackageName/files中。
3.5 保存缓存文件
如果你希望保存缓存文件到外部设备上,你可以使用getExternalCacheDir()方法,这个方法返回的File对象,在APP卸载时,也会自动被删除。和ContextCompat.getExternalFilesDirs()相似,你也可以通过调用ContextCompat.getExternalCacheDirs()来获取两个外部设备的缓存区。
为了保留缓存区域的大小以及APP的性能,在缓存文件不需要用时,记得将其删除。
四、SQLite Databases
Android完全支持SQLite数据库,你可以在你应用的任何地方通过数据库名称获取到这个数据库对象,而在其它的APP中则不能访问。
切记在Android中创建数据库的方法其实就创建一个SQLiteOpenHelper的子类,并且重写其onCreate()方法,在这个方法中,你可以通过执行SQL语句来创建数据库红的表。如下:
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类提供了一系列的操作数据库的方法。
五、Network Connection
使用
java.net.*
两个包中的相关类,将数据保存在web服务器上。