itslonua
10/21/2016 - 7:59 PM

Simple RxJava-based adapter for an Android RecyclerView

Simple RxJava-based adapter for an Android RecyclerView

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.jakewharton.rxbinding.view.RxView;

import java.util.Collections;
import java.util.List;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subjects.PublishSubject;


public class ReactiveRecylerAdapter<T> extends RecyclerView.Adapter<ReactiveRecylerAdapter.ReactiveViewHolder<T>> {
    private final Observable<List<T>> observable;
    private final ReactiveViewHolderFactory<T> viewHolderFactory;
    private List<T> currentList;

    public ReactiveRecylerAdapter(Observable<List<T>> observable, ReactiveViewHolderFactory<T> viewHolderFactory) {
        this.viewHolderFactory = viewHolderFactory;
        this.currentList = Collections.emptyList();
        this.observable = observable;
        this.observable.observeOn(AndroidSchedulers.mainThread()).subscribe(items -> {
            this.currentList = items;
            this.notifyDataSetChanged();
        });
    }
    private PublishSubject<T> mViewClickSubject = PublishSubject.create();

    public Observable<T> getViewClickedObservable() {
        return mViewClickSubject;
    }

    @Override
    public ReactiveViewHolder<T> onCreateViewHolder(@NonNull ViewGroup parent, int pViewType) {
        ReactiveViewHolderFactory.ViewAndHolder<T> viewAndHolder = viewHolderFactory.createViewAndHolder(parent, pViewType);
        ReactiveViewHolder<T> viewHolder = viewAndHolder.viewHolder;

        RxView.clicks(viewAndHolder.view)
                .takeUntil(RxView.detaches(parent))
                .map(aVoid -> viewHolder.getCurrentItem())
                .subscribe(mViewClickSubject);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ReactiveViewHolder<T> holder, int position) {
        T item = currentList.get(position);
        holder.setCurrentItem(item);
    }

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

    public static abstract class ReactiveViewHolder<T> extends RecyclerView.ViewHolder {
        public ReactiveViewHolder(View itemView) {
            super(itemView);
        }

        public abstract void setCurrentItem(T t);
        public abstract T getCurrentItem();
    }

    public interface ReactiveViewHolderFactory<T> {
        class ViewAndHolder<T> {
            public final View view;
            public final ReactiveViewHolder<T> viewHolder;

            public ViewAndHolder(View view, ReactiveViewHolder<T> viewHolder) {
                this.view = view;
                this.viewHolder = viewHolder;
            }
        }
        ViewAndHolder<T> createViewAndHolder(@NonNull ViewGroup parent, int pViewType);
    }
}
public class ReactiveTextViewHolder<T> extends ReactiveViewHolder<T> {

    private TextView label;
    private T currentItem;

    public ReactiveTextViewHolder(View itemView) {
        super(itemView);
        label = (TextView) itemView.findViewById(android.R.id.text1);
    }

    @Override
    public void setCurrentItem(T currentItem) {
        this.currentItem = currentItem;
        this.label.setText(currentItem.toString());
    }

    public T getCurrentItem() {
        return currentItem;
    }
}

ReactiveRecylerAdapter.ReactiveViewHolderFactory<String> viewAndHolderFactory = (parent, pViewType) -> {
    View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
    return new ReactiveRecylerAdapter.ReactiveViewHolderFactory.ViewAndHolder<>(
            view,
            new ReactiveRecylerAdapter.ReactiveTextViewHolder<>(view)
    );
};
ReactiveRecylerAdapter reactiveRecylerAdapter = new ReactiveRecylerAdapter(Observable.just("Here", "we", "go"), viewAndHolderFactory);