Kotlin - fragment lifecycle navigation issues; why does child fragment become current destination?

匆匆过客 提交于 2021-01-29 09:17:25

问题


Kotlin/Android novice. Please bear with me.

My app has the following navigation scheme: BottomNavigationView with navigationController where fragment One, Two and Three are "top destinations", from which I look to navigate further down in the navigation hierarchy. I implemented the scheme following this video tutorial.

MY ISSUE

Fragment Three is a QR-code scanner. Upon successful scan I aim to navigate to fragment X. However, when I reach the point of navigation, fragment X has become currentDestination (findNavController().currentDestination) and the navigation fails with error

java.lang.IllegalArgumentException: Navigation action/destination action_fragmentThree_to_fragmentX cannot be found from the current destination 

If I instead navigate to fragment X from fragment Three's onCreate, everything works fine. Hence, the navigation setup must be correct.

TROUBLESHOOTING

I don't know much about fragment lifecycles, but looking at the states of the fragments leading up to the navigation I think something is amiss.

Fragment Three -> onResume()
// QR-CODE is scanned and QR-string is captured (`ImageAnalysis.Analyzer`); method in fragment Three gets executed

// Current destination = fragment Three

// Method in fragment Three validates the QR-string using some simple String extension methods. 

Fragment X -> onCreate()
Fragment X -> onCreateView()

// Current destination = fragment X

Fragment Three -> onPause()
Fragment Three -> onStop()
// Navigation fails

What most likely causes fragment X to be created? Is this what makes it current destination? If so, how can I deal with this?

ANY suggestion will be much appreciated. Just tell me if you need to see some certain portion of code.

EDIT 1:

Upon navigation Fragment X is also current navigation fragment. Android Navigation Architecture Component - Get current visible fragment

EDIT 2 - fragment Three (ScanFragment) code:

Initialization for imageAnalyzer with callback, in fragment Threes onViewCreated

imageAnalyzer = ImageAnalyzer()
imageAnalyzer.codeWasScanned = { scannedCode ->
    if(!ScanningSession().isActive) { // internal class ScanningSession : Application() {}
        uponSuccessfulScan(scannedCode)
    }
}

fun uponSuccessfulScan(qrString: String) {

    // For debugging purposes
    println("ScanFragment || Scanned QR-code: $qrString")

    // Validate the code and handle it
    val identifierInScannedCode = ScanningSession().getIdentifierFor(qrString)

    println(identifierInScannedCode)

    if (identifierInScannedCode.isValid()) {

        println("ScanFragment || The QR-code is valid")

        if (identifierInScannedCode.isValidVehicleIdentifier()) {

            println("ScanFragment || Vehicle was scanned")

            if(!vehicleScanIsDisabled) {

                println("ScanFragment || Vehicle scan is enabled")
                // Prepare and navigate to fragment X

                println("Current destination: ${findNavController().currentDestination}")
                println("Current navigation fragment: ${activity?.supportFragmentManager?.currentNavigationFragment}")
                findNavController().navigate(R.id.action_scanFragment_to_fragmentX)

            } else {
                //TODO
            }

        } else if (identifierInScannedCode.isValidRoomOrPlaceIdentifier()){

            println("ScanFragment || Room or place was scanned")

        }

    } else {
        
        println("ScanFragment || The QR-code is NOT valid ")
        //presentInvalidCodeAlert()
    }

}

EDIT 3 - ImageAnalyzer code:

class ImageAnalyzer: ImageAnalysis.Analyzer {

    var codeWasScanned: ((String) -> Unit)? = null

    override fun analyze(imageProxy: ImageProxy) {
        scanBarcode(imageProxy)
    }

    @SuppressLint("UnsafeExperimentalUsageError")
    private fun scanBarcode(imageProxy: ImageProxy) {
        imageProxy.image?.let { image ->
            val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
            val scanner = BarcodeScanning.getClient()
            scanner.process(inputImage)
                .addOnCompleteListener {
                    imageProxy.close()
                    if (it.isSuccessful) {
                        readBarcodeData(it.result as List<Barcode>)
                    } else {
                        it.exception?.printStackTrace()
                    }
                }
        }
    }

    private fun readBarcodeData(barcodes: List<Barcode>) {
        for (barcode in barcodes) {
            when (barcode.valueType) {

                Barcode.TYPE_TEXT -> {
                    if (barcode.displayValue != null) {

                        this.codeWasScanned?.let { it(barcode.displayValue!!) }


                    } else {
                        // Tell user that the barcode couldn't be read properly. Or any other guidance.
                    }

                }
            }
        }
    }
}

EDIT 4:

OK, I played around with the navigation a bit. Instead of navigating to fragment X I wrote findNavController().navigateUp(). This took me back to main fragment (fragment 2) which was expected. However, after this navigating to fragment X upon successful scan worked once, the next time not.

I'm guessing since I never popped fragment X it is saved in an active/visible state which messed everything up somehow.

来源:https://stackoverflow.com/questions/65750176/kotlin-fragment-lifecycle-navigation-issues-why-does-child-fragment-become-cu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!