【转】M层SP与IO操作优化方案

背景

SP操作问题
SP是非常好用的轻量存储方式,对少量数据的存储性能出众。但是对SP错误的使用,也会带来各种各样的问题,甚至会导致ANR。
目前我们代码中所有的SP操作都封装在PreferencesHelp这个工具类。
SP性能优化点
SP性能变差的原因有很多。
1.原生API的限制主要有以下两方面:
     (1)IO瓶颈
     (2)锁性能差
2.对SP的不当封装也会间接造成数据读写性能差。(我们没有跨进程问题,并没有用到CP操作SP)
IO瓶颈
IO瓶颈造成SP性能差是最大的原因,解决了IO瓶颈,80%的性能问题就解决了。
SP的IO瓶颈包括读取数据到内存与数据写入磁盘两部分。
1.读取数据到内存有两个场景会触发:
     (1)SP文件没有被加载到内存时,调用getSharedPreferences方法会初始化文件并读入内存。
     (2)版本低于android_H或使用了MULTI_PROCESS标志时,每次调用getSharedPreferences方法时都会读入。
2.数据写入磁盘也有两个场景会触发:
     (1)Editor的commit方法,每次执行时同步写入磁盘。
     (2)Editor的apply方法,每次执行时在单线程池中加入写入磁盘Task,异步写入。
     commit和apply的方法区别在于同步写入和异步写入,以及是否需要返回值。
     在不需要返回值的情况下,使用apply方法可以极大的提高性能。
     同时,多个写入操作可以合并为一个commit/apply,将多个写入操作合并后也能提高IO性能。
如下的写法尽量避免:
锁性能差
SP的get操作,会锁定SharedPreferences对象,互斥其他操作。
SP的put操作,getEditor及commitToMemory会锁定SharedPreferences对象,put操作会锁定Editor对象,写入磁盘更会锁定一个写入锁。
由于锁的缘故,SP操作并发时,耗时会徒增。减少锁耗时,是另一个优化点。
由于读写操作的锁均是针对SP实例对象的,将数据拆分到不同的sp文件中,便是减少锁耗时的直接方案。
目前我们所有的sp键值对都放在一个xml文件中,我们需要降低单文件访问频率,多文件均摊访问,以减少锁耗时。
SP优化的建议
1.将SP作为耗时操作对待,尽量减少无谓的调用。
譬如以下代码,SP读一次即可:


if(sp.getUserId()>0){
     int id=sp.getUserId();
}


2.多个写入操作合并后统一commit/apply,提高IO性能。
3.拆分SP文件,降低锁耗时。
4.如果需要可以提供跨进程访问SP的接口。不过我们当前并没有跨进程的问题。
IO操作问题
在UI线程中存在许多不合理的IO操作:例如

这非常容易导致ANR,因此类似文件IO操作必须异步的方式,不能心存侥幸...

现在我们引入了Rxjava,我们需要逐渐适应Rxjava响应式编程的思想,替代目前代码中AsyncTask、new Thread或者handler这种处理异步操作的方式。

但是有时候用Rxjava,为了方便我们会这样写:

//错误写法
Observable.just(FileUtil.readBeanFromInputStream(mContext,mContext.getResources().openRawResource(R.raw.xueche_danmu),TanmuBeanList.class))
         .subscribeOn(Schedulers.io())
         .observeOn(AndroidSchedulers.mainThread())
         .subscribe(new Subscriber<TanmuBeanList>() {
            @Override
            public void onCompleted() {
               
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(TanmuBeanList tanmuBeanList) {
               //处理TanmuBeanList
            }
         });

问题:业务操作是在当前线程执行


推荐的写法:

Observable.create(new Observable.OnSubscribe<TanmuBeanList>() {
   @Override
   public void call(Subscriber<? super TanmuBeanList> subscriber) {
      // 业务功能代码开始
      TanmuBeanList beanList = FileUtil.readBeanFromInputStream(mContext,mContext.getResources().openRawResource(R.raw.xueche_danmu),TanmuBeanList.class);
      // 业务功能代码结束
      if(!subscriber.isUnsubscribed()) {
         subscriber.onNext(beanList);
         subscriber.onCompleted();
      }

   }
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<TanmuBeanList>() {
   @Override
   public void onCompleted() {

   }

   @Override
   public void onError(Throwable e) {

   }

   @Override
   public void onNext(TanmuBeanList tanmuBeanList) {

   }
});

Storage框架介绍

Storage使用说明

Storage设计说明

缺点:

1.Kvcache工厂类里方法比较多,这里为了统一SP操作和普通文件IO操作,牺牲了一些SP的api方法...

2.框架内部支持跨进程SP操作,但是已经被屏蔽掉,不过目前并不需要这部分功能

示例用法
//设置文件扩展信息,包括新鲜度日期,过期时间,路径(路径不推荐设置)
final StorageFileConfig config = new StorageFileConfig();
config.setFreshTime(Long.MAX_VALUE)//设置新鲜度日期,如果超过此日期会删除文件,并返回文件内容
        .setExpireTime(Long.MAX_VALUE);//设置过期时间,如果过期会删除文件并返回null
String fileName = "sample_file";
String content = "这是要保存的文件内容,一个String字符串";
//写入文件操作
RxDataManager.getInstance().createFilePersistent(config)
        .putStringAsync(fileName,content)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<Boolean>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Boolean aBoolean) {

            }
        });
//读取文件操作
RxDataManager.getInstance().createFilePersistent()
        .getStringAsync(fileName)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String s) {

            }
        });


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值