RecyclerView 中图像的奇怪行为

Strange behaviour of images in RecyclerView(RecyclerView 中图像的奇怪行为)

本文介绍了RecyclerView 中图像的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 android.support.v7.widget.RecyclerView 来显示包含文本的简单项目,在某些情况下还包含图像.基本上我从这里遵循了教程 https://developer.android.com/training/material/lists-cards.html 只是将 mDataset 的类型从 String[] 更改为 JSONArray 和 ViewHolder 的 xml.我的 RecyclerView 位于一个简单的 Fragment 中:

I am using android.support.v7.widget.RecyclerView to show simple items containing text and in some cases also images. Basically I followed the tutorial from here https://developer.android.com/training/material/lists-cards.html and just changed the type of mDataset from String[] to JSONArray and the xml of the ViewHolder. My RecyclerView is located in a simple Fragment:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
    android:id="@+id/my_hopps_recycler_view"
    android:scrollbars="vertical"
    android:layout_centerInParent="true"
    android:layout_width="200dp"
    android:layout_height="wrap_content"/>

</RelativeLayout>

在这个片段中,我从网络服务器加载所有信息.收到信息后,我初始化 RecyclerView 中的项目.我使用在我的 Fragment 的 onCreate 方法中设置的 LinearLayoutManager.添加 Adapter 后,我在 RecyclerView 上调用 setHasFixedSize(true) 方法.我的适配器类如下所示:

In this fragment I am loading all information from a webserver. After receiving the information I initialize the items in the RecyclerView. I use a LinearLayoutManager which is set in the onCreate method of my Fragment. After adding the Adapter, I call the setHasFixedSize(true) method on my RecyclerView. My Adapter class looks like this:

import android.graphics.BitmapFactory;
import android.support.v7.widget.RecyclerView;
import android.util.Base64;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.apache.commons.lang3.StringEscapeUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import saruul.julian.MyFragment;
import saruul.julian.R;

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

/**
* Fragment holding the RecyclerView.
*/
private MyFragment myFragment;
/**
* The data to display.
*/
private JSONArray mDataset;

public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView text;
    ImageView image;

    public ViewHolder(View v) {
        super(v);
        text = (TextView) v.findViewById(R.id.my_view_text);
        image = (ImageView) v.findViewById(R.id.my_view_image);
    }
}

public MyAdapter(MyFragment callingFragment, JSONArray myDataset) {
    myFragment = callingFragment;
    mDataset = myDataset;
}

@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.my_view, parent, false);
    ViewHolder vh = new ViewHolder(v);
    return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    try {
        JSONObject object = mDataset.getJSONObject(position);
        if ( object.has("image") ){
            if ( !hopp.getString("image").equals("") ){
                try {
                    byte[] decodedString = Base64.decode(StringEscapeUtils.unescapeJson(object.getString("image")), Base64.DEFAULT);
                    holder.image.setImageBitmap(BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length));
                    holder.image.setVisibility(View.VISIBLE);
                } catch ( Exception e ){
                    e.printStackTrace();
                }
            } 
        }
        if ( object.has("text") ){
            holder.text.setText(object.getString("text"));
        }
    } catch ( Exception e ){
        e.printStackTrace();
    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    return mDataset.length();
}
}

我的 xml 用于我的 RecyclerView 中的视图:

And my xml for a view inside my RecyclerView:

<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="@dimen/activity_horizontal_margin">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:id="@+id/my_hopp_people_reached"/>

    <ImageView
        android:id="@+id/my_hopp_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:adjustViewBounds="true"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:id="@+id/my_hopp_text"/>

    <ImageButton
        android:id="@+id/my_hopp_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:src="@drawable/ic_action_discard"
        />

</LinearLayout>

</android.support.v7.widget.CardView>

所以现在我的问题是:一切正常.文本和图片在我的 RecyclerView 中正确显示.但是,如果我通过向下滚动并再次向上滚动到达列表末尾,则图片将显示在不应包含图片的项目中.目前我有九个项目.其中最后两个包含一张图片.所以我向下滚动,只看到前七个项目中的文本.到达列表末尾时,我按预期显示了两张图片.但是,如果我再次向上滚动,这些图片会出现在其他项目中.

So now here is my problem: Everything works fine. Text and picture are shown correctly in my RecyclerView. However if I reach the end of the list by scrolling down and scroll up again, pictures are shown in items which should not contain pictures. At the moment I have got nine items. The last two of them contain a picture. So I scroll down and just see text in the first seven items. Reaching the end of the list shows me two pictures as expected. But if I scroll up again those pictures appear in other items.

向上和向下滚动总是以相同的顺序更改图片:

Scrolling up and down changes the pictures always in the same order:

  • 第一次向上滚动(向下滚动一次后)会在第二项中创建一张图片.
  • 向下滚动会在第 7 项中创建一张图片.
  • 向上滚动会在第一项中创建一张图片.
  • 向下滚动不会产生任何效果.
  • 向上滚动会在第三项中创建一张图片,而第二项中的图片会被另一张图片覆盖.
  • 向下滚动会在第 6 项中创建一张图片,并让第 7 项中的图片消失.
  • 等等……

我已经发现每次屏幕上再次出现项目时都会调用 onBindViewHolder(ViewHolder holder, int position) 方法.我检查了我的 mDataset 中的位置和给定信息.这里一切正常:位置正确,给定的信息也正确.所有项目中的文本都不会更改,并且始终正确显示.有没有人遇到过这种问题并知道一些解决方案?

I already discovered that the onBindViewHolder(ViewHolder holder, int position) method is called everytime an item appears again on the screen. I checked for the position and the given information in my mDataset. Everything works fine here: The position is right and the given information too. The text in all items does not change and is always shown correctly. Does anyone have any kind of this problem and knows some solution?

推荐答案

我认为你需要在 if ( object.has("image") )<onBindViewHolder(ViewHolder holder, int position)方法中的/code>语句,设置图片为null:

I think you need to add an else clause to your if ( object.has("image") ) statement in the onBindViewHolder(ViewHolder holder, int position) method, setting the image to null:

holder.image.setImageDrawable(null);

我认为 onBindViewHolder 的文档 最好地描述为什么这是必要的:

I think the documentation for onBindViewHolder describe it best why this is necessary:

由 RecyclerView 调用,在指定位置显示数据.此方法应更新 itemView 的内容以反映给定位置的项目.

Called by RecyclerView to display the data at the specified position. This method should update the contents of the itemView to reflect the item at the given position.

您应该始终假设传入的 ViewHolder 需要完全更新:)

You should always assume that the ViewHolder passed in needed to be completely updated :)

这篇关于RecyclerView 中图像的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:RecyclerView 中图像的奇怪行为

基础教程推荐