数据列表离线缓存的另一种方法

数据列表离线缓存的另一种方法

Android中很大一部分APP,都是非常“轻”的,这里的“轻”指的是APP的“体量”和业务逻辑。受手机性能的限制和安全的考虑,绝大部分运算以及业务逻辑都放在后台执行,移动端只是一个展示和操作(交互)的平台,所以在开发APP的过程中,推荐尽量使用比较轻度的方法或插件等。

工作这几年了,开发的APP大大小小应该超过20个了,极少使用到数据库,当然这和开发的APP业务相关。今天要说的是使用文件存储方式存储离线缓存列表数据。

先来介绍Android中几种存储方式。

Android提供以下四种存储方式:

SharePreference

SharedPreference是一种轻型的数据存储方式,实际上是基于XML文件存储的“key-value”键值对数据。通常用来存储程序的一些配置信息,例如是否夜间模式,是否接收推送等。其存储在“data/data/程序包名/shared_prefs目录下。

SQLite

SQLite是一个轻量级关系型数据库,主要存储一些缓存数据,例如用户信息,离线展示数据等。

File

文件储存方式,主要存储文件,例如下载下来的apk、图片等

ContentProvider

能够实现跨应用之间的数据操作,例如联系人(各个应用都能申请获取)

另一种思路

现在有个列表数据需要缓存在本地,根据官方推荐肯定是使用数据库存储,但是考虑到这是一个非常简单的需求,存储的数据不需要做修改、联查等(整存整取),可以试试使用文件存储。

下面是封装的文件存储类:

public class CacheList{

private static final String LOG_TAG = CacheList.class.getSimpleName();

private static Map _lockMap = new HashMap<>();

private static final String

LIST_FILE_DIR = "solid_list";

public static final int UNLIMITED_SIZE = -1;

private Context _context;

private String _name;

private int _maxSize;

private String _path;

private LinkedList _linkedList;

private Object _lock;

private DeadListCallback _callback;

public CacheList(Context context, String name, int maxSize, DeadListCallback callback) {

_context = context;

_name = name;

_maxSize = maxSize;

_callback = callback;

_path = _context.getDir(LIST_FILE_DIR, Context.MODE_PRIVATE) + "/" + _name;

createLock();

createList();

}

private void createLock() {

if( ! _lockMap.containsKey(_name)){

_lockMap.put(_name, new Object());

}

_lock = _lockMap.get(_name);

}

@SuppressWarnings("unchecked")

private void createList() {

synchronized (_lock) {

File listFile = new File(_path);

if( ! listFile.exists()) {

_linkedList = new LinkedList();

Log.d(LOG_TAG, "list file not exist, file=" + _path + ", create an empty list");

return;

}

try{

FileInputStream fis = new FileInputStream(_path);

ObjectInputStream ois = new ObjectInputStream(fis);

_linkedList = (LinkedList)(ois.readObject());

ois.close();

} catch(Exception e) {

Log.e("Exception" ,e.toString());

_linkedList = new LinkedList();

}

}

}

public boolean remove(int index) {

synchronized (_lock) {

if(index < 0 || index >= _linkedList.size()) {

return false;

}

T element = _linkedList.remove(index);

if(-1 == _linkedList.lastIndexOf(element)){

// no same element in list any more

if(null != _callback) {

_callback.onRemove(element);

}

}

solidify();

return true;

}

}

public boolean remove(T element) {

synchronized (_lock) {

if(_linkedList.remove(element)) {

if(-1 == _linkedList.lastIndexOf(element)){

// no same element in list any more

if(null != _callback) {

_callback.onRemove(element);

}

}

solidify();

return true;

}else{

Log.d(LOG_TAG, "remove element fail");

}

return false;

}

}

public boolean addAll(List elementList) {

synchronized (_lock) {

int i = 0;

for( ; i < elementList.size(); ++i) {

if(UNLIMITED_SIZE == _maxSize || _linkedList.size() < _maxSize) {

T element = elementList.get(i);

_linkedList.addLast(element);

if(null != _callback) {

_callback.onAdd(element);

}

} else {

break;

}

}

solidify();

return i >= elementList.size();

}

}

public boolean add(T element) {

synchronized (_lock) {

if(UNLIMITED_SIZE == _maxSize || _linkedList.size() < _maxSize) {

Log.e("cache", "add element,name: " + _name);

_linkedList.addLast(element);

if(null != _callback) {

_callback.onAdd(element);

}

solidify();

return true;

}

return false;

}

}

public boolean addFrist(T element) {

synchronized (_lock) {

if(UNLIMITED_SIZE == _maxSize || _linkedList.size() < _maxSize) {

Log.e("cache", "add element,name: " + _name);

_linkedList.addFirst(element);

if(null != _callback) {

_callback.onAdd(element);

}

solidify();

return true;

}

return false;

}

}

/**

* 固化链表(固化到本地)

*/

public void solidify() {

synchronized (_lock) {

try {

FileOutputStream fos = new FileOutputStream(_path);

ObjectOutputStream oos = new ObjectOutputStream(fos);

while(_maxSize != UNLIMITED_SIZE && _linkedList.size() > _maxSize) {

T element = _linkedList.removeLast();

if(-1 == _linkedList.lastIndexOf(element)){

// no same element in list any more

if(null != _callback) {

_callback.onRemove(element);

}

}

}

oos.writeObject(_linkedList);

oos.close();

} catch(Exception e) {

Log.e("Exception" ,e.toString());

}

}

}

public void clear() {

synchronized (_lock) {

int oldMaxSize = _maxSize;

setMaxSize(0);

solidify();

setMaxSize(oldMaxSize);

}

}

public boolean destroy(){

synchronized (_lock) {

try {

clear();

File listFile = new File(_path);

if(listFile.exists()) {

boolean succ = listFile.delete();

if(succ) {

Log.d(LOG_TAG, "list file delete succ, path=" + _path);

} else {

Log.e(LOG_TAG, "list file delete fail, path=" + _path);

}

return succ;

} else {

Log.d(LOG_TAG, "list file not exist, delete fail, path=" + _path);

return false;

}

} catch(Exception e) {

Log.e("Exception", e.toString());

return false;

}

}

}

public void setMaxSize(int maxSize) {

synchronized (_lock) {

_maxSize = maxSize;

}

}

public int size() {

synchronized (_lock) {

return _linkedList.size();

}

}

public LinkedList getList() {

synchronized (_lock) {

return _linkedList;

}

}

public interface DeadListCallback {

void onAdd(E element);

void onRemove(E element);

}

}

