Android中5种数据存储方式

Android中5种数据存储方式 

1 概述

  SharedPreferences存储数据。 



 ContentProvider存储 


 文件存储 


 SQLlite存储 


 网络存储 PreferenceFile DataBase这三种方式分别对应的目录是: 


 /data/data/Package Name/Shared_Pref 


 /data/data/Package Name/files 


 /data/data/Package Name/database 


关于这五种数据存储方式根据实际情况选择最合适的秉持最简单原则也就是说能用简单的


方式处理就不要用复杂的方式。比如存储几个数据或简单对象用SharedPreference也能做到


就没必要写个ContentProvider。 


 简单数据和配置信息SharedPreference是首选 


 如果SharedPreferences不够用那么就创建一个数据库 


 结构化数据一定要创建数据库虽然这稍显烦锁但是好处无穷 


 文件就是用来存储文件(也即非配置信息或结构化数据)如文本文件二进制文件PC文件


多媒体文件下载的文件等等 


 尽量不要创建文件 


 如果创建文件如果是私密文件或是重要文件就存储在内部存储否则放到外部存储。 2 SharedPreferences存储数据 SharedPreferences 可以将数据保存到应用程序的私有存储区这些存储区中的数据只能被写入


这些数据的软件读取。 


它的本质是基于XML文件存储key-value键值对数据通常用来存储一些简单的配置信息。 


其存储位置在  /data/data/<包名>/shared_prefs  目录下。 


使用SharedPreferences是有些限制的只能在同一个包内使用不能在不同的包之间使用。 


例如登录用户的用户名与密码。 


步骤如下 


1 使用Activity类的getSharedPreference 方法获得SharePreferences对象。其中存储


key-value 的文件名称由getSharedPreferences方法的第一个参数指定第二个参数表示所创建的


数据文件的访问权限“MODE_WORLD_READABLE”表示其他用户有“读”的权限


“MODE_WORLD_WRITEABLE ” 表示其他用户有 “写”权限MODE_PRIVATE 和


MODE_APPEND创建的文件对其他用户都是不可访问的 


2使用SharedPreferences 接口的edit 获得SharedPreferences.Editor对象 


3 通过Sharedreferences.Editor接口的putXxx方法保存key-value对。其中Xxx表示value


不同数据类型。例如Boolean类型的value需要用putBoolean方法字符串类型的value需要用


putString方法 


4通过Sharedreferences.Editor接口的commit方法保存key-value对。commit方法相当


于数据库事务中的提交(commit)操作只有在事务结束后进行提交才会将数据真正保存在数据库中。


保存key-value也是一样在使用putXxx方法指定了key-value对后必须调用commit方法才能


将key-value对真正保存在相应的文件中。  


运行该程序并在相应的组建输入值然后退出应用程序再次进入程序系统会将上次输入的


数据显示在相应组件中。 


*由于应用程序在退出时会将组件的值保存在文件中因此需要将保存的Key-value对的代码写在


Activity类的onStop方法中。 


  


private final String PREFERENCES_NAME = "bjh"; 


 


public void onStop() { 


  // 第1步获得SharedPreferences对象 


  SharedPreferences mySharedPreferences = getSharedPreferences( 


    PREFERENCES_NAME, Activity.MODE_PRIVATE); 


  // (第2步) 获得SharedPreferences.Editor对象 


  SharedPreferences.Editor editor = mySharedPreferences.edit(); 


  // (第3步) 保存组件中的值 


  editor.putString("name", myName.getText().toString()); 


  editor.putString("habit", myHabit.getText().toString()); 


  editor.putBoolean("employee", myEmployee.isChecked()); 


  editor.putInt("companyTypeId", myCompanyTypeId.getCheckedRadioButtonId()); 


  editor.commit(); 


  super.onStop(); 


 } 


  


 从bjh.xml中获得数据  


SharedPreferences sharedPreferences = getSharedPreferences( 


    PREFERENCES_NAME, Activity.MODE_PRIVATE); 


  // 使用getXxx方法获得value,getXxx方法的第2个参数是value的默认值 


  myName.setText(sharedPreferences.getString("name", "")); 


  myHabit.setText(sharedPreferences.getString("habit", "")); 


  myEmployee.setChecked(sharedPreferences.getBoolean("employee", false)); 


     myCompanyTypeId.check(sharedPreferences.getInt("companyTypeId", -1));     3 ContentProvider存储 3.1 用途  ContentProvider可以解决两个程序之间数据进行交换问题 


 ContentProvider提供了一种多应用间数据共享的方式比如联系人信息可以被多个应用


程序访问 


 ContentProvider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。 应用程


序可以在ContentProvider中执行如下操作: 查询、修改、添加、删除 


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


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


