游逛校园,书味满胸
时间:2017-11-17 18:09:43来源:杰瑞文章网点击:作文字数:400字
作文导读:一、缓存介绍:(一)、Android中缓存的必要性:智能手机的缓存管理应用非常的普遍和需要,是提高用户体验的有效手段之一。1、没有缓存的弊端:流量开销:对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量。加载速度:如果应用中图片加载速度很慢的话,那么用户体验会非常糟糕。那么如何处理好图片资源的获取和管理呢?异步下载+本地缓存2、缓存带来的好处:1. 服务器的压力大大减小;2. 客户端的响应速度大大变快(用户体验好);3. 客户端的数据加载出错情况大大较少,大大提高了应有的稳定性(用户体验好);4. 一定程度上可以支持离线浏览(或者说为离线浏览提供了技术支持)。3、缓存管理的应用场景:1. 提供网络服务的应用;2. 数据更新不需要实时更新,即便是允许3-5分钟的延迟也建议采用缓存机制;3. 缓存的过期时间是可以接受的(不会因为缓存带来的好处,导致某些数据因为更新不及时而影响产品的形象等)4、大位图导致内存开销大的原因是什么?1.下载或加载的过程中容易导致阻塞;大位图Bitmap对象是png格式的图片的30至100倍;2.大位图在加载到ImageView控件前的解码过程;BitmapFactory.decodeFile()会有内存消耗。5、缓存设计的要点:1.命中率;2.合理分配占用的空间;3.合理的缓存层级。(二)、加载图片的正确流程是:“内存-文件-网络 三层cache策略”1、先从内存缓存中获取,取到则返回,取不到则进行下一步;2、从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;3、从网络下载图片,并更新到内存缓存和文件缓存。具体说就是:同一张图片只要从网络获取一次,然后在本地缓存起来,之后加载同一张图片时就从缓存中去加载。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如10M,或者限定保存时间比如一天。在键值对(key-value)中,图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。(三)、内存缓存分类:在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因为也许将来还会派用场。对于这样的可有可无的物品,一种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃圾清除,还是无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。下图为对象层次的引用1、强引用:(在Android中LruCache就是强引用缓存)平时我们编程的时候例如:Object object=new Object();那object就是一个强引用了。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OOM异常,使程序异常终止,也不会回收具有强引用的对象来解决内存不足问题。2、软引用(SoftReference):软引用类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。使用软引用能防止内存泄露,增强程序的健壮性。3、弱引用(WeakReference):弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。4、虚引用(PhantomReference)"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。【相关应用:】在java.lang.ref包中提供了三个类:SoftReference类、WeakReference类和PhantomReference类,它们分别代表软引用、弱引用和虚引用。ReferenceQueue类表示引用队列,它可以和这三种引用类联合使用,以便跟踪Java虚拟机回收所引用的对 象的活动。Lru:Least Recently Used近期最少使用算法,是一种页面置换算法,其思想是在缓存的页面数目固定的情况下,那些最近使用次数最少的页面将被移出,对于我们的内存缓存来说,强引用缓存大小固定为4M,如果当缓存的图片大于4M的时候,有些图片就会被从强引用缓存中删除,哪些图片会被删除呢,就是那些近期使用次数最少的图片。(四)、内存保存:在内存中保存的话,只能保存一定的量,而不能一直往里面放,需要设置数据的过期时间、LRU等算法。这里有一个方法是把常用的数据放到一个缓存中(A),不常用的放到另外一个缓存中(B)。当要获取数据时先从A中去获取,如果A中不存在那么再去B中获取。B中的数据主要是A中LRU出来的数据,这里的内存回收主要针对B内存,从而保持A中的数据可以有效的被命中。(五)、缓存的案例代码:publicclassMainActivityextendsActivity {privatefinalstaticStringTAG="MainActivity";privateImageViewimageView_main;privateProgressDialogpDialog=null;privateStringurlString="http://c.hiphotos.baidu.com/image/pic/item/5366d0160924ab18dd54473737fae6cd7b890b6b.jpg";// private String urlString = "http://www.baidu.com/img/bdlogo.gif";privateLruCachelruCache=null;privateLinkedHashMap>softMap=newLinkedHashMap>();privateHandlerhandler=newHandler() {publicvoidhandleMessage(Message msg) {switch(msg.what) {case0:pDialog.show();break;case1:Bitmap bm = (Bitmap) msg.obj;if(bm !=null) {imageView_main.setImageBitmap(bm);}pDialog.dismiss();break;default:break;}}};@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView_main= (ImageView) findViewById(R.id.imageView_main);pDialog=newProgressDialog(this);pDialog.setIcon(R.drawable.ic_launcher);pDialog.setTitle("提示:");pDialog.setMessage("数据加载中。。。");//intmemClass = ((ActivityManager)// getSystemService(Context.ACTIVITY_SERVICE))// .getMemoryClass();intmemoryCount = (int) Runtime.getRuntime().maxMemory();// 获取剩余内存的8分之一作为缓存intcacheSize = memoryCount / 8;Log.i(TAG,"=="+ cacheSize);lruCache=newMyLruCache(cacheSize);// 这个初始化值是如何定义的?}classMyLruCacheextendsLruCache {publicMyLruCache(intmaxSize) {super(maxSize);}@OverrideprotectedintsizeOf(String key, Bitmap value) {// return value.getHeight() * value.getWidth() * 4;// Bitmap图片的一个像素是4个字节Log.i(TAG,"=="+ value.getByteCount());returnvalue.getByteCount();}@OverrideprotectedvoidentryRemoved(booleanevicted, String key,Bitmap oldValue, Bitmap newValue) {if(evicted) {SoftReference softReference =newSoftReference(oldValue);softMap.put(key, softReference);}}}publicvoidclickButton(View view) {switch(view.getId()) {caseR.id.button_main_submit:Bitmap bm = getBitmapFromMemoryCache(urlString);if(bm !=null) {imageView_main.setImageBitmap(bm);Log.i(TAG,"==从缓存中获取到的图片");}else{newThread(newRunnable() {@Overridepublicvoidrun() {handler.sendEmptyMessage(0);HttpClient httpClient =newDefaultHttpClient();HttpGet httpGet =newHttpGet(urlString);try{HttpResponse response = httpClient.execute(httpGet);if(response.getStatusLine().getStatusCode() == 200) {byte[] data = EntityUtils.toByteArray(response.getEntity());Log.i(TAG,"==文件尺寸:"+ data.length);Bitmap bm = BitmapFactory.decodeByteArray(data,0, data.length);// 放入强缓存lruCache.put(urlString, bm);Log.i(TAG,"==放入强缓存ok");Message msg = Message.obtain();msg.obj= bm;msg.what= 1;handler.sendMessage(msg);}}catch(IOException e) {e.printStackTrace();}}}).start();}break;default:break;}}publicBitmap getBitmapFromMemoryCache(String key) {// 1.先从强引用中获取Bitmap bitmap =null;bitmap =lruCache.get(key);if(bitmap !=null) {Log.i(TAG,"==从强引用中找到");returnbitmap;}else{// 2.如果强引用中没有找到的话 如果软引用中存在就将它移到强引用中 然后软引用移除SoftReference softReference =softMap.get(key);if(softReference !=null) {bitmap = softReference.get();Log.i(TAG,"==从软引用中找到");if(bitmap !=null) {// 添加到强引用中lruCache.put(key, bitmap);Log.i(TAG,"==添加到强引用中");// 从软引用集合中移除softMap.remove(key);Log.i(TAG,"==从软引用中移除");returnbitmap;}else{softMap.remove(key);}}}returnnull;}@OverridepublicbooleanonCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.next, menu);returntrue;}}二、封装异步任务类:(一)、AsynTaskHelper的核心代码:publicclassAsynTaskHelper {privatestaticfinalStringTAG="AsynTaskHelper";publicvoiddownloadData(String url, OnDataDownloadListener downloadListener) {newMyTask(downloadListener).execute(url);}privateclassMyTaskextendsAsyncTaskbyte[]> {privateOnDataDownloadListenerdownloadListener;publicMyTask(OnDataDownloadListener downloadListener) {this.downloadListener= downloadListener;}@Overrideprotectedbyte[] doInBackground(String... params) {BufferedInputStream bis =null;ByteArrayOutputStream baos =newByteArrayOutputStream();try{URL url =newURL(params[0]);HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();httpConn.setDoInput(true);httpConn.setRequestMethod("GET");httpConn.connect();if(httpConn.getResponseCode() == 200) {bis =newBufferedInputStream(httpConn.getInputStream());byte[] buffer =newbyte[1024 * 8];intc = 0;while((c = bis.read(buffer)) != -1) {baos.write(buffer, 0, c);baos.flush();}returnbaos.toByteArray();}}catch(Exception e) {e.printStackTrace();}returnnull;}@OverrideprotectedvoidonPostExecute(byte[] result) {// 通过回调接口来传递数据downloadListener.onDataDownload(result);super.onPostExecute(result);}}publicinterfaceOnDataDownloadListener {voidonDataDownload(byte[] result);}}三、带有缓存的异步加载图片类:(一)、ImageDownloader的核心代码:publicclassImageDownloadHelper {privatestaticfinalStringTAG="ImageDownloaderHelper";privateHashMapmap=newHashMap();privateMap>softCaches=newLinkedHashMap>();privateLruCachelruCache=null;publicImageDownloadHelper() {intmemoryAmount = (int) Runtime.getRuntime().maxMemory();// 获取剩余内存的8分之一作为缓存intcacheSize = memoryAmount / 8;if(lruCache==null) {lruCache=newMyLruCache(cacheSize);}Log.i(TAG,"==LruCache尺寸:"+ cacheSize);}/****@paramcontext*@paramurl* 该mImageView对应的url*@parammImageView*@parampath* 文件存储路径*@paramdownloadListener* OnImageDownload回调接口,在onPostExecute()中被调用*/publicvoidimageDownload(Context context, String url,ImageView mImageView, String path,OnImageDownloadListener downloadListener) {Bitmap bitmap =null;// 先从强引用中拿数据if(lruCache!=null) {bitmap =lruCache.get(url);}if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从强引用中找到数据");mImageView.setImageBitmap(bitmap);}else{SoftReference softReference =softCaches.get(url);if(softReference !=null) {bitmap = softReference.get();}// 从软引用中拿数据if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从软引用中找到数据");// 添加到强引用中lruCache.put(url, bitmap);Log.i(TAG,"==添加到强引用中");// 从软引用集合中移除softCaches.remove(url);mImageView.setImageBitmap(bitmap);}else{// 从文件缓存中拿数据String imageName ="";if(url !=null) {imageName = ImageDownloaderUtil.getInstance().getImageName(url);}bitmap = getBitmapFromFile(context, imageName, path);if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从文件缓存中找到数据");// 放入强缓存lruCache.put(url, bitmap);mImageView.setImageBitmap(bitmap);}else{// 从网络中拿数据if(url !=null&& needCreateNewTask(mImageView)) {MyAsyncTask task =newMyAsyncTask(context, url,mImageView, path, downloadListener);Log.i(TAG,"==从网络中拿数据");if(mImageView !=null) {task.execute();// 将对应的url对应的任务存起来map.put(url, task);}}}}}}/*** 判断是否需要重新创建线程下载图片,如果需要,返回值为true。**@paramurl*@parammImageView*@return*/privatebooleanneedCreateNewTask(ImageView mImageView) {booleanb =true;if(mImageView !=null) {String curr_task_url = (String) mImageView.getTag();if(isTasksContains(curr_task_url)) {b =false;}}returnb;}/*** 检查该url(最终反映的是当前的ImageView的tag,tag会根据position的不同而不同)对应的task是否存在**@paramurl*@return*/privatebooleanisTasksContains(String url) {booleanb =false;if(map!=null&&map.get(url) !=null) {b =true;}returnb;}/*** 删除map中该url的信息,这一步很重要,不然MyAsyncTask的引用会“一直”存在于map中**@paramurl*/privatevoidremoveTaskFromMap(String url) {if(url !=null&&map!=null&&map.get(url) !=null) {map.remove(url);Log.i(TAG,"当前map的大小=="+map.size());}}/*** 从文件中拿图片**@parammActivity*@paramimageName* 图片名字*@parampath* 图片路径*@return*/privateBitmap getBitmapFromFile(Context context, String imageName,String path) {Bitmap bitmap =null;if(imageName !=null) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path:"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(context)+ (path !=null&& path.startsWith("/") ? path:"/"+ path);}file =newFile(real_path, imageName);if(file.exists())bitmap = BitmapFactory.decodeStream(newFileInputStream(file));}catch(Exception e) {e.printStackTrace();bitmap =null;}}returnbitmap;}/*** 将下载好的图片存放到文件中**@parampath* 图片路径*@parammActivity*@paramimageName* 图片名字*@parambitmap* 图片*@return*/privatebooleansetBitmapToFile(String path, Context mActivity,String imageName, Bitmap bitmap) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(mActivity)+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}file =newFile(real_path, imageName);if(!file.exists()) {File file2 =newFile(real_path +"/");file2.mkdirs();}file.createNewFile();FileOutputStream fos =null;if(ImageDownloaderUtil.getInstance().hasSDCard()) {fos =newFileOutputStream(file);}else{fos = mActivity.openFileOutput(imageName, Context.MODE_PRIVATE);}if(imageName !=null&& (imageName.contains(".png") || imageName.contains(".PNG"))) {bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);}else{bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);}fos.flush();if(fos !=null) {fos.close();}returntrue;}catch(Exception e) {e.printStackTrace();returnfalse;}}/*** 辅助方法,一般不调用**@parampath*@parammActivity*@paramimageName*/privatevoidremoveBitmapFromFile(String path, Context mActivity,String imageName) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(mActivity)+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}file =newFile(real_path, imageName);if(file !=null)file.delete();}catch(Exception e) {e.printStackTrace();}}/*** 异步下载图片的方法**@author**/privateclassMyAsyncTaskextendsAsyncTask {privateContextcontext;privateImageViewmImageView;privateStringurl;privateOnImageDownloadListenerdownloadListener;privateStringpath;publicMyAsyncTask(Context context, String url, ImageView mImageView,String path, OnImageDownloadListener downloadListener) {this.context= context;this.url= url;this.mImageView= mImageView;this.path= path;this.downloadListener= downloadListener;}@OverrideprotectedBitmap doInBackground(String... params) {Bitmap bm =null;if(url!=null) {try{Log.i(TAG,"==访问网络加载图片");URL urlObj =newURL(url);HttpURLConnection httpConn = (HttpURLConnection) urlObj.openConnection();httpConn.setDoInput(true);httpConn.setRequestMethod("GET");httpConn.connect();if(httpConn.getResponseCode() == 200) {InputStream is = httpConn.getInputStream();bm = BitmapFactory.decodeStream(is);}String imageName = ImageDownloaderUtil.getInstance().getImageName(url);if(!setBitmapToFile(path,context, imageName, bm)) {removeBitmapFromFile(path,context, imageName);}// 放入强缓存lruCache.put(url, bm);Log.i(TAG,"==放入强缓存ok");}catch(Exception e) {e.printStackTrace();}}returnbm;}@OverrideprotectedvoidonPostExecute(Bitmap result) {// 回调设置图片if(downloadListener!=null) {downloadListener.onImageDownload(result,url);// 该url对应的task已经下载完成,从map中将其删除removeTaskFromMap(url);}super.onPostExecute(result);}}publicinterfaceOnImageDownloadListener {voidonImageDownload(Bitmap bitmap, String imgUrl);}// 定义强引用缓存classMyLruCacheextendsLruCache {publicMyLruCache(intmaxSize) {super(maxSize);}@OverrideprotectedintsizeOf(String key, Bitmap value) {// return value.getHeight() * value.getWidth() * 4;// Bitmap图片的一个像素是4个字节returnvalue.getByteCount();}@OverrideprotectedvoidentryRemoved(booleanevicted, String key,Bitmap oldValue, Bitmap newValue) {if(evicted) {SoftReference softReference =newSoftReference(oldValue);softCaches.put(key, softReference);}}}staticclassImageDownloaderUtil {privatestaticImageDownloaderUtilutil;privateImageDownloaderUtil() {}publicstaticImageDownloaderUtil getInstance() {if(util==null) {util=newImageDownloaderUtil();}returnutil;}/*** 判断是否有sdcard**@return*/publicbooleanhasSDCard() {booleanb =false;if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {b =true;}returnb;}/*** 得到sdcard路径**@return*/publicString getExtPath() {String path ="";if(hasSDCard()) {path = Environment.getExternalStorageDirectory().getPath();}returnpath;}/*** 得到包目录**@parammActivity*@return*/publicString getPackagePath(Context mActivity) {returnmActivity.getFilesDir().toString();}/*** 根据url得到图片名**@paramurl*@return*/publicString getImageName(String url) {String imageName ="";if(url !=null) {imageName = url.substring(url.lastIndexOf("/") + 1);}returnimageName;}}}(二)、应用举例:@Overridepublic View getView(int position, View convertView, ViewGroup parent) {final ViewHolder viewHolder;if (convertView == null) {viewHolder = new ViewHolder();convertView = LayoutInflater.from(context).inflate(R.layout.item_listview_main, null);viewHolder.CoverStoryImage = (ImageView) convertView.findViewById(R.id.CoverStoryImage);viewHolder.CoverStoryName = (TextView) convertView.findViewById(R.id.CoverStoryName);viewHolder.IssueDate = (TextView) convertView.findViewById(R.id.IssueDate);viewHolder.Issue = (TextView) convertView.findViewById(R.id.Issue);viewHolder.IssueYear = (TextView) convertView.findViewById(R.id.IssueYear);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.CoverStoryName.setText(dataList.get(position).get("CoverStoryName"));viewHolder.IssueDate.setText(dataList.get(position).get("IssueDate"));viewHolder.Issue.setText(dataList.get(position).get("Issue"));viewHolder.IssueYear.setText(dataList.get(position).get("IssueYear"));viewHolder.CoverStoryImage.setImageResource(R.drawable.defaultcovers);// 开始加载图片finalString urlString = dataList.get(position).get("CoverStoryImage");viewHolder.CoverStoryImage.setTag(urlString);Log.i(TAG, "settag:" + urlString);// 方法一:增加了缓存的异步加载图片if (mDownloader == null) {mDownloader = new ImageDownloader();}if (mDownloader != null) {// 异步下载图片mDownloader.imageDownload(urlString,viewHolder.CoverStoryImage, "/img_temp", context,new ImageDownloader.OnImageDownload() {@Overridepublic void onDownloadSuccess(Bitmap bitmap,String imgUrl, ImageView imageView) {ImageView image_item = (ImageView) imageView.findViewWithTag(imgUrl);if (image_item != null) {image_item.setImageBitmap(bitmap);image_item.setTag(null);Log.i(TAG, "findViewWithTag:" + imgUrl);} else {Log.i(TAG, "imageView is null:" + imgUrl); //???为什么会有为null的时候呢?}}});}return convertView;}class ViewHolder {private ImageView CoverStoryImage;private TextView CoverStoryName;private TextView IssueDate;private TextView Issue;private TextView IssueYear;}
一、缓存介绍:(一)、Android中缓存的必要性:智能手机的缓存管理应用非常的普遍和需要,是提高用户体验的有效手段之一。1、没有缓存的弊端:流量开销:对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量。加载速度:如果应用中图片加载速度很慢的话,那么用户体验会非常糟糕。那么如何处理好图片资源的获取和管理呢?异步下载+本地缓存2、缓存带来的好处:1. 服务器的压力大大减小;2. 客户端的响应速度大大变快(用户体验好);3. 客户端的数据加载出错情况大大较少,大大提高了应有的稳定性(用户体验好);4. 一定程度上可以支持离线浏览(或者说为离线浏览提供了技术支持)。3、缓存管理的应用场景:1. 提供网络服务的应用;2. 数据更新不需要实时更新,即便是允许3-5分钟的延迟也建议采用缓存机制;3. 缓存的过期时间是可以接受的(不会因为缓存带来的好处,导致某些数据因为更新不及时而影响产品的形象等)4、大位图导致内存开销大的原因是什么?1.下载或加载的过程中容易导致阻塞;大位图Bitmap对象是png格式的图片的30至100倍;2.大位图在加载到ImageView控件前的解码过程;BitmapFactory.decodeFile()会有内存消耗。5、缓存设计的要点:1.命中率;2.合理分配占用的空间;3.合理的缓存层级。(二)、加载图片的正确流程是:“内存-文件-网络 三层cache策略”1、先从内存缓存中获取,取到则返回,取不到则进行下一步;2、从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;3、从网络下载图片,并更新到内存缓存和文件缓存。具体说就是:同一张图片只要从网络获取一次,然后在本地缓存起来,之后加载同一张图片时就从缓存中去加载。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如10M,或者限定保存时间比如一天。在键值对(key-value)中,图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。(三)、内存缓存分类:在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因为也许将来还会派用场。对于这样的可有可无的物品,一种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃圾清除,还是无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。下图为对象层次的引用1、强引用:(在Android中LruCache就是强引用缓存)平时我们编程的时候例如:Object object=new Object();那object就是一个强引用了。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OOM异常,使程序异常终止,也不会回收具有强引用的对象来解决内存不足问题。2、软引用(SoftReference):软引用类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。使用软引用能防止内存泄露,增强程序的健壮性。3、弱引用(WeakReference):弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。4、虚引用(PhantomReference)"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。【相关应用:】在java.lang.ref包中提供了三个类:SoftReference类、WeakReference类和PhantomReference类,它们分别代表软引用、弱引用和虚引用。ReferenceQueue类表示引用队列,它可以和这三种引用类联合使用,以便跟踪Java虚拟机回收所引用的对 象的活动。Lru:Least Recently Used近期最少使用算法,是一种页面置换算法,其思想是在缓存的页面数目固定的情况下,那些最近使用次数最少的页面将被移出,对于我们的内存缓存来说,强引用缓存大小固定为4M,如果当缓存的图片大于4M的时候,有些图片就会被从强引用缓存中删除,哪些图片会被删除呢,就是那些近期使用次数最少的图片。(四)、内存保存:在内存中保存的话,只能保存一定的量,而不能一直往里面放,需要设置数据的过期时间、LRU等算法。这里有一个方法是把常用的数据放到一个缓存中(A),不常用的放到另外一个缓存中(B)。当要获取数据时先从A中去获取,如果A中不存在那么再去B中获取。B中的数据主要是A中LRU出来的数据,这里的内存回收主要针对B内存,从而保持A中的数据可以有效的被命中。(五)、缓存的案例代码:publicclassMainActivityextendsActivity {privatefinalstaticStringTAG="MainActivity";privateImageViewimageView_main;privateProgressDialogpDialog=null;privateStringurlString="http://c.hiphotos.baidu.com/image/pic/item/5366d0160924ab18dd54473737fae6cd7b890b6b.jpg";// private String urlString = "http://www.baidu.com/img/bdlogo.gif";privateLruCachelruCache=null;privateLinkedHashMap>softMap=newLinkedHashMap>();privateHandlerhandler=newHandler() {publicvoidhandleMessage(Message msg) {switch(msg.what) {case0:pDialog.show();break;case1:Bitmap bm = (Bitmap) msg.obj;if(bm !=null) {imageView_main.setImageBitmap(bm);}pDialog.dismiss();break;default:break;}}};@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView_main= (ImageView) findViewById(R.id.imageView_main);pDialog=newProgressDialog(this);pDialog.setIcon(R.drawable.ic_launcher);pDialog.setTitle("提示:");pDialog.setMessage("数据加载中。。。");//intmemClass = ((ActivityManager)// getSystemService(Context.ACTIVITY_SERVICE))// .getMemoryClass();intmemoryCount = (int) Runtime.getRuntime().maxMemory();// 获取剩余内存的8分之一作为缓存intcacheSize = memoryCount / 8;Log.i(TAG,"=="+ cacheSize);lruCache=newMyLruCache(cacheSize);// 这个初始化值是如何定义的?}classMyLruCacheextendsLruCache {publicMyLruCache(intmaxSize) {super(maxSize);}@OverrideprotectedintsizeOf(String key, Bitmap value) {// return value.getHeight() * value.getWidth() * 4;// Bitmap图片的一个像素是4个字节Log.i(TAG,"=="+ value.getByteCount());returnvalue.getByteCount();}@OverrideprotectedvoidentryRemoved(booleanevicted, String key,Bitmap oldValue, Bitmap newValue) {if(evicted) {SoftReference softReference =newSoftReference(oldValue);softMap.put(key, softReference);}}}publicvoidclickButton(View view) {switch(view.getId()) {caseR.id.button_main_submit:Bitmap bm = getBitmapFromMemoryCache(urlString);if(bm !=null) {imageView_main.setImageBitmap(bm);Log.i(TAG,"==从缓存中获取到的图片");}else{newThread(newRunnable() {@Overridepublicvoidrun() {handler.sendEmptyMessage(0);HttpClient httpClient =newDefaultHttpClient();HttpGet httpGet =newHttpGet(urlString);try{HttpResponse response = httpClient.execute(httpGet);if(response.getStatusLine().getStatusCode() == 200) {byte[] data = EntityUtils.toByteArray(response.getEntity());Log.i(TAG,"==文件尺寸:"+ data.length);Bitmap bm = BitmapFactory.decodeByteArray(data,0, data.length);// 放入强缓存lruCache.put(urlString, bm);Log.i(TAG,"==放入强缓存ok");Message msg = Message.obtain();msg.obj= bm;msg.what= 1;handler.sendMessage(msg);}}catch(IOException e) {e.printStackTrace();}}}).start();}break;default:break;}}publicBitmap getBitmapFromMemoryCache(String key) {// 1.先从强引用中获取Bitmap bitmap =null;bitmap =lruCache.get(key);if(bitmap !=null) {Log.i(TAG,"==从强引用中找到");returnbitmap;}else{// 2.如果强引用中没有找到的话 如果软引用中存在就将它移到强引用中 然后软引用移除SoftReference softReference =softMap.get(key);if(softReference !=null) {bitmap = softReference.get();Log.i(TAG,"==从软引用中找到");if(bitmap !=null) {// 添加到强引用中lruCache.put(key, bitmap);Log.i(TAG,"==添加到强引用中");// 从软引用集合中移除softMap.remove(key);Log.i(TAG,"==从软引用中移除");returnbitmap;}else{softMap.remove(key);}}}returnnull;}@OverridepublicbooleanonCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.next, menu);returntrue;}}二、封装异步任务类:(一)、AsynTaskHelper的核心代码:publicclassAsynTaskHelper {privatestaticfinalStringTAG="AsynTaskHelper";publicvoiddownloadData(String url, OnDataDownloadListener downloadListener) {newMyTask(downloadListener).execute(url);}privateclassMyTaskextendsAsyncTaskbyte[]> {privateOnDataDownloadListenerdownloadListener;publicMyTask(OnDataDownloadListener downloadListener) {this.downloadListener= downloadListener;}@Overrideprotectedbyte[] doInBackground(String... params) {BufferedInputStream bis =null;ByteArrayOutputStream baos =newByteArrayOutputStream();try{URL url =newURL(params[0]);HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();httpConn.setDoInput(true);httpConn.setRequestMethod("GET");httpConn.connect();if(httpConn.getResponseCode() == 200) {bis =newBufferedInputStream(httpConn.getInputStream());byte[] buffer =newbyte[1024 * 8];intc = 0;while((c = bis.read(buffer)) != -1) {baos.write(buffer, 0, c);baos.flush();}returnbaos.toByteArray();}}catch(Exception e) {e.printStackTrace();}returnnull;}@OverrideprotectedvoidonPostExecute(byte[] result) {// 通过回调接口来传递数据downloadListener.onDataDownload(result);super.onPostExecute(result);}}publicinterfaceOnDataDownloadListener {voidonDataDownload(byte[] result);}}三、带有缓存的异步加载图片类:(一)、ImageDownloader的核心代码:publicclassImageDownloadHelper {privatestaticfinalStringTAG="ImageDownloaderHelper";privateHashMapmap=newHashMap();privateMap>softCaches=newLinkedHashMap>();privateLruCachelruCache=null;publicImageDownloadHelper() {intmemoryAmount = (int) Runtime.getRuntime().maxMemory();// 获取剩余内存的8分之一作为缓存intcacheSize = memoryAmount / 8;if(lruCache==null) {lruCache=newMyLruCache(cacheSize);}Log.i(TAG,"==LruCache尺寸:"+ cacheSize);}/****@paramcontext*@paramurl* 该mImageView对应的url*@parammImageView*@parampath* 文件存储路径*@paramdownloadListener* OnImageDownload回调接口,在onPostExecute()中被调用*/publicvoidimageDownload(Context context, String url,ImageView mImageView, String path,OnImageDownloadListener downloadListener) {Bitmap bitmap =null;// 先从强引用中拿数据if(lruCache!=null) {bitmap =lruCache.get(url);}if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从强引用中找到数据");mImageView.setImageBitmap(bitmap);}else{SoftReference softReference =softCaches.get(url);if(softReference !=null) {bitmap = softReference.get();}// 从软引用中拿数据if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从软引用中找到数据");// 添加到强引用中lruCache.put(url, bitmap);Log.i(TAG,"==添加到强引用中");// 从软引用集合中移除softCaches.remove(url);mImageView.setImageBitmap(bitmap);}else{// 从文件缓存中拿数据String imageName ="";if(url !=null) {imageName = ImageDownloaderUtil.getInstance().getImageName(url);}bitmap = getBitmapFromFile(context, imageName, path);if(bitmap !=null&& url.equals(mImageView.getTag())) {Log.i(TAG,"==从文件缓存中找到数据");// 放入强缓存lruCache.put(url, bitmap);mImageView.setImageBitmap(bitmap);}else{// 从网络中拿数据if(url !=null&& needCreateNewTask(mImageView)) {MyAsyncTask task =newMyAsyncTask(context, url,mImageView, path, downloadListener);Log.i(TAG,"==从网络中拿数据");if(mImageView !=null) {task.execute();// 将对应的url对应的任务存起来map.put(url, task);}}}}}}/*** 判断是否需要重新创建线程下载图片,如果需要,返回值为true。**@paramurl*@parammImageView*@return*/privatebooleanneedCreateNewTask(ImageView mImageView) {booleanb =true;if(mImageView !=null) {String curr_task_url = (String) mImageView.getTag();if(isTasksContains(curr_task_url)) {b =false;}}returnb;}/*** 检查该url(最终反映的是当前的ImageView的tag,tag会根据position的不同而不同)对应的task是否存在**@paramurl*@return*/privatebooleanisTasksContains(String url) {booleanb =false;if(map!=null&&map.get(url) !=null) {b =true;}returnb;}/*** 删除map中该url的信息,这一步很重要,不然MyAsyncTask的引用会“一直”存在于map中**@paramurl*/privatevoidremoveTaskFromMap(String url) {if(url !=null&&map!=null&&map.get(url) !=null) {map.remove(url);Log.i(TAG,"当前map的大小=="+map.size());}}/*** 从文件中拿图片**@parammActivity*@paramimageName* 图片名字*@parampath* 图片路径*@return*/privateBitmap getBitmapFromFile(Context context, String imageName,String path) {Bitmap bitmap =null;if(imageName !=null) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path:"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(context)+ (path !=null&& path.startsWith("/") ? path:"/"+ path);}file =newFile(real_path, imageName);if(file.exists())bitmap = BitmapFactory.decodeStream(newFileInputStream(file));}catch(Exception e) {e.printStackTrace();bitmap =null;}}returnbitmap;}/*** 将下载好的图片存放到文件中**@parampath* 图片路径*@parammActivity*@paramimageName* 图片名字*@parambitmap* 图片*@return*/privatebooleansetBitmapToFile(String path, Context mActivity,String imageName, Bitmap bitmap) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(mActivity)+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}file =newFile(real_path, imageName);if(!file.exists()) {File file2 =newFile(real_path +"/");file2.mkdirs();}file.createNewFile();FileOutputStream fos =null;if(ImageDownloaderUtil.getInstance().hasSDCard()) {fos =newFileOutputStream(file);}else{fos = mActivity.openFileOutput(imageName, Context.MODE_PRIVATE);}if(imageName !=null&& (imageName.contains(".png") || imageName.contains(".PNG"))) {bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);}else{bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);}fos.flush();if(fos !=null) {fos.close();}returntrue;}catch(Exception e) {e.printStackTrace();returnfalse;}}/*** 辅助方法,一般不调用**@parampath*@parammActivity*@paramimageName*/privatevoidremoveBitmapFromFile(String path, Context mActivity,String imageName) {File file =null;String real_path ="";try{if(ImageDownloaderUtil.getInstance().hasSDCard()) {real_path = ImageDownloaderUtil.getInstance().getExtPath()+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}else{real_path = ImageDownloaderUtil.getInstance().getPackagePath(mActivity)+ (path !=null&& path.startsWith("/") ? path :"/"+ path);}file =newFile(real_path, imageName);if(file !=null)file.delete();}catch(Exception e) {e.printStackTrace();}}/*** 异步下载图片的方法**@author**/privateclassMyAsyncTaskextendsAsyncTask {privateContextcontext;privateImageViewmImageView;privateStringurl;privateOnImageDownloadListenerdownloadListener;privateStringpath;publicMyAsyncTask(Context context, String url, ImageView mImageView,String path, OnImageDownloadListener downloadListener) {this.context= context;this.url= url;this.mImageView= mImageView;this.path= path;this.downloadListener= downloadListener;}@OverrideprotectedBitmap doInBackground(String... params) {Bitmap bm =null;if(url!=null) {try{Log.i(TAG,"==访问网络加载图片");URL urlObj =newURL(url);HttpURLConnection httpConn = (HttpURLConnection) urlObj.openConnection();httpConn.setDoInput(true);httpConn.setRequestMethod("GET");httpConn.connect();if(httpConn.getResponseCode() == 200) {InputStream is = httpConn.getInputStream();bm = BitmapFactory.decodeStream(is);}String imageName = ImageDownloaderUtil.getInstance().getImageName(url);if(!setBitmapToFile(path,context, imageName, bm)) {removeBitmapFromFile(path,context, imageName);}// 放入强缓存lruCache.put(url, bm);Log.i(TAG,"==放入强缓存ok");}catch(Exception e) {e.printStackTrace();}}returnbm;}@OverrideprotectedvoidonPostExecute(Bitmap result) {// 回调设置图片if(downloadListener!=null) {downloadListener.onImageDownload(result,url);// 该url对应的task已经下载完成,从map中将其删除removeTaskFromMap(url);}super.onPostExecute(result);}}publicinterfaceOnImageDownloadListener {voidonImageDownload(Bitmap bitmap, String imgUrl);}// 定义强引用缓存classMyLruCacheextendsLruCache {publicMyLruCache(intmaxSize) {super(maxSize);}@OverrideprotectedintsizeOf(String key, Bitmap value) {// return value.getHeight() * value.getWidth() * 4;// Bitmap图片的一个像素是4个字节returnvalue.getByteCount();}@OverrideprotectedvoidentryRemoved(booleanevicted, String key,Bitmap oldValue, Bitmap newValue) {if(evicted) {SoftReference softReference =newSoftReference(oldValue);softCaches.put(key, softReference);}}}staticclassImageDownloaderUtil {privatestaticImageDownloaderUtilutil;privateImageDownloaderUtil() {}publicstaticImageDownloaderUtil getInstance() {if(util==null) {util=newImageDownloaderUtil();}returnutil;}/*** 判断是否有sdcard**@return*/publicbooleanhasSDCard() {booleanb =false;if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {b =true;}returnb;}/*** 得到sdcard路径**@return*/publicString getExtPath() {String path ="";if(hasSDCard()) {path = Environment.getExternalStorageDirectory().getPath();}returnpath;}/*** 得到包目录**@parammActivity*@return*/publicString getPackagePath(Context mActivity) {returnmActivity.getFilesDir().toString();}/*** 根据url得到图片名**@paramurl*@return*/publicString getImageName(String url) {String imageName ="";if(url !=null) {imageName = url.substring(url.lastIndexOf("/") + 1);}returnimageName;}}}(二)、应用举例:@Overridepublic View getView(int position, View convertView, ViewGroup parent) {final ViewHolder viewHolder;if (convertView == null) {viewHolder = new ViewHolder();convertView = LayoutInflater.from(context).inflate(R.layout.item_listview_main, null);viewHolder.CoverStoryImage = (ImageView) convertView.findViewById(R.id.CoverStoryImage);viewHolder.CoverStoryName = (TextView) convertView.findViewById(R.id.CoverStoryName);viewHolder.IssueDate = (TextView) convertView.findViewById(R.id.IssueDate);viewHolder.Issue = (TextView) convertView.findViewById(R.id.Issue);viewHolder.IssueYear = (TextView) convertView.findViewById(R.id.IssueYear);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.CoverStoryName.setText(dataList.get(position).get("CoverStoryName"));viewHolder.IssueDate.setText(dataList.get(position).get("IssueDate"));viewHolder.Issue.setText(dataList.get(position).get("Issue"));viewHolder.IssueYear.setText(dataList.get(position).get("IssueYear"));viewHolder.CoverStoryImage.setImageResource(R.drawable.defaultcovers);// 开始加载图片finalString urlString = dataList.get(position).get("CoverStoryImage");viewHolder.CoverStoryImage.setTag(urlString);Log.i(TAG, "settag:" + urlString);// 方法一:增加了缓存的异步加载图片if (mDownloader == null) {mDownloader = new ImageDownloader();}if (mDownloader != null) {// 异步下载图片mDownloader.imageDownload(urlString,viewHolder.CoverStoryImage, "/img_temp", context,new ImageDownloader.OnImageDownload() {@Overridepublic void onDownloadSuccess(Bitmap bitmap,String imgUrl, ImageView imageView) {ImageView image_item = (ImageView) imageView.findViewWithTag(imgUrl);if (image_item != null) {image_item.setImageBitmap(bitmap);image_item.setTag(null);Log.i(TAG, "findViewWithTag:" + imgUrl);} else {Log.i(TAG, "imageView is null:" + imgUrl); //???为什么会有为null的时候呢?}}});}return convertView;}class ViewHolder {private ImageView CoverStoryImage;private TextView CoverStoryName;private TextView IssueDate;private TextView Issue;private TextView IssueYear;}

游逛校园,书味满胸一文由杰瑞文章网免费提供,本站为公益性作文网站,此作文为网上收集或网友提供,版权归原作者所有,如果侵犯了您的权益,请及时与我们联系,我们会立即删除!
杰瑞文章网友情提示:请不要直接抄作文用来交作业。你可以学习、借鉴、期待你写出更好的作文。
说说你对这篇作文的看法吧