Android 数据存储详解(SharedPreferences, 文件, Sqlite, ContentProvider)
2016-07-21 21:22
776 查看
文章大部分内容来自 < < Android开发全程实录 > >, 希望大家能看看原书
获取Editor
写入数据
editor.commit()
查看结果如图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/20cab9e5f276a2d024cb8335869dde74)
导出 user_info.xml, 里面的内容是:
获取SharedPreferences对象有两种方法:
1.
2.
使用
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/a7d5967aa67b101e43f1cc05e8f2b97f)
1. 获取到SharedPreferences对象
2. 使用get方法读取指定值, 这里注意, 如果SharedPreferences没有存储指定键的值, 可以使用默认值代替返回值.
打印结果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/762d84be5b6bb20e17e8a8b7d28de0b9)
SPUtils.java
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/bc08c91e189a54f1666e144f32d37bcb)
注意: 这3个是比较典型的, 其中通过 context 获取的路径下的内容在 APP被卸载的时候都会被删除, 存在外接存储设备上的则不会被删除.
大家可以写代码测试:
打印结果
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/f340be70845a5a5aaf47d51e95bdda1b)
Sqlite Expert Professional (推荐)
SqliteAdmin
…
1. 创建, 删除数据库
2. 增加数据
3. 删除数据
4. 修改数据
5. 查询数据
Android数据库核心类是: SQLiteDatabase, 为了让Android中的数据库更加好使用, Android还提供了: SQLiteOpenHelper来帮助管理数据库. 这里我只简单介绍数据库的基本操作, 后面再写一篇专门介绍 SQLiteOpenHelper的使用, 和对数据库的封装.
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/6fb00ecd0916ded3fdafb72fc8c5bb16)
2. 使用
所以建议还是建议使用方法一, 而且数据库本来就不应该被其他应用访问, 所以应该放在最隐私的位置. 如果想为其他应用提供数据, 可以使用后面介绍的 ContentProvider
当然Adnroid还封装了很多其他关于 SQLiteDatabase 的方法, 大家自行探索, 都很easy.
声明 CONTENT_URI, 实现 UriMatcher
在 AndroidManifest.xml 中注册
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/d13924793499a6972bd85f20405d90ed)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/976986e468986c0e78a99e1a5425e057)
在抽象方法中我们发现一个重要的类: Uri, ContentProvider通过 Uri定位资源然后共享出来, Uri需要符合一定的格式, 来看看系统联系人的格式:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/438c1c7973b84c2a8ee4e0c9da8b358b)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/10/c74c1e856bdd51d34087386ba7e2a760)
感觉继续写下去太长了, 下次写一篇新的放在最后
SharedPreferences
sharepreferences是Android中最轻量级的数据存储. 原理相信很多人也很清楚, 这里简单再介绍以下. 系统提供了SharedPreferences这个类, 所有用这个类存储的内容都会放在 data/data/< package name >/shares_prefs/… 目录下以xml文件的形式存储. xml文件中存储的都是键值对形式的内容. 一般可以存储java的简单类型(boolean, int, float, long, string, set< string > 等). 通常只使用SharedPreferences存储一些简单配置信息.SharedPreferences存储基本流程
获取SharedPreferences 对象获取Editor
写入数据
editor.commit()
Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putString("username", "jake"); editor.putInt("age", 20); editor.putBoolean("islogin", true); editor.commit(); }
查看结果如图:
导出 user_info.xml, 里面的内容是:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="username">jake</string> <boolean name="islogin" value="true" /> <int name="age" value="20" /> </map>
获取SharedPreferences对象有两种方法:
1.
context.getSharedPreferences("user_info", MODE_PRIVATE);
2.
context.SharedPreferences sp = getPreferences(MODE_PRIVATE);
使用
getPreferences(mode)会直接使用 类名.xml 作为存储文件名, 注意只有Activity的context能使用
getPreferences(mode), 所以可以轻松的区分出每个activity保存的配置文件.
从SharedPreferences读取值
读取流程:1. 获取到SharedPreferences对象
2. 使用get方法读取指定值, 这里注意, 如果SharedPreferences没有存储指定键的值, 可以使用默认值代替返回值.
SharedPreferences sp_read = getSharedPreferences("user_info", MODE_PRIVATE); String username = sp_read.getString("username", "default_string"); int age = sp_read.getInt("age", 0); boolean islogin = sp_read.getBoolean("islogin", false); String not_exist = sp_read.getString("not_exist", null); Log.e(TAG, "username:" + username + " age:" + age + " islogin:" + islogin + " not_exits:" + not_exist);
打印结果:
E/MainActivity: username:jake age:20 islogin:true not_exits:null
SharedPreferences操作模式
封装SharedPreferences工具类
该工具类来自 hyman大神 的工具类, 很好用. 大家可自行尝试引入到自己项目中SPUtils.java
package com.zhy.utils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import android.content.Context; import android.content.SharedPreferences; public class SPUtils { public SPUtils() { /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } /** * 保存在手机里面的文件名 */ public static final String FILE_NAME = "share_data"; /** * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 * * @param context * @param key * @param object */ public static void put(Context context, String key, Object object) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { editor.putInt(key, (Integer) object); } else if (object instanceof Boolean) { editor.putBoolean(key, (Boolean) object); } else if (object instanceof Float) { editor.putFloat(key, (Float) object); } else if (object instanceof Long) { editor.putLong(key, (Long) object); } else { editor.putString(key, object.toString()); } SharedPreferencesCompat.apply(editor); } /** * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 * * @param context * @param key * @param defaultObject * @return */ public static Object get(Context context, String key, Object defaultObject) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sp.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { return sp.getInt(key, (Integer) defaultObject); } else if (defaultObject instanceof Boolean) { return sp.getBoolean(key, (Boolean) defaultObject); } else if (defaultObject instanceof Float) { return sp.getFloat(key, (Float) defaultObject); } else if (defaultObject instanceof Long) { return sp.getLong(key, (Long) defaultObject); } return null; } /** * 移除某个key值已经对应的值 * * @param context * @param key */ public static void remove(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.remove(key); SharedPreferencesCompat.apply(editor); } /** * 清除所有数据 * * @param context */ public static void clear(Context context) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.clear(); SharedPreferencesCompat.apply(editor); } /** * 查询某个key是否已经存在 * * @param context * @param key * @return */ public static boolean contains(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); return sp.contains(key); } /** * 返回所有的键值对 * * @param context * @return */ public static Map<String, ?> getAll(Context context) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); return sp.getAll(); } /** * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 * * @author zhy * */ private static class SharedPreferencesCompat { private static final Method sApplyMethod = findApplyMethod(); /** * 反射查找apply的方法 * * @return */ @SuppressWarnings({ "unchecked", "rawtypes" }) private static Method findApplyMethod() { try { Class clz = SharedPreferences.Editor.class; return clz.getMethod("apply"); } catch (NoSuchMethodException e) { } return null; } /** * 如果找到则使用apply执行,否则使用commit * * @param editor */ public static void apply(SharedPreferences.Editor editor) { try { if (sApplyMethod != null) { sApplyMethod.invoke(editor); return; } } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } editor.commit(); } } }
文件
Android文件操作就是使用Java的API, 这里需要注意的是 Android中的路径以及权限. Android中文件操作一般都用来存一些二进制文件和简单的文本, 例如图片, 视频等, 一般不用来存配置信息.几个典型的路径
使用context.this.openFileOutput("1.txt", MODE_PRIVATE);会将文件存储在 /data/data/< package name >/ files 下
context.getFilesDir();保存在 /data/user/0/< package name >/files 下
Environment.getExternalStorageDirectory();保存在 /storage/emulated/0下
注意: 这3个是比较典型的, 其中通过 context 获取的路径下的内容在 APP被卸载的时候都会被删除, 存在外接存储设备上的则不会被删除.
大家可以写代码测试:
try { FileOutputStream fos = this.openFileOutput("1.txt", MODE_PRIVATE); OutputStreamWriter osw = new OutputStreamWriter(fos); String test = "test"; osw.write(test, 0, test.length()); fos.close(); File file2 = this.getFilesDir(); File file3 = this.getCacheDir(); File file4 = Environment.getExternalStorageDirectory(); File file5 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); Log.e(TAG, "file2:" + file2); Log.e(TAG, "file3:" + file3); Log.e(TAG, "file4:" + file4); Log.e(TAG, "file5:" + file5); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
打印结果
file1:/data/data/< package name >/files // 这个看上面截图 file2:/data/user/0/org.yxm.filesimple/files file3:/data/user/0/org.yxm.filesimple/cache file4:/storage/emulated/0 file5:/storage/emulated/0/Pictures
文件读写权限:
如果要将文件写入外部存储设备, 需要一定的权限.<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Sqlite
简介
管理工具
SQLite Database BrowserSqlite Expert Professional (推荐)
SqliteAdmin
…
使用方法
使用Sqlite数据库和使用普通数据库一样, 都是以下几个步骤:1. 创建, 删除数据库
2. 增加数据
3. 删除数据
4. 修改数据
5. 查询数据
Android数据库核心类是: SQLiteDatabase, 为了让Android中的数据库更加好使用, Android还提供了: SQLiteOpenHelper来帮助管理数据库. 这里我只简单介绍数据库的基本操作, 后面再写一篇专门介绍 SQLiteOpenHelper的使用, 和对数据库的封装.
创建数据库
使用context.openOrCreateDatabase(...), 数据库文件会默认保存到 /data/data/< package name >/ databases/… 下
SQLiteDatabase db = this.openOrCreateDatabase("mySqliteDb.db", MODE_PRIVATE, null);
2. 使用
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(getFilesDir() + "/mySqliteDb.db", null);可以将数据库文件放在自定义目录中, 但是经过实验, 不能放在外部存储中, 会包下面的错误:
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
所以建议还是建议使用方法一, 而且数据库本来就不应该被其他应用访问, 所以应该放在最隐私的位置. 如果想为其他应用提供数据, 可以使用后面介绍的 ContentProvider
创建table
使用db.execSQL(createTableStr);来创建表, 例如:
String createTableStr = "CREATE TABLE IF NOT EXISTS account (" + "_id INTEGER PRIMARY KEY," + "username VARCHAR(60)," + "password VARCHAR(60)" + ");"; db.execSQL(createTableStr);
插入数据
当然可以直接使用原生sql语句, 使用 db.execSQL(insertStr); 执行插入, 但是Android为我们封装了键值对的map, 只需要构造键值对 ContentValues , 然后调用 insert 即可插入.ContentValues values = new ContentValues(); values.put("username","yxm"); values.put("password", "123"); db.insert("account", null, values);
删除数据
db.delete("account", "_id>?", new String[]{"5"});
更新数据
ContentValues values = new ContentValues(); values.put("username", "mxy"); values.put("password", "321"); db.update("account", values, "_id<?", new String[]{"5"});
查询数据
Cursor cur = db.query("account", null, null, null, null, null, null); if (cur.moveToFirst()) { while (!cur.isLast()) { int id = cur.getInt(0); String username = cur.getString(1); String password = cur.getString(2); Log.e(TAG, "id:" + id + " username:" + username + " password:" + password); cur.moveToNext(); } }
关闭数据库
db.close();
当然Adnroid还封装了很多其他关于 SQLiteDatabase 的方法, 大家自行探索, 都很easy.
ContentProvider
我们可以将ContentProvider 看做Android中一个应用向其他应用公开数据的接口, 做数据共享. Android系统本身就有一些 ContentProvider, 例如: Contacts, Browser, CallLog, Settrings 等. 当然我们也可以自己创建ContentProvider来向其他程序提供数据.创建自己的ContentProvider
继承ContentProvider声明 CONTENT_URI, 实现 UriMatcher
在 AndroidManifest.xml 中注册
继承ContentProvider
在抽象方法中我们发现一个重要的类: Uri, ContentProvider通过 Uri定位资源然后共享出来, Uri需要符合一定的格式, 来看看系统联系人的格式:
定义 CONTENT_URI, 实现UriMatcher
public static final Uri CONTENT_URI = Uri.parse("content://org.yxm.sqlitesimple");
在 AndroidManifest.xml 中注册
<provider android:authorities="org.yxm.sqlitesimple" android:name=".content.MyContentProvider" />
感觉继续写下去太长了, 下次写一篇新的放在最后
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories