问题
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