I have an object sitting in memory on the application that I'm using, and on a button press I do a startActivityForResult and launch the camera application, so I can attach a photo to that object. On every phone/tablet I've ever tested with (somewhere around 15 or so) it works completely fine, but for some reason with the Motorola Droid 3 (CDMA version) once the camera application starts, it's like onDestroy is called... even though it returns to my app after the photograph is snapped, all of the variables held in memory are erased. Can someone direct me as to how I can fix this please?
I'm guessing what's happening is that the camera app uses a big enough chunk of memory that android needs to destroy the paused activity. If you look at this page,
http://developer.android.com/reference/android/app/Activity.html
It shows that possibility pretty clearly.
You are seeing differing behavior on different devices because different devices have different apps loaded into memory and different amounts of memory to begin with.
If you need to save state in your app, you can hook in at onSaveInstanceState() and onRestoreInstanceState(). Here's a post that talks about it in more detail.
How to save an activity state using save instance state?
In summary, don't depend on the state being the same when you resume an activity. If you depend on that happening, you need to handle it yourself.
Related
This question is for Android developers who are familiar with the Activity Lifecycle.
I'm developing an app that performs face detection and facial landmark recognition.
The according machine learning models take a long time to be parsed from the SD storage and loaded into memory. On current average Android devices, it easily takes up to 20 seconds. By the way, all of this face analysis stuff and model loading happens in C++ native code, which is integrated using the Android NDK + JNI.
Because the model loading takes a long time, the actual parsing and loading is scheduled early in the background via AsyncTasks, so that the user does not notice a huge delay.
Before the actual face analysis is performed, the user can take a selfie via the MediaStore.ACTION_IMAGE_CAPTURE. This will call a separate camera app installed on the device and receive the picture via onActivityResult.
Now the problem starts: Almost always the whole app process will be killed while the user is in the separate camera Activity/App. Mostly it seems to happen right before returning from the Camera app (the timing seems odd). I did another test to confirm that it happens when the capture button is pressed inside the camer app. At that moment, my app is killed. When pressing the 'Accept image' button, the app is recreated. The reason given in logcat by the ActivityManager for the process kill is 'prev LAST' (I've found nothing via Google on the meaning of this, but I saw that many other apps are also killed with this reason, so it seems to happen quite often).
Thus, all of the Activities of my app need to be recreated by Android (fine by me, because it happens fast), but also the face analysis models must be loaded again from scratch, and the user will notice a huge delay before his selfie can be processed.
My question is: Is there any possibility to tell Android that an Activity/App has a legitimate reason to not be killed while being in the background temporarily to get a camera picture? After all, the ActivityManager makes a wrong decision to kill the app. Having to reload the models so frequently takes up a lot of CPU and memory resources.
It seems like an oversight in the Android lifecycle architecture. I know that few apps have the specific requirements of my app, but still, it seems stupid. The only way I can think of to 'fix' this issue is to implement my own camera Activity inside the app, but this goes counter Android's own best practices.
There is also some 'android:persistent' flag that you can stick to your Activity via AndroidManifest.xml, but the docs are totally unclear about the implications of this. See the docs on this.
By the way: onDestroy is not called when the app process is killed. I've read somewhere that there is no guarantee that onDestroy will be called, and this is actually not a problem for me. Although I wonder why the Android docs do not state this clearly.
Almost always the whole app process will be killed while the user is in the separate camera Activity/App
This is not surprising. A camera app can consume quite a bit of memory, so Android needs to free up memory by terminating background apps' processes.
After all, the ActivityManager makes a wrong decision to kill the app
Given that a likely alternative is the OS crashing, I suspect the user would agree with the OS decision to terminate your process.
Having to reload the models so frequently takes up a lot of CPU and memory resources.
Then perhaps you should not be starting another app from yours. Take the photo yourself. Use the camera APIs directly, or use libraries like Fotoapparat and CameraKit-Android as simpler wrappers around those APIs.
The only way I can think of to 'fix' this issue is to implement my own camera Activity inside the app, but this goes counter Android's own best practices.
By that argument, no devices would ever have a camera app, as writing any camera app "goes counter Android's own best practices".
Any app that needs a camera must use the camera APIs (directly or indirectly) to have any shot at reliable behavior. You are assuming that thousands of camera apps are all properly written and will correctly honor your ACTION_IMAGE_CAPTURE Intent (e.g., putting the results in the place that you designate with EXTRA_OUTPUT). Many camera apps have buggy ACTION_IMAGE_CAPTURE implementations. ACTION_IMAGE_CAPTURE is not unreasonable for cases where you and the user can live without the picture being taken (e.g., a note-taker app that has an "attach photo" feature), but that would not seem to be the case with your app.
I'm trying to create an application where there is a need of uploading images from my mobile. In this case, when I open my Gallery and choose a image and come back to my application, onCreate() is called again due to which the TextView, EditText and the booleans which I've used earlier are cleared.
I don't want this to happen, I want all the values to remain same and when I come back from Device Gallery to my own application. Can you please help me solving this issue?
In this case, when I open my Gallery and choose a image and come back to my application, onCreate() is called again due to which the TextView, EditText and the booleans which I've used earlier are cleared.
Presumably, your process was terminated while your app was not in the foreground. This happens quite a bit in Android. While it is a bit unusual for it to happen when launching a gallery-style app, it is not out of the question, particularly on devices with limited RAM.
Activities will be destroyed and re-created in other situations as well, such as the default behavior on a configuration change (e.g., rotating the screen, changing the language, putting the device into a dedicated car dock).
Use onSaveInstanceState() to save state information for these sorts of short-term scenarios.
I am working on an android project with a few other developers and a bug was raised where Instance states were not being retained on garbage collection:
The actual bug reported:
The app has one activity with a bunch of fragments. If "don't keep activities" is checked in developer options and the user clicks on any button that changes the visible fragments, and then navigates away from the app and then back, it relaunches the app to its original state instead of the last state.
Another Dev on the project raised the following concern:
"The saving of instances will cause the apps in memory size to bloat.
Already, because of the amount of drawables, the apps memory size is
too high.
Its ok, if the app restarts after a while of non usage by the user."
My understanding was that the savedInstance Bundle actually gets written to physical memory, is that not correct? Is the above quote a valid concern?
My understanding was that the savedInstance Bundle actually gets written to physical memory, is that not correct?
I am interpreting "written to physical memory" as meaning "written to a file on a filesystem" (a.k.a., "persisted").
The instance state Bundle is not persisted. Android 5.0+ gives you a different hook for a PersistableBundle that is persisted and therefore survives a reboot.
However, the instance state Bundle is passed across process boundaries to a core OS process. That data can then be used if your process is terminated, but the user returns to your app while your task is still around (e.g., via the recent-tasks list).
Is the above quote a valid concern?
The only piece of that quote that could reasonably be evaluated by people here on SO is:
The saving of instances will cause the apps in memory size to bloat
Saving one byte in the Bundle will consume more memory than will saving zero bytes in the Bundle. Hence, mathematically, the quote is accurate. The key is to keep the Bundle small. They can't get too big anyway for other reasons (1MB limit for IPC calls). Small instance state Bundles should not be a problem.
A correctly coded saveinstance state will survive in the background for weeks at a time and doesn't require anything more than a few bytes worst case a few k of ram.
Your other dev has a learning curve issue.
InstanceState save what you need to recreate the way the app currently looks to the user. Let's use a tic tac toe analogy. You have nine positions. Each position is x o or blank. and you save who's turn it is. A ten character string no bloat here this is not rocket science.
InstanceState for the app with a 10 drawables on the screen. you save the drawables to external storage as jpg or even bmp. Then you save the name of the drawables in the instanceState. A 1000 chars of instance state no bloat this is computer science 1k to restart a very complex app.
SaveinstanceState is not bloat ware its an awesome app.
I'm working on an app that doesn't support screen rotation. Do I really need to save the instance state of all my activities? How rare is it for android to kill activities? If the activity is killed and restored it will just look to the user as it did when they first came to it, which was probably quite a while ago anyway if the system has killed it. It doesn't seem like such a bad user experience to me if it is rarely going to happen. What do you think?
It is a catastrophic UX if an application loses its state just because I went to the settings to change the screen brightness. This happens frequently on 512MB RAM devices - which are still sold in large quantities. There are even devices with 256MB produced right now.
Yes, it happens a lot. It will happen to certain users much more frequent than to others. Those users will have no pardon with your app.
it really depends on the type of screens you are developing. When the activity contains a lot of data for example, it should be convenient to save the state of your activity (not all activities).
If you have several fields that the user must refill, it can be a bad experience especially if the virtual keyboard of device is not that easy (assume you are using a Galaxy mini for example)
In other words, it is a good practice but its up to you to decide if the user experience will be degraded or not
Serge
FWIW, I have written several single orientation apps for our current product and I feel that it's still important to save state. It just makes for a more usable application when everything is how you left it when you return.
In general, it's not that much work either. First, keep in mind that if you assign an ID to views in your layout's, the default Activity.onSaveInstanceState() will do most of the work. It will remember Checkbox states, EditText contents, etc. There are relatively few things you need to save. Here are some of the things I've saved with the state:
Relevant Activity parameters
ListView position information
Current Tab in TabView
Activity parameters are by far the most common.
I have an Android app that in the onCreate() method, preloads a lot of graphics.
When I test my app on my HTC Aria and launch it, it runs fine. However, if I press the back button to exit my app, and then launch the app again, it crashes with an OutOfMemoryError: bitmap size exceeds VM budget. If I then launch the app for the third time (right after it has crashed) it launches fine. Then if I close and re-launch it, it crashes again with out of memory. It continues this every-other-time-crashing pattern forever if I keep trying.
I checked to see what life cycle methods were being called and onStop() and onDestroy() are both being called when I exit the app, yet I have a feeling that something is not yet being cleaned up and that by "crashing" the app when I try to launch it the second time, it somehow free's the memory.
Any thoughts on what could be happening or how to remedy this? Please let me know if you need me to post more info. Thanks!
Info:
My app is fairly simple and only has 1 activity that plays some frame animations.
Maybe you are unnecessarily holding onto Context references? Check Avoiding memory leaks for some tips, as well as Attacking memory problems.
It sounds like something in the Activity life cycle is not quite right. Are you sure you have every start covered? http://developer.android.com/reference/android/app/Activity.html
You have onStop but do you have onDestroy? You're probably missing one of those that you need.
You may find some useful information the many answers to this question:
Strange out of memory issue while loading an image to a Bitmap object
Also, I second the "Avoiding Memory Leaks" blog post. Especially if you can trigger the same problem with orientation changes. Using "this" context when creating display objects is a sneaky way to leak the Activity context. In my own app, I managed to leak a whole chain of contexts, and would very rapidly run out of memory when doing orientation changes.