2015-04-10 2 views
7

То, что я пытаюсь создать, представляет собой галерею изображений с горизонтальной прокруткой. У меня есть RecyclerView (поддержка 22.0.0). Проблема, с которой я сталкиваюсь, заключается в том, что когда я прокручиваю до конца и затем прокручиваю назад, обычно одно изображение будет отсутствовать иногда два. Как ни странно, когда я держусь взад-вперед, другое изображение может отсутствовать. Вот макет для элемента:RecyclerView исчезающих изображений

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="160dp"> 

<ImageView 
    android:id="@+id/product_variation_image" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:scaleType="centerCrop" 
    android:layout_gravity="center"/> 

Вот Adaper:

public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> { 
private String[] mDataset; 

public static class ViewHolder extends RecyclerView.ViewHolder { 

    public ImageView mImageView; 
    public ViewHolder(View v) { 
     super(v); 
     mImageView = (ImageView) v.findViewById(R.id.product_variation_image); 
    } 
} 

public TestAdapter(String[] myDataset) { 
    mDataset = myDataset; 
} 

@Override 
public TestAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 
               int viewType) { 
    // create a new view 
    View v = LayoutInflater.from(parent.getContext()) 
      .inflate(R.layout.variaton_list_item, parent, false); 
    ViewHolder vh = new ViewHolder(v); 
    return vh; 
} 

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 

    holder.mImageView.setImageDrawable(null); 
    String url = mDataset[position]; 
    Log.i("TEST", "position = " + position); 
    ((MainActivity)MainActivity.getInstance()).imageDownloader.download(url, holder.mImageView); 
} 

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

метод загрузки извлекает изображение, из URL или получает его из памяти, если она имеет был кеширован. Это отлично работает во всех других макетах, например. ListView или GridView. Вот код, я использую, чтобы установить его в фрагменте:

final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); 
    layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); 
    mRecyclerView.setLayoutManager(layoutManager); 

Это в методе onCreateView. Когда я получаю URLs я заполнить их и установить адаптер с помощью:

myDataset[i] = imageURL; // for each image  
    mAdapter = new TestAdapter(myDataset); 
    mRecyclerView.setAdapter(mAdapter); 

Интересно, линия в методе onBindViewHolder в адаптере, где я войти в положение. Я обнаружил, что ячейки, где изображение не показано, это то, что этот метод не вызывается. Похоже, что он пропускает эту ячейку по какой-то причине. Даже незнакомец, если я держу ячейку и продолжаю прокручивать слева направо, если ячейка уходит с экрана, а затем возвращается, ее изображение, как и снова, метод onBindViewHolder не вызывается.

+0

пожалуйста, поделитесь код ImageDownloader с вашего MainActivity –

+0

Привет, Я не могу сказать, что он большой. В основном он извлекает изображение, а затем устанавливает выталкиваемый, как только он получил его из памяти или удаленно. Он основан на образце BitmapFun. Он отлично работает в любом месте, где я использую изображения в приложении. Я думаю, что проблема заключается в самом адаптере, а не в выборе изображения. –

+0

Ничего страшного, я думаю, что ваша проблема приведена ниже, ваш призыв загружает новое изображение, но ваш параметр растрового изображения равен нулю для вашего изображения. вы должны скачать его каждый раз, когда вы вызываете onBindViewHolder, если его уже загрузили –

ответ

2

Тот класс, который я не думаю, что было бы важно, был один, который вызывает проблему. Я не уверен, в чем причина, но он находится в пользовательском классе ImageView, который я использую для утилизации, который я получил из образца BitmapFun.

public class RecyclingImageView extends ImageView { 

    public RecyclingImageView(Context context) { 
     super(context); 
    } 

    public RecyclingImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    /** 
    * @see android.widget.ImageView#onAttachedToWindow() 
    */ 
    @Override 
    protected void onAttachedToWindow() {} 

    /** 
    * @see android.widget.ImageView#onDetachedFromWindow() 
    */ 
    @Override 
    protected void onDetachedFromWindow() { 
     // This has been detached from Window, so clear the drawable 

     setImageDrawable(null); 

     super.onDetachedFromWindow(); 
    } 

    /** 
    * @see android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable) 
    */ 
    @Override 
    public void setImageDrawable(Drawable drawable) { 
     // Keep hold of previous Drawable 
     final Drawable previousDrawable = getDrawable(); 

     // Call super to set new Drawable 
     super.setImageDrawable(drawable); 

     // Notify new Drawable that it is being displayed 
     notifyDrawable(drawable, true); 

     // Notify old Drawable so it is no longer being displayed 
     notifyDrawable(previousDrawable, false); 
    } 

