Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App is crashing after taking a picture on Samsung devices

My app allows users to take pictures by using the device's default camera app, like so:

    private void takePhoto(Uri outputUri) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
        startActivityForResult(intent, TAKE_PHOTO_REQUEST_CODE);
    }

Looking at crash logs, I'm seeing lots of app crashes happening around what seems to be the app resuming after taking a photo.
The exception and stack trace:

Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11379)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2562)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6324)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6925)
android.app.servertransaction.ActivityConfigurationChangeItem.execute (ActivityConfigurationChangeItem.java:53)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2571)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8741)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)

There are a few different variants of the stack trace, but they all go through some configuration change which led me to believe the user must be rotating the device while taking the picture and the app crashes when it's returning to the foreground in a different orientation.
My app's activity has android:configChanges="orientation|screenSize" in its manifest because it's containing a WebView, but it's not doing anything during onConfigurationChanged.
While investigating the crash I added logs to print the thread name and ID to the main lifecycle methods as well as to onConfigurationChanged. I found that onConfigurationChanged called right before the app crashes on the same main thread as onCreate is called. onStart and onResume aren't called before the crash.
To add more mystery to the whole thing, the crash happens only on Samsung devices (but on a verity of phones/tables models).
Even though I don't think my app is doing anything unique or unusual I couldn't find any similar reports online.

Any ideas/suggestions would be appreciated!

Edit
Adding more stack trace variants:

Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11586)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2648)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.widget.TextView.onConfigurationChanged (TextView.java:4706)
android.view.View.dispatchConfigurationChanged (View.java:16145)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6502)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6941)
android.app.servertransaction.ActivityConfigurationChangeItem.execute (ActivityConfigurationChangeItem.java:53)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2574)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8757)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11586)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2648)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.widget.TextView.onConfigurationChanged (TextView.java:4706)
android.view.View.dispatchConfigurationChanged (View.java:16145)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6502)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6941)
android.app.ActivityThread$ActivityClientRecord$1.onConfigurationChanged (ActivityThread.java:797)
android.view.ViewRootImpl.performConfigurationChange (ViewRootImpl.java:6462)
android.view.ViewRootImpl.handleResized (ViewRootImpl.java:2424)
android.view.ViewRootImpl.-$$Nest$mhandleResized
android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl (ViewRootImpl.java:6728)
android.view.ViewRootImpl$ViewRootHandler.handleMessage (ViewRootImpl.java:6697)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8757)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
like image 749
Tako Avatar asked Oct 25 '25 14:10

Tako


1 Answers

Yes. It does happen with only samsung devices. I faced that issue once upon a time.

Here is what happens when you capture a picture

  1. Open a camara intent to capture a picture
  2. Take picture
  3. Return to your activity or fragment
  4. Get captured image & use it

This is a usual lifecycle of an image capture using device camera.

Now Samsung devices running on android 13 (Don't know about lower versions, I don't have one with lower versions, so) have a problem that if you take a picture using camera intent in portrait and then return to the activity or fragment with landscape orientation then it destroys the previous objects on configuration change.

It also happens even if you capture picture in portrait, then rotate device in landscape mode and then again rotate it to the portrait mode and come back to the activity, because of configuration change as I mentioned above.

So, here is my take on that which is working just fine. I now apply it to all my apps containing such functionality.

1. Fix activity orientation in manifest with traditional method providing fixed screen orientation either portrait or landscape according to your need

<activity
    android:name=".activity.MainActivity"
    android:screenOrientation="portrait" />

2. If you have responsive screen which can either be portrait or landscape on device orientation changes, then add this config to the activity tag in Manifest

<activity
    android:name=".activity.MainActivity"
    android:configChanges="orientation|screenSize"/>

So now, you will have the objects created before launching camera intent undestroyed when you return back to your activity after taking picture.

EDIT:

If you've already put the configurations in the Manifest, then you can go one step ahead as I did in some of my apps.

When user launches camera, set screen orientation to portrait programmatically,

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

Then, when user returns to the activity, then release the portrait lock by setting the orientation you've already set.

So, it won't rotate your device orientation while in camera screen.

like image 172
Dev4Life Avatar answered Oct 27 '25 06:10

Dev4Life