3

When I set adapter's data directly then the scroll position of the list is correct after I come back from detial fragment, but If I'm using RXAndroid to handle data then the scroll is always jump to the top. Here is an example about my problem:

public class ListFragment extends Fragment {

private MyAdapter adapter;
private List<String> data = new ArrayList<>();

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    for (int i = 1; i < 30; i++) {
        data.add("POS: " + i);
    }
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_list, container, false);
    adapter = new MyAdapter();
    ((RecyclerView) root.findViewById(R.id.bone_list)).setAdapter(adapter);
    return root;
}

@Override
public void onResume() {
    super.onResume();
    data.add("POS: " + (data.size() + 1));

    // Working
    //adapter.setData(data);

    // Not working
    Observable.just(data)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<List<String>>() {
                @Override
                public void accept(List<String> strings) throws Exception {
                    adapter.setData(strings);
                }
            });
}

class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> values = new ArrayList<>();

    public void setData(List<String> items) {
        values = items;
        notifyDataSetChanged();
    }

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

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.content.setText(values.get(position));
        holder.root.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager().beginTransaction()
                        .replace(R.id.container, Fragment.instantiate(getContext(), DetialFragment.class.getName()))
                        .addToBackStack(null)
                        .commit();
            }
        });
    }

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

    class ViewHolder extends RecyclerView.ViewHolder {
        final View root;
        final TextView content;

        ViewHolder(View view) {
            super(view);
            root = view;
            content = (TextView) view.findViewById(R.id.content);
        }
    }
}

}

Working (simple set data):

enter image description here

Not working (rx):

enter image description here

Thanks, Robert

Robertoq
  • 559
  • 1
  • 10
  • 21

1 Answers1

0

I may be late but got the same problem.

RecyclerView automatically (as any view with ID) saves state, but you should provide a data before the first layout pass.

So synchronous adapter.setData(data) works, but asynchronous Rx operations don't.

You can cache data and set it synchronously or directly save and set position in your accept function.

Maxim G
  • 1,479
  • 1
  • 15
  • 23