文章目录
- SharedPreferences
- 简介
- 流程解析
- commit和apply的区别
- 多进程同步安全实现
- File存储
- 内部存储
- 外部存储
- SQLite数据库存储
- 简介
- 使用
SharedPreferences
简介
SharedPreference是一种轻量级的存储方式,在创建的时候会把整个文件加载进内存,如果sp文件较大,则会导致以下几个严重问题:
第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧。
解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿。
这些key和value会永远存在于内存之中,占用大量内存。
只支持Java基本数据类型,不支持自定义数据类型,应用内数据共享。
流程解析
存储
protected void onStop() {
//获取一个文件名为test、权限为private的xml文件的SharedPreferences对象
SharedPreferences sharedPreferences = getSharedPreferences("test", MODE_PRIVATE);
//得到SharedPreferences.Editor对象,并保存key-value键值对数据到该对象中
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("username", et_username.getText().toString().trim());
editor.putString("password", et_password.getText().toString().trim());
//commit提交数据,保存key-value对到文件中
editor.commit();
super.onStop();
}
注意:sp.edit()每次都会返回一个新的Editor对象,Editor的实现类EditorImpl里面会有一个缓存的Map,最后commit的时候先将缓存里面的Map写入内存中的Map,然后将内存中的Map写进XML文件中。
取出数据
protected void onCreate() {
et_username = (EditText) findViewById(R.id.et_username);
et_password = (EditText) findViewById(R.id.et_password);
SharedPreferences sharedPreferences = this.getSharedPreferences("test", MODE_PRIVATE);
et_username.setText(sharedPreferences.getString("username",""));
et_password.setText(sharedPreferences.getString("password",""));
}
commit和apply的区别
- apply没有返回值而commit返回boolean表明修改是否提交成功
- apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘,;而commit是同步的提交到硬件磁盘,会阻塞调用它的线程。因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。
- apply方法不会提示任何失败的提示。由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。
- SharedPreferences还提供一个监听接口可以监听SharedPreferences的键值变化,需要监控键值变化的可以用registerOnSharedPreferenceChangeListener添加监听器。
多进程同步安全实现
SP其实是将key-value对保存在手机的data/data/you.package.name/shared_prefs/目录下的文件中。为了减少IO造成的性能损失,SP使用了缓存的机制,会先把数据保存在内存中,在读取的时候直接从内存中读取,而写的时候才会保存到文件。也就是说普通SP是一次读取,多次写入的工作模式。所以如果多个进程中都使用了普通的SP,分别进行保存就会导致相互覆盖。
设置了MODE_MULTI_PROCESS之后,在多进程使用的时候,会在检测到文件变化的时候重新加载文件到内存中,这样虽然损失了一部分性能,但是却部分实现了多进程间同步。
MODE_PRIVATE 私有模式,常用模式
使用contentProvider
如果调用进程与SharedPreference 本身就是同一个进程,只用走原生的流程,如果不是同一进程,则使用contentProvider确保一个文件只有一个进程在读写操作。
File存储
内部存储
外部存储
SQLite数据库存储
简介
独占锁:只允许进行锁定操作的程序使用,其他任何对他的操作均不会被接受。执行数据更新命令时,SQL Server会自动使用独占锁。当对象上有其他锁存在时,无法对其加独占锁。
共享锁:共享锁锁定的资源可以被其他用户读取,但其他用户无法修改它,在执行Select时,SQL Server会对对象加共享锁。
更新锁:当SQL Server准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server确定要进行更新数据操作时,他会自动将更新锁换为独占锁,当对象上有其他锁存在时,无法对其加更新锁。
使用
1、创建一个类继承SQLiteOpenHelper
SQLiteOpenHelper是SQLIteDatabase一个辅助类,用于生成一个数据库,并对数据库版本进行管理。
当在程序当中调用这个类的方法getWritableDatabase()或者 getReadableDatabase()方法的时候,如果当时没有数据,那么Android系统就会自动生成一个数据库。 SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里面的3个函数:
1.onCreate(SQLiteDatabase)
在数据库第一次生成的时候会调用这个方法,也就是说,只有在创建数据库的时候才会调用,当然也有一些其它的情况,一般我们在这个方法里边生成数据库表。
onUpgrade(SQLiteDatabase,int,int)
当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,当然是否还需要做其他的操作,完全取决于应用的需求。
onOpen(SQLiteDatabase):
这是当打开数据库时的回调函数,一般在程序中不是很常使用。
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
//构造函数
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//第一次创建数据库,调用该方法
//execSQL用于执行SQL语句
db.execSQL(T_UserInfo);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//更新数据库时,调用该方法
}
//使用者登录信息
private static final String T_UserInfo =
"create table T_UserInfo("
+ "id varchar,"//id
+ "account varchar,"//手动输入的账号
+ "Name varchar,"//账号姓名
+ "pwd varchar)";//pwd
}
2、得到SQLiteDatabase
public class DBUtil {
public static SQLiteDatabase db(Context context) {
//创建一个DBHelper并得到一个可写的SQLiteDatabase对象
return new DBHelper(context, "text.db", null, 1).getWritableDatabase();
}
}
3、使用数据库进行增删改查
db.insert("T_UserInfo",null,values);//增
db.delete("T_UserInfo","id = ?",new String[]{"1"});//删
db.update("T_UserInfo",values,"name = ?",new String[]{"allens"});//改
Cursor cursor = db.query("T_UserInfo", new String[]{"id", "account", "name", "pwd"}, null, null, null, null, null);//查
while (cursor.moveToNext()) {
Log.e("TAG", "id--->" + cursor.getString(0));
Log.e("TAG", "account--->" + cursor.getString(1));
Log.e("TAG", "name--->" + cursor.getString(2));
Log.e("TAG", "pwd--->" + cursor.getString(3));
}
4、数据库更新
// 数据库版本的更新,由原来的1变为2
DBHelper dbHelper = new DBHelper(context.this,"text.db",null,2);
SQLiteDatabase db =dbHelper.getReadableDatabase();
greenDao数据库实际使用案例