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