What does removing a Fragment in Android really do? - java

What impact does removing a Fragment in Android have on the performance of an application. What I am referring to is something like:
fragmentTransaction.remove(myFragment);
I've read the documentation about the Fragment Lifecycle Fragments and the description of the remove method in the Fragment Transaction Fragment Transaction remove() but haven't found whether calling the remove actually frees the memory occupied the Fragment's views.
Also, is there a way that I can suspend Fragments into a low memory state? The idea is that in an application with many Fragments and assuming that only one Fragment is visible at a time, is there anything I can do to optimize memory?

Your app should be optimized for best performance from design. It should not change it's behavior upon system resources. If you are low on memory, the background apps are killed so that your app can run smoothly and you user can get the best of it.
Just use a fragment when you need it. And remove it when it's not needed. If you do it the right way, you're already optimizing your app.

Related

Activity being destroyed when taking photo

When I do startActivityForResult to take a photo, the underlying Activity is destroyed. Even when I put
android:configChanges="orientation|keyboardHidden|screenSize"
in the manifest, any ideas would be extremely appreciated!
Probably your process is being terminated while your app is in the background. This is perfectly normal and will happen in many other cases, not just this one. You will need to adjust your application to deal with this situation (e.g., use the saved instance state Bundle).

Click on item leads to IllegalStateException

How can this happen? I use a RecyclerView in an fragment and the fragment itself implements my click listener...
Sometimes, clicking an item in the list results in following error:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
How can this happen? Clicks should be forwarded to their handlers synchronous and this should not happen, should it?
Some code fragment would really help. But your error already states Can not perform this action after onSaveInstanceState
This means that after the function onSaveInstanceState() has been called, you try to do something. Put that code before onSaveInstanceState() and you might have a solution.
OnSaveInstance is called when the activity is about to be destroyed.
The android gives a last attempt to save all the data in a bundle that can be retrived back when the activity is recreated onRestoreInstance.
Mostly this case occurs when the android decide to garbage collect your activity due to lack of memory.
The error state that you are doing some work on UI -fragment after the onSaveInstance has been called.
Android does not allow any work on fragments after this has been called and soon onDestroy will be called.
So kindly revisit your logic or place a isFinishing() check before doing any work.
Actually it's because you're activity is getting destroyed due to lack of memory and before it gets destroyed it saves the fragment state also, and like you mentioned it happens sometine, during this you might have clicked your own which tried calling that previous state non click on the destroyed fragment.
How can you avoid it
Use volley and Picasso. And check which part of your application is using more memory using memory monitor given in android studio.
Also if you are not able to reduce memory usage consider adding.
large heap="true"
in your manifest

Android Studio: Out of Memory Error, Parse API [duplicate]

