Home > Blockchain >  kotlin Flow And Emit
kotlin Flow And Emit

Time:12-30

i am trying to use kotlin liveData and Emit some Data to my viewModel and use that in my fragment as viewLifecycleOwner.

1-i have an Singleton class that name is OrderBasket that have a mrthod to get a String

  public String getMyText() {
        if (myText == null || TextUtils.isEmpty(myText))
            return "Nothing to Show";
        return myText;
    }

2-i have a Repository that have a function

//Exactly thats my Problem!!!!!!

 val myText: Flow<String> = flow {
    while (true) {
        val textResult = OrderBasket.getInstance().myText
        emit(textResult)
    }

}

3- my View model is

val myText: LiveData<String> = repository.myText.asLiveData()

at the end my Fragment 4- Fragment

 basketViewModel.myText.observe(viewLifecycleOwner) { text ->
        text.let {

            binding.textHome.setText(text)
        }

the problem is i want to Do Like Room. Emit Automatically data only after data changes on My Singleton Class Like Room After change Data On Database

i Know where is my problem but i dont know the solution!

in fact i want to Do like this in Room

fun <T> createFlow(query: Query, tables: List<Tables>): Flow<T> = flow {
val changeTracker = tableChangeTracker(tables)

while(true) {
    emit(suspendQuery(query))
    changeTracker.suspendUntilChanged()
}

}

CodePudding user response:

You can try to use MutableSharedFlow in your OrderBasket class to have a hot stream of data. It will look something like this:

// In OrderBasket class
private val textFlow = MutableSharedFlow<String>() 
val myText(): Flow<String> = textFlow

var myText: String? = "Nothing to Show"
    set(value) {
        val v = if (value == null || TextUtils.isEmpty(value)) "Nothing to Show"
                else value
        field = v
        textFlow.tryEmit(v)
    }

// In Repository
val myText: Flow<String> = OrderBasket.getInstance().myText

// ViewModel and Fragment are the same

CodePudding user response:

We can't easily observe changes to a regular String field (OrderBasket.myText). We have to somehow intercept mutations of this value and send some kind of event/notification that it was changed.

Assuming myText is mutated through a setter, this is a good place to trigger the event. We can notify using a classic approach with a callback, but you already use flows, so I suggest using a flow here as well. It is a little tricky to use from Java, but nothing really hard:

public class OrderBasket {
    private final MutableStateFlow<String> myTextFlow = StateFlowKt.MutableStateFlow(null);

    public StateFlow<String> getMyTextFlow() {
        return FlowKt.asStateFlow(myTextFlow);
    }

    public String getMyText() {
        String myText = myTextFlow.getValue();
        if (myText == null || TextUtils.isEmpty(myText))
            return "Nothing to Show";
        return myText;
    }

    public void setMyText(String myText) {
        myTextFlow.setValue(myText);
    }
}

Then you can use OrderBasket.myTextFlow in the repository:

val myText: Flow<String> get() = OrderBasket.getInstance().myTextFlow
  • Related