Search code examples
androidlistkotlincontains

Ignore variable with .contains method in kotlin?


Ignore an attribute from contains function. I mean if an attribute value changes it still be the same object.

I have implemented tracking of object in RecyclerView android. Now When some product is favourite by clicking a heart icon. One of it's attribute

 isFavourite = true /// become true

Below method get called on onScrollStateChanged of RecyclerView

 private fun trackVisibleItems(visiblePositions: IntRange) {
    for (position in visiblePositions) {
        if (position != -1) {
            trackableCollectionCallback?.getViewedItem(position)?.let {
                if(isPresent() && shownTrackablePositions.contains(it).not()){
                    it.trackView()
                    trackableCollectionCallback?.onTrackedItem(it,position)
                    shownTrackablePositions.add(it)
                }
            }
        }
    }
}  

Now after selecting heart icon from any product . An attribute name isFavourite got updated in the database. I want to ignore that variable from contains.

I have tried to write a data class in kotlin and put isFavourite out of the base constructor So that equal , hash etc don't work on it.

But contains function match all attributes. How could I ignore a var from contains.

TrackableObject.kt

abstract class TrackableObject {
    abstract fun getClickEventName(): String
    abstract fun getViewEventName(): String
    abstract fun getTrackParams(): MutableSet<Pair<String, Any>>

    fun trackClick() {
        Analytics.trackEvent(getClickEventName(), getTrackParams())
    }

    fun trackView() {
        Analytics.trackEvent(getViewEventName(), getTrackParams())
    }
}

                   

Solution

  • Moving the property out of the constructor should work. It should look like this:

    data class MyItem(
        val id: Long,
        val foo: String
    ) {
        var isFavourite: Boolean = false
    }
    

    However, I think it would be preferable to keep that in your constructor so you don't break your equals/hashCode functionality for other purposes, such as using them in a DiffUtil.

    In that case, you can use any instead of contains. Since you have to go through all the properties manually, I'd break it out into a function to keep your logic more readable.

    data class MyItem(
        val id: Long,
        val foo: String,
        var isFavourite: Boolean = false
    )
    
    fun Iterable<MyItem>.containsMatch(item: MyItem): Boolean = any { 
        it.id == item.id && it.foo == item.foo
    }
    
    // ...
    
     if(isPresent() && shownTrackablePositions.containsMatch(it).not()){
           it.trackView()
           trackableCollectionCallback?.onTrackedItem(it,position)
           shownTrackablePositions.add(it)
     }