Search code examples
androidkotlinlistenerkotlin-delegate

How to set up a listener for a variable in Kotlin


How to I set up an interface listener for detecting a variable change in Kotlin. I successful implemented the following in Java, but am running into issues doing it in Kotlin:

Interface:

public interface InterfaceRefreshList
    {
    public void refreshListRequest();
    }

Class containing listener:

public class SignalChange
    {
    private static boolean refreshListSwitch;
    private static List<InterfaceRefreshList> refreshListListeners = new ArrayList<>();
    public static void setRefreshList(boolean value)
    {
    refreshListSwitch = value;
    for(InterfaceRefreshList l : refreshListListeners)
        l.refreshListRequest();
    }
    public static void addRefreshListListener(InterfaceRefreshList l)
        {
        refreshListListeners.add(l);
        }
    }

Class where listener is listening:

public class FragmentBrowse extends Fragment
{
    public FragmentBrowse() /// Constructor
        {
        SignalChange.addRefreshListListener(() -> refreshList());
        }
    refreshList()
    {
    // do something
    }
}

To signal a change:

SignalChange.setRefreshList(true);

I can set up the interface and the signal class:

class SignalChange
{
    private var refreshListSwitch: Boolean = false
    var setSwitch: Boolean
        get() = refreshListSwitch
        set(value)
        {
            refreshListSwitch = value
        }

    private var refreshListListeners = ArrayList<InterfaceRefreshPersonsList>()
    fun sendRefreshSignal()
    {
        for(l in refreshListListeners) l.refreshPersonsList()
    }

    fun addRefreshListListener(l: InterfaceRefreshPersonsList)
    {
        refreshListListeners.add(l)
    }

}

But I cannot setup the listener in the FragmentBrowse class. The fragment class doesn't allow constructors.


Solution

  • You can use built-in Kotlin delegates, for example:

    object SignalChange {
        var refreshListListeners = ArrayList<InterfaceRefreshList>()
    
        // fires off every time value of the property changes
        var property1: String by Delegates.observable("initial value") { property, oldValue, newValue ->
            // do your stuff here
            refreshListListeners.forEach { 
                it.refreshListRequest()
            }
        }
    }
    
    interface InterfaceRefreshList {
        fun refreshListRequest()
    }
    

    Add listeners like this:

    SignalChange.refreshListListeners.add(object : InterfaceRefreshList {
        override fun refreshListRequest() {
            refreshList()
        }
    })
    

    OR

    Intead of interface you can use lambda:

    object SignalChange {
        var refreshListListeners = ArrayList<() -> Unit>()
    
        // fires off every time value of the property changes
        var property1: String by Delegates.observable("initial value") { property, oldValue, newValue ->
            // do your stuff here
            refreshListListeners.forEach {
                it()
            }
        }
    }
    

    And to add listener just call:

    SignalChange.refreshListListeners.add(::refreshList)
    //or
    SignalChange.refreshListListeners.add { refreshList() }
    
    fun refreshList() {
    
    }