需求:一个页面里面有图片,对象,第一次进入的时候缓存进手机,下次如果没有网络,则进入该页面的时候,就不会木有东西了。如果在有网络的情况下,网速比较的慢,那么先读取本地手机数据会比网络快,先展示手机里面的东西,当网络上的数据加载完之后,则更新网络上的数据;
大概思路:sharedPreferences(键值对,键一样,则将之前的数据覆盖,存入的数据,木有大小的限制)进行保存,后台进来的JsonObject进行保存。图片使用ImageLoader
保存数据:
1.判断是否是第一页的信息,如果是,则将后台返回的数据,保存在sharedPreferences里面
2.onCreate()里面的时候,先执行缓存数据initCache(),再执行网路获取数据init();
3.数据的刷新,用adapter局部更新就可以~
initCache()代码:
private void initCache() {
String resultNews=MobileApplication.sp.getString("PostingNews", "");
if(resultNews!=null && !resultNews.trim().equals("") && !resultNews.trim().equals("null")){
isPostingNew=true;
MobileApplication.isNewsCache=true;
Message msg = new Message();
Bundle b = new Bundle();
b.putString("h_type", "GetNewestPost");
b.putString("result", resultNews);
msg.setData(b);
myHandler = new MyHandler();
PostingHomeActivity.this.myHandler.sendMessage(msg);
}
}
数据加载:
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (lastItem == count && scrollState == this.SCROLL_STATE_IDLE) {
if (page < maxpage) {
moreView.setVisibility(View.VISIBLE);
if(MobileApplication.isNewsCache){ //如果有缓存(第一页),则为true.如果有缓存,那么加载第二页(设置page=1)
MobileApplication.isNewsCache=false;
page=1;
new GetNewestPost().execute("");
}else if(isNew){
new GetNewestPost().execute("");
}else if(isEssence){
new GetEssencePost().execute("");
}else if(isHot){
new GetHotPost().execute("");
}
}else {
if(isNew){
Toast.makeText(getApplicationContext(), "亲,已经没有更多最新贴了",Toast.LENGTH_SHORT).show();
}else if(isEssence){
Toast.makeText(getApplicationContext(), "亲,已经没有更多精华贴了",Toast.LENGTH_SHORT).show();
}else if(isHot){
Toast.makeText(getApplicationContext(), "亲,已经没有更多热门贴了",Toast.LENGTH_SHORT).show();
}
}
}
}
MobileApplication.isNewsCache:用作第二页,加载判断
图片缓存(imageLoader):
options = new DisplayImageOptions.Builder()
.imageScaleType(ImageScaleType.IN_SAMPLE_INT)
.cacheInMemory(false) //是否缓存至内存
<span style="color:#6600cc;"><strong>.cacheOnDisc(true) //是否缓存至手机SD卡</strong></span>
.bitmapConfig(Config.RGB_565)
.build();
imageLoader.displayImage(img, iv, <strong><span style="color:#ff0000;background-color: rgb(255, 255, 255);">options</span></strong>);
-----------------------------------------------曾经弯路---------------------------------------
考虑到后台返回的数据有对象和图片两种,就将对象序列化,将数据保存成对象流存入。图片也分别存入。存入的地址:优先存入sd卡,如果木有sk卡,那么就存入内存,为了区分这些对象和图片,还将这些对象放入集合之中。存入的数据,按时间+名字设置。还定时删除里面的数据,防止内存泄露,删除sd卡或者内存里面的数据时,要重名文件名,防止报错。这种方法,要考虑很多方面,最后实现了,但是在内存优化方面,远远没有以上的快捷,简单。其中static的生命周期是这个应用,如果关了这个应用,static里面的东西会不见。
public static String mDataRootPath = null;
mDataRootPath = PostingHomeActivity.this.getCacheDir().getPath();
获取储存的Image的目录:
private String getImageDirectory(String floderName){
String storageDirectory=Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ? MobileApplication.mSdRootPath + floderName : mDataRootPath + floderName;
return storageDirectory;
}
保存Image的方法,有sd卡存储到sd卡,没有就存储到手机目录:
public String saveBitmap(String fileName, Bitmap bitmap) {
try {
String path = getNewsDirectory();
String path = getImageDirectory(MobileApplication.FOLDER_NAME_NEWS);
if(bitmap == null){
return "";
}
File folderFile = new File(path);
if(!folderFile.exists()){
folderFile.mkdir();
}
File file = new File(path + File.separator + fileName);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 20, fos);
fos.flush();
fos.close();
return path + File.separator + fileName;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
将对象存入:
public void savePostNewsEntity(PostingPostEntity fpes, String fileName) {
try {
String path = getImageDirectory(MobileApplication.FOLDER_NAME_NEWS);
File folderFile = new File(path);
if(!folderFile.exists()){
folderFile.mkdir();
}
File file = new File(path + File.separator + fileName);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file,true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(fpes);
oos.flush();
fos.flush();
oos.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
读取对象PostingPostEntity:
private PostingPostEntity readPostRecommendEntity(String fileName){
try {
String path = getImageDirectory(MobileApplication.FOLDER_NAME_RECOMMEND);
FileInputStream fis = new FileInputStream(path + File.separator + fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
PostingPostEntity postingPostEntity =null;
if(ois!=null){
postingPostEntity = (PostingPostEntity) ois.readObject();
}
ois.close();
fis.close();
return postingPostEntity;
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (OptionalDataException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
删除SD卡或者手机的缓存图片和目录:
public void clearRecommendCache() {
File dirFile = new File(getImageDirectory(MobileApplication.FOLDER_NAME_RECOMMEND));
if(! dirFile.exists()){
return;
}
File reName = new File(getImageDirectory(MobileApplication.FOLDER_NAME_RECOMMEND) + System.currentTimeMillis());
dirFile.renameTo(reName);
if (reName.isDirectory()) {
String[] children = reName.list();
for (int i = 0; i < children.length; i++) {
new File(reName, children[i]).delete();
}
}
reName.delete();
}
存储第一页数据:
<span style="white-space:pre"> </span>if(page==1){
InfoCache.infoUrls.clear();
InfoCache.infoImgs.clear();
for(int j=0;j<postingList.size();j++){
InfoCache.infoUrls.add(postingList.get(j).getForum_reply_id());
PostingPostEntity fpes=new PostingPostEntity();
String head_img1=postingList.get(j).getForum_reply_head();
<span style="white-space:pre"> </span>new AsynImageLoader().execute(head_img1);
fpes.setForum_reply_head(postingList.get(j).getForum_reply_id());
<span style="white-space:pre"> </span>fpes.setForum_reply_id(postingList.get(j).getForum_reply_id());
<span style="white-space:pre"> </span>fpes.setForum_reply_time(postingList.get(j).getForum_reply_time());
<span style="white-space:pre"> </span>fpes.setForum_reply_img(postingList.get(j).getForum_reply_img());
fpes.setForum_reply_title(postingList.get(j).getForum_reply_title());
fpes.setForum_area(postingList.get(j).getForum_area());
<span style="white-space:pre"> </span>......
savePostNewsEntity(fpes,postingList.get(j).getForum_reply_id());
}
}
通过uri来获取bitmap:
private Bitmap decodeUriAsBitmap(Uri uri) {
Bitmap bitmap = null;
try {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable=true;
opt.inInputShareable=true;
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri),null,opt);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return bitmap;
}
保存广告图片:
// private class AsynImageRecommendLoader extends AsyncTask<String, Void, Map<String,Bitmap>>{
// @Override
// protected Map<String, Bitmap> doInBackground(String... params) {
// try {
// Bitmap urlBitmaps = Tools.returnBitMap2(params[0]);
// if(urlBitmaps!=null){
// Map<String,Bitmap> maps=new HashMap<String,Bitmap>();
// maps.put(params[1], urlBitmaps);
// return maps;
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// return null;
// }
//
// @Override
// @SuppressWarnings({ "rawtypes", "unchecked" })
// protected void onPostExecute(Map<String, Bitmap> result) {
// super.onPostExecute(result);
// if(result!=null){
// Iterator iterator= result.entrySet().iterator();
// while(iterator.hasNext()){
// Map.Entry<String, Bitmap> entry=(Entry<String, Bitmap>) iterator.next();
// InfoCache.infoRecommendImgs.add(entry.getKey());
// saveBitmap2(entry.getKey(),entry.getValue());;
// }
// }else{
// InfoCache.infoRecommendImgs.add("");
// }
//
// }
// }
从Url中获取Bitmap:
// private class AsynImageLoader extends AsyncTask<String, Void, Bitmap>{
// @Override
// protected Bitmap doInBackground(String... params) {
// try {
// Bitmap urlBitmaps = Tools.returnBitMap(params[0]);
// if(urlBitmaps!=null){
// return urlBitmaps;
// }
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// return null;
// }
//
// @Override
// protected void onPostExecute(Bitmap result) {
// super.onPostExecute(result);
// if(result!=null){
// InfoCache.infoImgs.add(result.toString()+"_img");
// saveBitmap(result.toString()+"_img",result);;
// }else{
// InfoCache.infoImgs.add("");
// }
// }
// }
Disk缓存
可以简单的理解为将图片缓存到sd卡中~
由于内存缓存在程序关闭第二次进入时就清空了,对于一个十分常用的图片比如头像一类的~
我们希望不要每次进入应用都重新下载一遍,那就要用到disk缓存了,直接图片存到了本地,打开应用时直接获取显示~
网上获取图片的大部分逻辑顺序是
内存缓存中获取显示(强引用缓存池->弱引用缓存池) -> 内存中找不到时从sd卡缓存中获取显示 -> 缓存中都没有再建立异步线程下载图片,下载完成后保存至缓存中
按照获取图片获取效率的速度,由快到慢的依次尝试几个方法
以文件的形式缓存到SD卡中,优点是SD卡容量较大,所以可以缓存很多图片,且多次打开应用都可以使用缓存,
缺点是文件读写操作会耗费一点时间,
虽然速度没有从内存缓存中获取速度快,但是肯定比重新下载一张图片的速度快~而且还不用每次都下载图片浪费流量~
所以使用优先级就介于内存缓存和下载图片之间了
注意:
sd卡缓存一般要提前进行一下是否装载sd卡的检测, 还要检测sd卡剩余容量是否够用的情况
程序里也要添加注明相应的权限
推荐博客:
于是我用了手机缓存,大概思路就是先从SoftReference中获取图片,如果SoftReference没有就去手机缓存中获取,手机缓存中没有就开启先从去下载,然后成功的解决了OOM的问题
http://blog.youkuaiyun.com/jdsjlzx/article/details/21231551
http://blog.youkuaiyun.com/jdsjlzx/article/details/8853992
故现在增加一个缓存用来存储图片,缓存中包含内存存储和sdcard存储。先从缓存中去,在缓存中先从内存中取出,如果内存中没有再从sdcard去,如果sdcard中存在则直接返回该图片资源并放入内存中,如果两者都没有则从网络上下载,下载后并放入sdcard中供下次使用,这样就节约了资源开销
http://blog.youkuaiyun.com/jdsjlzx/article/details/8586885
http://blog.youkuaiyun.com/jdsjlzx/article/details/7871516(Android以最省内存的方式读取本地资源的方法)
http://blog.youkuaiyun.com/jdsjlzx/article/details/7609275(android,性能优化,内存优化管理,高级缓存)
-----------------------------------ASimpleCache--------------
定义:
private ACache mACache;
初始化:
mACache = ACache.get(this);
取出:
String result=mACache.getAsString("app_init");
存储(保存时间3天):
mACache.put("app_home",response,3* ACache.TIME_DAY);
历史: (转载自:https://github.com/yangfuhai/ASimpleCache)
ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。
- 特色主要是:
- 1:轻,轻到只有一个JAVA文件。
- 2:可配置,可以配置缓存路径,缓存大小,缓存数量等。
- 3:可以设置缓存超时时间,缓存超时自动失效,并被删除。
- 4:支持多进程。
##3、它在android中可以用在哪些场景?
- 1、替换SharePreference当做配置文件
- 2、可以缓存网络请求数据,比如oschina的android客户端可以缓存http请求的新闻内容,缓存时间假设为1个小时,超时后自动失效,让客户端重新请求新的数据,减少客户端流量,同时减少服务器并发量。
- 3、您来说...
##4、如何使用 ASimpleCache? 以下有个小的demo,希望您能喜欢:
ACache mCache = ACache.get(this);
mCache.put("test_key1", "test value");
mCache.put("test_key2", "test value", 10);//保存10秒,如果超过10秒去获取这个key,将为null
mCache.put("test_key3", "test value", 2 * ACache.TIME_DAY);//保存两天,如果超过两天去获取这个key,将为null
获取数据
ACache mCache = ACache.get(this);
String value = mCache.getAsString("test_key1");
#关于作者michael
- 屌丝程序员一枚,喜欢开源。
- 个人博客:http://www.yangfuhai.com
- 交流QQ群 : 192341294(已满) 246710918(未满)
http://blog.youkuaiyun.com/zhoubin1992/article/details/46379055
http://blog.youkuaiyun.com/working_harder/article/details/52269920
http://www.jb51.net/article/103282.htm
http://blog.youkuaiyun.com/superjunjin/article/details/45096805
----------------ASimpleCache----------------