Android的数据管理总结

四大数据存储方式:

一. SharedPreferences
1. 保存:

SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("xml_file_name", Context.MODE_PRIVATE);

Editor editor = sharedPreferences.edit();//获取编辑器

editor.putString("key", "value");//还可以保存Set<String>,int,long,float,boolean

editor.commit();//提交修改

默认保存在:/data/data/<package name>/shared_prefs/xml_file_name.xml

2. 读取:

SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("xml_file_name", Context.MODE_PRIVATE);

String value = sharedPreferences.getString( "key", "" );

注意:
如果应用A要访问应用B的SharedPreferences,必须先获取应用B的Context,通过B的Context来获取SharedPreferences,才会在应用B所在包下的shared_prefs目录找到XML文件。

二. File
1. 内部资源文件,只读:
InputStream in = getResources().openRawResource(R.raw.test);  //得到资源中的Raw数据流
InputStream in = getResources().getAssets().open(fileName);  //得到资源中的asset数据流

2. 可以读写的文件:
String filePath = getFilesDir().getPath(); //路径:/data/data/<package name>/files
String CachePath = getCacheDir().getPath(); //路径:/data/data/<package name>/cache,换存目录有可能被系统删除
String sdPath = Environment.getExternalStorageDirectory().getPath() // 路径:/mnt/sdCard

 private String read( boolean savedInExternal, String path ){

  String result = new String();

  FileInputStream in = null;

  try{

   if( savedInExternal ) {

    //SD卡中的文件使用FileInputStream和FileOutputStream进行文件的操作

    in = new FileInputStream(path);

   } else {

    //存放在数据区(/data/data/..)的文件只能使用openFileOutput和openFileInput进行操作

    in = openFileInput(path);

   }

   int len = in.available();

   if( len > 0 ){

    byte[] buffer = new byte[len];

    in.read(buffer);

    result = EncodingUtils.getString(buffer, "UTF-8");

   }

  }catch(Exception e){

   e.printStackTrace();

  }finally{

   if (in != null) {

    try {

     in.close();

    } catch (IOException e) {

     // TODO Auto-generated catch block

     e.printStackTrace();

    }

   }

  }

  return result;

 }

 

 private void write(boolean savedInExternal, String path, String text){

  FileOutputStream out = null;

  try{

   if(savedInExternal){

    out = new FileOutputStream(path);

   }else{

    out = openFileOutput(path, MODE_PRIVATE);

   }

   byte[] buffer = text.getBytes();

   out.write(buffer);

  }catch(Exception e){

   e.printStackTrace();

  }finally{

   if(out!=null){

    try {

     out.close();

    } catch (IOException e) {

     e.printStackTrace();

    }

   }

  }

 }

3.RandomAccessFile同时将FileInputStream和FileOutputStream整合到一起,而且支持访问文件任意字节处读或写数据,常用于断点续传保存文件。
定位用的getFilePointer()
在文件里移动用的seek()
判断文件大小的length()
跳过多少字节数skipBytes()
注意:read()和write(),都是从文件当前位置开始读和写。

//打开文件时,FilePointer指向文件起始位置。

RandomAccessFile r = new RandomAccessFile(file,"rwd");

   

// 将String转byte[],在文件起始位置写入byte[]。

String f = "123456789";

byte[] buffer = f.getBytes("UTF-8");

r.write(buffer);

   

// 验证:让FilePointer指向文件起始位置。

r.seek(0);

// 从文件起始位置开始读byte[],然后转String。

long len = r.length();

byte[] dst = new byte[(int) len];

r.read(dst);

String f_read = new String(dst,"UTF-8");//结果:123456789

   

// 让FilePointer指向文件末尾位置,在末尾处接着写入byte[]。

r.seek(len);

r.write(buffer);

   

// 验证:让FilePointer指向文件起始位置。从文件起始位置开始读byte[]。

r.seek(0);

len = r.length();

byte[] dst2 = new byte[(int) len];

r.read(dst2);

f_read = new String(dst2,"UTF-8");//结果:123456789123456789

   

// 关闭

r.close();

