Coder Social home page Coder Social logo

rxrecycleradapter's Introduction

RxRecyclerAdapter

Release GitHub license Android Arsenal

Rx based generic RecyclerView Adapter Library.

How to use it?

Example!

  • Enable Databinding by adding these lines to your build.gradle
dataBinding {
      enabled = true
}
  • Create the layout file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_horizontal_margin">

        <TextView android:id="@+id/textViewItem"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  tools:text="Recycler Item"/>

    </LinearLayout>
</layout>
  • Create your dataSet
//Dummy DataSet
val dataSet = mutableListOf<String>()
dataSet.add("Lorem")
dataSet.add("ipsum")
dataSet.add("dolor")
dataSet.add("sit")
dataSet.add("amet")
  • Create RxDataSource
// Simple data source
val rxDataSource = RxDataSource<ItemLayoutBinding, String>(R.layout.item_layout, dataSet)

rxDataSource
        .map { it.toUpperCase() }
        .repeat(4)
        .asObservable()
        .subscribe {
            val binding = it.viewDataBinding ?: return@subscribe
            binding.textViewItem.text = it.item
        }

And that's it! The recyclerView is going to show

Changing the data dynamically

Simply call updateAdapter after making changes to the dataSet and that'll do the trick!

rxDataSource.map(...).filter(...).take(...).updateAdapter();

Adapter for multiple View Types

If multiple view types are required for your recyclerView, let's say, we have two types HEADER and ITEM then the coding steps will be :-

  • Enable Databinding
  • Create a list of ViewHolderInfo
//ViewHolderInfo List
val viewHolderInfoList = ArrayList<ViewHolderInfo>()
viewHolderInfoList.add(ViewHolderInfo(R.layout.item_layout, TYPE_ITEM))
viewHolderInfoList.add(ViewHolderInfo(R.layout.item_header_layout, TYPE_HEADER))
  • Create an instance of RxDataSourceSectioned implementation
 // Sectioned data source
val rxDataSourceSectioned = RxDataSourceSectioned(dataSet, viewHolderInfoList, object : OnGetItemViewType() {
    override fun getItemViewType(position: Int): Int {
        if (position % 2 == 0) { // even are headers
            return TYPE_HEADER
        }
        return TYPE_ITEM
    }
})
  • Compose and call bindRecyclerView passing in recyclerView, viewHolderInfoList and viewTypeCallBack
rxDataSourceSectioned
    .asObservable()
    .subscribe {
        val viewDataBinding = it.viewDataBinding
        val data = it.item

        when (viewDataBinding) {
            is ItemLayoutBinding -> viewDataBinding.textViewItem.text = "ITEM: " + data
            is ItemHeaderLayoutBinding -> viewDataBinding.textViewHeader.text = "HEADER: " + data
        }
    }

And the output would look something like

More examples and details here

How to update adapter?

You can update all the data set by call updateDataSet(), then call updateUdapter() to update the adapter (get "notifiyDataSetChange()" effect)

rxDataSource.updateDataSet(newDataSet)
rxDataSource.updateAdapter()

If you want to update one item of the data set, you can use updateDataSet(updatedList, effectedPosition, transactionType),

rxDataSource.updateDataSet(
  dataSet.apply { removeAt(deletedPosition) },
  deletedPosition,
  RxDataSource.TransactionTypes.DELETE
)

Download

Repository available on jCenter

implementation 'com.minimize.android:rxrecycler-adapter:1.3.2'

If the dependency fails to resolve, add this to your project repositories

repositories {
  maven {
      url  "http://dl.bintray.com/ahmedrizwan/maven"
  }
}

License

Copyright 2015 Ahmed Rizwan

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

rxrecycleradapter's People

Contributors

ahmedrizwan avatar bryant1410 avatar nightscape avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rxrecycleradapter's Issues

Specify License

I've used this in personal projects and it's pretty good: kudos to you for making it.

I now want to use this library in some commercial projects. However, without an explicit license I won't be able to due to my client's policies. Would you kindly mention the license by adding it on the root directory of this project?

How to set Adapter onItemClick event it please?

