2011-11-17 81 views
1

我有一個ListView,它包含一個ImageView和一個TextView。我是繼承ArrayAdapter,以便我可以通過一個子類AsyncTask從互聯網加載圖像。迄今爲止都很好。當我使用convertView時出現問題,當我沒有問題時

的問題是,如果我嘗試使用convertView,我有其中圖像簡單地回收進錯行了問題。 (這是一個公司的標誌,所以這是...不好。)

如果我不使用convertView,但是,圖像丟失的用戶滾動時。所以,如果他們向下滾動,備份,圖像從互聯網(數據使用這顯然是不好的,電池壽命等)

有一個簡單的辦法解決這一問題,以便它不會重新加載每次從互聯網加載,或移動圖像?

下面是我使用的是什麼至今:

public class SupplierAdapter extends ArrayAdapter<Supplier>{ 
    int resource; 
    String response; 
    Context context; 

    public SupplierAdapter(Context context, int resource, List<Supplier> suppliers) { 
     super(context, resource, suppliers); 
     this.resource = resource; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent){ 
    LinearLayout view; 
     Supplier s = getItem(position); 

     if(convertView == null){ 
      view = new LinearLayout(getContext()); 
      String inflater = Context.LAYOUT_INFLATER_SERVICE; 
      LayoutInflater vi; 
      vi = (LayoutInflater) getContext().getSystemService(inflater); 
      vi.inflate(resource, view, true); 
     } else { 
      view = (LinearLayout) convertView; 
     } 

     ImageView iv = (ImageView) view.findViewById(R.id.thumbnail); 
     // s.getThumbnail returns a URL 
     new DownloadImageTask(iv).execute(s.getThumbnail()); 

     TextView titleText =(TextView) view.findViewById(R.id.titleText); 
     titleText.setText(s.getTitle()); 
     titleText.setTag(s.getId()); 

     return view; 
    } 
} 

所有幫助非常感謝:)

+0

你有沒有考慮過使用SimpleAdapter和緩存? –

+0

@丹,我沒有。如何緩存?保存到SD卡?我不確定那將如何工作。 –

+0

如果您要處理的不是字符串數組,而是SimpleAdapter更好。對於緩存,您可以將其保存到SD中,並有一些標準來檢查更新。 –

回答

2

約翰,嘗試使用raptureinvenice.comWebImageView。我最近重構了我的代碼來使用這個簡單輕量級的庫,到目前爲止,這麼好。它很容易提供兩級緩存,同時更新多個目標,並且非常容易設置。它看起來似乎下降了大約1/20個顯示圖像的請求。除了這個可能是圖書館過錯的潛伏錯誤之外,它非常好。

+0

不錯,這與我所擁有的非常相似,但我無法分享我的代碼,因爲我爲我的僱主寫了代碼。有趣的是,我認爲我在我的實現中似乎也有類似的錯誤。我相信這與內存使用有關。我唯一的問題是,它使用SoftReferences,它在Android上有些破碎。我使用LruCache,我寧願反正給我一個一致的最大緩存大小。 – kabuko

+0

謝謝,這很理想! –

1

這是一個煩人複雜的問題。我甚至有兩層緩存(內存和磁盤緩存)來平滑第二個線程中更智能的更新(您的情況爲AsyncTask)的性能。有很多小的細節,如嘗試不要下載同一圖像兩次(這是一個問題,如果你有多個列表項相同的公司標誌)。通過跟蹤與ImageView關聯的當前URL是什麼,並確保與設置最終圖像之前傳遞給AsyncTask的相同,可以簡單地修復顯示錯誤圖像的主要問題。也許可以將這些信息存儲在HashMap中。實際上,我只是將所有這些東西都抽象成了一個WebImageView類,它擴展了ImageView以使其全部可重用。

1

對於RAM緩存圖像,您可以使用SoftReference。因此,代碼會是這樣的:

ImageView iv = (ImageView) view.findViewById(R.id.thumbnail); 
// s.getDrawable returns a SoftReference to Drawable 
SoftReference<Drawable> thumbRef = s.getDrawable(); 
Drawable thumb = thumbRef.get(); 
if (thumb == null) { 
    new DownloadImageTask(s).execute(); 
} else { 
    iv.setDrawable(thumb); 
} 

DownloadImageTask將獲得的圖像,包裝成SoftReference,設置基準以收集並通知適配器墊層數據已經改變。設計可以更高效,但這只是一個粗略的計劃。

+0

這看起來相當有希望 - 我會給它一個鏡頭,讓你知道我如何繼續。謝謝:) –

1

如果你只是需要下載一些圖片,如果你不需要顯示大的圖像,你可以使用下面的代碼。它將位圖存儲在內存中。它的效果很好,圖像不是太大。