代码非常简单,不做解释了,使用时:

1、新建列表:(如果已经存在缓存则会读取缓存)

userCacheList = new CacheList<>(this, "test", 50, new CacheList.DeadListCallback() {

@Override

public void onAdd(User element) {

Log.e("tag", "add element id: " + element.getId());

}

@Override

public void onRemove(User element) {

Log.e("tag", "remove element id: " + element.getId());

}

});

2、添加数据并固化到本地:

List userList = new ArrayList<>();

for (int i=0; i<50; i++){

User user = new User();

user.setId(i);

user.setName("name"+i);

user.setAddress("中华人民共和国北京天安门"+i);

user.setImgUrl("lskdjflsajflsajflsafjlasdjflasdfasfasdfasfsaf"+i);

user.setPwd("pwd"+i);

user.setSex(1);

userList.add(user);

}

userCacheList.addAll(userList);

userCacheList.solidify();

3、删除数据:

3种删除方法

userCacheList.clear();//全清

userCacheList.remove(1);//按Position删除数据

userCacheList.remove(new User());//按对象删除数据

删除完别忘了固化到本地:

userCacheList.solidify();

实测50条数据的读取

12-22 15:59:14.533 23506-23506/com.twsm.testdemo E/tag: get data before: 1513929554533

12-22 15:59:14.570 23506-23506/com.twsm.testdemo E/tag: get data after: 1513929554570

不到40毫秒,完全可以在主线程读取(测试的数据量比较小,当然不推荐在主线程做操作)。

这样看起来是不是很方便,挺适合做列表展示数据的离线缓存。当然,还是推荐使用SqlLite,这只是提供另一种思路。

相关推荐

常吃的鱼有哪些
best365官网手机版

常吃的鱼有哪些

📅 07-08 👁️ 8234
771 针 DDR2 主板:见证科技发展历程,满足特定需求的经典之选
手机字幕文件怎么用,如何用手机字幕
365官网哪个是真的

手机字幕文件怎么用,如何用手机字幕

📅 06-28 👁️ 935
国产手机不卡的有哪些
bet体育365官网怎么样

国产手机不卡的有哪些

📅 06-30 👁️ 8829
荒野行动直升飞机在哪里(幽灵行动荒野直升机位置)
best365官网手机版

荒野行动直升飞机在哪里(幽灵行动荒野直升机位置)

📅 07-10 👁️ 6074
手机换个屏幕要多久
bet体育365官网怎么样

手机换个屏幕要多久

📅 07-01 👁️ 2903