安卓图片的异步请求及使用LruCache缓存和手机内存两层存储图片,避免重新加载页面带来的重新请求

我只是一个虾纸丫 提交于 2019-12-01 15:37:26

    看到网友的一片技术博客讲解了LruCache的使用,我把它加到了我的项目中,但是加入断点发现,列表上下滑动时,确实可以不用重新加载图片,但是重新打开这个activity或者重新启动应用,LruCache的缓存都不再存在,而需要重新联网下载,所有我对这个方法加以改进,加入了一层往手机内存存储图片的过程。

    这样的话,使用图片时,先从LruCache中加载,如果LruCache中不存在该图片资源的话,再从手机存储中进行加载,如果同样不存在,则先显示一个默认图片。

    另一方面,我的项目使用图片的是listview,在它滑动的时候,不进行请求图片的操作,以免浪费不必要的流量,在它不滑动的时候,会检查哪些图片没有在手机存储中,进行异步请求,并将返回的bitmap同时存储在LruCache和手机存储中。

    下面是关键代码,其中有一些是我项目中的变量,可以忽略:

public class TaocanListAdapter extends BaseAdapter implements OnScrollListener{
		 /** 
		 * 记录所有正在下载或等待下载的任务。 
		 */  
	    private Set<BitmapWorkerTask> taskCollection;  
	  
	    /** 
	     * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 
	     */  
	    private LruCache<String, Bitmap> mMemoryCache;    
	  
	    /** 
	     * 第一张可见图片的下标 
	     */  
	    private int mFirstVisibleItem;  
	  
	    /** 
	     * 一屏有多少张图片可见 
	     */  
	    private int mVisibleItemCount;  
	    
	    /** 
	     * 记录是否刚打开程序,用于解决进入程序不滚动屏幕,不会下载图片的问题。 
	     */  
	    private boolean isFirstEnter = true;  
		
