Android提供了多种存储持久数据的途径,具体使用哪种存储方法,要根据需求而定,比如数据是程序私有的还是可以和其他程序共享,还要考虑的是数据占用多少存储空间。
数据存储的五种方法如下:
1、 Shared Preferences
使用键值对存储私有的简单数据。
2、 Internal Storage
在设备内部存储器中存储私有数据
3、 External Storage
在外部存储器上存储公共数据
4、 SQLite Database
利用数据库存储结构化数据
5、 Netwok Connection
通过网络服务器存储数据
下面逐一讲解。
Shared Preferences |
SharedPreferences类允许存储和获取由基本数据类型组成的键值对,这些基本数据类型包括:boolean, float, int, long, string.只要程序没有被卸载,这些数据将一直存在,哪怕程序进程被杀死,数据依旧存在。
有两种方法获取一个SharedPreferences对象:
●getSharedPreferences()–这个方法允许定义多个属性文件,只需要给这些属性文件设定不同的名字(第一个参数)即可。
●getPreferences() –如果你的程序中只需要一个属性文件,那么可以选择这个方法。由于只有唯一的属性文件,因此不需给属性文件命名。
设置一个属性,可以参考如下模板:
SharedPreferences sp =getSharedPreferences("PREF_NAME", 0);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("silentMode", mSilentMode);
etidtor.putInt("times", mTimes);
editor.commit();
第一行:创建一个名为PREF_NAME的属性文件,并设定为默认模式(第二个参数0)。
publicabstract SharedPreferences getSharedPreferences (String name,int mode)
第一个参数即你为属性文件取的名字,第二参数是操作模式。0或MODE_PRIVATE表示默认操作,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE则可以控制对属性文件的操作权限。
第二行:创建SharedPreferences的编辑器。
第三、四行:通过编辑器向属性文件中加入具体的属性---即键值对。键值对的数据类型包括boolean, float, int, long, string五种。依次为:
abstract SharedPreferences . Editor putBoolean ( String key , boolean value )abstract SharedPreferences . Editor putFloat ( String key , float value )
abstract SharedPreferences . Editor putInt ( String key , int value )
abstract SharedPreferences . Editor putLong ( String key , long value )
abstract SharedPreferences . Editor putString ( String key , String value )
第五行:添加或修改数据后一定要commit()或apply()后才能生效。二者的区别在于,commit直接将数据写回存储器,而apply则只是修改内存中的数据。
取SharedPreferences中存储的值时,参考如下代码:
SharedPreferences sp = getSharedPreferences ( "PREF_NAME" , 0 );boolean silent = sp . getBoolean ( "silentMode" , false );
int times = sp.getInt( "silentMode" , 0);
很好理解,唯一需要解释的是get…()方法中的第二个参数,就拿第三行来说,要从名为PREF_NAME的属性文件中取出键’silentMode’所对应的整数值,如果’silentMode’不存在,则以第二个参数作为默认值返回。
下面我们做一个简单的例子(源文件下载),通过SharedPreferences记录程序使用的次数。新建工程SharedPreferencesDemo,布局文件mail.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/txt1"/>
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/txt2"/>
</LinearLayout>
在string.xml中,txt1和txt2定义如下:
<string name="txt1">This is your </string>
<string name="txt2">time using this app!</string>
在主程序中,首先声明相关变量和常量:
TextView tv;
private static final String PREF_NAME = "mPref";
private static final String VISIT_TIMES = "visitTimes";
在onCreate方法中,加入以下代码:
tv = (TextView)findViewById(R.id.tv1);
SharedPreferences sp = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
int times = sp.getInt(VISIT_TIMES, 0);
SharedPreferences.Editor editor = sp.edit();
editor.putInt(VISIT_TIMES, ++times);
editor.commit();
tv.setText(Integer.toString(times));
在模拟器中第一次运行时,结果如下:
重新启动该程序,结果如下:
此程序实现了简单计数,同样,我们可以通过SharedPreferences来记录其他比较简洁的数据。在大多数程序中,都会涉及到”设置”这样的选项,比如屏幕亮度,默认主题等,这时候,SharedPreferences就是存储这些简单数据的首选。
有关SharedPreferences的讲解就到这里,请看下一篇Internal Storage的使用。
小知识点,即其他程序想使用本应用程序的配置,那应该如何使用SharedPreferences呢?如下:
Context otherAppContext = createPackageContext("com.changcheng.sharedpreferences", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = otherAppContext.getSharedPreferences("preferences", Context.MODE_WORLD_READABLE);
注意,为了使其他程序可以访问本应用程序的配置。那么在我们使用 getSharedPreferences创建配置的时候必须为它的文件访问模式设置为允许其他程序读取或写入等。
内部存储,就是将文件保存在设备内部存储器中。默认情况下,这些文件是相应程序私有的,对其他程序不透明,对用户也是不透明的。当程序卸载后,这些文件就会被删除。 要在内部存储器中创建并保存数据文件,可以按照以下步骤来做: 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 (); openFileOutput()方法的第二个参数可能的值包括:MODE_PRIVATE, MODE_APPEND, MODE_WORLD_READABLE,MODE_WORLD_WRITEABLE. 欲从内部存储器中读取数据: 1、 调用openFileInput()方法,参数为即将读取的文件名,该方法返回一个FileInputStream. 2、 调用read()方法读取字节. 3、 调用close()方法关闭输入流。 代码段如下: String FILENAME = "hello_file" ;FileInputStream fis = openFileInput ( FILENAME ); byte [] input = new byte [ fis . available ()]; while ( fis . read ( input ) != - 1 ){} String str = new String ( input ); fis . close (); 下面我们一起来做个演示InternalStorageDemo.(由于百度空间字数限制,无法将代码贴上来,具体请下载源文件查看) 效果截图: |
所有Android设备都支持可以保存文件的共享外部存储器,这个外部存储器可以是可移动存储器(如SD卡),也可以是内置在设备中的外部存储器(不可移动)。外部存储器上的文件时全部可读的,当设备通过USB连接电脑和电脑互传文件时,外部存储器上的文件不可修改。 当外部存储器被挂载到电脑上或被移除,文件对android设备就不可见了,且此时外部存储器上的文件是没有安全保障的。所有程序都可以读写外部存储器上的文件,用户也可以删除这些文件。 检查存储器的可用性 对存储器进行任何操作之前,为了防止存储设备因挂载到电脑、丢失、只可读或其他原因造成无法使用,必须调用getExternalStorageState() 方法来检查存储设备是否可用。下面的代码演示了如何检查其可用性(可读可写): booleanmExternalStorageAvailable = false;booleanmExternalStorageWriteable = false; Stringstate = 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; } 如果你是用API Level 8或更高的版本,调用getExternalFilesDir()来打开外部存储器中你想用来保存文件的目录。这个方法需要一个指定子目录类型的参数,如DIRECTORY_MUSIC和DIRECTORY_RINGTONES.如果相应的目录不存在,该方法将在必要时创建所需的目录。通过指定目录的类型,可以保证android媒体扫描器可以方便的给系统中的文件归类(如,铃声文件归为铃声而不是音乐)。程序被卸载后,相应目录及里面的内容都会被删除。 如果是用API Level 7或者更老的版本,就需要调用getExternalStorageDirectory()来获取外部存储器的根目录。向外部存储器写入数据时的目录如下: /Android/data/<package_name>/files/如果希望外部存储器上的文件不是只对指定的程序有用,并且不会因为卸载程序而被删除,就应该把这些文件保存在外部存储器的公共目录下,这些目录在外部存储器的根目录下,如Music/, Pictures/, Ringtones/等。 API Level 8及更高版本中,调用getExternalStoragePublicDirectory(),如前面所述,传递一个目录的类型参数,该方法就会创建相应的目录。类型参数可以为: DIRECTORY_MUSIC, DIRECTORY_PODCASTS,DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS,DIRECTORY_PICTURES,DIRECTORY_MOVIES,IRECTORY_DOWNLOADS, or DIRECTORY_DCIM. API Level 7及较低版本中,调用getExternalStorageDirectory()来获取外部存储器的跟目录,然后就可以把文件保存在以下相应的文件夹中: · Music/ - Media scanner classifies all media found here as user music. · Podcasts/ - Media scanner classifies all media found here asa podcast. · Ringtones/ - Media scanner classifies all media found here as aringtone. · Alarms/ - Media scanner classifies all media found here asan alarm sound. · Notifications/ - Media scanner classifies all media found here asa notification sound. · Pictures/ - All photos (excluding those taken with the camera). · Movies/ - All movies (excluding those taken with thecamcorder). · Download/ - Miscellaneous downloads. 有关getExternalStoragePublicDirectory(String type)和getExternalStorageDirectory()的使用,下面给出官方文档上的例子。 publicstatic File getExternalStoragePublicDirectory (String type)
void createExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory. Note that you should be careful about // what you place here, since the user often manages these files. For // pictures and other media owned by the application, consider // Context.getExternalMediaDir(). File path =Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); try { // Make sure the Pictures directory exists. path.mkdirs(); // Very simple code to copy a picture from the application's // resource into the external file. Note that this code does // no error checking, and assumes the picture is small (does not // try to copy it in chunks). Note that if external storage is // not currently mounted this will silently fail. InputStream is = getResources().openRawResource(R.drawable.balloons); OutputStream os = new FileOutputStream(file); byte[] data = new byte[is.available()]; is.read(data); os.write(data); is.close(); os.close(); // Tell the media scanner about the new file so that it is // immediately available to the user. MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, newMediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Log.i("ExternalStorage", "Scanned " + path +":"); Log.i("ExternalStorage", "-> uri=" + uri); } }); }catch (IOException e) { // Unable to create file, likely because external storage is // not currently mounted. Log.w("ExternalStorage", "Error writing " + file,e); } }
void deleteExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory and delete the file. If external // storage is not currently mounted this will fail. File path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); file.delete(); }
boolean hasExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory and check if the file exists. If // external storage is not currently mounted this will think the // picture doesn't exist. File path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); return file.exists(); }
publicstatic File getExternalStorageDirectory ()
|