Hi All, I'm currently facing some issues with my c...
# orbit-mvi
t
Hi All, I'm currently facing some issues with my code and Orbit-MVI and don't fully get why this happens and how to fix. I'm using a Android Jetpack Compose function with following code:
Copy code
@Composable
fun MyComposeApp(modifier: Modifier = Modifier, viewModel: MyAppViewModel = getStateViewModel()) {
...
ConstraintLayout(modifier = modifier
        .pointerInput(Unit) {
            detectTapGestures(
                onLongPress = {
                    Log.d("xxx","TabGestures: longPress recognized")
                    viewModel.switchToEditMode(true)
                })
        }
My state class look like this:
Copy code
data class MyAppState(
    ...
    val editMode: Boolean = false,
MyAppViewModel:
Copy code
class MyAppViewModel(
    private val repository: MyAppRepository,
    private val savedState: SavedStateHandle
) : ContainerHost<MyAppState, Nothing>, ViewModel() {

    override val container = container<MyAppState, Nothing>(
        MyAppState(...)
    ) {
        ...
    }

    fun switchToEditMode(editMode: Boolean) {
        Log.d("xxx","1 switchToEditMode: $editMode")

        intent {
            Log.d("xxx","2 switchToEditMode")

            reduce {
                state.copy(
                    editMode = editMode,
                    ...
                )
            }
            Log.d("xxx","3 switchToEditMode")
        }
    }
My code is embedded in some Fragment pages with a pager implementation. The Compose code is rendered on one of those Fragments. Due to some legacy code and extended Drag&Drop functionality I was not able to use Compose for the rest of the Fragment pages. On that legacy Fragment pages (Kotlin code) I'm using Drag&Drop functionality enabled by long-press. This code and all the relevant classes are separated from the Compose code (see above). So there shouldn't be any interference. The only code they share is the whole fragment pager logic. But the content of this single compose ui is embedded like this:
Copy code
class MyComposeFragment : Fragment() {

    val myAppViewModel: MyAppViewModel by viewModel()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                HomeTheme {
                    MyComposeApp(Modifier.fillMaxSize(), MyAppViewModel)
                }
            }
        }
    }
}
Bug scenario: As long as I do not perform any drag&drop on those legacy code pages, the Compose impl. and Orbit code works like charm. Then I perform a drag&drop gesture on those non Compose code pages and swipe back to my Fragment using the Compose code above. The Compose code on longpress calls:
Copy code
viewModel.switchToEditMode(true)
and the Log is printed. This now leads to my viewModel where the following function is called:
Copy code
fun switchToEditMode(editMode: Boolean) {
        Log.d("xxx","1 switchToEditMode: $editMode")
...
This log is printed as well but it seems that the complete intent { } block is not going to be executed anymore. At least I cannot see my logs in there. NOTE: Clicks on the Compose UI are still possible and show a result and also the long-press gesture seems to be recognized correctly. It's just that the intent block is not executed anymore. Can anybody give a hint or explain to me why and in what situations the intent {} block will not be executed anymore? How can I fix or work-around? Help is highly appreciated.
o
the only thing I could think of is the crash inside the
intent{}
(but I don’t remember what is the behaviour if the exceptionHandler is not installed) or some kind of dead loop with state subscription
✍️ 1
t
I have added an exceptionhandler but cannot see any crash in my ViewModel
Copy code
val handler = CoroutineExceptionHandler { _, exception ->
        Log.d("xxx","CoroutineExceptionHandler got $exception")
    }

    override val container = container<MyAppState, Nothing>(
        MyAppState(...), Container.Settings(exceptionHandler = handler)
    ) {
Any other idea or things I can do/try out?
Hi All, I have debugged a little further. I have made a copy of the .intent extension function and added some more logs in it:
Copy code
public fun <STATE : Any, SIDE_EFFECT : Any> ContainerHost<STATE, SIDE_EFFECT>.intentx(
        registerIdling: Boolean = true,
        transformer: suspend SimpleSyntax<STATE, SIDE_EFFECT>.() -> Unit
    ): Unit {
        Log.d("OOO", "0 intentx")
        kotlinx.coroutines.runBlocking {
            Log.d("OOO", "1 intentx")

            container.orbit {
                Log.d("OOO", "2 intentx")
                withIdling(registerIdling) {
                    SimpleSyntax(this).transformer()
                }
            }
        }
    }

    fun switchToEditMode(editMode: Boolean) {
        Log.d("OOO", "0 switchToEditMode: $editMode")
        intentx {
            //intent {
            Log.d("OOO", "1 switchToEditMode: $editMode state: ${state.editMode} ")

            reduce {
                state.copy(
                    editMode = editMode,
                    ...
                )
            }
            Log.d("OOO", "2 switchToEditMode: $editMode state: ${state.editMode} ")
        }
    }
In my bug scenario the .intentx function prints the logs until Log.d("OOO", "1 intentx"). The last one in the "container.orbit" is NOT printed out. If I understand this correctly the intents should now be in the orbit event loop and waiting to be processed. But what can hold them back, not to be taken and processed by orbit? Note: It seems that in this bug scenario non of my orbit intents can go through anymore. Feedback is highly appreciated.