I spent 4 full days trying everything I can to figure out the memory leak in an app I'm developing, but things stopped making sense a long time ago.
The app I'm developing is of social nature, so think profile Activities (P) and list Activities with data - for example badges (B). You can hop from profile to a badge list to other profiles, to other lists, etc.
So imagine a flow like this P1 -> B1 -> P2 -> B2 -> P3 -> B3, etc. For consistency, I'm loading profiles and badges of the same user, so each P page is the same and so is each B page.
The general gist of the problem is: after navigating for a bit, depending on the size of each page, I get an out-of-memory exception in random places - Bitmaps, Strings, etc - it doesn't seem to be consistent.
After doing everything imaginable to figure out why I am running out of memory, I have come up with nothing. What I don't understand is why Android isn't killing P1, B1, etc if it runs out of memory upon loading and instead crashes. I would expect these earlier activities to die and be resurrected if I ever Back to them via onCreate() and onRestoreInstanceState().
Let alone this - even if I do P1 -> B1 -> Back -> B1 -> Back -> B1, I still get a crash. This indicates some sort of a memory leak, yet even after dumping hprof and using MAT and JProfiler, I can't pinpoint it.
I've disabled loading of images from the web (and increased the test data loaded to make up for it and make the test fair) and made sure the image cache uses SoftReferences. Android actually tries to free up the few SoftReferences it has, but right before it crashes out of memory.
Badge pages get data from the web, load it into an array of EntityData from a BaseAdapter and feed it to a ListView (I'm actually using CommonsWare's excellent MergeAdapter, but in this Badge activity, there is really only 1 adapter anyway, but I wanted to mention this fact either way).
I've gone through the code and was not able to find anything that would leak. I cleared and nulled everything I could find and even System.gc() left and right but still the app crashes.
I still don't understand why inactive activities that are on the stack don't get reaped, and I'd really love to figure that out.
At this point, I'm looking for any hints, advice, solutions... anything that could help.
Thank you.
I still don't understand why inactive activities that are on the stack
don't get reaped, and I'd really love to figure that out.
This is not how things work. The only memory management that impacts activity lifecycle is the global memory across all processes, as Android decides that it is running low on memory and so need to kill background processes to get some back.
If your application is sitting in the foreground starting more and more activities, it is never going into the background, so it will always hit its local process memory limit before the system ever comes close to killing its process. (And when it does kill its process, it will kill the process hosting all the activities, including whatever is currently in the foreground.)
So it sounds to me like your basic problem is: you are letting too many activities run at the same time, and/or each of those activities is holding on to too many resources.
You just need to redesign your navigation to not rely on stacking up an arbitrary number of potentially heavy-weight activities. Unless you do a serious amount of stuff in onStop() (such as calling setContentView() to clear out the activity's view hierarchy and clear variables of whatever else it may be holding on to), you are just going to run out of memory.
You may want to consider using the new Fragment APIs to replace this arbitrary stack of activities with a single activity that more tightly manages its memory. For example if you use the back stack facilities of fragments, when a fragment goes on the back stack and is no longer visible, its onDestroyView() method is called to completely remove its view hierarchy, greatly reducing its footprint.
Now, as far as you crashing in the flow where you press back, go to an activity, press back, go to another activity, etc and never have a deep stack, then yes you just have a leak. This blog post describes how to debug leaks: http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html
Some tips:
Make sure you are not leak activity context.
Make sure you are don't keep references on bitmaps. Clean all of your ImageView's in Activity#onStop, something like this:
Drawable d = imageView.getDrawable();
if (d != null) d.setCallback(null);
imageView.setImageDrawable(null);
imageView.setBackgroundDrawable(null);
Recycle bitmaps if you don't need them anymore.
If you use memory cache, like memory-lru, make sure it is not using to much memory.
Not only images take alot of memory, make sure you don't keep too much other data in memory. This easily can happens if you have infinite lists in your app. Try to cache data in DataBase.
On android 4.2, there is a bug(stackoverflow#13754876) with hardware acceleration, so if you use hardwareAccelerated=true in your manifest it will leak memory. GLES20DisplayList - keep holding references, even if you did step (2) and no one else is referencing to this bitmap. Here you need:
a) disable hardware acceleration for api 16/17;
or
b) detach view that holding bitmap
For Android 3+ you can try to use android:largeHeap="true" in your AndroidManifest. But it will not solve your memory problems, just postpone them.
If you need, like, infinite navigation, then Fragments - should be your choice. So you will have 1 activity, which will just switch between fragments. This way you will also solve some memory issues, like number 4.
Use Memory Analyzer to find out the cause of your memory leak.
Here is very good video from Google I/O 2011: Memory management for Android Apps
If you dealing with bitmaps this should be a must read: Displaying Bitmaps Efficiently
Bitmaps are often the culprit for memory errors on Android, so that would be a good area to double check.
Are you holding some references to each Activity? AFAIK this is a reason which keeps Android from deleting activities from the stack.
We're you able to reproduce this error on other devices as well? I've experienced some strange behaviour of some android devices depending on the ROM and/or hardware manufacturer.
I think the problem maybe a combination of many factors stated here in the answers are what is giving you problems. Like #Tim said, a (static) reference to an activity or an element in that activity can cause the GC to skip the Activity. Here is the article discussing this facet. I would think the likely issue comes from something keeping the Activity in an "Visible Process" state or higher, which will pretty much guaranty that the Activity and its associated resources never get reclaimed.
I went through the opposite problem a while back with a Service, so that's what got me going on this thought: there is something keeping your Activity high on the process priority list so that it won't be subject to the system GC, such as a reference (#Tim) or a loop (#Alvaro). The loop doesn't need to be an endless or long running item, just something that runs a lot like a recursive method or cascaded loop (or something along those lines).
EDIT: As I understand this, onPause and onStop are called as needed automatically by Android. The methods are there mainly for you to overide so that you can take care of what you need to before the hosting process is stopped (saving variables, manually saving state, etc.); but note that it is clearly stated that onStop (along with onDestroy) may not be called in every case. Additionally, if the hosting process is also hosting an Activity, Service, etc. that has a "Forground" or "Visible" status, the OS might not even look at stopping the process/thread. For example: an Activity and a Service are both luanched in the same process and the Service returns START_STICKY from onStartCommand() the process automatically takes at least a visible status. That might be the key here, try declaring a new proc for the Activity and see if that changes anything. Try adding this line to the declaration of your Activity in the Manifest as: android:process=":proc2" and then run the tests again if your Activity shares a process with anything else. The thought here is that if you've cleaned up your Activity and are pretty sure that the problem is not your Activity then something else is the problem and its time to hunter for that.
Also, I can't remember where I saw it (if I even saw it in the Android docs) but I remember something about a PendingIntentreferencing an Activity may cause an Activity to behave this way.
Here is a link for the onStartCommand() page with some insights on the process non-killing front.
One of the things that really helped the memory issue in my case ended up being setting inPurgeable to true for my Bitmaps. See Why would I ever NOT use BitmapFactory's inPurgeable option? and the answer's discussion for more info.
Dianne Hackborn's answer and our subsequent discussion (also thanks, CommonsWare) helped clarify certain things I was confused about, so thank you for that.
so the only thing i can really think of is if you have a static variable that references directly or indirectly to the context. Even something so much as a reference to part of the application. I'm sure you have already tried it but i will suggest it just in case, try just nulling out ALL of your static variables in the onDestroy() just to make sure the garbage collector gets it
The biggest source of memory leak I have found was caused by some global, high level or long-standing reference to the context. If you are keeping "context" stored in a variable anywhere, you may encounter unpredictable memory leaks.
Try passing getApplicationContext() to anything that needs a Context. You might have a global variable that is holding a reference to your Activities and preventing them from being garbage collected.
I encountered the same problem with you. I was working on a instant messaging app, for the same contact, it is possible to start a ProfileActivity in a ChatActivity, and vice versa.
I just add a string extra into the intent to start another activity, it takes the information of class type of starter activity, and the user id. For example, ProfileActivity starts a ChatActivity, then in ChatActivity.onCreate, I mark the invoker class type 'ProfileActivity' and user id, if it's going to start an Activity, I would check whether it is a 'ProfileActivity' for the user or not. If so, just call 'finish()' and go back to the former ProfileActivity instead of creating a new one.
Memory leak is another thing.

Nested Fragments - IllegalStateException "Can not perform this action after onSaveInstanceState"

Background
Asynchronous Callbacks in Android
Trying to perform an asynchronous operation in a reliable fashion on Android is unnecessarily convoluted i.e. Is AsyncTask really conceptually flawed or am I just missing something?
Now, this is all prior to the introduction of Fragments. With the introduction of Fragments, onRetainNonConfigurationInstance() has been deprecated. So the latest Google condoned hack is to use a persistent non-UI fragment that attaches/detaches from your Activity when configuration changes occur (i.e. Rotating the screen, changing language settings etc.)
Example:
https://code.google.com/p/android/issues/detail?id=23096#c4
IllegalStateException - Can not perform this action after onSaveInstanceState
Theoretically the hack above allows you to get around the dreaded:
IllegalStateException - "Can not perform this action after onSaveInstanceState"
because a persistent non-UI fragment will receive callbacks for onViewStateRestored() (alternatively onResume) and onSaveInstanceState() (alternatively onPause). As such you can tell when the instance state is saved/restored. It's a fair bit of code for something so simple, but utilising this knowledge, you could queue up your asynchronous callbacks until the activity's FragmentManager has its mStateSaved variable set to false before executing them.
mStateSaved being the variable who is ultimately responsible for firing this exception.
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
So theoretically, now you know when it's safe to perform fragment transactions, and you can hence avoid the dreaded IllegalStateException.
Wrong!
Nested Fragments
The solution above only works for the Activity's FragmentManager. Fragments themselves also have a child fragment manager, which is utilised for nesting fragments. Unfortunately, child fragment managers are not kept in sync with the Activity's fragment manager at all. So whilst the activity's fragment manager is up-to-date and always has the correct mStateSaved; child fragments think otherwise and will happily throw the dreaded IllegalStateException at inappropriate times.
Now, if you've looked at Fragment.java and FragmentManager.java in the support library you won't in any way be surprised that everything and anything to do with fragments is error prone. The design and code quality is... ah, questionable. Do you like booleans?
mHasMenu = false
mHidden = false
mInLayout = false
mIndex = 1
mFromLayout = false
mFragmentId = 0
mLoadersStarted = true
mMenuVisible = true
mNextAnim = 0
mDetached = false
mRemoving = false
mRestored = false
mResumed = true
mRetainInstance = true
mRetaining = false
mDeferStart = false
mContainerId = 0
mState = 5
mStateAfterAnimating = 0
mCheckedForLoaderManager = true
mCalled = true
mTargetIndex = -1
mTargetRequestCode = 0
mUserVisibleHint = true
mBackStackNesting = 0
mAdded = true
Anyway, getting a bit off topic.
Dead-end solution
So, you might think the solution to the problem is simply, which seems like a bit of an antonym at this point, to add another one of those nice hacky non-UI fragments to your child fragment managers. Presumably its callbacks are in sync with its internal state and things will all be dandy.
Wrong again!
Android doesn't support retained fragment instances that are attached as children to other fragments (aka nested fragments). Now, in hindsight this should make sense. If the parent fragment is destroyed when the activity is destroyed because its not retained, there is nowhere to reattach the child fragment. So that's just not going to work.
My Question
Does someone out there have a solution for determining when it is safe to perform fragment transactions on child fragments in conjunction with asynchronous code callbacks?
Update 2
React Native
If you can stomach it, use React Native. I know, I know... "dirty web technologies", but in all seriousness, the Android SDK is a disaster, so swallow your pride and just give it a go. You might surprise yourself; I know I did!
Can't or Won't use React Native
No worries, I'd suggest fundamentally changing your approach to networking. Firing a request and running a request handler to update the UI just doesn't work well with Android's component life-cycles.
Instead try one of:
Move to simple message passing system based around LocalBroadcastReceiver and have long-living objects (regular Java classes or Android Services) do your requests and fire events when your app's local state changes. Then in your Activity/Fragment, just listen for certain Intent and update accordingly.
Use a Reactive event library (e.g. RxJava). I've not tried this myself on Android, but had pretty good success using a similar concept library, ReactiveCocoa for a Mac/desktop app. Admittedly these libraries have a fairly steep learning curve, but the approach is quite refreshing once you get used to it.
Update 1: Quick and Dirty (Official) Solution
I believe this is latest official solution from Google. However, the solution really doesn't scale very well. If you're not comfortable messing with queues, handlers and retained instance states yourself then this may be your only option... but don't say I didn't warn you!
Android activities and fragments have support for a LoaderManager which can be used with AsyncTaskLoader. Behind the scenes loader managers are retained in precisely the same way as retained fragments. As such this solution does share a bit in common with my own solution below. AsyncTaskLoader is a partially pre-canned solution that does technically work. However, the API is extremely cumbersome; as I'm sure you'll notice within a few minutes of using it.
My Solution
Firstly, my solution is by no means simple to implement. However, once you get your implementation working it's a breeze to use and you can customise it to your heart's content.
I use a retained fragment that is added to the Activity's fragment manager (or in my case support fragment manager). This is the same technique mentioned in my question. This fragment acts as a provider of sorts which keeps track of which activity it is attached to, and has Message and Runnable (actually a custom sub-class) queues. The queues will execute when the instance state is no longer saved and the corresponding handler (or runnable) is "ready to execute".
Each handler/runnable stores a UUID that refers to a consumer. Consumers are typically fragments (which can be nested safely) somewhere within the activity. When a consumer fragment is attached to an activity it looks for a provider fragment and registers itself using its UUID.
It is important that you use some sort of abstraction, like UUID, instead of referencing consumers (i.e. fragments) directly. This is because fragments are destroyed and recreated often, and you want your callbacks to have a "reference" to new fragments; not old ones that belong to a destroyed activity. As such, unfortunately, you rarely can safely use variables captured by anonymous classes. Again, this is because these variables might refer to an old destroyed fragment or activity. Instead you must ask the provider for the consumer that matches the UUID the handler has stored. You can then cast this consumer to whatever fragment/object it actually is and use it safely, as you know its the latest fragment with a valid Context (the activity).
A handler (or runnable) will be "ready to execute" when the consumer (referred to by UUID) is ready. It is necessary to check if the consumer is ready in addition to the provider because as mentioned in my question, the consumer fragment might believe its instance state is saved even though the provider says otherwise. If the consumer (or provider) are not ready then you put the Message (or runnable) in a queue in the provider.
When a consumer fragment reaches onResume() it informs the provider that it is ready to consume queued messages/runnables. At which point the provider can try execute anything in its queues that belong to the consumer that just became ready.
This results in handlers always executing using a valid Context (the Activity referenced by the provider) and the latest valid Fragment (aka "consumer").
Conclusion
The solution is quite convoluted, however it does work flawlessly once you work out how to implement it. If someone comes up with a simpler solution then I'd be happy to hear it.

design patterns for persisting state on android app

For android I am trying persist state if onDestroy() is called. I'm wondering what are common design patterns used to do such a thing so that the actual app functionality is decoupled from the persistence functionality? For example, I have a for loop that iterates through all of the players in the game. This update happens at the end of each round in the game. Would it be possible that the app gets destroyed half way through the update? If that happened, what kind of logic would i need to include to remember which player was updated.
You have two main options for saving state. If you are concerned with instance variables, then override Activity.onSaveInstanceState The answer to this question provides a good sample of how to do this.
For persistent data, you can either store it in SharedPreferences, the SQLite database, or write it to a file. This article should help you get started: http://developer.android.com/reference/android/app/Activity.html#SavingPersistentState
Your app can be killed half way during the update if users switch to another app such as receiving a phone call.
Considering such cases, you may need to persist your state in onPause() instead of onDestroy() since onPause() is the last method which is guaranted to be called when your activity is killed by the system.
And in onPause(), you can start a background service to do the update which can give your process higher priority so that it's less likely to be killed by the system when you are doing the update.
See more details in the Activity lifecycle and the Process document.
Android is not very nice about killing apps. You may or may not get onPause or onDestory. You may or may not be able to receive a hook onShutdown of the VM. Basically your app can die at any time (low memory pressure), user kills it, or etc and you won't get any warning. Basically it is best practice to assume that you can die at ANY time and store or update critical state as soon as you get it.
Basically I would either make a SQLitedatabase or use shared preferences for this.

Categories