三. 数据库(默认路径:/data/data/<package name>/databases/)
在Android平台上,集成了一个嵌入式关系型数据库—SQLite,支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)。
1. SQLiteOpenHelper 是用来管理数据库的,因为是抽象类,所以必须自定义子类来继承它。
SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version)的构造函数中,name表示数据库的名字,默认路径是:/data/data/<package name>/databases/name,可以自定义数据库路径赋值给name,将数据库保存在指定路径下,比如SD卡下。
提供了获取SQLiteDatabase的接口:getReadableDatabase(),getWritableDatabase()。

2. SQLiteDatabase 操作SQLite数据库。
execSQL()接口,主要是执行无需返回数据的操作:
CREATE TABLE IF NOT EXISTS table_name (id INTERGER PRIMARY KEY, content TEXT)
DROP TABLE IF EXISTS table_name
ALTER TABLE table_name ADD COLUMN add_content TEXT
下面的SQL方法也可以用execSQL()执行,也可以使用SQLiteDatabase对应接口。
INSERT INTO table_name (k1,k2) VALUES (v1,v2)
UPDATE table_name SET k1=v1 WHERE 条件
DELETE FROM table_name WHERE 条件

rawQuery()接口,主要是执行返回结果的操作,返回值是结果集游标Cursor:
SELECT * FROM table_name WHERE 条件 GROUP BY 分组 HAVING 分组条件 ORDER BY 排序

public class DatabaseHelper extends SQLiteOpenHelper {
 private static int DATABASE_VERSION = 1;
 
 public DatabaseHelper(Context context, String dbPath) {
  super(context, dbPath, null, DATABASE_VERSION);
 }
 @Override
 public void onCreate(SQLiteDatabase db) {
 }
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 }
}
public class DatabaseUtil {
 private static final String DATABASE_DIR = "database_dir";
 private static final String DATABASE_NAME = "database.db";
 
 private Context mContext;
 private DatabaseHelper mDatabaseHelper;
 private String mDatabaseDirPath;
 private String mDatabaseFullPath;
 private static DatabaseUtil mInstance; //单例模式
 public static DatabaseUtil getInstance(Context c) {
  if( mInstance == null ) {
   mInstance = new DatabaseUtil(c);
  }
  return mInstance;
 }
 
 private DatabaseUtil (Context c) {
  mContext = c.getApplicationContext();
  StringBuffer path = new StringBuffer();
  if ( Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED) ) {
   File file = Environment.getExternalStorageDirectory();
   path.append(file.getPath());
  } else {
   path.append(mContext.getFilesDir());
  }
  path.append(File.separator);
  path.append(DATABASE_DIR);
  mDatabaseDirPath = path.toString();
  File dir = new File(mDatabaseDirPath);
  if(!dir.exists()){
   dir.mkdir();
  }
  path.append(File.separator);
  path.append(DATABASE_NAME);
  mDatabaseFullPath = path.toString();
  mDatabaseHelper = new DatabaseHelper(mContext, mDatabaseFullPath);
 }
 
 public void createDatabaseTable(String table){
  SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
  db.beginTransaction();//开始事务
  try{
   StringBuffer str = new StringBuffer();
   str.append("CREATE TABLE IF NOT EXISTS ");
   str.append(table);
   str.append(" (id INTERGER PRIMARY KEY, content TEXT)");
   db.execSQL(str.toString());
   for(int i = 0; i < 200; ++i){
    StringBuffer buf = new StringBuffer();
    buf.append("数据:");
    buf.append(i+1);
    StringBuffer s = new StringBuffer();
    s.append("INSERT INTO ");
    s.append(table);
    s.append(" (id,content) values (?,?)");
    db.execSQL(s.toString(), new Object[]{i+1, buf.toString()});
   }
   db.setTransactionSuccessful();//设置事务的标志为成功
  } finally {
   db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
   db.close();
  }
 }
 
 public void deleteDatabaseTable(String table) {
  SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
  StringBuffer str = new StringBuffer();
  str.append("DROP TABLE IF EXISTS ");
  str.append(table);
  db.execSQL(str.toString());
  db.close();
 }
 
 public ArrayList<String> getDataFromDatabaseTable(String table){
  ArrayList<String> list = new ArrayList<String>();
  SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
  StringBuffer str = new StringBuffer();
  str.append("SELECT * FROM ");
  str.append(table);
  Cursor c = db.rawQuery(str.toString(),null);
  while(c.moveToNext()){
   int content_index = c.getColumnIndex("content");
   String content = c.getString(content_index);
   list.add(content);
  }
  c.close();
  db.close();
  return list;
 }
}

