缓存页面数据(对象+图片)

需求:一个页面里面有图片,对象,第一次进入的时候缓存进手机,下次如果没有网络,则进入该页面的时候,就不会木有东西了。如果在有网络的情况下,网速比较的慢,那么先读取本地手机数据会比网络快,先展示手机里面的东西,当网络上的数据加载完之后,则更新网络上的数据;

大概思路: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.csdn.net/jdsjlzx/article/details/21231551

http://blog.csdn.net/jdsjlzx/article/details/8853992
故现在增加一个缓存用来存储图片,缓存中包含内存存储和sdcard存储。先从缓存中去,在缓存中先从内存中取出,如果内存中没有再从sdcard去,如果sdcard中存在则直接返回该图片资源并放入内存中,如果两者都没有则从网络上下载,下载后并放入sdcard中供下次使用,这样就节约了资源开销

http://blog.csdn.net/jdsjlzx/article/details/8586885

http://blog.csdn.net/jdsjlzx/article/details/7871516(Android以最省内存的方式读取本地资源的方法)

http://blog.csdn.net/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.csdn.net/zhoubin1992/article/details/46379055

http://blog.csdn.net/working_harder/article/details/52269920

http://www.jb51.net/article/103282.htm

http://blog.csdn.net/superjunjin/article/details/45096805

----------------ASimpleCache----------------




----------------------------------- ASimpleCache
----------------------------------- ASimpleCache

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值