1

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>
Knossos
  • 15,802
  • 10
  • 54
  • 91
hasan
  • 57
  • 1
  • 13
  • So in `public void swap(ArrayList newFoods) { ... }` - You checked that `newFoods` length is not 0, and the data is consistent with your expectations? – Knossos Nov 15 '16 at 09:23
  • @Knossos sometime there will be no data as i am sending category filter request , but the view is not refreshing even when the data is available. – hasan Nov 15 '16 at 09:29
  • Please supply your entire `Adapter` source. I don't think that this is enough information. – Knossos Nov 15 '16 at 09:34
  • The code *seems* to be OK. I still think there is an issue with the data source. Could you add something like `Log.i("DATASOURCE", "Data size: "+newFoods.size());` before this line `foodItems.clear();`. – Knossos Nov 15 '16 at 09:43
  • the log message is like this --E/DATASOURCE: Data size: 1 – hasan Nov 15 '16 at 09:49
  • Is your `RecyclerView` perhaps under your `Toolbar`? (so the one single result is actually hidden)? – Knossos Nov 15 '16 at 09:49
  • @Knossos yes, it's under toolbar , what should i do in that case ? – hasan Nov 15 '16 at 09:51
  • It depends on your implementation. I quite like to use `ConstraintLayout` with `android:layout_constraintTop_toBottomOf ="@+id/toolbar"`. But any layout is fine. You can test if this is your issue by adding a `android:marginTop="90dp"` to your `RecyclerView` temporarily. – Knossos Nov 15 '16 at 09:54
  • tried adding this , but still same result . – hasan Nov 15 '16 at 09:58
  • Perhaps share your layout XML also, in your question. The one that contains your RecyclerView (and any parent layouts). – Knossos Nov 15 '16 at 09:59

5 Answers5

3

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.

Community
  • 1
  • 1
hasan
  • 57
  • 1
  • 13
1
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);
Harish Gyanani
  • 1,366
  • 2
  • 22
  • 43
  • both are same list , i passed allFood to adapter and received it in foodItemsList – hasan Nov 15 '16 at 10:22
  • `public void swap(ArrayList newFoods){ foodItems=newFoods; notifyDataSetChanged(); }` try this, because List only contains object references not object. May be you are changing state of object. – Harish Gyanani Nov 15 '16 at 10:38
1

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 your RecyclerView.
  • You could add a layout rule to ConstraintLayout similar to android:layout_constraintTop_toBottomOf ="@id/toolbar".
  • You could add a layout rule to RelativeLayout similar to android: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!");
}
Knossos
  • 15,802
  • 10
  • 54
  • 91
0

Fine, you can change too

allFood.clear();
allFood.addAll(newFoods);
notifyDataSetChanged();
Raju
  • 1,183
  • 3
  • 11
  • 19
0

Change code like this

public void swap(ArrayList<FoodItem> newFoods){
    foodItems.clear();
    foodItems.addAll(newFoods);
    foodAdapter.notifyDataSetChanged();
}
EKN
  • 1,886
  • 1
  • 16
  • 29