我使用android.support.v7.widget.RecyclerView来显示包含文本的简单项目,在某些情况下还显示图像。基本上我从这里跟随教程https://developer.android.com/training/material/lists-cards.html,只是将mDataset的类型从String []更改为JSONArray和ViewHolder的xml。我的RecyclerView位于一个简单的片段中:
<?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中的项目。我使用了一个LinearLayoutManager,它在我的Fragment的onCreate方法中设置。添加适配器后,我在RecyclerView上调用setHasFixedSize(true)方法。我的Adapter类看起来像这样:
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:
<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中正确显示了文本和图片。但是,如果我通过向下滚动并再次向上滚动到达列表的末尾,则图片将显示在不应包含图片的项目中。 目前我有九件物品。最后两个包含一张图片。所以我向下滚动,只看到前七项中的文字。到达列表的末尾显示了我预期的两张图片。但如果我再次向上滚动,那些图片会出现在其他项目中。
向上和向下滚动会以相同的顺序更改图片:
我已经发现,每当项目再次出现在屏幕上时,就会调用onBindViewHolder(ViewHolder holder,int position)方法。我在mDataset中检查了位置和给定的信息。这里的一切都很好:位置是正确的,也是给定的信息。所有项目中的文本都不会更改,并始终正确显示。 有没有人有任何这种问题,并且知道一些解决方案?
答案 0 :(得分:46)
我认为您需要在else
方法中为if ( object.has("image") )
语句添加onBindViewHolder(ViewHolder holder, int position)
子句,将图像设置为null:
holder.image.setImageDrawable(null);
我认为the documentation for onBindViewHolder最能说明为什么这是必要的:
由RecyclerView调用以显示指定位置的数据。此方法应更新itemView的内容以反映给定位置的项目。
你应该总是假设传入的ViewHolder需要完全更新:)
答案 1 :(得分:14)
不确定人们是否仍有这方面的问题,但if语句对我不起作用。对我有用的是:
在适配器中使用此方法的覆盖
@Override
public int getItemViewType(int position) {
return position;
}
然后在onBindViewHolder中为图像本身调用基于此的if语句,如下所示:
int pos = getItemViewType(position);
if(theList.get(pos).getPicture() == null) {
holder.picture.setVisibility(View.GONE);
} else {
Picasso.with(context).load(R.drawable.robot).into(holder.picture);
}
我正在使用毕加索,但它应该适用于任何其他情况。希望这有助于某人!
答案 2 :(得分:3)
基于@ Lion789的回答。 我正在使用Google的Volley进行图片和json加载。
这允许我们检索稍后将要回收的视图上的位置。
@Override
public int getItemViewType(int position) {
return position;
}
发出请求时,将位置设置为TAG
@Override
public void onBindViewHolder(final ItemHolder holder, int position) {
ImageRequest thumbnailRequest = new ImageRequest(url,
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
holder.itemThumbnail.setImageBitmap(response);
}
},[...]);
thumbnailRequest.setTag(String.valueOf(position)); //setting the TAG
mQueue.addToRequestQueue(thumbnailRequest);
}
当视图被回收时,我们将取消请求,并删除当前图像
@Override
public void onViewRecycled(ItemHolder holder) {
super.onViewRecycled(holder);
mQueue.cancelAll(String.valueOf(holder.getItemViewType()));
holder.itemThumbnail.setImageDrawable(null);
}
取消请求的Volley garanties将无法发送。