信息图片等等。 3.2 好处 当应用继承ContentProvider类并重写该类用于提供数据和存储数据的方法就可以向其他应


用共享其数据。虽然使用其他方法也可以对外共享数据但数据访问方式会因数据存储的方式而不同


如采用文件方式对外共享数据需要进行文件操作读写数据采用sharedpreferences共享数据


需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据


访问方式。 


Android 这个系统和其他的操作系统还不太一样我们需要记住的是数据在Android当中是私


有的当然这些数据包括文件数据和数据库数据以及一些其他类型的数据。要想解决两个程序之间数


据交换问题主要靠ContentProvider。一个ContentProvider类实现了一组标准的方法接口从而能


够让其他的应用保存或读取此ContentProvider的各种数据类型。也就是说一个程序可以通过实现


一个ContentProvider的抽象接口将自己的数据暴露出去。外界根本看不到也不用看到这个应用暴


露的数据在应用当中是如何存储的或者是用数据库存储还是用文件存储还是通过网上获得这些


一切都不重要重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道可以读取程序的数据也可以删除程序的数据当然中间也会涉及一些权限的问题。一个程序可以通过实现


ContentProvider的抽象接口将自己的数据完全暴露出去而且ContentProviders是以类似数据库


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


据也就应该与从数据库中获取数据的操作基本一样只不过是采用 URI来表示外界需要访问的“数


据库”。 


ContentResolver通过ContentProvider来获取其他与应用程序共享的数据。其中


ContentProvider 负责 


 组织应用程序的数据 


 向其他应用程序提供数据 


 ContentResolver则负责 


 获取ContentProvider提供的数据 


 修改/添加/删除更新数据等 3.3 例如 3.3.1 依次读取联系人信息表中的指定数据列name和number   


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()); 


   } 


  } 


 } 


  


3.3.2 使用ContentResolver.update()方法来修改数据 


使用下面的方法可以更新指定记录 updateRecord(10, ”XYZ”); //更改第10条记录的name


字段值为“XYZ”    


  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); 


  } 


  


3.3.3 添加记录    


  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); 


  } 


  


