有一陣沒更新了,不過項目也已經基本完成,可以寫一部分新文章咯。項目雖然已經做完,但是問題還是不少,在3月份會有新的領導過來帶領做新版,解決各種手機的適配及最佳化工作。
這回先講一下ListView非同步載入圖片的問題,相關的文章很多,不過在這裡我將載入、壓縮下載、儲存到SD卡等功能全部放上來,方便大家使用或者研究。
1. ListView中的SimpleAdapter中的操作
大家在使用ListView顯示複雜的頁面時,我們都全重寫一個SimpleAdapter,重寫其中的getView方法來顯示具體內容。相關的內容我們下篇文章再說,這裡主要看片顯示的代碼。
//圖片內容顯示 if(!topic.getImage_value().equals("")){ vh.tl_ll_content_image.setVisibility(View.VISIBLE); //加上標識,要不圖片載入會變亂 vh.tl_img_content_image.setTag(topic.getTid()); vh.tl_img_content_image.setImageResource(R.drawable.default_image_load); //新開非同步載入圖片 LoadingTopicImageAsyncTaskloadingTopicImageAsyncTask = new LoadingTopicImageAsyncTask(vh.tl_img_content_image, topic,ctxContext,true,String.valueOf(topic.getTid())); loadingTopicImageAsyncTask.execute(); }
·vh. tl_ll_content_image是我們在ListView中要顯示相關圖片的控制項。Topic是我們通過getView取到的當前行的資料對象。Topic.getImage_value()中則是要顯示的圖片url地址,比如:http://www.huoban168.com/huoban/upload/topic/2012/02/weibo_1329196372_1112447.png。
·為圖片控制項加上setTag主要是防止圖片混亂。
·LoadingTopicImageAsyncTask是我們新開一個非同步,下載或者載入相關的圖片的類。基本上主要的操作都在此類中進行。
2. LoadingTopicImageAsyncTask類中的操作
packagehb.hbwb.asynctask;importhb.hbwb.model.beans.Topic;importhb.hbwb.tools.PicTool;importhb.hbwb.var.PublicVariable; importandroid.app.Activity;importandroid.app.Dialog;importandroid.graphics.Bitmap;importandroid.os.AsyncTask;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.ImageView; /** * @name 非同步載入圖片 * @author zhang.yue * @create_date 2011-12-15 * @last_edit_author * @last_edit_date * @remark * @edit_remark */public classLoadingTopicImageAsyncTask extends AsyncTask<String, Integer,String> {private ImageView imageView = null;private Topic topic = null;private Bitmap bt = null;private Activity activity;private boolean isClick = true;private String tag = ""; /** * 重寫構造 * * @paramheaderView * 影像控制 * @paramtopic * @paramactivity * @paramisClick * 是否可以點擊放大 */public LoadingTopicImageAsyncTask(ImageViewimageView, Topic topic, Activity activity, booleanisClick, String tag) { super(); this.imageView = imageView; this.topic = topic; this.activity = activity; this.isClick = isClick; this.tag = tag;} @Overrideprotected String doInBackground(String...params) { // 添加如果是本機快取的從本地讀取... bt =PublicVariable.allTopicImage.get(String.valueOf(topic.getTid())); if (bt == null) { // 映像擷取並儲存 if (topic.getImage_value().equals("")){ bt = null; } else { bt =PicTool.ReturnBitMap(topic.getImage_value()); } } if (bt!=null) { if(bt.getWidth()>PublicVariable.TOPIC_IMAGE_SHOW-40 ||bt.getHeight()>PublicVariable.TOPIC_IMAGE_SHOW_HEIGHT-40) { bt =PicTool.ChangeSizeBitMap(bt, PublicVariable.TOPIC_IMAGE_SHOW-40); } } return null;} @Overrideprotected void onPostExecute(String result) { super.onPostExecute(result); if (imageView != null &&topic != null && !tag.equals("")) { if(imageView.getTag().toString().equals(tag)) { if (bt != null) { if(isClick) { //點擊大圖效果 imageView.setOnClickListener(newOnClickListener() { @Override publicvoid onClick(View v) { ShowImageClickListener(bt,activity); } }); } imageView.setImageBitmap(bt); PublicVariable.allTopicImage.put( String.valueOf(topic.getTid()),bt); // 儲存到數組中 } } }} /** * 圖片點擊功能事件處理 * * @parambt * @paramactivity */public static voidShowImageClickListener(Bitmap bt, Activity activity) { Bitmap maxBt =PicTool.ChangeSizeBitMap(bt, PublicVariable.TOPIC_IMAGE_SHOW); ImageView showImageView = newImageView(activity); showImageView.setImageBitmap(maxBt); //兩個嵌套的TabHost中,必須使用activity.getParent() //在首頁中使用並無報錯,全域使用 Dialog d = newDialog(activity.getParent(), hb.hbwb.R.style.no_back_title_dialog); d.setContentView(showImageView); d.setCanceledOnTouchOutside(true); d.show();} }
·PublicVariable.allTopicImage是我們寫的一個HashMap,儲存Bitmap的一個集合,如果在程式的運行過程中多次顯示同一個圖片即可直接從這裡面取出Bitmap並顯示,可以節省網上載入或者sd卡讀取的步驟,索引值是topic的tid,一個微博僅顯示一張圖片。
·如果上述的Bitmap集合中不存在圖片的話,調用PicTool類中的ReturnBitMap返回SD卡上緩衝的圖片。
·如果圖片超過我們規定的一個大小,那麼調用PicTool類中的ChangeSizeBitMap方法。
·onPostExecute方法是線程執行完成後,我們將Bitmap對象給予Image圖片控制項並顯示出來。在這裡我們還添加了點擊事件。
3. ReturnBitMap解析
/** * 返回圖片檔案用 * * @paramurl * 圖片url地址 *@return */public static Bitmap ReturnBitMap(String url) { String imgName =StringTool.GetImageNameForUrl(url); if (imgName.equals("")) { return null; } else { FileTool ft = newFileTool(); String path =FileFinals.SDCARDROOT + File.separator + FileFinals.SDCARDIMAGEPATH; // 圖片檔案存在並且不是重新整理的時候 if (ft.IsFileExist(imgName +FileFinals.IMAGE_SYSTEM_EXT, FileFinals.SDCARDIMAGEPATH)) { Bitmap bm =ReturnLocalBitMap(path + File.separator + imgName); if(bm==null){ returnReturnWebBitMap(url, imgName, path); }else{ returnbm; } } else { // 先刪除原有的 returnReturnWebBitMap(url, imgName, path); } }} /** * 本地擷取圖片資訊 * * @parampath * 圖片路徑 *@return bitmap對象 */public static Bitmap ReturnLocalBitMap(Stringpath) { Bitmap bitmap =BitmapFactory.decodeFile(path + ".image"); return bitmap;} /** * 抓取遠程圖片 * * @paramurl * 圖片地址 * @paramimgName * 圖片名 * @parampath * 地址 *@return */public static Bitmap ReturnWebBitMap(Stringurl, String imgName, String path) { Bitmap bitmap = null; try { // 圖片大小判斷操作 InputStream size_is =HTMLTool.GetHttpConnection(url).getInputStream(); BitmapFactory.Options op =new BitmapFactory.Options(); op.inJustDecodeBounds =true; @SuppressWarnings("unused") Bitmap size_bitmap =BitmapFactory.decodeStream(size_is, null, op); op.inJustDecodeBounds =true; // 僅擷取寬高資訊,不載入整個圖片 boolean isop = false; int size =PublicVariable.TOPIC_IMAGE_SHOW; // 設定擷取的大小不能超過寬高 int bili = 0; // 壓縮比例 BitmapFactory.Options op_new= new BitmapFactory.Options(); if(op.outWidth>op.outHeight){ if (op.outWidth> size) { bili =op.outWidth / size; isop =true; } }else{ if (op.outHeight> size) { bili =op.outHeight / size; isop =true; } } // 根據比例判斷 if (bili != 0) { if (bili < 2) { bili = 2; }else{ bili = bili*2-2; } if(bili%2!=0){ bili =bili+1; } op_new.inSampleSize= bili; } else { isop = false; } System.out.println(bili); size_bitmap = null; size_is.close(); // 如果進行過壓縮,載入處理後的圖片,如果沒有直接載入 InputStream is =HTMLTool.GetHttpConnection(url).getInputStream(); if (isop) { op_new.inPreferredConfig= Bitmap.Config.ARGB_4444; op_new.inPurgeable= true; op_new.inInputShareable= true; bitmap =BitmapFactory.decodeStream(is, null, op_new); } else { bitmap =BitmapFactory.decodeStream(is); } // 將圖片寫入到記憶卡中,做為緩衝,將來直接本地讀取 WriteBitmapToSdCard(FileFinals.SDCARDIMAGEPATH,path + File.separator + imgName, bitmap); is.close(); } catch (Exception e) { return null; } return bitmap;}
·StringTool.GetImageNameForUrl是截取檔案名稱,比如:http://www.huoban168.com/huoban/upload/topic/2012/02/weibo_1329196372_1112447.png,返回的是weibo_1329196372_1112447.png這一部分的內容。
·接下來查看當前SD卡的快取檔案路徑下有沒有這張圖,如果有的話,直接調用ReturnLocalBitMap載入圖片,如果沒有的話,調用ReturnWebBitMap方法去調用網狀圖片並下載下來。
·尾碼名都加了一個".image",目的是防止Android的圖片瀏覽器去載入這些圖片。
·ReturnWebBitMap中,先通過HTMLConnection擷取圖片的InputStream二進位流,然後通過op.inJustDecodeBounds = true; // 這個方法,擷取一個只有高度等屬性的Bitmap對象,接著根據圖片原始大小擷取需要大小的壓縮比例op_new.inSampleSize = bili;。
·最後取到壓縮過的Bitmap對象寫入到記憶卡或者直接顯示均可。至此,圖片的下載和儲存已完成。
4. ChangeSizeBitMap解析
/** * 等比例縮放圖片 * * @param bt * bitmap圖片對象 * @param resize * 狀態,是否進行縮放 * @return bitmap圖片對象 */ publicstatic Bitmap ChangeSizeBitMap(Bitmap bt, int resize) { intsrc_width = bt.getWidth(); intsrc_height = bt.getHeight(); floatwidth = (float)bt.getWidth(); floatheight = (float)bt.getHeight(); floatbmpWidth = (float) resize / width; floatbmpHeight = (float) resize / height; if(width >= height) { if(width > resize) { bmpWidth= (float) resize / height; bmpHeight= bmpWidth; } }else{ if(height > resize) { bmpHeight= (float) resize / height; bmpWidth= bmpHeight; } } if(bmpWidth > 1 || bmpHeight > 1) { returnbt; } Matrixmatrix = new Matrix(); matrix.postScale(bmpWidth,bmpHeight); BitmapresizeBmp = Bitmap.createBitmap(bt, 0, 0, src_width, src_height, matrix, true); returnresizeBmp; }
這個方法裡的東西就很簡單了,不過計算的方式可以參考下,和下載圖片時候的差不多,有更好的建議歡迎大家來指導一下。