Skip to content

Instantly share code, notes, and snippets.

@addam01
Last active March 4, 2020 07:22
Show Gist options
  • Save addam01/a33a1488061ab747d31afc8be10ba6b2 to your computer and use it in GitHub Desktop.
Save addam01/a33a1488061ab747d31afc8be10ba6b2 to your computer and use it in GitHub Desktop.
Filterable RecyclerView for Android

DEPENDENCIES

  • implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
  • implementation "io.reactivex.rxjava2:rxjava:2.1.9"
  • implementation "io.reactivex.rxjava2:rxkotlin:2.2.0"
  • implementation 'com.jakewharton.rxbinding2:rxbinding-kotlin:2.1.1'
  • implementation "android.arch.lifecycle:extensions:1.1.1"

Process Flow

ViewModel --> Business Logic (Initiate Model, listen to changes on textViews, and filter) -> Callback to Activity to refresh recycleView

Credits to

data class User(
val id: Int,
val name: String,
val age: Int)
class SimpleRecyclerAdapter(private val context: Context, private val users: List<User>) : RecyclerView.Adapter<SimpleRecyclerAdapter.UserHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserHolder {
//Declare the layout Resources
return UserHolder(LayoutInflater.from(context).inflate(R.layout.rcl_item_post, parent, false))
}
override fun getItemCount() = users.size
override fun onBindViewHolder(holder: PostHolder, position: Int) {
holder.bind(users[position])
}
class UserHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(user: User) {
//Bind layout
itemView.NameView.text = user.name
itemView.AgeView.text = user.age
}
}
}
class ViewModel: UserViewModel(){
//This remains unchanged
private val originalList = listof(
User(1, Addam, 30),
User(2, Herpderp, 20)
)
//This will change often as user inputs
val filteredUsers: MutableList<User> = mutableListOf()
//This will be passed to the Adapter after filtering
val oldUsers: MutableList<User> = mutableListOf()
init{
oldUsers.addAll(originalList)
}
//bind the Textview to this function for onTextChanged
fun search(query: String): Completable = Completable.create {
val wanted = originalList.filter {
it.name.contains(query) || it.age.contains(query)
}.toList()
filteredUsers.clear()
filteredUsers.addAll(wanted)
it.onComplete()
}
}
class UserDiffUtilCallback(private val oldList: List<User>, private val newList: List<User>) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = oldList[oldItemPosition].id == newList[newItemPosition].id
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = true
}
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
private val disposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
//Add the old users into the adapter to show all first
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = SimpleRecyclerAdapter(this, viewModel.oldFilteredUsers)
//Here is the business logic executor, actually can be placed into the viewmodel also can
search_text_view
.textChanges()
.debounce(200, TimeUnit.MILLISECONDS)
.subscribe{
viewModel
.search(it.toString())
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
//dispatch the different result from the callback into adapter
val diffResult = DiffUtil.calculateDiff(UserDiffUtilCallback(viewModel.oldFilteredPosts, viewModel.filteredPosts))
viewModel.oldFilteredPosts.clear()
viewModel.oldFilteredPosts.addAll(viewModel.filteredPosts)
diffResult.dispatchUpdatesTo(recyclerView.adapter)
}.addTo(disposable)
}.addTo(disposable)
}
override fun onDestroy() {
super.onDestroy()
disposable.clear()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment