Fixed
Status Update
Comments
il...@google.com <il...@google.com>
jb...@google.com <jb...@google.com>
ap...@google.com <ap...@google.com> #2
I got the same issue only in a Pixel 5 emulator running API 24. Adding a breakpoint in `loadImageBitmapResource` showed that it was an `OutOfMemoryException` being swallowed like you say. Would be handy if it threw the actual exceptions
Description
Version used: androidx.fragment:fragment-ktx:1.3.0-alpha02
Devices/Android versions reproduced on: Emulator API level 29
When using the Activity Result API in a fragment, it crashes when receiving a result form an activity in a different configuration than when it was launched. The steps are like this:
1. Launch first activity.
2. Call second activity for result
3. Reorient the device/emulator
4. Finish the second activity (back button)
5. Crash with this stack:
```
2020-03-22 08:55:07.407 6338-6338/my.testapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: my.testapp, PID: 6338
java.lang.RuntimeException: Unable to resume activity {my.testapp/my.testapp.activity.main.MainActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=0, data=null} to activity {my.testapp/my.testapp.activity.main.MainActivity}: java.lang.NullPointerException: Attempt to read from field 'androidx.activity.result.ActivityResultCallback androidx.activity.result.ActivityResultRegistry$CallbackAndContract.mCallback' on a null object reference
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4205)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4237)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=0, data=null} to activity {my.testapp/my.testapp.activity.main.MainActivity}: java.lang.NullPointerException: Attempt to read from field 'androidx.activity.result.ActivityResultCallback androidx.activity.result.ActivityResultRegistry$CallbackAndContract.mCallback' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4845)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4192)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4237)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.NullPointerException: Attempt to read from field 'androidx.activity.result.ActivityResultCallback androidx.activity.result.ActivityResultRegistry$CallbackAndContract.mCallback' on a null object reference
at androidx.activity.result.ActivityResultRegistry.doDispatch(ActivityResultRegistry.java:281)
at androidx.activity.result.ActivityResultRegistry.dispatchResult(ActivityResultRegistry.java:275)
at androidx.activity.ComponentActivity.onActivityResult(ComponentActivity.java:444)
at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:181)
at android.app.Activity.dispatchActivityResult(Activity.java:8110)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4838)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4192)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4237)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
```
There are no problems if there was no configuration change. Also, oddly, there are no problems if there were two configuration changes (e.g. portrait -> landscape -> portrait).
Code for the fragment:
```kotlin
class MainFragment : Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private val viewModel: MainViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = MainFragmentBinding.inflate(inflater, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
observeViewModel()
}
private fun observeViewModel() {
// This is just effectively a listener on button press delivered through a BroadcastChannel
LifecycleChannelListener(viewLifecycleOwner.lifecycle, viewModel.navigateToFirebaseUi) {
onSignInButtonClicked()
}
}
private val onSignInButtonClicked = prepareCall(StartActivity()) { result ->
Log.d("@@@@", "R: $result")
}
private inner class StartActivity: ActivityResultContract<Unit, Int>() {
override fun createIntent(input: Unit?): Intent {
return Intent(requireContext(), MainActivity::class.java)
}
override fun parseResult(resultCode: Int, intent: Intent?): Int {
return 0
}
}
}
```