多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > 異步下載照片墻

異步下載照片墻

來源:程序員人生   發布時間:2016-07-11 08:48:13 閱讀次數:2543次

android異步下載照片墻


版權聲明:本文出自ShengFQ的博客.
轉載請注明出處:http://www.jianshu.com/p/1709ea24ebbb

我的問題

我要實現從服務器端下載1個圖片地址列表,并異步下載圖片展現在imageview,實現緩存和緊縮。如果要下載緊縮后的圖片,應當是由服務器端先緊縮后存儲,這里只說客戶端范圍,不做討論。

需要豫備的知識點:
1.AsyncTask異步調用方法下載json數據
2.listview,viewadapter的高性能寫法
3.HandlerThread,Hander,Message異步消息機制
4.LurCache緩存
5.BitmapFactory的緊縮圖片

1.AsyncTask異步調用方法下載json數據
1個AsyncTask和1個Adapter組合,從服務器端拉取包括圖片地址的json格式數據。
2.listview,viewadapter的高性能寫法

viewadapter.java 部份實現 Object mlock;//異步操作list時,需要對list進行同步鎖定 Context mContext;//調用上下文 List<Model> datalist;//list數據源 int itemLayoutId;//adapterview的個性化顯示布局id getDataList(); reload(List models); add(model model); addAll(List models); render(Model model,View view,int position);//重復利用ViewHolder提升getView方法的性能 getCount(); getItem(int position); getItemId(int position); class ViewHolder{} getView(int position,View convertView,ViewGroup parent); //將1特定的數據格式添加到view中 protected void render(LinkModel linkmodel,View view,int position){ final LinkModel item=linkmodel; ViewHolder viewHolder=(ViewHolder)view.getTag(); //重復利用視圖組件,將視圖組件存儲到裝載對象中 if(viewHolder==null){ viewHolder=new ViewHolder(); viewHolder.app_layout= (FrameLayout)view.findViewById(R.id.iv_app_layout); viewHolder.app_icon_layout=(LinearLayout)view.findViewById(R.id.app_icon_layout); viewHolder.app_log_iv=(ImageView)view.findViewById(R.id.ic_app_ico); viewHolder.app_name_tv=(TextView)view.findViewById(R.id.ic_app_name); view.setTag(viewHolder); }else{ viewHolder=(ViewHolder)view.getTag(); } if(item!=null){ viewHolder.app_log_iv.setImageResource(R.drawable.app_img_app_normal); viewHolder.app_name_tv.setText(item.name); if (ImageCache.getInstance(mCacheSize).isCache(item.photoUrl)) { viewHolder.app_log_iv.setImageBitmap(ImageCache.getInstance(mCacheSize).getBitmapFromMemCache(item.photoUrl)); }else{ //后臺線程異步下載圖片,Token在這里指定了imageview的實例 mThumbnailThread.queueThumbnail(viewHolder.app_log_iv, item.photoUrl); } } }

在AsyncTask中將后臺的json數據封裝到實體對象,通過上述的adapter.addAll(List models)注入到adapter中.

3.HandlerThread,Hander,Message異步消息機制
定義ThunbnailDownloader類,用來通過發送下載要求消息,從另外一個線程去后臺下載并通過與前臺UI線程交互加載.

