Android数据存储(一)

一、SharedPreferences

SharePreferences是用来存储一些简单配置信息的一种机制,使用Map数据结构算法与数据结构知识库")来存储数据,以键值对的方式存储,采用了XML格式将数据存储到设备中。例如保存登录用户的用户名和密码。只能在同一个包内使用,不能在不同的包之间使用,其实也就是说只能在创建它的应用中使用,其他应用无法使用。

适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口令密码等

核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data//shared_prefs目录下。

SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,mode参数具体如下:

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编辑完成后,使用该方法提交修改

提交数据

//步骤1:获取输入值
String string= editText.getText().toString().trim();
//步骤2-1:创建一个SharedPreferences.Editor接口对象,name表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作
SharedPreferences.Editor editor = getSharedPreferences("name", MODE_WORLD_WRITEABLE).edit();
 //步骤2-2:将获取过来的值放入文件
editor.putString("name", string);
//步骤3:提交
editor.commit();

获取数据

//步骤1:创建一个SharedPreferences接口对象
 SharedPreferences read = getSharedPreferences("name", MODE_WORLD_READABLE);
//步骤2:获取文件中的值
 String value = read.getString("name", "");

读写其他应用的SharedPreferences: 步骤如下

1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取.
2、创建其他应用程序对应的Context:
Context pvCount = createPackageContext("com.xxx.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.xxx.app就是其他程序的包名
3、使用其他程序的Context获取对应的SharedPreferences
SharedPreferences read = pvCount.getSharedPreferences("name", Context.MODE_WORLD_READABLE);
4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。

SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。


二、文件存储

核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:

MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可 以使用Context.MODE_APPEND
MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

除此之外,Context还提供了如下几个重要的方法:

getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录
File getFilesDir():获取该应用程序的数据文件夹得绝对路径
String[] fileList():返回该应用数据文件夹的全部文件               

核心代码

/**
     * 判断内部存储还是外部存储,带SD卡使用外部存储,不带SD卡使用内部存储。
     */
    public File getFileDir(Context context, String uniqueName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalFilesDir(uniqueName).getPath();
        } else {
            cachePath = context.getFilesDir().getPath();
        }
        return new File(cachePath);
    }

写文件操作

public void write(String msg){
        // 步骤1:获取输入值
        if(msg == null) return;
        try {
            // 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式
            FileOutputStream fos = openFileOutput("message.txt",MODE_APPEND);
            // 步骤3:将获取过来的值放入文件
            fos.write(msg.getBytes());
            // 步骤4:关闭数据流
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

读取文件操作

public String read() {
        try {
            FileInputStream fis= this.openFileInput("message.txt");
            byte[] buffer = new byte[1024];
            int hasRead = 0;
            StringBuilder sb = new StringBuilder();
            while ((hasRead = inStream.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, hasRead));
            }
            fis.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null;
    }

三、ContentProvider存储

ContentProvider的作用是为别的应用调用本应用中的数据或者文件提供接口,而它也是唯一的跨应用数据传递的接口。如果仅仅是同一个应用中的数据传递,则完全没有必要使用到自定义的ContentProvider。

另一方面,虽然ContentProvider也能组织文件数据或者SharedPreferences(其实也是文件数据)这种数据,但大多数情况下ContentProvider是作为SQLite数据库的调用接口来被继承的。其原因大概是在于重写的query()方法始终需要返回Cursor,而Cursor作为数据库数据的容器,并没有提供直接往Cursor中写入数据的方法。

实现步骤

  1. 创建一个数据源,例如继承SQLiteOpenHelper创建一个SQLite数据库;
  2. 创建一个继承自ContentProvider的类,并重写insert、delete、query、update、getType、onCreate方法,在这些方法中实现对数据源的操作;
  3. 在AndroidManifest.xml文件中添加标签,两个必写的属性是android:name和android:authorities;
  4. 在本应用或者其它应用的Activity、Service等组件中使用ContentResolver通过对应的URI来操作该自定义ContentProvider。

注意

  1. onCreate() 默认执行在主线程,别做耗时操作,query() 也最好异步执行
  2. 上面的 4 个增删改查操作都可能会被多个线程并发访问,因此需要注意线程安全

URI

ContentProvider 使用 URI 标识要操作的数据,这里的内容 URI 主要包括两部分:

authority:整个提供程序的符号名称
path:指向表的名称/路径

内容 URI 统一的形式就是:

content://authority/path

注意

形如content://com.xxx.MyProvider/phone/1
com.xxx.MyProvider表示authority,是AndroidManifest.xml文件中标签的android:authorities属性值,或者是远程数据源的主机名,必需;
phone/1表示path,是数据源路径,非必需,其中的phone对于数据库来说可以视为表名,1表示的是该条数据的编号,如果没有则一般认为是返回当前路径(当前表)中的所有数据。

当调用 ContentResolver 方法来访问 ContentProvider 中的表时,需要传递要操作表的 URI。
在通过 ContentResolver 进行数据请求时(比如 contentResolver.insert(uri, contentValues);), 系统会检查指定 URI 的 authority 信息,然后将请求传递给注册监听这个 authority 的 ContentProvider 。这个 ContentProvider 可以监听 URI 想要操作的内容,Android 中为我们提供了 UriMatcher 来解析 URI。

UriMatch对象

该类主要是是对传入的Uri进行匹配,确保传来的Url对ContentProvider确实可以处理的。

  1. 通过new UriMatcher(UriMatcher.NO_MATCH); 实例化,常量NO_MATCH作为参数表示不匹配任何URI;
    该类主要提供了如下两个方法:

  2. 实例化后调用addURI(String authority, String path, int code)方法注册URI,该方法有三个参数,分别需要传入URI字符串的authority部分、path部分以及自定义的整数code三者;

  3. 在其它地方调用match(Uri uri) 方法匹配相应的URI,需要传入Uri作为唯一的参数,返回上述自定义的code值。根据前面注册的Uri返回其对应的标识码,如果在UriMatcher中找不到对应的Uri则返回-1。

ContentUris类

这个类是一个操作Uri字符串的工具类,主要是拼接Uri字符串用,它有两个方法:
public static Uri withAppendedId(Uri uri, long id) 用于为路径加上id部分
例如:

Uri  uri = Uri.parse("content://com.lzb.provide.myContentProvide:200/students");
Uri newUri = ContentUris.withAppendedId(uri,2);

那么 newUri 就变成了content://com.lzb.provide.myContentProvide:200/students/2。
public static long parseId(Uri uri) 用于从指定的Uri中解析出所包含的id
例如上述newUri解析出来的ID为2。

ContentResolver类

通过调用Content的getContentResolver()方法获取ContentResolver对象实例,其实ContentResolver的作用类似于HttpClient,获取对象后就可以根据Uri对应用的数据进行CRUD操作了。ContentResolver有如下方法:

 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
说明:根据Uri查询出select条件所匹配的全部记录,projection表示一个列名列表,表明只选择指定的数据列
public Uri insert(Uri uri, ContentValues values)
说明:根据该Uri插入values对应的数据
public int delete(Uri uri, String selection, String[] selectionArgs)
说明:根据Uri,删除selection条件匹配全部记录。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
说明:根据Uri,更新selection条件匹配的
Android数据存储(一)_第1张图片
ContentProvider、Uri、ContentResolver之间的关系

你可能感兴趣的:(Android数据存储(一))