I follow you.And thanks a lot. You open my eyes. but how to set Adapter onItemClick event it ?please ใ€‚ like this?
rxDataSource.repeat(1).
bindRecyclerView(fragmentBinding.mGridView, R.layout.item_homepage_gridview)
.subscribe(viewHolder -> {
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(ViewGroup
.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
ItemHomepageGridviewBinding dataBinding = viewHolder.getViewDataBinding();
param.width=screenWidth/3;
param.height = screenWidth/5;
dataBinding.gridviewRoot.setLayoutParams(param);
long itemId = viewHolder.getItemId();
String item = viewHolder.getItem();
if(itemId < lastCount){
Picasso.with(getActivity()).load(item).into(dataBinding.gridviewNetImage);
}else{
dataBinding.gridviewNetImage.setImageResource(R.drawable.gridview_background);
}
dataBinding.getRoot().setOnClickListener(new View.OnClickListener() {
@OverRide
public void onClick(View v) {

                    }
                });
            });

Simpler approach?

Hi @ahmedrizwan,

I'm relatively new to RxJava and also not an Android expert, so take this proposal with a grain of salt.
I have a use-case where not all items of the RecyclerView are known in advance (Bluetooth devices that are discovered dynamically).
AFAIS, this use case is not currently covered by RxRecyclerAdapter because all classes basically take a List<T> in advance and allow a certain set of operations on this list.

Now I was wondering why the classes in the library don't just accept a Observable<List<T>>. Then you wouldn't have to reimplement all those methods in RxDataSource because you could just pass an Observable which has all those operations applied already.

I've drafted a minimal working example here.
Do you see any problems with that approach?
Would this be worthy a direction to pursue in RxRecyclerAdapter, or should I rather create this as a separate project?

Only showing one element

I'm trying to use the lib and my list view is only displaying the first element.

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.simple_recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

RxDataSource<SimpleViewModel> rxDataSource = new RxDataSource<>(generateSimpleList());

rxDataSource
	.<MyLayoutBinding>bindRecyclerView(recyclerView, R.layout.my_layout)
	.subscribe(viewHolder -> {
		MyLayoutBinding b = viewHolder.getViewDataBinding();
		SimpleViewModel x = viewHolder.getItem();
		b.simpleTextView.setText(x);
	});

The list is of 100 elements

	private List<SimpleViewModel> generateSimpleList() {
		List<SimpleViewModel> simpleViewModelList = new ArrayList<>();

		for (int i = 0; i < 100; i++) {
			simpleViewModelList.add(new SimpleViewModel(String.format(Locale.US, "This is item %d", i)));
		}

		return simpleViewModelList;
	}

SimpleViewModel

public class SimpleViewModel {
	private String simpleText;

	public SimpleViewModel(@NonNull final String simpleText) {
		Check.requireNonNull(simpleText);
		setSimpleText(simpleText);
	}

	@NonNull
	public String getSimpleText() {
		return simpleText;
	}

	public void setSimpleText(@NonNull final String simpleText) {
		Check.requireNonNull(simpleText);
		this.simpleText = simpleText;
	}
}

Viewholder Data binding and click listener

Sorry to ask, But I do have 2 question with RxReyclerAdapter,

  1. How can we specific set data for many view in the viewholder, Ex. We have 1 ImageView, and Title, And Description.Support we use List, that contain 3 attribute for the list,
  2. How to set event click for each row of the item in the viewholder, to get the index of position.

Use inside a fragment?

Hi, i have this code on my fragment:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        fragmentHomeBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.fragment_home, container, false);
        fragmentHomeBinding.rv.setLayoutManager(new LinearLayoutManager(getContext()));
        fragmentHomeBinding.rv.setHasFixedSize(true);
        //Dummy DataSet
        mCompositeSubscription.add(HaipService.getMyPendingCampaigns()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .flatMap(campaigns -> {
                    pending = new RxDataSource<>(campaigns);
                    return pending.<MainItemBinding>bindRecyclerView(fragmentHomeBinding.rv, R.layout.main_item);
                })
                .doOnNext(campaignMainItemBindingSimpleViewHolder -> {
                    fragmentHomeBinding.rv.setAdapter(pending.getRxAdapter());
                })
                .subscribe(viewHolder -> {
                    MainItemBinding item = viewHolder.getViewDataBinding();
                    Campaign campaign = viewHolder.getItem();
                    Log.d("I'm here", campaign.getName());

                    Picasso.with(getContext()).load(campaign.getLogo()).fit().centerInside().into(item.brandImage);
                    Picasso.with(getContext()).load(campaign.getImage())
                            .fit().centerCrop().into(item.campaignImage);
                    item.brandName.setText(campaign.getName());
                    item.progressBar.setProgress(campaign.getCompleteStatus());
                    item.completedPercent.setText(String.valueOf(campaign.getCompleteStatus()) + "%");
                }, Throwable::printStackTrace));
        return fragmentHomeBinding.getRoot();

    }

but when I run the app, i'm only get

E/RecyclerView: No adapter attached; skipping layout

If I test the same code on an Activity, it works (changing DataBindingUtil.inflate by DataBindingUtil.setContentView).

Is this the correct way to bind a recyclerView inside a fragment?

[Question] How to pass an Rx obserable as the dataset instead?

I'm trying to combine this with RxPreferences. I have a List stored as shared preferences and every time this pref object gets updated I want the recycler view (using this library) to be updated as well. Think of Whatsapp chats example where when a new message comes it updated the list but all data it stored internally (shared prefs in this example).

I'm currently using this code to solve my problem (which kinda works perfectly):

val chatsPref = rxSharedPreferences.getObject("chats", emptyList(), ChatsPreferenceAdapter(gson))
val chats = chatsPref.get()
val rxDataSource = RxDataSource<ChatItemBinding, Chat>(R.layout.chat_item, chats)
disposables.add(
    rxDataSource.asObservable()
        .subscribe {
            val item = it.item!!
            val binding = it.viewDataBinding!!

            binding.tvMessage.text = item.message
        }
)

disposables.add(chatsPref.asObservable()
    .subscribe {
        rxDataSource.updateDataSet(it).updateAdapter()
    }
)

You can see that in this, I'm first extracting the initial value of chats using chatsPref.get() and then initializing my RxDataSource object using that and then in the last few lines, using the observable stream of the preference item to let the data source update. Is there a way I can cut down the lines to directly pass chatsPref.asObservable() into RxDataSource during initialization to avoid all these extra steps?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.