4

This issue is only occurring on two older Samsung Galaxy models, but is nevertheless very reproducable.

I have a simple app that displays a photo that is taken through the device's camera app. It has one button to start that app, and processes the result in an AsyncTask to downsample it into an ImageView.

The trouble arises from the flow of the activity when returning from the camera app: for some reason, the activity is created, processes result in an AsyncTask in the onActivityResult(), is destroyed, only to immediately be recreated. Once the AsyncTask completes, it hold a reference to the incorrect/old activity.

Placing some debug statements into the various lifecycle callbacks reveals this odd behavior:

06-02 16:01:53.509: I/myapp(4437): onCreate com.myapp.PhotoActivity_@488cbef8
06-02 16:01:53.509: I/myapp(4437): onResume com.myapp.PhotoActivity_@488cbef8
06-02 16:01:58.298: I/myapp(4437): onPause com.myapp.PhotoActivity_@488cbef8
06-02 16:01:59.470: I/myapp(4437): onStop com.myapp.PhotoActivity_@488cbef8
[a photo is taken in the camera app]
06-02 16:02:10.196: I/myapp(4437): onCreate com.myapp.PhotoActivity_@4874f8b8
06-02 16:02:10.251: I/myapp(4437): onActivityResult com.myapp.PhotoActivity_@4874f8b8
06-02 16:02:10.259: I/myapp(4437): onResume com.myapp.PhotoActivity_@4874f8b8
06-02 16:02:10.712: I/myapp(4437): onPause com.myapp.PhotoActivity_@4874f8b8
06-02 16:02:10.720: I/myapp(4437): onStop com.myapp.PhotoActivity_@4874f8b8
06-02 16:02:10.923: I/myapp(4437): onCreate com.myapp.PhotoActivity_@48817118
06-02 16:02:10.931: I/myapp(4437): onResume com.myapp.PhotoActivity_@48817118
06-02 16:02:12.564: I/myapp(4437): onBitmapLoaded com.myapp.PhotoActivity_@4874f8b8

The instance of the activity on which onActivityResult() is called (note the hash codes above) no longer matches the final instance that is being displayed. When my bitmap loading through onBitmapLoaded() completes, it therefore also holds the incorrect instance.

Why is this happening, and how can I prevent the activity from being (needlessly) recreated?

Paul Lammertsma
  • 37,593
  • 16
  • 136
  • 187
  • This behavior does seem strange on the surface, and my guess is system memory pressure. Try adding logs in the `onLowMemory()` callback to see if that provides any additional information. Also, perhaps the Activity code so we can see if something is unnecessarily inflating the heap? – devunwired Jun 01 '12 at 14:31
  • The heap is indeed being inflated due to decoding of the bitmap. Remarkably, the GC statements in the log only occur after the activity has been recreated (those would appear only prior to `onBitmapLoaded` in the log above). – Paul Lammertsma Jun 01 '12 at 14:40
  • I believe this problem is related to resource management and has to do with the [behavior of recreating an activity as described in the documentation](http://developer.android.com/training/basics/activity-lifecycle/recreating.html). It appears that the activity is resumed just long enough for it to call `onSaveInstanceState()`, and is subsequently destroyed for recreation. A solution to this specific problem might be to store the response from `onActivityResult()` into the instance state, and perform the same logic from `onRestoreInstanceState()`. – Paul Lammertsma Jun 01 '12 at 15:03

2 Answers2

3

Apparently configuration of application changes! Add logs in onDestroy and improve log in onCreate to show what is the value of Bundle savedInstanceState. if savedInstanceState is not null then configuration change enforced recreation of Activity. Adding logs in onSaveInstanceState(Bundle) could help to.

You can handle yourself configuration changes by setting Activity property android:configChanges in manifest.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • 1
    Good theory, but it doesn't appear to be the case as `onConfigurationChanged()` is never called. – Paul Lammertsma Jun 01 '12 at 14:46
  • 2
    since it is called only when you set some values for android:configChanges in manifest! If this is not set then default behaviour is to recreate Activity and don't calls onConfigurationChanged. Like I wrote improve logs by checking value of savedInstanceState in onCreate add logs onSaveInstanceState! – Marek R Jun 01 '12 at 15:02
  • 1
    Indeed, it seems you're right! When returning out of the camera, the activity has adopted the landscape orientation, despite that not being permitted by the manifest. – Paul Lammertsma Jun 01 '12 at 15:17
  • 4
    In my case (**disclaimer: a very specific case**), I could indeed avoid the strange recreation behavior by added `configChanges="orientation"` to the activity's entry in the manifest. This essentially just ignores the orientation change, which isn't a problem for my activity as it also has `screenOrientation="portrait"`. – Paul Lammertsma Jun 01 '12 at 15:23
  • 3
    "nice" incoherency of Android. I recommend you to use configChanges="orientation|screenSize" since on tablets orientation changes will cause also screen size changes. – Marek R Jun 01 '12 at 15:32
  • @MarekR Thanks for the helpful comment! You saved me a ton of time. – LiuWenbin_NO. Jun 25 '21 at 07:29
0

Small article about this issue, hope helps: The problem with an external camera in Android using MediaStore.ACTION_IMAGE_CAPTURE

GeX
  • 619
  • 1
  • 9
  • 19