【问题标题】:RecyclerView is not refreshingRecyclerView 不刷新
【发布时间】:2017-03-29 02:35:31
【问题描述】:

在我的应用程序中,我从 Web 服务器接收到一些数据。该数据被发送到RecyclerView。首先,所有数据都显示正常。但是,当我尝试刷新它时,数据不再显示。数据来自网络服务(使用 Logcat 验证)。

设置数据

ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
    foodAdapter.swap(allFood);
} else {
    foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);

我的RecyclerView 适配器

public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> {
    Context mContext;
    ArrayList<FoodItem> foodItems;

    public FoodAdapter(Context context, ArrayList<FoodItem> foodItems) {
        this.mContext = context;
        this.foodItems = foodItems;
    }

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

    public void swap(ArrayList<FoodItem> newFoods) {
        foodItems.clear();
        foodItems.addAll(newFoods);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                notifyDataSetChanged();
            }
        }, 500);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        FoodItem foodItem = foodItems.get(position);
        String stringPicture = foodItem.getPhoto();
        byte[] decodedPictureStringArray = Base64.decode(stringPicture, Base64.DEFAULT);
        Bitmap bitmapPhoto = BitmapFactory.decodeByteArray(decodedPictureStringArray, 0, decodedPictureStringArray.length);
        Uri photoUri = getImageUri(mContext, bitmapPhoto);
        Picasso.with(mContext).load(photoUri).resize(300, 300)
            .centerCrop().into(holder.foodImage);
        holder.foodItemNameText.setText(foodItem.getFoodItemName());
        holder.foodPriceText.setText(foodItem.getUnitPrice() + " / " + foodItem.getUnitType());
    }
    public Uri getImageUri(Context inContext, Bitmap inImage) {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        inImage.compress(Bitmap.CompressFormat.JPEG, 10, bytes);
        String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
        return Uri.parse(path);
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView foodImage;
        public TextView foodItemNameText;
        public TextView foodPriceText;

        public ViewHolder(View itemView) {
            super(itemView);
            foodImage = (ImageView) itemView.findViewById(R.id.foodPhoto);
            foodItemNameText = (TextView) itemView.findViewById(R.id.foodItemNameText);
            foodPriceText = (TextView) itemView.findViewById(R.id.foodPriceText);
        }
    }
}

包含我的ToolbarRecyclerViewRelativeLayout

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  tools:context=".FoodViewForCustomerActivity">

  <include
      android:id="@+id/toolbar"
      layout="@layout/toolbar"
      />
  <android.support.v7.widget.RecyclerView
      android:layout_below="@id/toolbar"
      android:id="@+id/photoCollectionView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="#f8f8f8"
      android:divider="@null"
      android:listSelector="@android:color/transparent"/>
</RelativeLayout>

【问题讨论】:

  • 那么在public void swap(ArrayList&lt;FoodItem&gt; newFoods) { ... } - 你检查了newFoods 的长度不为0,并且数据与你的预期一致?
  • @Knossos 有时会没有数据,因为我正在发送类别过滤请求,但即使数据可用,视图也不会刷新。
  • 请提供您的整个Adapter 来源。我认为这些信息还不够。
  • 代码似乎没问题。我仍然认为数据源存在问题。你能在这行foodItems.clear();之前添加Log.i("DATASOURCE", "Data size: "+newFoods.size());之类的东西吗?
  • 日志信息是这样的 --E/DATASOURCE: Data size: 1

标签: android android-recyclerview


【解决方案1】:

对不起,回答我自己的问题。我通过关注solution provided here解决了我的问题。我的问题的主要原因是当我尝试刷新它时,RecyclerView 没有调用 onCreateViewHolder 或 onBindView。

【讨论】:

  • 确保将您的答案设置为已接受,当它适合您时。
  • 它说我不能在另外 23 小时之前接受我的回答
【解决方案2】:
foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,allFood);

更改上面的行。 在适配器构造函数中发送 foodItems 数组列表引用而不是 allFood

正确的行是

foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,foodItems);

【讨论】:

  • 两者是同一个列表,我将 allFood 传递给适配器并在 foodItemsList 中接收它
  • public void swap(ArrayList&lt;FoodItem&gt; newFoods){ foodItems=newFoods; notifyDataSetChanged(); } 试试这个,因为 List 只包含对象引用而不是对象。可能是你正在改变对象的状态。
【解决方案3】:

诊断 #1

从评论讨论来看。似乎您的 RecyclerView 正在从您的源中获取正确的数据。

但是,当数据计数为 1 时,它会隐藏在其他 UI 元素之下。

您需要确保您的 RecyclerView 不会被其他 UI 元素(例如 Toolbar)遮挡。

有多种方法可以做到这一点。

  • 您可以将?attr/actionBarSize 中的marginTop 添加到您的RecyclerView
  • 您可以向ConstraintLayout 添加类似于android:layout_constraintTop_toBottomOf ="@id/toolbar" 的布局规则。
  • 您可以向RelativeLayout 添加类似于android:layout_below="@id/toolbar" 的布局规则。

诊断 #2

你刷新数据的代码有点奇怪:

ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
    foodAdapter.swap(allFood);
} else {
    foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);

通常,您不会在每次数据更改时都设置适配器。您在初始化时设置一次,然后使用通知方法刷新数据。

请不要将结构分开,如下所示:

FoodViewForCustomerActivity 的成员变量:

private ArrayList<FoodItem> mAllFood = new ArrayList<>();

onCreate():

foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, mAllFood);
photoCollectionView.setAdapter(foodAdapter);

在您的数据收集方法中:

ArrayList<FoodItem> food = response.body();
if(foodAdapter != null) {
    Log.e(TAG, "Data retrieved (size="+food.size()+"), sending it to Adapter.");
    foodAdapter.swap(food);
} else {
    Log.e(TAG, "Data retrieved (size="+food.size()+"), but Adapter is null!");
}

【讨论】:

  • 有时数据大小大于 1 ,但仍然没有视图。
  • @hasan 请查看我的Diagnosis #2
  • 我按照这个stackoverflow.com/a/35802948/6609839的指示解决了我的问题
  • 很高兴你修好了!
  • 我应该如何选择已解决的答案?因为我从另一个问题中收集了答案。我应该提供链接作为答案吗?
【解决方案4】:

像这样修改代码

public void swap(ArrayList<FoodItem> newFoods){
    foodItems.clear();
    foodItems.addAll(newFoods);
    foodAdapter.notifyDataSetChanged();
}

【讨论】:

    【解决方案5】:

    好吧,你也可以换

    allFood.clear();
    allFood.addAll(newFoods);
    notifyDataSetChanged();
    

    【讨论】:

    • 我在上面的交换方法中做到了
    • 你必须做 youradater.notifyDataSetChanged();那么只有更改才会更新
    • @RajuSubramanian:他的交换方法在他的适配器中。因此,通知方法正在调用您建议的相同方法。
    • swap 方法在适配器类中,我尝试按照您的建议进行操作,但结果仍然相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    相关资源
    最近更新 更多