四. ContentProvider 向其他应用共享其数据,其他应用通过ContentResolver来访问这些数据。
Android系统提供的常见Content Provider,可以在源码src\android\provider目录中找到。

 

数据传递:

一. Activity, Service, BroadcastReceiver通过Intent对象来实现:
Intent的功能包括启动四大组件以及相关信息+传递数据。
其中传递数据Intent提供了putExtra和对应的getExtra方法,所以无需再创建一个bundle对象。
对应自定义数据结构,可以封装成Serializable和Parcelable来实现序列化。
但是,数据类型有限,比如遇到不可序列化的数据Bitmap,InputStream,或者LinkList链表等数据类型就不太好。
1. Serializable使用IO读写存储在外存上,在序列化时会产生大量的临时变量,从而引起频繁的GC,适用于保存对象的字节序列到本地文件或数据库中,以及网络传输。
自定义数据结构只需要实现Serializable接口,并提供一个序列化版本id(serialVersionUID)即可。
使用ObjectOutputStream.writeObject()可以将自定义数据写入文件流或网络流。
使用ObjectInputStream.readObject()可以从文件流或网络流中读取自定义数据。
2. Parcelable是直接在内存中读写,是通过IBinder通信的消息的载体,只适用进程间传递对象。
需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,务必保持写入和读取的类型及顺序一致,否则会发生异常。

二. 利用Application定义的全局变量:
A通过getApplication()对全局变量进行值的修改,B可以访问Application的值。修改全局变量的代码段需要用synchronized包裹来实现同步,防止多线程同时修改。

三. 通过单例模式实现:
可以保证Application中的这个类有且只有一个实例。在A中设置参数,在B中直接访问了。

public class Singleton  

{  

    //单例模式实例  

    private static Singleton instance = null;  

      

    //synchronized 用于线程安全,防止多线程同时创建实例  

    public synchronized static Singleton getInstance(){  

        if(instance == null){  

            instance = new Singleton();  

        }     

        return instance;  

    }     

      

    private HashMap<String, Object> mMap;  

    public Singleton()  

    {  

        mMap = new HashMap<String,Object>();  

    }  

      

    public void put(String key,Object value){  

        mMap.put(key,value);  

    }  

      

    public Object get(String key) 

    {  

        return mMap.get(key);  

    }

}

四. 通过Handler实现线程间的消息传递:
Handler类的主要作用有两个:
    1.在新启动的线程中发送消息。
    2.在主线程中获取、处理消息。

五. 基于外部存储的传输,使用SharedPreferences,File,SQLite,针对第三方应用需要ContentProvider+ContentResolver。

六. 基于IPC通信机制:

1. 定义AIDL接口文件实现进程间通信:

为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现,使用接口定义语言(Interface Definition Language,IDL)来公开服务的接口。

建立AIDL服务的步骤:
(1)在工程的Java包目录中建立一个扩展名为aidl的文件。每个文件只能定义一个接口,而且只能是接口的声明和方法的声明。

(2)如果aidl文件的内容是正确的,刷新工程,ADT会在gen包下自动生成一个Java接口文件(*.java)

(3)建立一个服务类(Service的子类),定义了一个内嵌类来实现.aidl文件定义的Java接口。

(4)在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。如果服务端service定义了android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。

客户端获取接口:
(1)将服务端自动生成的IMyService.java文件连同包目录一起复制到客户端工程的src目录中(R文件除外).

(2)客户端通过ServiceConnection获取从Service返回的IBinder,bindService以后可调用服务器的接口

2. 通过Messager实现进程间通信:

使用场景:当仅有2个应用要互相通讯时
(1)service 内部需要有一个 Handler 的实现,它被用来处理从每一个 client 发送过的来请求
(2)通过这个 Handler ,来生成一个 Messenger
(3) 在 service 的onBind() 方法中,需要向 client 返回由该 Messenger 生成的一个 IBinder 实例
(4) client 使用从 service 返回的 IBinder 实例来初始化一个 Messenger, 然后使用该 Messenger 与 service 进行通信
(5) service 通过它自身内部的 Handler 实现(Handler 人 handleMessage() 方法中)来处理从 client 发送过来的请求

你可能感兴趣的:(Android的数据管理总结)