3.3.4 删除记录    


  private void deleteRecords() { 


   Uri uri = People.CONTENT_URI; 


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


  } 


 


    


  4 文件存储 默认位置/data/data/<包>/files/***.***。 


openFileOutput 和 openFileInput 方法于 SharedPreferences 在某些方面非常类似。 4.1 使用 getSharedPreference 方法获得 SharePreferences 对象     


SharedPreferences mySharedPreferences  


   = getSharedPreferences(PREFERENCES_NAME,Activity.MODE_PRIVATE);  


  4.2 使用openFileOutput 方法返回一个OutputStream对象 OutputStream os = openFileOutput(“file.txt”,Activity.MODE_PRIVATE); 


 4.3 使用openFileInput方法获得 InputStream对象 InputStream is=openFileInput(“file.txt”); 


openFileOutput() 方法的第一参数用于指定文件名称不能包含路径分隔符“/” 如果文件不


存在Android 会自动创建它。 


创建的文件保存在 /data/data/<package name>/files目录如 


/data/data/cn.itcast.action/files/itcast.txt 通过点击Eclipse菜单“Window”-“Show View”-“Other”在对话窗口中展开android文件夹选择下面的File Explorer视图然后在File 


Explorer视图中展开/data/data/<package name>/files目录就可以看到该文件。 


openFileOutput()方法的第二参数用于指定操作模式有四种模式分别为 


 Context.MODE_PRIVATE = 0 


 Context.MODE_APPEND = 32768 


 Context.MODE_WORLD_READABLE = 1 


 Context.MODE_WORLD_WRITEABLE = 2 Context.MODE_PRIVATE为默认操作模式代表该文件是私有数据只能被应用本身访问


在该模式下写入的内容会覆盖原文件的内容如果想把新写入的内容追加到原文件中。可以使用


Context.MODE_APPEND Context.MODE_APPEND模式会检查文件是否存在存在就往文件追加内容否则就创建


新文件。 Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用


来控制其他应用是否有权限读写该文件。 MODE_WORLD_READABLE表示当前文件可以被其他应用读取 MODE_WORLD_WRITEABLE表示当前文件可以被其他应用写入。 


如果希望文件被其他应用读和写可以传入 openFileOutput(“itcast.txt”, 


Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);  android有一套自己的安全模型当应用程序(.apk)在安装时系统就会分配给他一个userid当


该应用要去访问其他资源比如文件的时候就需要userid匹配。默认情况下任何应用创建的文件


sharedpreferences数据库都应该是私有的位于/data/data /<package name>/files其他程


序无法访问。 


除非在创建时指定了Context.MODE_WORLD_READABLE或者


Context.MODE_WORLD_WRITEABLE 只有这样其他程序才能正确访问。 


Activity 还提供了getCacheDir() 和 getFilesDir() 方法  


 getCacheDir()方法用于获取/data/data/<package name>/cache目录 


 getFilesDir()方法用于获取/data/data/<package name>/files目录 4.4 向文件写入内容    


   


FileOutputStream outStream = this.openFileOutput( 


    "a.txt", Context.MODE_WORLD_READABLE); 


  outStream.write(text.getText().toString().getBytes()); 


  outStream.close(); 


  4.5 读取文件中的数据    


  FileInputStream inStream = this.openFileInput("a.txt"); 


  ByteArrayOutputStream stream = new ByteArrayOutputStream(); 


  byte[] buffer = new byte[1024]; 


  int length = -1; 


  while ((length = inStream.read(buffer)) != -1) { 


   stream.write(buffer, 0, length); 


  } 


  stream.close(); 


  inStream.close();   text.setText(stream.toString()); 


 


   4.6 把文件存入SDCard *注意访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限。 


使用Activity的openFileOutput() 方法保存文件文件是存放在手机空间上一般手机的存储


空间不是很大存放些小文件还行如果要存放像视频这样的大文件是不可行的。对于像视频这样


的大文件我们可以把它存放在SDCard。 


在AndroidManifest.xml中加入访问SDCard的权限如下:  


<!– 在SDCard中创建与删除文件权限 –> 


<uses-permission android:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS”/> 


<!– 往SDCard写入数据权限 –> 


<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/> 


 要往SDCard存放文件程序必须先判断手机是否装有SDCard并且可以进行读写。  


  if (Environment.getExternalStorageState().equals( 


    Environment.MEDIA_MOUNTED)) { 


   // 获取SDCard目录 


   File sdCardDir = Environment.getExternalStorageDirectory(); 


   File saveFile = new File(sdCardDir, "a.txt"); 


   FileOutputStream outStream = new FileOutputStream(saveFile); 


   outStream.write("test".getBytes()); 


   outStream.close(); 


  }   5  SQLite数据库存储数据 SQLite是轻量级嵌入式数据库引擎它支持 SQL 语言 并且只利用很少的内存就有很好的性能。 


数据库存储在 data/<项目文件夹>/databases/ 下。 5.1 派生自 SQLiteOpenHelper  Android 提供了 SQLiteOpenHelper 帮助你创建一个数据库你只要继承 


SQLiteOpenHelper 类就可以轻松的创建数据库。 


SQLiteOpenHelper 的子类至少需要实现三个方法 


 构造函数调用父类 SQLiteOpenHelper 的构造函数。这个方法需要四个参数上下文环


境例如一个 Activity数据库名字一个可选的游标工厂通常是 Null一个代表


你正在使用的数据库模型版本的整数。 


 onCreate方法它需要一个 SQLiteDatabase 对象作为参数根据需要对这个对象填


充表和初始化数据。 


 onUpgrage() 方法它需要三个参数一个 SQLiteDatabase 对象一个旧的版本号和一


个新的版本号这样你就可以清楚如何把一个数据库从旧的模型转变到新的模型。 


 5.2 数据库操作 5.2.1 onOpen() 每次成功打开数据库后首先被执行。 


创建表、插入数据、删除表等等。 调用 getReadableDatabase() 或 getWriteableDatabase() 


方法你可以得到 SQLiteDatabase 实例具体调用那个方法取决于你是否需要改变数据库的内容 db = (new DatabaseHelper(getContext())).getWritableDatabase(); 


上面这段代码会返回一个 SQLiteDatabase 类的实例使用这个对象你就可以查询或者修改数


据库。 当你完成了对数据库的操作例如你的 Activity 已经关闭需要调用 SQLiteDatabase 的 


Close() 方法来释放掉数据库连接。 创建表和索引 为了创建表和索引需要调用 SQLiteDatabase 


的 execSQL() 方法来执行 DDL 语句。如果没有异常这个方法没有返回值。 5.2.2 执行SQL语句 创建表   db.execSQL("CREATE TABLE mytable " + 


    "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " + 


    "title TEXT, value REAL);"); 


插入数据   db.execSQL("INSERT INTO widgets (name, inventory)"  


    + "VALUES ('Sprocket', 5)"); 


另一种方法可以使用 SQLiteDatabase 对象的 insert(), update(), delete() 方法。这些方法把 


SQL 语句的一部分作为参数。 5.2.3 insert()  


  ContentValues cv = new ContentValues(); 


  cv.put(Constants.TITLE, "example title"); 


  cv.put(Constants.VALUE, SensorManager.GRAVITY_DEATH_STAR_I); 


  db.insert("mytable", getNullColumnHack(), cv); 


  5.2.4 update update 方法有四个参数分别是表名列名和值的 ContentValues 对象可选的 WHERE 


条件和可选的填充 WHERE 语句的字符串这些字符串会替换 WHERE 条件中的“”标记。 


update() 根据条件更新指定列的值所以用 execSQL() 方法可以达到同样的目的。 WHERE 


条件和其参数和用过的其他 SQL APIs 类似。  


  String[] parms = new String[] { "this is a string" }; 


  db.update("widgets", replacements, "name=?", parms); 


 5.2.5 delete() delete() 方法的使用和 update() 类似使用表名可选的 WHERE 条件和相应的填充 WHERE 


条件的字符串。 查询数据库 类似 INSERT, UPDATE, DELETE。 5.2.6 检索数据 有两种方法使用 SELECT 从 SQLite 数据库检索数据。 


5.2.6.1 rawQuery() 


使用 rawQuery() 直接调用 SELECT 语句 使用 query() 方法构建一个查询。 


Raw Queries 正如 API 名字rawQuery() 是最简单的解决方法。通过这个方法你就可以调用 


SQL SELECT 语句。    


  Cursor c = db.rawQuery("SELECT name " + 


    "FROM sqlite_master " +     "WHERE type=’table’ " + 


    "AND name='mytable'", null); 


   在上面例子中我们查询 SQLite 系统表sqlite_master检查 table 表是否存在。返回值是一个 cursor 对象这个对象的方法可以迭代查询结果。 如果查询是动态的使用这个方法就会非常


复杂。 


例如当你需要查询的列在程序编译的时候不能确定这时候使用 query() 方法会方便很多。 


5.2.6.2 Regular Queries query() 


Regular Queries query() 方法用 SELECT 语句段构建查询。SELECT 语句内容作为 query() 方


法的参数 比如要查询的表名要获取的字段名WHERE 条件包含可选的位置参数去替代 


WHERE 条件中位置参数的值 GROUP BY 条件 HAVING 条件。 除了表名 其他参数可以是 


null。所以以前的代码段可以可写成  


  String[] columns = { "ID", "inventory" }; 


  String[] parms = { "snicklefritz" }; 


  Cursor result = db.query("widgets", columns, "name=?", parms,  


    null, null, null); 


  


5.2.6.3 


使用游标 


不管你如何执行查询都会返回一个 Cursor这是 Android 的 SQLite 数据库游标使用游标


你可以 


 通过使用 getCount() 方法得到结果集中有多少记录  通过 moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍历所有记录 


 通过 getColumnNames() 得到字段名 


 通过 getColumnIndex() 转换成字段号 


 通过 getString()getInt() 等方法得到给定字段当前记录的值 


 通过 requery() 方法重新执行查询得到游标 


 通过 close() 方法释放游标资源 


  


  6 网络存储 6.1 访问网络 6.1.1 在配置文件中设置访问网络权限 <uses-permission android:name="android.permission.INTERNET" /> 


 6.1.2 获取数据 可以通过调用WebService返回的数据或是解析HTTP协议实现网络数据交互。 


以下展示了Android SDK 中一些与网络有关的package。 


java.net 提供与联网有关的类包括流和数据包datagramsockets、Internet 协议和常见 


HTTP 处理。该包是一个多功能网络资源。有经验的 Java 开发人员可以立即使用这个熟悉的包创建


应用程序。 


java.io 虽然没有提供显式的联网功能但是仍然非常重要。该包中的类由其他 Java 包中提供的 


socket 和连接使用。它们还用于与本地文件在与网络进行交互时会经常出现的交互。 


java.nio 包含表示特定数据类型的缓冲区的类。适合用于两个基于 Java 语言的端点之间的通信。 


org.apache.* 表示许多为 HTTP 通信提供精确控制和功能的包。 可以将 Apache 视为流行的


开源 Web 服务器。 android.net 除核心 java.net.* 类以外包含额外的网络访问 socket。该包包括 URI 类后者


频繁用于 Android 应用程序开发而不仅仅是传统的联网方面。 


android.net.http 包含处理 SSL 证书的类。 


android.net.wifi 包含在 Android 平台上管理有关 WiFi802.11 无线 Ethernet所有方面的


类。 


android.telephony.gsm 包含用于管理和发送 SMS文本消息的类。一段时间后可能会引


入额外的包来来为非 GSM 网络提供类似的功能比如 CDMA 或 android.telephony.cdma 等网


络。 


下面是一个通过地区名称查询该地区的天气预报以POST发送的方式发送请求到


webservicex.net站点访问WebService.webservicex.net站点上提供查询天气预报的服务。  


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(); 


  } 


 } 





  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值