public class ThumbnailDownLoader<Token> extends HandlerThread { private static final String TAG="ThumbnailDownLoader"; private static final int MESSAGE_DOWNLOAD=0; private Handler mHandler; private String requestToken; private int mCacheSize; Map<Token,String> requestMap= Collections.synchronizedMap(new HashMap<Token,String>()); /** * 主線程中的Handler對象 * */ Handler mRespoonseHandler; //回調接口變量 Listener<Token> mListener; /** * 用于通訊的監聽器接口 * 當下載完要履行的事情:將圖片加載到UI線程的ImageView * */ public interface Listener<Token>{ /** * 后臺線程的輸出,將下載的圖片指定給前臺的ImageView * @param token 寄存圖片的容器 * @param thumbnail 圖片格式 * */ void onThumbnailDownloaded(Token token,Bitmap thumbnail); } public void setListener(Listener<Token> listener){ mListener=listener; } public ThumbnailDownLoader(String requesttoken){ super(TAG); this.requestToken=requesttoken; } /** * 主線程傳遞的Handler * @param responseHandler 前臺UI線程handler * @param requesttoken 遠程下載要求的token * @param cacheSize 緩存大小 * */ public ThumbnailDownLoader(Handler responseHandler,String requesttoken,int cacheSize){ super(TAG); mRespoonseHandler=responseHandler; this.requestToken=requesttoken; this.mCacheSize=cacheSize; } /** * 該方法的調用產生在Looper第1次檢查消息隊列之前 * */ @SuppressLint("handlerLeak") @Override protected void onLooperPrepared(){ mHandler=new Handler(){ //looper獲得消息隊列中的特定消息,回調方法根據消息what屬性進行處理 public void handleMessage(Message msg){ if(msg.what==MESSAGE_DOWNLOAD){ @SuppressWarnings("unchecked") Token token=(Token)msg.obj;//Handler.obtainMessage(msg,obj);通過Handler發送Message傳遞了message.obj,這里處理消息時,可以獲得obj,屬于約定內容。 Log.i(TAG,"Got a request for url:"+requestMap.get(token)); handleRequest(token,requestToken); } } }; } /** * 發送message要求下載圖片,將URL和Token傳遞到同步hashMap中 * 在調用getView()的時候要求下載 * @param token 前臺交互的UI控件 * @param url 前臺指定的下載地址 * */ public void queueThumbnail(Token token,String url){ Log.i(TAG,"Got to URL:"+url); requestMap.put(token,url);//調用getview()的時候調用 Message message=mHandler.obtainMessage(MESSAGE_DOWNLOAD,token);//創建信息并傳入消息字段,自動完成目標handler的設置 message.sendToTarget();//將消息壓入消息隊列 } /** * 遠程下載圖片,將后臺下載的圖片加載到前臺UI的ImageView中 * @param token 泛型參數,這里指前臺的ImageView * */ private void handleRequest(final Token token,final String requestToken){ try{ final String url=requestMap.get(token); if(url==null) return; byte[] bitmapBytes=new ImageLoaderUtils().getUrlBytes(url,requestToken); // final Bitmap bitmap= BitmapFactory.decodeByteArray(bitmapBytes,0,bitmapBytes.length); final Bitmap bitmap= ImageCompress.decodeSampleBitmapFromBytes(bitmapBytes, 54, 54);//圖片緊縮 ImageCache.getInstance(mCacheSize).addBitmapToMemoryCache(url, bitmap); Log.i(TAG,"Bitmap created"); //此處定義了主線程在后臺線程交互操作的UI處理 mRespoonseHandler.post(new Runnable(){ public void run(){ if(requestMap.get(token)!=url) return; requestMap.remove(token);// Bitmap cachebitmap =ImageCache.getInstance(mCacheSize).getBitmapFromMemCache(url); if(cachebitmap!=null) mListener.onThumbnailDownloaded(token,cachebitmap); else{ mListener.onThumbnailDownloaded(token,bitmap); } } }); }catch(IOException ioe){ Log.e(TAG,"Error downloading image",ioe); } } public void clearQueue(){ mHandler.removeMessages(MESSAGE_DOWNLOAD); requestMap.clear(); } }

說明:HandlerThread是1個消息通知處理線程類
onLooperPrepared();//初始化Handler的地方,由于此處在HandlerThread初始化后,進入Loop()之前就會調用的方法,在這里初始化Handler有助于在消息發送之前handler已初始化.

Handler
handlleMessage(Message msg);//根據消息的種別和消息附帶的參數進行異步下載
handler.obtainMessage(String msg,object) //構建1個Message對象
message.sendToTarget();//將消息發送到消息隊列
handler.removeMessages(String msg);//清除該消息,釋放資源

如何與前臺UI線程交互

已將image下載下來了,要填充到UI線程的Imageview中,這就需要與前臺交互,沒錯,前臺UI線程也有Handler,而且只有1個,將前臺的handler傳遞到后臺同享

/** * 主線程中的Handler對象 * Handler mRespoonseHandler; /** * 主線程傳遞的Handler * @param responseHandler 前臺UI線程handler * @param requesttoken 遠程下載要求的token * @param cacheSize 緩存大小 * */ public ThumbnailDownLoader(Handler responseHandler,String requesttoken,int cacheSize){ super(TAG); mRespoonseHandler=responseHandler; this.requestToken=requesttoken; this.mCacheSize=cacheSize; }

在下載完圖片后,通過handler.post();方法與前臺UI交互

//此處定義了主線程在后臺線程交互操作的UI處理 mRespoonseHandler.post(new Runnable(){ public void run(){ if(requestMap.get(token)!=url) return; requestMap.remove(token);// Bitmap cachebitmap =ImageCache.getInstance(mCacheSize).getBitmapFromMemCache(url); if(cachebitmap!=null) mListener.onThumbnailDownloaded(token,cachebitmap);//回調接口方法 else{ mListener.onThumbnailDownloaded(token,bitmap); } } });

Listener mListener;//回調接口對象,下載圖片后,定義行動將圖片設置到imageview

/** * 用于通訊的監聽器接口 * 當下載完要履行的事情:將圖片加載到UI線程的ImageView * */ public interface Listener<Token>{ /** * 后臺線程的輸出,將下載的圖片指定給前臺的ImageView * @param token 寄存圖片的容器 * @param thumbnail 圖片格式 * */ void onThumbnailDownloaded(Token token,Bitmap thumbnail); } public void setListener(Listener<Token> listener){ mListener=listener; }

回到主線程UI

因此在UI線程中,做兩件事,初始化HandlerThread,實現回調接口

//初始化后臺線程下載圖片 mThumbnailThread = new ThumbnailDownLoader<ImageView>(new Handler(),token,mCacheSize);//與主線程Looper綁定的Handler mThumbnailThread.setListener(new ThumbnailDownLoader.Listener<ImageView>() { public void onThumbnailDownloaded(ImageView imageView, Bitmap thumbnail) { if (true) { //給ImageView設置圖片Bitmap imageView.setImageBitmap(thumbnail); } } }); mThumbnailThread.start(); mThumbnailThread.getLooper();

如何觸發異步下載

我們要實現的效果是,下拉gridview時,自動下載圖片并加載到gridview里的imageview視圖,所以我們將焦點回到adapter.getView()方法里,要實現這個功能,需要兩個重要參數傳遞到HandlerThread中
當前的Imageview實例和需要下載的圖片URL

mThumbnailThread.queueThumbnail(viewHolder.app_log_iv, item.photoUrl);

4.LurCache緩存,對圖片進行緩存處理
主要使用了LruCache

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 使用最大可用內存值的1/8作為緩存的大小。 mCacheSize = maxMemory / 8;
/** * 圖片緩存 * */ public class ImageCache { private static ImageCache instance; /** * 實例化,緩存大小 */ public static ImageCache getInstance(int cacheSize) { if (instance == null) { synchronized (ImageCache.class) { if (instance == null) { instance = new ImageCache(cacheSize); } } } return instance; } private LruCache<String,Bitmap> mMemoryCache; private ImageCache(int cacheSize){ mMemoryCache=new LruCache<String,Bitmap>(cacheSize){ protected int sizeOf(String key,Bitmap bitmap){ return bitmap.getByteCount()/1024; } }; } /** * 加載到緩存 * */ public void addBitmapToMemoryCache(String key,Bitmap bitmap){ if(getBitmapFromMemCache(key) ==null){ mMemoryCache.put(key, bitmap); } } /** * 從緩存中讀取 * */ public Bitmap getBitmapFromMemCache(String key){ return mMemoryCache.get(key); } /** * 檢查是不是緩存 * */ public boolean isCache(String key){ Bitmap map=mMemoryCache.get(key); return map!=null; } }

5.BitmapFactory的緊縮圖片

ImageCompress.java /** * * 加載輸入流圖片 網絡*/ public static Bitmap decodeSampleBitmapFromBytes(byte[] data,int reqWidth,int reqHeight){ final BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true; //BitmapFactory.decodeResource(resource, resId, options); BitmapFactory.decodeByteArray(data, 0, data.length, options); options.inSampleSize=calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds=false; return BitmapFactory.decodeByteArray(data, 0, data.length, options); } //怎樣緊縮呢,依照縮放比例inSamplesize,這個值是可要計算出來的 public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){ // final int height=options.outHeight; final int width=options.outWidth; int inSampleSize=1; if(height>reqHeight || width>reqWidth){ final int heightRatio=Math.round((float)height/(float)reqHeight); final int widthRatio=Math.round((float)width/(float)reqWidth); inSampleSize=heightRatio<widthRatio ?heightRatio:widthRatio; } return inSampleSize; }

參考資料

1.http://blog.csdn.net/guolin_blog/article/details/9526203 Android照片墻利用實現,再多的圖片也不怕崩潰
2 http://blog.csdn.net/guolin_blog/article/details/9316683 Android高效加載大圖、多圖解決方案,有效避免程序OOM
3.android開發編程權威指南
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲v日本 | 看片久久| 国产精品久久现线拍久青草 | 日韩国产欧美成人一区二区影院 | 午夜dj高清中文免费观看 | 亚洲国产成人精品女人久久久 | 国产成人在线播放视频 | 日本中文字幕在线看 | 亚洲免费观看网站 | 春暖花开亚洲性无区一区二区 | 亚洲毛片免费在线观看 | 亚洲女人天堂a在线播放 | 天堂网男人 | 欧美一区视频在线 | 国产欧美另类久久精品91 | 欧美jizzjizz| 欧美日本在线视频 | 欧美一级毛片在线播放 | 亚洲一区精品伊人久久伊人 | 高清视频 一区二区三区四区 | 日韩一级淫片 | 日本特黄视频 | 一二三四在线观看免费播放视频 | 欧美激情视频二区 | 国产精品视频成人 | 亚洲影视先锋 | 国产三级精品三级在线专区1 | 黑人逼| hd性欧美俱乐部中文 | 国产三级视频 | www.黄色片.com | 午夜dj免费视频观看社区 | 福利午夜影院 | 国产成人高清精品免费5388密 | 中文在线视频观看 | 日本二区免费一片黄2019 | 日本一区不卡视频 | 欧美一区二区视频 | 羞羞网站入口 | 在线碰碰视频在线观看 | 性欧美video视频另类 |