I am using recyclerview in kotlin and I am new to kotlin. I have used button.setOnClickListner method inside this. I want to call a method which is in my mainActivity. How should I do it
I want to call below method which is in mainActivity
fun sendOrder() {
Log.e("TAG", "SendOrder: " )
}
my adapter is below
class CustomAdapterJob(val jobList: ArrayList<JobData>): RecyclerView.Adapter<CustomAdapterJob.ViewHolder>(){
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
val jobData :JobData = jobList[position]
holder?.textViewId?.text = jobData.id
holder?.textViewArea?.text = jobData.area
holder?.textViewCarType?.text = jobData.carType
holder?.textViewCarName?.text = jobData.carName
holder?. textViewDutyHours?.text = jobData.dutyHours
holder?.textViewWeeklyOff?.text = jobData.weeklyOff
holder?.textViewDriverAge?.text = jobData.driverAge
holder?.textViewDriverExperience?.text = jobData.drivingExperience
holder?.textViewOutstationDays?.text = jobData.outstationDays
holder?.textViewDutyDetails?.text = jobData.dutyDetails
holder?.button?.text =jobData.submit
if(jobData.submit == "true"){
holder?.button?.setVisibility(View.GONE);
}
holder?.button?.setOnClickListener( View.OnClickListener (){
Log.d("TAG", "job list position : ${jobList[position].id}")
var id = jobList[position].id
val p = Pattern.compile("-?\\d+")
val m = p.matcher(id)
while (m.find()) {
System.out.println(m.group())
sendOrder()
}
});
//To change body of created functions use File | Settings | File Templates.
}
override fun getItemCount(): Int {
return jobList.size//To change body of created functions use File | Settings | File Templates.
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val v=LayoutInflater.from(parent?.context).inflate(R.layout.job_card,parent,false)
return ViewHolder(v)
//To change body of created functions use File | Settings | File Templates.
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val textViewId = itemView.findViewById<TextView>(R.id.job_id)
val textViewArea = itemView.findViewById<TextView>(R.id.area)
val textViewCarType = itemView.findViewById<TextView>(R.id.car_type)
val textViewCarName = itemView.findViewById<TextView>(R.id.car_name)
val textViewDutyHours = itemView.findViewById<TextView>(R.id.duty_hours)
val textViewWeeklyOff = itemView.findViewById<TextView>(R.id.weekly_off)
val textViewDriverAge = itemView.findViewById<TextView>(R.id.driver_age)
val textViewDriverExperience = itemView.findViewById<TextView>(R.id.driving_experience)
val textViewOutstationDays = itemView.findViewById<TextView>(R.id.outstation_days)
val textViewDutyDetails = itemView.findViewById<TextView>(R.id.duty_details)
val button = itemView.findViewById<Button>(R.id.apply_job)
}}
now how i have to call sendOrder() method in kotline
Its better you create a listener and pass it to the adapter.
Interface
interface ActivityInteractor {
fun onInteraction(data: Any?)
}
Implement the interface in your activity
class MainActivity : Activity(), ActivityInteractor {
override fun onCreate(savedInstance : Bundle) {
CustomAdapterJob(jobList, this)
}
override fun onInteraction(data: Any?) {
// you can do any activity related tasks here
sendOrder()
}
}
Accept the listener in your adapter
class CustomAdapterJob(val jobList: ArrayList<JobData>, val activityInteractor: ActivityInteractor) : RecyclerView.Adapter<CustomAdapterJob.ViewHolder>() {
holder?.button?.setOnClickListener( View.OnClickListener () {
Log.d("TAG", "job list position : ${jobList[position].id}")
var id = jobList[position].id
val p = Pattern.compile("-?\\d+")
val m = p.matcher(id)
while (m.find()) {
System.out.println(m.group())
//sendOrder()
activityInteractor.onInteraction(jobList[position].id)
}
});
}
Instead of creating the new interface you can implement onClickListener in the activity and can pass it as a parameter to the adapter class. In the adapter, you can set this onClick listener to your button.
Use kotlin data binding concept to avoid those boilerplate codes like findViewById. please check this link
First you need to create a context:
private val context: Context
Then add this context, along with other variables you might have, to your adapter constructor:
class Adapter(..., context: Context)
Inside you while loop:
while (m.find()) {
System.out.println(m.group)
if (context is MainActivity)
{
(context as MainActivity).SendOrder()
}
}
Apologies for any syntax error, etc. My Kotlin is still a little rough.
The easiest solution would be to your activity as parameter to your recycler view. Then you could easaly call that function. But obviously this is not a very good aproach, so you should prefer the following.
Create an interface which is implemented by your activity and called instead of the activities method. Within the implementation of the interface function you can call the activity function or whatever you like. As it is implemented by the activity itself you have full access to the whole activity context.
A short example how this could be implemented is already answered here
you can do like this:
holder?.button?.setOnClickListener( View.OnClickListener (){
Log.d("TAG", "job list position : ${jobList[position].id}")
var id = jobList[position].id
val p = Pattern.compile("-?\\d+")
val m = p.matcher(id)
while (m.find()) {
System.out.println(m.group())
mySendOrder()
}
});
public void mySendOrder(){
}
and then in main activity:
yourCustomAdapter = new YourCustomAdapter(){
public void mySendOrder(){
sendOrder();
}
}
In case if you don't need Context or Activity object in your adapter. You can pass callback as parameters. May be something like this
class MyAdapter(private val sendOrder: () -> Unit = {}) : BaseAdapter() {
fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
sendOrder()
}
}
Then implement callback in Activity
fun onCreate(...) {
recyclerView.adapter = MyAdapter() {
// Do something
}
}
Related
The problem I am facing with the RecyclerView is the data is coming from Server and the API response is getting printed correctly in the console.
but when I am trying to set data in the adapter what is wrong or something is not going correctly with the flow that the data is not being updated on UI.
//This is my adapter class
class DashboardAdapter(val context: Context) : RecyclerView.Adapter<DashBoardHolder>() {
private var transactionList = ArrayList<DashboardData>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashBoardHolder {
val inflator = LayoutInflater.from(parent.context)
val view = ActivityDashboardDataBinding.inflate(inflator, parent, false)
val viewHolder = DashBoardHolder(view)
return viewHolder
}
override fun onBindViewHolder(holder: DashBoardHolder, position: Int) {
val quickModel = transactionList[position]
holder.tvName.text = quickModel.bookingTitle
}
fun showListItems(dashboardlist: List<DashboardData>?, aboolean: Boolean) {
when {
aboolean -> transactionList.clear()
}
if (dashboardlist != null && !dashboardlist.isEmpty())
this.transactionList.addAll(dashboardlist)
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return transactionList.size
}
}
MyHolderClass
class DashBoardHolder(val binding: ActivityDashboardDataBinding) :
RecyclerView.ViewHolder(binding.root) {
var tvName: TextView = binding.textViewGrandrukName
var tvTime: TextView = binding.tvGrandrukTripDetails
var tvPlace: ImageView = binding.btnGhandruk
var ivRectangle: ImageView = binding.imageView5
}
Similarly,I set the adapter in view section like this way:
//setting adapter in Presenter class
fun setAdapter() {
var layoutmanager: LinearLayoutManager? = LinearLayoutManager(appCompatActivity)
val firstVisiblePosition = layoutmanager!!.findFirstVisibleItemPosition()
binding!!.includesDashboardRecyclerview.rvBookingList.setHasFixedSize(true)
binding!!.includesDashboardRecyclerview.rvBookingList.layoutManager = layoutmanager
binding!!.includesDashboardRecyclerview.rvBookingList.adapter = dashboardAdapter
layoutmanager!!.scrollToPositionWithOffset(firstVisiblePosition, 0)
}
In Presenter Class, calling setAdapter class from presenter like this way
class DashboardPresenter(
private val dashboardView: DashboardView,
private val dashboardModel: DashboardModel
) {
fun onCreateView() {
onClick()
dashboardView.setAdapter()
getDashboardRequest()
}
//calling adpter function here
fun showList(termlist: List<DashboardData>?, aboolean: Boolean) {
(null as DashboardAdapter?)?.showListItems(termlist!!, aboolean)
}
}
I'm not able to understand what is getting wrong here.
(null as DashboardAdapter?)?.showListItems(termlist!!, aboolean)
You are calling showListItems() on the DashboardAdapter as a type not the instance dashboardAdapter. Assuming that dashboardAdapter is a local class field.
Also I guess this type casting is not necessary as you already using the optional ?
So, it can be simplified to:
dashboardAdapter?.showListItems(termlist!!, aboolean)
Assuming that this should be called whenever you retrieve the API response. So, showList() must be called when there's new API data.
I marked the parts that were added (added to code) after the moment
when the application was working, the data was successfully downloaded
from the database. I may be mistakenly trying to pass this information
to another screen. I tried to find a video that connects to the
database and forwards that data of recicler on another screen, but
without success, or they are in Java, which I understand less.
MySecondActivity
class BookDescription : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_book_description)
var books = intent.getSerializableExtra("noti") as Book //added to code
Glide.with(this).load(books.imageUrl).into(bookImg2)// added to code
nameTxt2.text = books.name //added to code
autorTxt2.text = books.writer //added to code
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var adapter : Adapter
private val viewModel by lazy { ViewModelProviders.of(this).get(MainViewModel::class.java)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setUpRecyclerView()
}
private fun setUpRecyclerView(){
adapter = Adapter(this){
startBookDescription()
}
recycle.layoutManager = GridLayoutManager(this, 2)
recycle.adapter = adapter
observerData()
}
fun observerData(){
viewModel.fetchUserData().observe(this,Observer{
adapter.setListdata(it)
adapter.notifyDataSetChanged()
})
}
private fun startBookDescription(){
val intent = Intent (this, BookDescription::class.java )
startActivity(intent)
}
}
Class Adapter with inner class Holder
class Adapter(private val context: Context,
private val onItemCliked: () -> Unit ) : RecyclerView.Adapter<Adapter.Holder>() {
private var datalist = mutableListOf<Book>()
fun setListdata(data: MutableList<Book>){
datalist = data
}
inner class Holder(itemView : View) : RecyclerView.ViewHolder(itemView){
fun bindView(book: Book, onItemClicked: () -> Unit){
Glide.with(context).load(book.imageUrl).into(itemView.bookImg)
itemView.nameTxt.text = book.name
itemView.autorTxt.text= book.writer
itemView.setOnClickListener { onItemClicked.invoke() }
itemView.bookImg.setOnClickListener(View.OnClickListener { //added
val intent = Intent(context, BookDescription::class.java)//added to code
intent.putExtra("noti", book)//added to code
context.startActivity(intent)//added to code
})
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(context).inflate(R.layout.book_format, parent,
false )
return Holder(view)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val book = datalist[position]
holder.bindView(book, onItemCliked)
}
override fun getItemCount(): Int {
return if (datalist.size> 0){
datalist.size
}else{
0
}
}
}
The problem is here:
intent.putExtra("noti", book)
The book variable is of type Book, which is apparently neither a Parcelable or Serializable class. You must implement one of these two interfaces in the Book class in order to add it to an Intent or Bundle.
Assuming Book is made up of simple data types (String, Int, etc), then you can use the #Parcelize annotation to easily implement Parcelable. More here: https://developer.android.com/kotlin/parcelize
In your bindView() method, you have this block of code:
val intent = Intent(context, BookDescription::class.java)//added to code
intent.putExtra("noti", book)//added to code
context.startActivity(intent)//added to code
})
However, you don't actually do anything with this Intent; you start your activity from another place:
private fun startBookDescription(){
val intent = Intent (this, BookDescription::class.java )
startActivity(intent)
}
You will have to pass the Book instance to this method (via invoke(book)). This will require a corresponding type change to the click listener parameter of your adapter.
I'm successfully passing data from MainActivity to my recyclerView via adapter, and my view with items is rendering correctly. However, I need to change one member of my item object on click (status), and i wrote a method for that (updateStatus), and it works great, it changes the value and save it to database.
But i cannot refresh my recyclerView, so it could render changed Status attribute. I need to go back on my phone, reenter, and then it renders it correctly. I have tried everything, from notifyDataSetChanged to restarting adapter, no luck. There is something missing and I can't find what.
Here is my MainActivity class
class MainActivity : AppCompatActivity() {
private var posiljkaDAO: PosiljkaDAO? = null
private var dostavnaKnjizicaDAO: DostavnaKnjizicaDAO? = null
private var allItems: ArrayList<DostavnaKnjizicaModel> = arrayListOf()
var adapter = RecycleViewAdapter(allItems)
private var eSifraPosiljke: EditText? = null
#RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_listview)
//get logo
supportActionBar!!.setDisplayShowHomeEnabled(true)
supportActionBar!!.setLogo(R.drawable.logo_bp)
supportActionBar!!.setDisplayUseLogoEnabled(true)
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(this)
dostavnaKnjizicaDAO?.closeDB()
getAllItems(this)
//connecting adapter and recyclerView
adapter = RecycleViewAdapter(allItems)
recycleView.adapter = adapter
recycleView.layoutManager = LinearLayoutManager(this)
recycleView.setHasFixedSize(true)
eSifraPosiljke = findViewById<EditText>(R.id.eSifraPosiljke)
posiljkaDAO = PosiljkaDAO(this)
}
//method that gets all items from database
private fun getAllItems(context: Context) {
var dostavenFromLOcal = dostavnaKnjizicaDAO?.getAllLocalDostavneKnjizice(context)
if (dostavenFromLOcal != null) {
allItems = dostavenFromLOcal
}
}
//method that changes status of an item
fun changeStatus(context: Context, IdDostavne: Int, statusDostavne: Int) {
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(context)
dostavnaKnjizicaDAO?.changeStatus(IdDostavne, statusDostavne)
getAllItems(context)
adapter.notifyDataSetChanged()
}
}
and my Adapter class
class RecycleViewAdapter(var dostavneKnjiziceBP: ArrayList<DostavnaKnjizicaModel>)
: RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
val nazivPrimaoca: TextView = view.txtNazivPrimaoca
val brojPosiljke: TextView = view.txtBrojPosiljke
val statusDostave: TextView = view.txtStatusDostave
val imgMore: ImageView = view.img_more
val context: Context = view.context
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.urucenje_posiljke_layout, parent, false)
return ViewHolder(layoutView)
}
override fun getItemCount() = dostavneKnjiziceBP.size
#RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
//New variable to get all modeliPosiljakaBP and their position
var dosKnjizica = dostavneKnjiziceBP[position]
val mainActivity = MainActivity()
//Sending data to layout for display in specific field
if (dosKnjizica.naziv_primaoca != null) {
holder.brojPosiljke.text = "${dosKnjizica.id_dostavna_knjizica}, "
holder.nazivPrimaoca.text = "${dosKnjizica.naziv_primaoca}"
if (dosKnjizica.naziv_primaoca!!.length > 25) {
holder.nazivPrimaoca.text = "${dosKnjizica.naziv_primaoca!!.subSequence(0, 25)}..."
}
} else {
holder.brojPosiljke.text = "${dosKnjizica.id_dostavna_knjizica}"
holder.nazivPrimaoca.text = ""
}
holder.statusDostave.text = "${dosKnjizica.status_dostave_naziv}"
when (dosKnjizica.status_dostave) {
StatusDostaveEnum.Neurucena.value -> {
holder.statusDostave.setTextColor(Color.RED)
}
StatusDostaveEnum.Uruceno.value, StatusDostaveEnum.ZaRejon.value, StatusDostaveEnum.Nadoslano.value, StatusDostaveEnum.Izgubljeno.value -> {
holder.statusDostave.setTextColor(Color.GREEN)
}
StatusDostaveEnum.Obavjesteno.value, StatusDostaveEnum.ZaNarednuDostavu.value -> {
holder.statusDostave.setTextColor(Color.BLUE)
}
StatusDostaveEnum.Retour.value -> {
holder.statusDostave.setTextColor(Color.parseColor("#dda0dd"))
}
}
//Calling menu menu_pregled_drugih_vrsta_posiljke to display menu options on click on three dots
holder.imgMore.setOnClickListener {
val popupMenu = PopupMenu(holder.context, it, Gravity.START)
popupMenu.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.uruci -> {
//calling new activity from second item in dropdown menu
holder.imgMore.context.startActivity(
Intent(holder.imgMore.context, MainActivityInfo::class.java).putExtra(
"Id", dosKnjizica.id_dostavna_knjizica.toString()
)
)
true
}
//here i am calling my changeStatus method from MainActivity
R.id.obavjesti -> {
mainActivity.changeStatus(holder.context, dosKnjizica.id_dostavna_knjizica!!, StatusDostaveEnum.Uruceno.value)
Toast.makeText(holder.context, "obavjesti", Toast.LENGTH_SHORT).show()
true
}
R.id.vrati -> {
Toast.makeText(holder.context, "vrati", Toast.LENGTH_SHORT).show()
true
}
else -> false
}
}
popupMenu.inflate(R.menu.menu_urucenje_posiljke)
popupMenu.show()
}
}
}
Your adapter doesn't have the updated data. Initially, you fetch all data from the database and create an adapter with it: adapter = RecycleViewAdapter(allItems). Afterwards, you are updating the database, calling getAllItems(Context) but you don't pass the data to the adapter.
Add the line adapter.dostavneKnjiziceBP = allItems to the changeStatus method like this:
//method that changes status of an item
fun changeStatus(context: Context, IdDostavne: Int, statusDostavne: Int) {
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(context)
dostavnaKnjizicaDAO?.changeStatus(IdDostavne, statusDostavne)
getAllItems(context)
adapter.dostavneKnjiziceBP = allItems
adapter.notifyDataSetChanged()
}
Save dostavneKnjiziceBP as a private var inside the adapter and create functions for assigning and updating that ArrayList from within the adapter, using notifyDataSetChanged() everytime a change is done.
class RecycleViewAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>() {
private var items = ArrayList<DostavnaKnjizicaModel>()
// ...
internal fun setItems(items: ArrayList<DostavnaKnjizicaModel>) {
this.items = items
notifyDataSetChanged()
}
override fun getItemCount() = this.items.size
}
Also, try using adapter.notifyItemChanged(updateIndex); if you know the index of the updated item.
I am trying to access to mBeers fromd HomeViewHolder but I got this "You need to create a abstrac property" but that is not a solution because I have a base class. I need to make a new request when recyclerview doesnt have more data to display.
class HomeAdapter(private val beers: ArrayList<Beer>, val context: Context):
RecyclerView.Adapter<BaseViewHolder>() {
class HomeViewHolder(itemView: View): BaseViewHolder(itemView) {
val beerImage: ImageView = itemView.findViewById(R.id.iv_row_image)
val beerLayout: ConstraintLayout = itemView.findViewById(R.id.cl_row_layout)
val beerName: TextView = itemView.findViewById(R.id.tv_row_name)
val beerTagLine: TextView = itemView.findViewById(R.id.tv_row_name)
override fun clear() {}
override fun onBind(position: Int) {
super.onBind(position)
Picasso.get().load(mBeers!![position].imageURL).fit().centerCrop().transform(
RoundedCornersTransformation(10, 0)
).into(beerImage)
beerName!!.text = mBeers!![position].name
beerTagLine!!.text = mBeers!![position].tagLine
beerLayout!!.setOnClickListener {
val intent = Intent(context, DetailActivity::class.java)
context!!.startActivity(intent)
}
}
}
}
I have a recycler view adapter in android. Part of my adapter class looks like this:
private lateinit var itemLongClick: ItemLongClick
override fun onCreateViewHolder(parent: ViewGroup, a: Int): RecyclerAdapter.ViewHolder {
// Define And Initialize The Custom View And Its Holder//
val myView = LayoutInflater.from(parent.context).inflate(customLayout, parent, false)
val viewHolder = ViewHolder(myView)
// What Happens When A List Item Is Long Clicked//
myView.setOnLongClickListener { view ->
// Differ Action To Class Instance//
itemLongClick.longClicked(context, viewHolder.layoutPosition, view)
// End Function//
true
}
// Returns The Custom View//
return viewHolder
}
fun setItemLongClick(itemLongClick: ItemLongClick) {
// Sets The Value For this.itemLongClick//
this.itemLongClick = itemLongClick
}
I created an interface tat looks like this:
interface ItemLongClick {
// Function Declaration For When An Item Is Long Clicked//
fun longClicked(context: Context, position: Int, view: View)
}
Instead of writing my on long click code in the adapter class I want to differ it to the activity that is calling the adapter class. I know one way of doing this is to make a kotlin interface then call it in the other class like this
userAdapter.setItemLongClick(object: ItemLongClick {
override fun longClicked(context: Context, position: Int, view: View) {
}
})
But this looks messy. I know java interfaces work with SAM but I don't want to do that either. What I want is for the onLongClick to be a Lambda but I'm not sure how to set up a Kotlin lambda expression to make this work and I can't find a good example anywhere.
Thanks in advance
You have two options:
1.) replace interface with typealias
typealias ItemLongClick = (Context, Int, View) -> Unit
2.) add an extension function for setting the interface as a lambda instead of with anonymous object
inline fun UserAdapter.setItemLongClick(crossinline longClick: (Context, Int, View) -> Unit) {
setItemLongClick(object: ItemLongClick {
override fun longClicked(context: Context, position: Int, view: View) {
longClick(context, position, view)
}
})
}
Now you can call
userAdapter.setItemLongClick { context, position, view ->
...
}
I had an adapter that i need to change the data based on a switch and i did something like this:
ListAdapter(private val context: Context, private val switchListener: (Boolean) -> Unit)
Then where i binded the header of my sectioned list i had:
private fun bindHeader(holder: HeaderViewHolder) {
holder.switch.setOnCheckedChangeListener { _, isChecked ->
callbackSwitchListener(isChecked)
}
}
And in my fragment:
private fun setupRecyclerView() {
fabricationDataListAdapter =
FabricationDataListAdapter(context!!) { isChecked: Boolean -> switchControl(isChecked) }
val layoutManager = ListLayoutManager(context!!)
this.recycler_view_all.layoutManager = layoutManager
this.recycler_view_all.adapter = fabricationDataListAdapter
}
Where the fun switchControl changed the data based on the boolean.
I'm not sure if this is what you need, i'm in a bit of a hurry, but this is called high order functions in kotlin, if i'm not mistaken.
As the Kotlin documentation for the Kotlin 1.4 release points out:
Before Kotlin 1.4.0, you could apply SAM (Single Abstract Method) conversions only when working with Java methods and Java interfaces from Kotlin. From now on, you can use SAM conversions for Kotlin interfaces as well. To do so, mark a Kotlin interface explicitly as functional with the fun modifier.
fun interface Operation1 {
operator fun invoke(x: String): String
}
fun interface Operation2 {
fun doSomething(x: Int): String
}
val operation1 = Operation1 { "$it world!" }
val operation2 = Operation2 { "$it world!" }
fun main() {
// Usage: First sample.
println(operation1("Hello"))
println(operation2.doSomething(0))
// Usage: Second sample.
println(Operation1 { "$it world!" }("Hello"))
println(Operation2 { "$it!" }.doSomething(0))
}
You can read more about functional interfaces here.
In below code I using filterable adapter to do search on list. Here I am using lambda as callback to notify to view model when no data is found for the search.
Instantiating Adapter in ViewModel. And passing lambda
var matterAdapter = MatterAdapter(matterList) {
//todo - got callback
}
Adapter
class MatterAdapter (var filteredList : MutableList<AndroidViewModel>, val funcNoSearchData : () -> Unit) : DataBindingRecyclerViewAdapter(filteredList), Filterable {
private var mViewModelMap: MutableMap<Class<*>, Int> = mutableMapOf()
private var originalList : MutableList<AndroidViewModel> = mutableListOf()
private val mFilter = ItemFilter()
init {
mViewModelMap.put(MatterRowViewModel::class.java, R.layout.row_matter)
}
override fun getViewModelLayoutMap(): MutableMap<Class<*>, Int> {
return mViewModelMap
}
override fun getFilter(): Filter {
return mFilter
}
private inner class ItemFilter : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
val filterString = constraint.toString().toLowerCase()
val results = FilterResults()
val list = originalList
val count = list.size
val nlist = ArrayList<AndroidViewModel>(count)
var filterableString: String
for (i in 0 until count) {
filterableString = (list.get(i) as MatterRowViewModel).matter.casestitle!!
if (filterableString.toLowerCase().contains(filterString)) {
nlist.add(list.get(i))
}
}
results.values = nlist
results.count = nlist.size
return results
}
override fun publishResults(constraint: CharSequence, results: Filter.FilterResults) {
filteredList.clear()
filteredList.addAll(results.values as ArrayList<AndroidViewModel>)
// sends empty search callback to viewmodel
if(filteredList.size == 0) {
funcNoSearchData()
}
notifyDataSetChanged()
}
}
fun resetSearch() {
filteredList.clear()
filteredList.addAll(originalList)
notifyDataSetChanged()
}
fun refreshData() {
originalList = ArrayList(filteredList)
notifyDataSetChanged()
}
}