Android数据存储五种方式总结

399 阅读11分钟

Android平台进行数据存储的五大方式

适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等
核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:
             Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
             Context.MODE_WORLD_READABLE:  指定该SharedPreferences数据能被其他应用程序读,但不能写。
             Context.MODE_WORLD_WRITEABLE:  指定该SharedPreferences数据能被其他应用程序读,写

Editor有如下主要重要方法:

              SharedPreferences.Editor clear():清空SharedPreferences里所有数据
              SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据
              SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项
               boolean commit(): 当Editor编辑完成后,使用该方法提交修改

代码如下:

       private String print() {
     StringBuffer buff = new StringBuffer();
	BufferedReader reader= null;
	try {
		reader = new BufferedReader(new InputStreamReader(new FileInputStream(PATH)));
		String str;
		while ((str = reader.readLine()) != null) {
			buff.append(str + "/n");
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
	 Log.d("1111111", buff.toString());
	return buff.toString();
}

2.Android本身的数据库(SQLite数据库)

SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧 SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用

     1 db.executeSQL(String sql);  
     2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 

除了统一的形式之外,他们还有各自的操作方法:

      1 db.insert(String table, String nullColumnHack, ContentValues values);  
     2 db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
     3 db.delete(String table, String whereClause, String whereArgs);

以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样

3.ContentProvider存储

Android这个系统和其他的操作系统还不太一样,我们需要记住的是,数据在Android当中是私有的,当然这些数据包括文件数据

和数据库数据 以及一些其他类型的数据。那这个时候有读者就会提出问题,难道两个程序之间就没有办法对于数据进行交换?

Android这么优秀的系统不会让这种情况发生 的。解决这个问题主要靠ContentProvider。一个Content

Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content

Provider的各种数据类型。也就是说,一个程序可以通过实现一个Content

Provider的抽象接口将自己的数据暴露出去。外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是

用数据库存储还是用文件 存储,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和程序里

的数据打交道,可以读取程序的数据,也可以删除程序的数 据,当然,中间也会涉及一些权限的问题。

一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据

库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取

数据的操作基 本一样,只不过是采用URI来表示外界需要访问的“数据库”。

Content Provider提供了一种多应用间数据共享的方式,比如:联系人信息可以被多个应用程序访问。

Content Provider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。 应用程序可以在Content

Provider中执行如下操作: 查询数据 修改数据 添加数据 删除数据

标准的Content Provider: Android提供了一些已经在系统中实现的标准Content

Provider,比如联系人信息,图片库等等,你可以用这些Content Provider来访问设备上存储的联系人信息,图片等等。

查询记录:

在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete,

modify等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”,

代表数据的路径,和一个可选的标识数据的ID。

以下是一些示例URI:

content://media/internal/images 这个URI将返回设备上存储的所有图片

content://contacts/people/ 这个URI将返回设备上的所有联系人信息

content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)

尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下

),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,参见下例:

MediaStore.Images.Media.INTERNAL_CONTENT_URI Contacts.People.CONTENT_URI

因此,如上面content://contacts/people/45这个URI就可以写成如下形式:

Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);

然后执行数据查询: Cursor cur = managedQuery(person, null, null, null);

这个查询返回一个包含所有数据字段的游标,我们可以通过迭代这个游标来获取所有的数据:

   package com.wissen.testApp; 
     public class ContentProviderDemo extends Activity { 
     @Override 
     public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
   displayRecords(); 
} 

private void displayRecords() { 
    //该数组中包含了所有要返回的字段 
 String columns[] = new String[] { People.NAME, People.NUMBER }; 
   Uri mContacts = People.CONTENT_URI; 
   Cursor cur = managedQuery( 
       mContacts, 
      columns,  // 要返回的数据字段 
   null,          // WHERE子句 
   null,         // WHERE 子句的参数 
   null         // Order-by子句 
 ); 
   if (cur.moveToFirst()) { 
       String name = null; 
       String phoneNo = null; 
       do { 
          // 获取字段的值 
     name = cur.getString(cur.getColumnIndex(People.NAME)); 
         phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER)); 
         Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show(); 
      } while (cur.moveToNext()); 
   } 
} 

}

修改记录: 我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:

      private void updateRecord(int recNo, String name) { 
      Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo); 
     ContentValues values = new ContentValues(); 
     values.put(People.NAME, name); 
     getContentResolver().update(uri, values, null, null); 

}

添加记录:

要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。 上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:

        private void insertRecords(String name, String phoneNo) { 
       ContentValues values = new ContentValues(); 
       values.put(People.NAME, name); 
      Uri uri = getContentResolver().insert(People.CONTENT_URI, values); 
      Log.d(”ANDROID”, uri.toString()); 
     Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); 
     values.clear(); 
     values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE); 
     values.put(People.NUMBER, phoneNo); 
     getContentResolver().insert(numberUri, values); 
        }

删除记录: Content Provider中的getContextResolver.delete()方法可以用来删除记录。

        private void deleteRecords() {  

      Uri uri = People.CONTENT_URI;  

        getContentResolver().delete(uri, null, null);  

   }

创建Content Provider: 至此我们已经知道如何使用Content Provider了,现在让我们来看下如何自己创建一个Content Provider。 要创建我们自己的Content Provider的话,我们需要遵循以下几步:

1.创建一个继承了ContentProvider父类的类

2.定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如: public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);

3.创建你的数据存储系统。大多数ContentProvider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。

4.定义你要返回给客户端的数据列名。如果你正在使用Android数据库,则数据列的使用方式就和你以往所熟悉的其他数据库一样。但是,你必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。

5.如果你要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存文件的URI字符串,客户端通过它来读取对应的文件数据,处理这种 数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而 且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该 URI指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。

6.声明public static String型的变量,用于指定要从游标处返回的数据列。

7.查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。

8.在AndroidMenifest.xml中使用标签来设置Content Provider。

9.如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。

4.网络存储数据

我们可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。 具体需要熟悉java.net.*,Android.net.*这两个包的内容,在这就不赘述了,请大家参阅相关文档。 下面是一个通过地区名称查询该地区的天气预报,以POST发送的方式发送请求到webservicex.net站点,访问WebService.webservicex.net站点上提供查询天气预报的服务。

     package com.android.weather;  

      import java.util.ArrayList; 
      import java.util.List; 

       import org.apache.http.HttpResponse; 
        import org.apache.http.NameValuePair; 
      import org.apache.http.client.entity.UrlEncodedFormEntity; 
      import org.apache.http.client.methods.HttpPost; 
       import org.apache.http.impl.client.DefaultHttpClient; 
      import org.apache.http.message.BasicNameValuePair; 
       import org.apache.http.protocol.HTTP; 
        import org.apache.http.util.EntityUtils; 

      import android.app.Activity; 
     import android.os.Bundle; 

        public class MyAndroidWeatherActivity extends Activity { 
         //定义需要获取的内容来源地址 
        private static final String SERVER_URL =  
    "http://www.webservicex.net/WeatherForecast.asmx/GetWeatherByPlaceName";  

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    HttpPost request = new HttpPost(SERVER_URL); //根据内容来源地址创建一个Http请求 
    // 添加一个变量  
    List<NameValuePair> params = new ArrayList<NameValuePair>();  
    // 设置一个地区名称 
    params.add(new BasicNameValuePair("PlaceName", "NewYork"));  //添加必须的参数 

    try {  
        //设置参数的编码 
        request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));  
        //发送请求并获取反馈 
        HttpResponse httpResponse = new DefaultHttpClient().execute(request); 

        // 解析返回的内容 
        if(httpResponse.getStatusLine().getStatusCode() != 404){  
           String result = EntityUtils.toString(httpResponse.getEntity());  
           System.out.println(result); 
        } 
    } catch (Exception e) { 
        e.printStackTrace(); 
   }  
}
```

5.文件存储数据

分为内部储存和外部存储。内部存储是应用程序使用Android为自己分配的内存空间,数据存储到“/data/data/程序包名/files”路径下的相应文件中。外部存储是使用手机sdcard的内存(

这个sdcard并不是我们经常说的那个可以拆卸替换的SD卡,那个SD卡我们称之为扩展卡),使用这部分内存要声明相应的权限。

1.assets(只读、不能修改或删除)

代码如下:

           try {

            //创建流

             InputStream in = this.getAssets().open(“文件名.扩展名”);
            //读出数据
               Bitmap bm=BitmapFactory.decodeStream(in);
              in.close();
            in=null;
             } catch (IOException e) {
            // TODO Auto-generated catch block
              e.printStackTrace();
         }
            2.读写数据(读写手机自身内存)
           位置:data/data/主包名/files目录下的 也可以使用context.getFilesDir().getAbsolutePath()获得内存根路径
 存:
       try {
        OutputStream os=this.openFileOutput(“文件名”, MODE_PRIVATE);
          os.write(“wa”.getBytes());
           os.close();
           } catch (FileNotFoundException e) {
         e.printStackTrace();
          } catch (IOException e) {
         e.printStackTrace();
      }
         取:
         try {
        InputStream in=this.openFileInput(“文件名”);
           //缓冲区
        byte b[]=new byte[1024];
       //创建缓存
          ByteArrayBuffer ba=new ByteArrayBuffer(0);
         int l;
            //读
            while((l=in.read(b))>-1)
          {
         ba.append(b,0,l);
         }
          //转化
           String s=new String(ba.toByteArray());
          } catch (FileNotFoundException e) {
       e.printStackTrace();
         } catch (IOException e) {
        e.printStackTrace();
         }