安卓圖片的異步請求及使用LruCache緩存和手機內存兩層存儲圖片,避免從新加載頁面帶來的從新請求

    看到網友的一片技術博客講解了LruCache的使用,我把它加到了個人項目中,可是加入斷點發現,列表上下滑動時,確實能夠不用從新加載圖片,可是從新打開這個activity或者從新啓動應用,LruCache的緩存都再也不存在,而須要從新聯網下載,全部我對這個方法加以改進,加入了一層往手機內存存儲圖片的過程。 java

    這樣的話,使用圖片時,先從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);
相關文章
相關標籤/搜索