2015-11-20 43 views
11

我有一個RecyclerView適配器,看起來像這樣:RecyclerView適配器顯示錯誤的圖像

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { 

    private static Context context; 
    private List<Message> mDataset; 

    public RecyclerAdapter(Context context, List<Message> myDataset) { 
     this.context = context; 
     this.mDataset = myDataset; 
    } 

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener { 
     public TextView title; 
     public LinearLayout placeholder; 

     public ViewHolder(View view) { 
      super(view); 
      view.setOnCreateContextMenuListener(this); 

      title = (TextView) view.findViewById(R.id.title); 
      placeholder = (LinearLayout) view.findViewById(R.id.placeholder); 
     } 
    } 

    @Override 
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false); 
     ViewHolder vh = new ViewHolder((LinearLayout) view); 

     return vh; 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     Message item = mDataset.get(position); 

     holder.title.setText(item.getTitle()); 

     int numImages = item.getImages().size(); 

     if (numImages > 0) { 
      View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
      ImageView image = (ImageView) test.findViewById(R.id.image); 
      Glide.with(context) 
       .load("http://www.website.com/test.png") 
       .fitCenter() 
       .into(image); 
      holder.placeholder.addView(test); 
     } 
    } 

    @Override 
    public int getItemCount() { 
     return mDataset.size(); 
    } 

} 

然而,一些在RecyclerView的項目都出現了圖像時,他們不應該。我怎樣才能阻止這種情況發生?

我做if (numImages > 0) {的檢查onBindViewHolder(),但這仍然沒有阻止它顯示圖像的項目,應該沒有圖像。

+2

如果你得到的回答,請批准它 –

回答

2

這裏的問題是,當您正在處理將要回收的視圖時,您需要在綁定視圖時處理所有可能的場景。例如,如果要將ImageView添加到數據源位置0上的LinearLayout,則如果位置4不符合條件,則其視圖很可能會在綁定位置0時添加ImageView 。

您可以添加R.layout.images內容的內容你

R.layout.message_layout佈局的R.id.placeholder內,顯示/隱藏根據情況的佔位符。

所以,你onBindViewHolder方法是這樣的:

@Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     Message item = mDataset.get(position); 

     holder.title.setText(item.getTitle()); 

     int numImages = item.getImages().size(); 

     if (numImages > 0) { 
      holder.placeholder.setVisivility(View.VISIBLE); 
      ImageView image = (ImageView)holder.placeholder.findViewById(R.id.image); 
      Glide.with(context) 
       .load("http://www.website.com/test.png") 
       .fitCenter() 
       .into(image); 
     }else{ 
      holder.placeholder.setVisibility(View.INVISIBLE); 
     } 
    } 
+0

如果我只是使'placeholder'不可見,這是不是意味着它仍在加載圖像,但隱藏它? – user5578746

+0

@ user5578746是的,我認爲可能會發生。但我認爲,如果你沒有圖像顯示,你不想顯示任何圖像容器 – mmark

+0

是的,但爲了表現,我寧願不加載圖像不必要的。你也錯過了我膨脹另一個佈局的線,這意味着它膨脹佈局以及加載圖像,然後隱藏它。 – user5578746

8

你應該設置使用滑行圖像之前設置imageView.setImageDrawable (null)onBindViewHolder()

設置圖像繪製爲null解決問題。

希望它有幫助!

+2

來幫助你,但是它在再次加載圖像時會減慢滾動的速度。 – Bharatesh

+0

謝謝,爲我工作..和快速滾動有點慢。預期的結果是沒有放錯位置的圖像..so upvoted .. –

+0

我有一個小小的疑問,讓我們假設當屏幕第一次加載它有一個圖像,然後在一些更新相應,這imageview更改,以便在哪一刻我應該設置它空值?請澄清我的疑問。提前致謝。 :) –

7

的問題是在onBindViewHolder,在這裏:

if (numImages > 0) { 
     View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
     ImageView image = (ImageView) test.findViewById(R.id.image); 
     Glide.with(context) 
      .load("http://www.website.com/test.png") 
      .fitCenter() 
      .into(image); 
     holder.placeholder.addView(test); 
    } 

如果numImages等於0,你只是讓以前開工負荷爲你重用繼續視圖。完成後,仍然會將舊圖像加載到您的視圖中。爲了防止這種情況,告訴滑行通過調用明確取消前負荷:

if (numImages > 0) { 
     View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
     ImageView image = (ImageView) test.findViewById(R.id.image); 
     Glide.with(context) 
      .load("http://www.website.com/test.png") 
      .fitCenter() 
      .into(image); 
     holder.placeholder.addView(test); 
    } else { 
     Glide.clear(image); 
    } 

當你調用into(),滑翔手柄取消舊的負載爲您服務。如果你不打電話給into(),你必須自己撥打clear()

每次調用onBindViewHolder必須包含一個load()調用或一個clear()調用。

+0

使用'clear()'是處理待處理請求的最佳方法。 –

+0

您爲此處的某個主題添加了一個主要點。在滾動的過程中,有許多圍繞在recyclerview上的主題搞砸了項目。我認爲這是在某些情況下針對這種情況的解決方案。無論如何,非常感謝你。 – Setmax

+0

似乎你與Bumptech合作。這工作像魔術一樣。謝謝 – Idee

8

我還與RecyclerView顯示錯誤的圖像的問題。發生這種情況是因爲RecyclerView沒有爲每個新的列表項目擴充視圖:而是正在回收列表項目。

通過回收意見,我們可以粗魯理解克隆意見。克隆的視圖可能會從前一個交互中設置一個圖像。

這如果您使用的是畢加索,滑翔,或其他一些lib中異步加載是特別公平。這些庫持有對ImageView的引用,並在加載圖像時在該引用上設置圖像。

當圖像加載完成後,項目視圖可能被克隆,圖像將被設置爲錯誤的克隆

爲了使長話短說,我解決了這個問題從我的克隆項目視圖限制RecyclerView:

在ViewHolder構造setIsRecyclable(false)

現在RecyclerView工作速度稍慢,但至少圖像設置正確。

或者在onViewRecycled(ViewHolder holde)

+0

根據android SDK文檔: 調用setIsRecyclabe(false)應該始終與以後調用 setIsRecyclable(true))匹配。成對的調用可能是嵌套的,因爲該狀態是內部引用計數的。 [RecyclerView#setIsRecycable](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#setIsRecyclable(boolean)) 不幸的是您不推薦使用您的解決方案。 – Garytech

+0

這不建議特別適用於非常大型和重度的數據集。通過回答Prashant Solanki是更好的選擇。 –

0

其他cansel加載圖片我有同樣的問題,我固定它是這樣的:

目標:onViewAttachedToWindow

@Override 
public void onViewAttachedToWindow(Holder holder) { 
    super.onViewAttachedToWindow(holder); 
    StructAllItems sfi = mArrayList.get(position); 
    if (!sfi.getPicHayatParking().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicHayatParking() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicSleepRoom().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSleepRoom() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicSalonPazirayi().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSalonPazirayi() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicNamayeStruct().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicNamayeStruct() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
}