    /** 
    * Notifies the drawable that it's displayed state has changed. 
    * 
    * @param drawable 
    * @param isDisplayed 
    */ 
    private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) { 
     if (drawable instanceof RecyclingBitmapDrawable) { 
      // The drawable is a CountingBitmapDrawable, so notify it 
      ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed); 
     } else if (drawable instanceof LayerDrawable) { 
      // The drawable is a LayerDrawable, so recurse on each layer 
      LayerDrawable layerDrawable = (LayerDrawable) drawable; 
      for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) { 
       notifyDrawable(layerDrawable.getDrawable(i), isDisplayed); 
      } 
     } 
    } 

} 

Когда я заменяю это обычным ImageView, у меня больше не возникает проблема.

+1

RecyclingBitmapDrawable - что это? где реализуется –

1

Можно ли проверить что-то? Не могли бы вы использовать эту библиотеку для загрузки изображений из URL-адресов? http://square.github.io/picasso/ Он кэширует все, и он обрабатывает все в асинхронном режиме.

Используйте это что-то вроде ...

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 

    Picasso.with(mImageView.getContext()).cancelRequest(holder.mImageView); 

    String url = mDataset[position]; 
    Picasso.with(mImageView.getContext()).load(url).placeholder(R.drawable.placeholder).into(holder.mImageView); 

} 

... и посмотреть, если он еще не отображает некоторые изображения. Если это так, то, по крайней мере, вы будете на 100% уверены, что проблема не в вашем загрузочном механизме (который, я думаю, может быть).

Если вы используете Android Studio, просто добавьте зависимость compile 'com.squareup.picasso:picasso:2.5.2', если нет, вы можете добавить библиотеку, которую найдете по приведенной выше ссылке.

Это стоит попробовать ...

+0

Спасибо, но это не имеет никакого значения. –

0

Мы можем исправить проблему, расширив LinearLayoutManager и ImageView.

1. Creats PrecachingLinearLayoutManager

public class PrecachingLinearLayoutManager extends LinearLayoutManager { 

    private static final int DEFAULT_EXTRA_LAYOUT_SPACE = 600; 

    private int extraLayoutSpace = -1; 

    @SuppressWarnings("unused") 
    private Context mContext; 

    public PrecachingLinearLayoutManager(Context context) { 
     super(context); 
     this.mContext = context; 
    } 

    public PrecachingLinearLayoutManager(Context context, int extraLayoutSpace) { 
     super(context); 
     this.mContext = context; 
     this.extraLayoutSpace = extraLayoutSpace; 
    } 

    public PrecachingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 
     super(context, orientation, reverseLayout); 
     this.mContext = context; 
    } 

    public void setExtraLayoutSpace(int extraLayoutSpace) { 
     this.extraLayoutSpace = extraLayoutSpace; 
    } 

    @Override 
    protected int getExtraLayoutSpace(RecyclerView.State state) { 
     if (extraLayoutSpace > 0) { 
      return (extraLayoutSpace); 
     } 
     return (DEFAULT_EXTRA_LAYOUT_SPACE); 
    } 
} 

2.Используйте PrecachingLinearLayoutManager заменить LinearLayoutManager

DisplayMetrics displayMetrics = new DisplayMetrics(); 
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); 
    PrecachingLinearLayoutManager layout = new PrecachingLinearLayoutManager(getActivity()); 
    layout.setExtraLayoutSpace(displayMetrics.heightPixels); 
    recyclerview.setLayoutManager(layout); 

3. Creats RecycleImageView

private Object tag = null; 

@Override 
protected void onAttachedToWindow() { 
    Object tag = getTag(); 
    if (tag == null || !tag.equals(this.tag)) { 
     // Will cause displayed bitmap wrapper to 
     // be 'free-able' 
     setImageDrawable(null); 
     this.tag = null; 
     super.onDetachedFromWindow(); 
    } 
    super.onAttachedToWindow(); 
} 

@Override 
protected void onDetachedFromWindow() { 
    Object tag = getTag(); 
    if (tag != null) { 
     this.tag = tag; 
    } else { 
     // Will cause displayed bitmap wrapper to 
     // be 'free-able' 
     setImageDrawable(null); 
     this.tag = null; 
     super.onDetachedFromWindow(); 
    } 
} 

4. Использование RecycleImageView для замены ImageView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:extends="http://schemas.android.com/apk/res/com.yourdomain.yourpackage" 
xmlns:tools="http://schemas.android.com/tools" 
android:id="@+id/viewgroup" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:orientation="vertical" > 
<com.yourdomain.yourpackage.RecycleImageView 
    android:id="@+id/photo" 
    android:layout_width="40dp" 
    android:layout_height="40dp" 
    extends:delayable="true" 
    android:contentDescription="@string/nothing" 
    android:src="@drawable/photo_placeholder" > 
</com.yourdomain.yourpackage.RecycleImageView> 
</LinearLayout> 
Смежные вопросы