最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android ListView異步加載圖片方法詳解

 更新時(shí)間:2016年02月29日 09:18:08   作者:炫_(tái)愛羊  
這篇文章主要介紹了Android ListView異步加載圖片方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了ListView異步加載圖片的原理與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下

本文實(shí)例講述了Android ListView異步加載圖片方法。分享給大家供大家參考,具體如下:

先說說這篇文章的優(yōu)點(diǎn)把,開啟線程異步加載圖片,然后刷新UI顯示圖片,而且通過弱引用緩存網(wǎng)絡(luò)加載的圖片,節(jié)省了再次連接網(wǎng)絡(luò)的開銷。

這樣做無疑是非常可取的方法,但是加載圖片時(shí)仍然會(huì)感覺到輕微的卡屏現(xiàn)象,特別是listview里的item在進(jìn)行快速滑動(dòng)的時(shí)候。

我找了一下原因,可能是在listview快速滑動(dòng)屏幕的時(shí)候劃過的item太多 而且每次調(diào)用getView方法后就會(huì)異步的在過去某個(gè)時(shí)間內(nèi)用handler刷新一下UI,

如果在同一時(shí)間調(diào)用handler刷新UI次數(shù)多了就會(huì)造成這樣的卡屏現(xiàn)象。

后來又一想,其實(shí)我們完全沒有必要在listview正在滑動(dòng)的時(shí)候去后臺(tái)加載圖片(不管這是圖片是在緩存里還是在網(wǎng)絡(luò)上),這樣無疑造成了很大的資源浪費(fèi)。

我們只需要在listview滑動(dòng)停止之后再去加載listview里面顯示的幾個(gè)item里面的圖片就好了。

根據(jù)以上想法,我做了一些設(shè)計(jì)改造:

1.在adapter 的 getview方法里面啟動(dòng)加載圖片的thread,如果listview在滑動(dòng)則wait

2.監(jiān)聽listview滑動(dòng)停止事件,獲得listview顯示的item的最上面和最下面的序號(hào),并喚醒所有加載圖片的thread,判斷加載圖片的序號(hào)是否是在范圍內(nèi),如果是則繼續(xù)加載,如果不是則結(jié)束thread

部分代碼如下:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
  if(convertView == null){
    convertView = mInflater.inflate(R.layout.book_item_adapter, null);
  }
  BookModel model = mModels.get(position);
  convertView.setTag(position);
  ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
  TextView sItemTitle = (TextView) convertView.findViewById(R.id.sItemTitle);
  TextView sItemInfo = (TextView) convertView.findViewById(R.id.sItemInfo);
  sItemTitle.setText(model.book_name);
  sItemInfo.setText(model.out_book_url);
  iv.setBackgroundResource(R.drawable.rc_item_bg);
  syncImageLoader.loadImage(position,model.out_book_pic,imageLoadListener);
  return convertView;
}
SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener(){
  @Override
  public void onImageLoad(Integer t, Drawable drawable) {
    //BookModel model = (BookModel) getItem(t);
    View view = mListView.findViewWithTag(t);
    if(view != null){
      ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
      iv.setBackgroundDrawable(drawable);
    }
  }
  @Override
  public void onError(Integer t) {
    BookModel model = (BookModel) getItem(t);
    View view = mListView.findViewWithTag(model);
    if(view != null){
      ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
      iv.setBackgroundResource(R.drawable.rc_item_bg);
    }
  }
};
public void loadImage(){
  int start = mListView.getFirstVisiblePosition();
  int end =mListView.getLastVisiblePosition();
  if(end >= getCount()){
    end = getCount() -1;
  }
  syncImageLoader.setLoadLimit(start, end);
  syncImageLoader.unlock();
}
AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
  @Override
  public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
      case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
        DebugUtil.debug("SCROLL_STATE_FLING");
        syncImageLoader.lock();
        break;
      case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
        DebugUtil.debug("SCROLL_STATE_IDLE");
        loadImage();
        //loadImage();
        break;
      case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        syncImageLoader.lock();
        break;
      default:
        break;
    }
  }
  @Override
  public void onScroll(AbsListView view, int firstVisibleItem,
      int visibleItemCount, int totalItemCount) {
    // TODO Auto-generated method stub
  }
};

