2

The RecyclerView shows only items that was in ArrayList (data of the adapter) on creation. All my attempts to add more lines seems to work, but the list stays with initial data. It isn't duplicate, as I tried all the suggestions found on google. What I already did:

  • adapter.notifyDataSetChanged();
  • adapter.notifyItemChanged(5);
  • recycleList.invalidate();
  • recycleList.setAdapter(adapter);
  • running the update on UIThread with Handler

The adapter work as it should - onCreateView do it's work (creat new lines) as well as onBindView (bind new data). getItemCount() returns correct value (larger after update). Everything looks like it should be - instead of the final view - does not change.

The only thing that will work is recreate the adapter from scratch with new dataset - completely unacceptable by design (ugly on long lists).

Here is the code:

Create in fragment:

adapter = new MyListAdapter(getContext());
adapter.addItems(initialItems); // These and only these I see on the list
LinearLayoutManager mLayoutManager=new LinearLayoutManager(getContext());
recycleList.setLayoutManager(mLayoutManager);
recycleList.setAdapter(adapter);

Trying to update from fragment:

public void onUpdateReady(ArrayList<Model> freshData) {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() { // UI thread
            adapter.addItems(freshData);
            adapter.notifyDataSetChanged();
            adapter.notifyItemChanged(5);
            recycleList.invalidate();
            //notifyItemRangeInserted(3,freshData.size());
        }
    });
}

Adapter:

private Context mContext;
private ArrayList<Model> data;

public MyListAdapter(Context mContext) {
    this.mContext = mContext;
    data=new ArrayList<>();
}

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

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {        
    viewHolder.textName.setText(data.get(position).getName());
}

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

public void addItems(Collection<Model> list) {
    data.addAll(list);
}

public class ViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.textName) TextView textName;

    public ViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }
}

UPDATE: Changed according to comments:

public void addItems(Collection<Model> list) {
    ArrayList<Model> newData=new ArrayList<>(); // Make new array
    newData.addAll(data); // Take old
    newData.addAll(list); // Add new
    data=newData; // change to data to newly created array
    notifyDataSetChanged();
}
Shmuel
  • 488
  • 1
  • 6
  • 18
  • Take a look at my answer here: https://stackoverflow.com/a/38568013/5223744 – Igor Fridman Aug 31 '17 at 09:12
  • do not add items directly to your adapter , add items to arraylist and pass that list to your adapter , and whenever you call adapter.notifyDataSetChanged(); it will reflected to your recyclerview – Shashwat Gupta Aug 31 '17 at 09:13
  • the previous comment is incorrect. You have got the same address for arraylist. it is not needed to reassign the value outside of the class. – Vyacheslav Aug 31 '17 at 09:29
  • Did as you say. Changed the addItems (see update in the post). But no unfortunately - nothing changed. Still see the old lines - even if I do data.clear() - the initial lines persist without data. In other words - no update. – Shmuel Aug 31 '17 at 09:29
  • will `getItemCount` be fired after `notifyDataSetChanged()`? – Vyacheslav Aug 31 '17 at 09:32
  • are you sure that the code inside handler is really fired? – Vyacheslav Aug 31 '17 at 09:33
  • Yes. It is working as needed. It called on initial lines and then on added (for each new line added) Yes, the handler is called. I have Toast there – Shmuel Aug 31 '17 at 09:36
  • adapter.notifyItemInserted(adapter,getCount()-1); try this – J Ramesh Aug 31 '17 at 09:51
  • notifyItemInserted doesn't work too – Shmuel Aug 31 '17 at 10:01

3 Answers3

1
try this

In Fragment
ArrayList<Data> items=new ArrayList<>();

items.addAll(initialItems);
adapter = new MyListAdapter(getContext(),items);
LinearLayoutManager mLayoutManager=new LinearLayoutManager(getContext());
recycleList.setLayoutManager(mLayoutManager);
recycleList.setAdapter(adapter);


public void onUpdateReady(ArrayList<Model> freshData) {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() { // UI thread
            items.addAll(freshData);
            adapter.notifyDataSetChanged();
            followList.invalidate();

        }
    });
}



private Context mContext;
private ArrayList<Model> data;

public MyListAdapter(Context mContext,ArrayList<Model> data) {
    this.mContext = mContext;
    this.data=data;
}

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

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {        
    viewHolder.textName.setText(data.get(position).getName());
}

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


public class ViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.textName) TextView textName;

    public ViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }
}
J Ramesh
  • 548
  • 4
  • 11
0

Change your Adapter constructor:

private ArrayList<Model> data;
public MyListAdapter(Context mContext,ArrayList<Model> data) {
this.mContext = mContext;
this.data = data;}

public void addItems(Collection<Model> list) {
data.addAll(list);
 }

fragment:

adapter = new MyListAdapter(getContext(),initialItems);
0

I had a similar problem once and calling invalidateViews on the ListView worked, even if it was a hack. Instead of recycleList.invalidate(); try recycleList.invalidateViews();

cwbowron
  • 1,015
  • 6
  • 10