我改變了我的代碼,您的情況:

進口android.graphics.Bitmap;

公共類供應商{

// Data 
private String mText; 
private Bitmap mImage; 
private String mImageUrl; 

// Flags 
private boolean mIsLoading; 

public Supplier() { 
    mText  = "test"; 
    mImage  = null; 
    mImageUrl = "image_url"; 
    mIsLoading = false; 
} 

public Supplier setLoadingStatus(boolean pIsLoading){ 
    mIsLoading = pIsLoading; 
    return this; 
} 

public boolean isLoading(){ 
    return mIsLoading; 
} 

public Supplier setImageUrl(String pImageUrl){ 
    mImageUrl = pImageUrl; 
    return this; 
} 

public String getImageUrl(){ 
    return mImageUrl; 
} 

public Supplier setText(String pText){ 
    mText = pText; 
    return this; 
} 

public String getText(){ 
    return mText; 
} 

public Supplier setImageBitmap(Bitmap bmp){ 
    mImage = bmp; 
    return this; 
} 

public Bitmap getImageBitmap(){ 
    return mImage; 
}  

}

進口產生java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList;

import android.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics。BitmapFactory; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;

公共類TestAdapter延伸BaseAdapter {

protected static final int MSG_IMAGE_DOWNLOADED = 0; 

// Constants 
private final String TAG = "TestAdapter"; 

private ArrayList<Supplier> mItems; 
private Context mContext; 
private LayoutInflater mLf; 
private Handler mHandler; 


public TestAdapter(Context pContex) { 
    mContext = pContex; 
    mLf   = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mItems  = new ArrayList<Supplier>(); 
    mHandler = new Handler(){ 
     public void handleMessage(Message msg) { 
      switch (msg.what) { 
      case MSG_IMAGE_DOWNLOADED: 
       if(null != msg.obj){ 
        mItems.get(msg.arg1).setImageBitmap((Bitmap)msg.obj) 
             .setLoadingStatus(false); 
        notifyDataSetChanged(); 
       } 
       break; 

      default: 
       break; 
      } 
     }; 
    }; 
} 

public TestAdapter addItem(Supplier pItem){ 
    mItems.add(pItem); 
    return this; 
} 

@Override 
public int getCount() { 
    return mItems.size(); 
} 

@Override 
public Supplier getItem(int position) { 
    return mItems.get(position); 
} 

@Override 
public long getItemId(int position) { 
    return position; 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder vh; 

    if(null == convertView){ 
     convertView  = mLf.inflate(R.layout.your_resource, parent, false); 
     vh    = new ViewHolder(); 
     vh.mTextView = (TextView)convertView.findViewById(R.id.your_textview_from_resource); 
     vh.mImage  = (ImageView)convertView.findViewById(R.id.yout_imageview_from_resource); 
     convertView.setTag(vh); 
    }else{ 
     vh = (ViewHolder)convertView.getTag(); 
    }  

    vh.mTextView.setText(mItems.get(position).getText()); 
    if(mItems.get(position).getImageBitmap() == null && !mItems.get(position).isLoading()){ 
     // download image 
     downloadImage(mItems.get(position).getImageUrl(), position); 
     // set a flag to know that the image is downloading and it is not need to 
     // start another download if the getView method is called again. 
     mItems.get(position).setLoadingStatus(true); 
    }else{ 
     vh.mImage.setImageBitmap(mItems.get(position).getImageBitmap()); 
    } 
    return null; 
} 

private void downloadImage(String pImageUrl, int pItemPosition){ 
    final int cItemPosition = pItemPosition; 
    final String cImageUrl = pImageUrl; 

    Thread tGetImage = new Thread(new Runnable() {   
     @Override 
     public void run() {    
      Message msg = new Message(); 
      msg.what = MSG_IMAGE_DOWNLOADED; 

      BitmapFactory.Options options = new BitmapFactory.Options();                        
      Bitmap bmImg;  
      URL  myFileUrl = null; 

      try { 
       myFileUrl= new URL(cImageUrl); 
      } catch (MalformedURLException e) { 
       e.printStackTrace();       
      }      
      try { 
       HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection(); 
       conn.setDoInput(true); 
       conn.connect(); 
       InputStream is = conn.getInputStream(); 
       bmImg   = BitmapFactory.decodeStream(is, null, options); 

       is.close(); 
       conn.disconnect();   
       msg.obj  = bmImg;      
      } catch (IOException e) { 
       e.printStackTrace();       
      }      
      msg.arg1 = cItemPosition; 
      mHandler.sendMessage(msg);    
     } 
    }); 
    tGetImage.start(); 
} 

private class ViewHolder{ 
    public TextView  mTextView; 
    public ImageView mImage; 
} 

}

的代碼沒有進行測試,但應該工作。

相關問題