package cindy.android.test.synclistview;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
public class SyncImageLoader {
  private Object lock = new Object();
  private boolean mAllowLoad = true;
  private boolean firstLoad = true;
  private int mStartLoadLimit = 0;
  private int mStopLoadLimit = 0;
  final Handler handler = new Handler();
  private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
  public interface OnImageLoadListener {
    public void onImageLoad(Integer t, Drawable drawable);
    public void onError(Integer t);
  }
  public void setLoadLimit(int startLoadLimit,int stopLoadLimit){
    if(startLoadLimit > stopLoadLimit){
      return;
    }
    mStartLoadLimit = startLoadLimit;
    mStopLoadLimit = stopLoadLimit;
  }
  public void restore(){
    mAllowLoad = true;
    firstLoad = true;
  }
  public void lock(){
    mAllowLoad = false;
    firstLoad = false;
  }
  public void unlock(){
    mAllowLoad = true;
    synchronized (lock) {
      lock.notifyAll();
    }
  }
  public void loadImage(Integer t, String imageUrl,
      OnImageLoadListener listener) {
    final OnImageLoadListener mListener = listener;
    final String mImageUrl = imageUrl;
    final Integer mt = t;
    new Thread(new Runnable() {
      @Override
      public void run() {
        if(!mAllowLoad){
          DebugUtil.debug("prepare to load");
          synchronized (lock) {
            try {
              lock.wait();
            } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
          }
        }
        if(mAllowLoad && firstLoad){
          loadImage(mImageUrl, mt, mListener);
        }
        if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){
          loadImage(mImageUrl, mt, mListener);
        }
      }
    }).start();
  }
  private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener){
    if (imageCache.containsKey(mImageUrl)) {
      SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
      final Drawable d = softReference.get();
      if (d != null) {
        handler.post(new Runnable() {
          @Override
          public void run() {
            if(mAllowLoad){
              mListener.onImageLoad(mt, d);
            }
          }
        });
        return;
      }
    }
    try {
      final Drawable d = loadImageFromUrl(mImageUrl);
      if(d != null){
        imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
      }
      handler.post(new Runnable() {
        @Override
        public void run() {
          if(mAllowLoad){
            mListener.onImageLoad(mt, d);
          }
        }
      });
    } catch (IOException e) {
      handler.post(new Runnable() {
        @Override
        public void run() {
          mListener.onError(mt);
        }
      });
      e.printStackTrace();
    }
  }
  public static Drawable loadImageFromUrl(String url) throws IOException {
    DebugUtil.debug(url);
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
      File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/"+MD5.getMD5(url));
      if(f.exists()){
        FileInputStream fis = new FileInputStream(f);
        Drawable d = Drawable.createFromStream(fis, "src");
        return d;
      }
      URL m = new URL(url);
      InputStream i = (InputStream) m.getContent();
      DataInputStream in = new DataInputStream(i);
      FileOutputStream out = new FileOutputStream(f);
      byte[] buffer = new byte[1024];
      int  byteread=0;
      while ((byteread = in.read(buffer)) != -1) {
        out.write(buffer, 0, byteread);
      }
      in.close();
      out.close();
      Drawable d = Drawable.createFromStream(i, "src");
      return loadImageFromUrl(url);
    }else{
      URL m = new URL(url);
      InputStream i = (InputStream) m.getContent();
      Drawable d = Drawable.createFromStream(i, "src");
      return d;
    }
  }
}

除了本身已有的弱引用緩存圖片,我還添加了本地SD卡緩存圖片(這兩種緩存方法各有好處,如果圖片經(jīng)常變化建議內(nèi)存緩存圖片,如果是不經(jīng)常修改的圖片建議SD卡緩存)

