问题
In my application I receive some data from a web server. This data is sent to a RecyclerView
. Firstly, all data is displayed fine. However, when I try to refresh it, the data no-longer shows. The data arrives from the web service (as verified using Logcat).
Setting the data
ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
foodAdapter.swap(allFood);
} else {
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);
My RecyclerView
Adapter
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);
}
}
}
The RelativeLayout
that contains my Toolbar
and RecyclerView
<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>
回答1:
Sorry, for answering my own question. I solved my question by following solution provided here.Main cause of my problem was that RecyclerView was not calling onCreateViewHolder or onBindView, when i was trying to refresh it.
回答2:
foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,allFood);
Change above line. Send foodItems arraylist reference in adapter constructor instead of allFood
Correct line is
foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,foodItems);
回答3:
Diagnosis #1
Judging from the comment discussion. It seems like your RecyclerView
is being fed the correct data from your source.
However, when the data count is 1, it is hidden underneath other UI elements.
You need to make sure that your RecyclerView
is not obscured by other UI elements, such as the Toolbar
.
There are multiple ways you can do this.
- You could add a
marginTop
of?attr/actionBarSize
to yourRecyclerView
. - You could add a layout rule to
ConstraintLayout
similar toandroid:layout_constraintTop_toBottomOf ="@id/toolbar"
. - You could add a layout rule to
RelativeLayout
similar toandroid:layout_below="@id/toolbar"
.
Diagnosis #2
Your code for refreshing data is a little strange:
ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
foodAdapter.swap(allFood);
} else {
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);
Normally, you do not set the Adapter every time your data has changed. You set it once on initialization, and then refresh the data with the notify methods.
Instead of what you have, please separate the structure as follows:
Member variable of your FoodViewForCustomerActivity
:
private ArrayList<FoodItem> mAllFood = new ArrayList<>();
In onCreate()
:
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, mAllFood);
photoCollectionView.setAdapter(foodAdapter);
In your data collection method:
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!");
}
回答4:
Change code like this
public void swap(ArrayList<FoodItem> newFoods){
foodItems.clear();
foodItems.addAll(newFoods);
foodAdapter.notifyDataSetChanged();
}
回答5:
Fine, you can change too
allFood.clear();
allFood.addAll(newFoods);
notifyDataSetChanged();
来源:https://stackoverflow.com/questions/40605985/recyclerview-is-not-refreshing