		final OnCheckedChangeListener checkedChangeListener = new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(CompoundButton btn, boolean value) {
				if(value){
					if(yixuanNum < xuanXiangNum){
						//值有改变则设为1
						btn.setTag(R.id.tag_check, 1);
						yixuanNum += 1;
						checkedTaocanIdList.add((String)btn.getTag(R.id.tag_dataid));
					}else{
						Toast.makeText(TaoCanActivity.this, "最多能选" + xuanXiangNum + "个", Toast.LENGTH_SHORT).show();
						btn.setChecked(false);
					}
				}else{
					checkedTaocanIdList.remove((String)btn.getTag(R.id.tag_dataid));
					yixuanNum -= 1;
				}
				
			}
		};
		
		public TaocanListAdapter(){
			super();
			taskCollection = new HashSet<BitmapWorkerTask>();  
	        // 获取应用程序最大可用内存  
	        int maxMemory = (int) Runtime.getRuntime().maxMemory();  
	        int cacheSize = maxMemory / 8;  
	        // 设置图片缓存大小为程序最大可用内存的1/8  
	        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
	            @Override  
	            protected int sizeOf(String key, Bitmap bitmap) {  
	                return bitmap.getByteCount();  
	            }  
	        };  
	        taocanListView.setOnScrollListener(this);  
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup arg2) {
			ViewHolder holder = null;
			if(convertView == null){
				convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.taocan_list_item, null);
				holder = new ViewHolder();
				holder.taocan_caiImg = (ImageView)convertView.findViewById(R.id.taocan_caiImg);
				holder.taocan_caiming_text = (TextView)convertView.findViewById(R.id.taocan_caiming_text);
				holder.taocan_caiming_jiage = (TextView)convertView.findViewById(R.id.taocan_caiming_jiage);
				holder.taocan_tianjia_btn = (CheckBox)convertView.findViewById(R.id.taocan_tianjia_btn);
				convertView.setTag(holder);
			}
			holder = (ViewHolder)convertView.getTag();
			Taocan taocan = taocanList.get(position);
			holder.taocan_caiming_text.setText(taocan.getFoodCnName());
			holder.taocan_caiming_jiage.setText(taocan.getPrice() + " 元/" + taocan.getUnit());
			holder.taocan_tianjia_btn.setTag(R.id.tag_dataid, taocan.getFoodId());
			if(position < xuanXiangNum && holder.taocan_tianjia_btn.getTag(R.id.tag_check) == null){
				holder.taocan_tianjia_btn.setChecked(true);
				yixuanNum += 1;
				checkedTaocanIdList.add(taocan.getFoodId());
			}
			holder.taocan_tianjia_btn.setOnCheckedChangeListener(checkedChangeListener);
			
			if(taocan.getPhotoPath() != null && !taocan.getPhotoPath().equals("")){
				String imgurl = globalVariables.getEdnpointOut() + "/food/" + taocan.getPhotoPath();
				holder.taocan_caiImg.setTag(imgurl);
				setImageView(imgurl, holder.taocan_caiImg);
			}else{
				holder.taocan_caiImg.setImageDrawable(getResources().getDrawable(R.drawable.cai));
			}
			return convertView;
		}
		
		@Override
		public long getItemId(int arg0) {
			return 0;
		}
		
		@Override
		public Object getItem(int arg0) {
			return null;
		}
		
		@Override
		public int getCount() {
			return taocanList.size();
		}

	    @Override  
	    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
	            int totalItemCount) {  
	        mFirstVisibleItem = firstVisibleItem;  
	        mVisibleItemCount = visibleItemCount;  
	        // 下载的任务应该由onScrollStateChanged里调用,但首次进入程序时onScrollStateChanged并不会调用,  
	        // 因此在这里为首次进入程序开启下载任务。  
	        if (isFirstEnter && visibleItemCount > 0) {  
	            loadBitmaps(firstVisibleItem, visibleItemCount);  
	            isFirstEnter = false;  
	        }  
	    }  
	    
	    @Override  
	    public void onScrollStateChanged(AbsListView view, int scrollState) {  
	        // 仅当GridView静止时才去下载图片,GridView滑动时取消所有正在下载的任务  
	        if (scrollState == SCROLL_STATE_IDLE) {  
	            loadBitmaps(mFirstVisibleItem, mVisibleItemCount);  
	        } else {  
	            cancelAllTasks();  
	        }  
	    } 
		
		 /** 
	     * 给ImageView设置图片。首先从LruCache中取出图片的缓存,设置到ImageView上。如果LruCache中没有该图片的缓存, 
	     * 就给ImageView设置一张默认图片。 
	     *  
	     * @param imageUrl 
	     *            图片的URL地址,用于作为LruCache的键。 
	     * @param imageView 
	     *            用于显示图片的控件。 
	     */  
	    private void setImageView(String imageUrl, ImageView imageView) {  
	        Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);  
	        if (bitmap != null) {  
	            imageView.setImageBitmap(bitmap);  
	        } else {  
	        	/**   
	             * 对本地缓存的查找   
	             */    
	        	Bitmap bitmap1 = findImgFromStorage(imageUrl);
	        	imageView.setImageBitmap(bitmap1);  
	            if(bitmap1 == null){
	            	imageView.setImageResource(R.drawable.cai);  
	            }
	        }  
	    }  
	    
	    /**   
         * 对本地缓存的查找   
         */
	    public Bitmap findImgFromStorage(String imageUrl) {
			 String bitmapName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);  
	         String path = Environment.getExternalStorageDirectory().getPath();
	         File cacheDir = new File(path + "/mkb/");    
	         File[] cacheFiles = cacheDir.listFiles();    
	         int i = 0;    
	         if(null != cacheFiles){   
	            for(; i<cacheFiles.length; i++)  {    
	                if(bitmapName.equals(cacheFiles[i].getName())) {    
	                    break;    
	                }    
	            }    
	            if(i < cacheFiles.length) {   
	            	return BitmapFactory.decodeFile(path + "/mkb/" + bitmapName);  
	            	 
	            }  
	         }  
			return null;
		}
		
		/** 
	     * 将一张图片存储到LruCache中。 
	     *  
	     * @param key 
	     *            LruCache的键,这里传入图片的URL地址。 
	     * @param bitmap 
	     *            LruCache的键,这里传入从网络上下载的Bitmap对象。 
	     */  
	    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
	        if (getBitmapFromMemoryCache(key) == null) {  
	            mMemoryCache.put(key, bitmap);  
	        }  
	    }  
		
		/** 
	     * 从LruCache中获取一张图片,如果不存在就返回null。 
	     *  
	     * @param key 
	     *            LruCache的键,这里传入图片的URL地址。 
	     * @return 对应传入键的Bitmap对象,或者null。 
	     */  
	    public Bitmap getBitmapFromMemoryCache(String key) {  
	        return mMemoryCache.get(key);  
	    }  
		
		/** 
	     * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象, 
	     * 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。 
	     *  
	     * @param firstVisibleItem 
	     *            第一个可见的ImageView的下标 
	     * @param visibleItemCount 
	     *            屏幕中总共可见的元素数 
	     */  
	    private void loadBitmaps(int firstVisibleItem, int visibleItemCount) {  
	        try {  
	            for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {  
	            	Taocan taocan = taocanList.get(i);
	            	if(taocan.getPhotoPath() != null && !taocan.getPhotoPath().equals("")){
	            		Bitmap bitmap1 = findImgFromStorage(taocan.getPhotoPath());
	            		//如果内存中不存在则重新请求
	    	            if(bitmap1 == null){
	    	            	String imageUrl = globalVariables.getEdnpointOut() + "/food/" + taocan.getPhotoPath();
	    	                Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);  
	    	                if (bitmap == null) {  
	    	                    BitmapWorkerTask task = new BitmapWorkerTask();  
	    	                    taskCollection.add(task);  
	    	                    task.execute(imageUrl);  
	    	                } else {  
	    	                    ImageView imageView = (ImageView) taocanListView.findViewWithTag(imageUrl);  
	    	                    if (imageView != null && bitmap != null) {  
	    	                        imageView.setImageBitmap(bitmap);  
	    	                    }  
	    	                }  
	    	            }
	    	        }
	                
	            }  
	        } catch (Exception e) {  
	            e.printStackTrace();  
	        }  
	    }  
		
		
		 /** 
	     * 取消所有正在下载或等待下载的任务。 
	     */  
	    public void cancelAllTasks() {  
	        if (taskCollection != null) {  
	            for (BitmapWorkerTask task : taskCollection) {  
	                task.cancel(false);  
	            }  
	        }  
	    }  
		
		/** 
	     * 异步下载图片的任务。 
	     *  
	     * @author zhangda
	     */  
	    class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {  
	  
	        /** 
	         * 图片的URL地址 
	         */  
	        private String imageUrl;  
	  
	        @Override  
	        protected Bitmap doInBackground(String... params) {  
	            imageUrl = params[0];  
	            // 在后台开始下载图片  
	            Bitmap bitmap = downloadBitmap(params[0]);  
	            if (bitmap != null) {  
	                // 图片下载完成后缓存到LrcCache中  
	                addBitmapToMemoryCache(params[0], bitmap);  
	            }  
	            
	          //存储至手机内存中
	            String path = Environment.getExternalStorageDirectory().getPath();
	            File dir = new File(path + "/mkb/");    
                if(!dir.exists())    
                {    
                    dir.mkdirs();    
                }    
                    
                File bitmapFile = new File(path + "/mkb/" + imageUrl.substring(imageUrl.lastIndexOf("/") + 1));    
                if(!bitmapFile.exists())    
                {    
                    try {    
                        bitmapFile.createNewFile();    
                    }    
                    catch (IOException e) {    
                        e.printStackTrace();    
                    }    
                }    
                FileOutputStream fos;    
                try    
                {    
                    fos = new FileOutputStream(bitmapFile);    
                    bitmap.compress(Bitmap.CompressFormat.PNG,     
                            100, fos);    
                    fos.close();    
                }    
                catch (FileNotFoundException e)    
                {    
                    e.printStackTrace();    
                }    
                catch (IOException e)    
                {    
                    e.printStackTrace();    
                }
                
	            return bitmap;  
	        }  
	  
	        @Override  
	        protected void onPostExecute(Bitmap bitmap) {  
	            super.onPostExecute(bitmap);  
	            // 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。  
	            ImageView imageView = (ImageView) taocanListView.findViewWithTag(imageUrl);  
	            if (imageView != null && bitmap != null) {  
	                imageView.setImageBitmap(bitmap);  
	            }  
	            taskCollection.remove(this);  
	        }  
	  
	        /** 
	         * 建立HTTP请求,并获取Bitmap对象。 
	         *  
	         * @param imageUrl 
	         *            图片的URL地址 
	         * @return 解析后的Bitmap对象 
	         */  
	        private Bitmap downloadBitmap(String imageUrl) {  
	            Bitmap bitmap = null;  
	            HttpURLConnection con = null;  
	            try {  
	                URL url = new URL(imageUrl);  
	                con = (HttpURLConnection) url.openConnection();  
	                con.setConnectTimeout(5 * 1000);  
	                con.setReadTimeout(10 * 1000);  
	                bitmap = BitmapFactory.decodeStream(con.getInputStream());  
	            } catch (Exception e) {  
	                e.printStackTrace();  
	            } finally {  
	                if (con != null) {  
	                    con.disconnect();  
	                }  
	            }  
	            return bitmap;  
	        }  
	  
	    }  
	    
	    
	    private class ViewHolder{
			private ImageView taocan_caiImg;
			private TextView taocan_caiming_text;
			private TextView taocan_caiming_jiage;
			private CheckBox taocan_tianjia_btn;
		}
	}



adapter = new TaocanListAdapter();
taocanListView.setAdapter(adapter);




标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!