更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android開發(fā)入門與進(jìn)階教程》、《Android多媒體操作技巧匯總(音頻,視頻,錄音等)》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)

希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Android仿微信或支付寶方塊密碼輸入框

    Android仿微信或支付寶方塊密碼輸入框

    這篇文章主要為大家詳細(xì)介紹了Android仿微信或支付寶方塊密碼輸入框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Android App后臺(tái)服務(wù)報(bào)告工作狀態(tài)實(shí)例

    Android App后臺(tái)服務(wù)報(bào)告工作狀態(tài)實(shí)例

    這篇文章主要介紹了Android App后臺(tái)服務(wù)報(bào)告工作狀態(tài)實(shí)例,使用LocalBroadcastManager發(fā)送和接收狀態(tài),需要的朋友可以參考下
    2014-06-06
  • Android實(shí)現(xiàn)文字消除效果

    Android實(shí)現(xiàn)文字消除效果

    由于項(xiàng)目和語音識(shí)別相關(guān),有時(shí)候人在不經(jīng)意間交流的無效音頻會(huì)被識(shí)別出來,并展示于界面,為了美觀,客戶要求我們將這些無效的識(shí)別文本用一個(gè)從右到左的動(dòng)畫給清除,于是便有了下述的技術(shù)實(shí)現(xiàn)。感興趣的朋友可以參考下
    2021-06-06
  • Android 軟引用和弱引用詳解及實(shí)例代碼

    Android 軟引用和弱引用詳解及實(shí)例代碼

    這篇文章主要介紹了Android 軟引用和弱引用詳解的相關(guān)資料,并附實(shí)現(xiàn)實(shí)例代碼,需要的朋友可以參考下
    2016-11-11
  • Android折疊式Toolbar使用完全解析(CollapsingToolbarLayout)

    Android折疊式Toolbar使用完全解析(CollapsingToolbarLayout)

    這篇文章主要為大家詳細(xì)介紹了Android折疊式Toolbar的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • android和js的交互之jsbridge使用教程

    android和js的交互之jsbridge使用教程

    這篇文章主要給大家介紹了關(guān)于android和js的交互之jsbridge使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • 多語言切換在Androidx失效的踩坑解決記錄

    多語言切換在Androidx失效的踩坑解決記錄

    這篇文章主要為大家介紹了多語言切換在Androidx失效的踩坑解決記錄詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Android fragment 轉(zhuǎn)場(chǎng)動(dòng)畫創(chuàng)建步驟

    Android fragment 轉(zhuǎn)場(chǎng)動(dòng)畫創(chuàng)建步驟

    在 Android 中,可以使用 setCustomAnimations() 方法來繪制自定義的 Fragment 轉(zhuǎn)場(chǎng)動(dòng)畫,本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • android Textview文字監(jiān)控(Textview使用方法)

    android Textview文字監(jiān)控(Textview使用方法)

    以手機(jī)號(hào)充值為例,當(dāng)用戶輸入最后一位數(shù)時(shí)候,進(jìn)行匯率的變換,本文就實(shí)現(xiàn)類似這樣的功能
    2013-11-11
  • Android中TelephonyManager用法實(shí)例

    Android中TelephonyManager用法實(shí)例

    這篇文章主要介紹了Android中TelephonyManager用法,結(jié)合實(shí)例形式分析了TelephonyManager類的功能,使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2016-03-03

最新評(píng)論

白山市| 临沧市| 大化| 连云港市| 义马市| 海原县| 简阳市| 环江| 闻喜县| 彩票| 邵阳县| 阳城县| 吉安市| 长寿区| 札达县| 邵阳县| 昌宁县| 临潭县| 阳泉市| 缙云县| 南宫市| 景宁| 勃利县| 武强县| 柳林县| 宣武区| 响水县| 河津市| 册亨县| 浠水县| 聊城市| 喀喇沁旗| 兴隆县| 忻城县| 延津县| 博客| 南华县| 大方县| 赣榆县| 西乡县| 天全县|