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.
Related
I'm using NativeActivity and android_native_app_glue.c/h and the android_main function on the c++ side.
I just learned that when the app is completely destroyed (APP_CMD_DESTROY event is generated), the Linux process of the app is still NOT destroyed but keeps running; instead just android_main() returns and will be called again when the app restarts.
The funny effect that this has is that there will be some memory which is not freed even when the app is completely destroyed. For example if I make a global variable in my c++ code called int test; and set a value 123 to it, it will still be the same 123 when the app will be created the next time.
I assume that I'm supposed to free all the memory that I've allocated when APP_CMD_DESTROY is generated and android_main will return. Is that assumption true? The question is: is there some rules about how much memory can stay in the memory and not be freed? Is a kilobyte ok? Is 500k ok? Is 50 megs ok? Is 400 megs ok?
The reason why my app is destroyed in the first place is because the user is doing something in another app and will then return to my app, and the other app will tell my app what the user did in the other app. It would be the most convenient if I could just keep all the data that I need in the memory (through a global variable) so that the app would just know where to continue after it was destroyed. Even though I know that making global variables is generally thought to be a bad idea.
So is it a good idea to free absolutely all the memory that I've allocated, or can I keep a little, or can I keep a lot and trust that the Android operating system will go ahead and kill the actual Linux process in the case that it really wants to get rid of the allocated memory? Because I would appreciate if my app restarted really fast after resuming from the other app and it wouldn't need to load some resources in the beginning.
When running on Huawei G300 with Gingerbread, my app crashes after 5 minutes or so of usage during setContentView() as it runs out of memory.
Each individual page doesn't use much memory, but from some research it seems the memory accumulates in the back stack.
Following advice here, I've replaced all my calls to startActivity with a utility function that also calls finish().
Android: Clear the back stack
This works; but there is no more back stack - the back button immediately quits the app, which isn't what I wanted.
Is there a way to only finish() the applications when I actually do run out of memory, and is that a reasonable approach to take?
You should search for memory leaks. A good tool for that is MAT if you use eclipse. MAT is not that hard to handle and you can get quickly some very valuable information.
One of the most common mistakes I have seen on Android is to keep a reference on a context that is dead. For instance, having a singleton holding a reference on one of the activities you created. There is no real reason for an app to crash the memory if it is well coded.
The Android Activity Manager was designed to manage this exact problem. The OS is designed to kill activities in the background and then restore them using onSaveInstanceState and onRestoreInstanceState.
The fact that your app is accumulating memory usage over time indicates to me that you may have a Context leak somewhere (a static reference to a view, adapter, etc. that has a reference to a Context), or that you have a caching mechanism that's not adjusting to your memory heap, or some other situation that's causing the out of memory.
I highly doubt that it's the Activities in the Back Stack causing the Out of Memory.
Here's a great guide on tracking down memory leaks on Android:
http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html
Memory is a very tricky subject in Android.
Every app gets a heap memory limit depending on the device. This heap memory is the dalvik memory plus the native memory, and you can see it as the total column in the dumpsys meminfo results. The dalvik memory deals with everything except with the bitmaps, that are allocated in the native memory (this is true for Android versions before Honeycomb).
Having said that I can only answer to some of your questions:
As far as I know, Android will always allocate memory for Bitmaps, even if they are the same. Therefore, in your case, every activity allocates memory for your background.
I don't know if its better to work with themes, you'll have to try that.
On one hand, activities are not reclaimed while the device has enough memory to deal with the next activity. Every activity is pushed to a pile from where it is recovered when you pressed the back button. In case Android needs more memory it removes one activity from the pile deallocating its memory (going back to question number one, maybe this is the reason for not sharing memory). On the other hand, you can set the activities launchMode to change this behaviour (have a look here).
I think MAT doesn't show native memory data. Use dumpsys meminfo's native column to see how much allocated memory for Bitmaps you have.
I have had hard times dealing with OutOfMemory problems myself. Now I have a much more clear idea of how it works and I am able to work with large files without running out of memory. I would highly recommend these two resources that helped me a lot:
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 some problems with the memory usage of my android app and don't know what causes the high memory usage. When I start my app, it uses up to 40 mb ram (says DDMS) and when I open another app, my app gets immediately killed.
I read a lot about memory leaks and I'm unbinding drawables, running the GC and so on but my app still needs a lot of memory.
I have about 3mb resources in my app, but afaik they are loaded into ram on demand. Am I wrong? May this cause the 40mb of ram usage?
EDIT: I think I'm not having memory leaks because I can switch the orientation on each activity as often as I want and the app does not crash because of low memory. So it can't be a memoryleak, can it?
you need to do memory management into your android application, please free the resources which is no longer used, try to override onStop(), onDestroy(), onPause() methods of Activity which will keep track of activity stack.
in OnDestroy() method free your whole availed resources, so that another app can use the same resources again.
What data structures are you using? Very large data structures (long Lists, big graphs, big maps, etc) can quickly use up RAM.
It could also be that you're leaking the Context on orientation change in your app.
It could also be that your layouts are really badly designed along with some heavy data structures.
It's difficult to tell unless you describe a bit more about what your app tries to do.
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.