文章目录

  • 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存储

内部存储

Android写入sp需要写的权限吗_Android写入sp需要写的权限吗

外部存储

Android写入sp需要写的权限吗_eclipse_02

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数据库实际使用案例