WebView memory leak - android

Sorry if this is some kind of duplicate question. I googled for about an hour but still have problems with the memory usage of the WebView component.
I'm starting an Activity (NewsDetail) from a ListActivity to display a specific news article. The HTML-Code of the article is added into the WebView which is included in the Activity layout. (it also loads 1 or 2 images via newsDetail.loadDataWithBaseURL())
I'm starting the article Activity via:
Intent i = new Intent(getApplicationContext(), NewsDetail.class);
i.putExtra("position", position);
startActivity(i);
After reading this question, I changed my Layout so that I add the WebView programmatically:
newsDetail = new WebView(getApplicationContext());
In my onDestroy method is set:
public void onDestroy(){
super.onDestroy();
newsDetail.destroy();
newsDetail = null;
finish();
System.gc();
}
After a while, the Garbage Collector reduce the amount of memory from about 4 MB to 2 MB. If I open/close several news articles it rises to a critical heap size. :/
As mentioned, after destroying the activity, there's a rest of 2 MB left to the activity (which doesn't exist if I completely remove the WebView from the code). So it seems to have sth to do with the WebView itself.
The same problem is mentioned here.
I also set:
android:noHistory="true"
Has anyone of you an idea how to completely get rid of memory usage of the "NewsDetail" Activity after returning to my ListActivity?
Would be glad to hear any ideas, this is driving me crazy. Is there a chart for Android phones providing more than 16 MB heap size?

I think its a known bug. Please refer to this official http://code.google.com/p/android/issues/detail?id=2137
you can refer to this link to let one know that this is a known issue or such

There is a mParent reference which points to the ViewGroup that contains the WebView and eventually to your Activity. WebView leaks anything it can get its hands on, so you have to remove it from the view hierarchy.
See my answer here:
Memory leak in WebView

If your onDestroy is located in the newsDetail activity, it's kind of weird code.
First you do super.onDestroy() which should do what you want so the object is flagged for GC. But in the line after you reference the same object. I'm no expert but that might cause troubles.
If the onDestroy method is inside your listActivity, it makes sense that it doesn't work because the method is never called as the listActivity stays open while other newsDetails are opened.

Related

Android, memory leakage through what? Context? Listview? SDK?

I'm still a beginner in Java and Android.
Recently I came accross a youtube video suggesting to avoid using 'this' when context is asked as a parameter. (: https://www.youtube.com/watch?v=gz7acZGaXoc&list=PLfuE3hOAeWhYlesGCkCU7xa4_SIfpLCgT&index=4)
And... it all seemed good, and reasonable. But, I'm not quite sure.
I started learning through courses of Udacity and they (as far as I've got) always used 'this' as a keyword for getting the current context. For example:
ArrayAdapter<String> itemsAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, numberList);
ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(itemsAdapter);
And this would seem reasonable too. Since, when you are in an activity you would not nessecarily want to grasp the context of the application.
As I understand, Java's garbagecollector wouldn't catch whatever is being referenced and, when (from the first youtuber) you turn your screen - create a new instance - a new activity is actually started without collecting the old. Leading to leakage.
/getApplicationContext() probably wouldn't be a good choice for running a ListView but for the sake of experimenting and having an other test-case.../
So, I started out an experiment without turning the screen, yet... instead I would just open a/the new activity through an explicit intent, return, redo, return, redo, etc.. Meanwhile I would run ADB and look at the memory usage.
Both cases would seem to leak a little bit (climbing up 1MB after +/-10 clicks). It would increase in a wave-like fashion: start (at y), opening (jump to x), back (jump to y+1), opening (jump to x+1), back (jump to y+1+1), etc.
So I wanted to ask: is this due to the use of context being partially re-used? Or is there something else in play here? But before that, I decided to go back to the complete basics, remove some of the code and just only explicitly open a new activity, go back, open, etc... Same result.
Now to test a bit further, I brought the app to the background by pressing home, re-opening it again, bringing back to the background, etc... Here too, same restults.
Eventually I ended up with the question: Is this normal? Or... to be more precies. Why does the monitor says it leaks a small amount of memory? It can also be not a leakage in the application but in the part of the contract it made to monitor this?
And, if, in the case it actually does leak why? Is it part of the collector, and should we live with it?.
Side note my phone runs a SDK < 25.
Rest of the code: Main:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView NumbersList = (TextView) findViewById(numbers);
NumbersList.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class);
startActivity(numbersIntent);
}
});
Rest of the code: Activity:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_numbers);
I came accross a youtube video suggesting to avoid using 'this' when context is asked as a parameter
Hopefully, that is not what they said, as that would be bad advice.
As I understand, Java's garbagecollector wouldn't catch whatever is being referenced and, when (from the first youtuber) you turn your screen - create a new instance - a new activity is actually started without collecting the old. Leading to leakage.
Using the Activity instance for an ArrayAdapter does not create a memory leak.
Both cases would seem to leak a little bit
Both cases consume a bit more memory. That does not imply a leak. Bear in mind that the Android garbage collector is not particularly aggressive. Just because you rotate the screen does not mean that every bit of garbage will be collected immediately.
Why does the monitor says it leaks a small amount of memory?
It doesn't. It says that you are consuming a small amount of additional memory.
The documentation covers generating heap dumps, which is one way to detect leaks. For detecting leaked activities, you could also integrate LeakCanary into your app.

Is it ok to use setContentView() once in OnResume()

I have heard things about how it is bad to use setContentView()
Pattern "One activity, multiple views": Advantages and disadvantages
However I was wondering, would it be unlikely that my application will cause memory leaks, if I use setContentView() once in the onResume() method of my activity?
Whenever the user opens my app, it checks to see if something has been enabled in settings. If it has been enabled then the app uses a different screen compared to the original screen.
Therefor my code looks like this:
#Override
protected void onResume() {
super.onResume();
InputMethodManager im = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
String list = im.getEnabledInputMethodList().toString();
if(Stuff is true){
setContentView(R.layout.activityscreen_enabled);
}
}
}
Would using setContentView() be unlikely to cause memory leaks and other such problems? Or is there a better solution?
I'm doing Android since few years now and I have never done that because I like to stick to the pattern which is almost always having the setContentView in the onCreate.
However, I do not believe that you would have big troubles doing that (for the memory leaks I mean).
Nevertheless, I do not see the point of doing such a thing, the pattern of the Activity (or how I understood it) is more:
I create a view in the onCreate and I update its data in the onResume and if the data are A then add/remove this view and if the data are B add/remove this other view.
To be complete, I read your (really good) link and I think you maybe misunderstood how you can apply what Commonsware is saying: you can have multiply views without having different setContentView: your view structure needs, in this case, to be really modular and you will be able to load all the subviews dynamically (or, at least, it's how my colleague and I are doing ;) ).
For your example, I would have an empty layout for the base of the activity (let's say a blue background) and then for every view I want to have (every case), I would have a dynamic layout that I load at some point in the life cycle (probably at onResume). I do not believe that what you're doing is particularly bad but I doubt that it was thought like this ^^
This link agrees with me
If you need multiple screens use a Fragment or even create a new Activity inside of messing around with the view for some reasons
It's not good to have single Activity for the whole app or it will be so long and complicated.
Your onResume() would need to handle the new views and their ids, onClickListeners... etc.
onResume() is called many times unlike onCreate() so it would be a waste of time and memory to load the views over and over.
According to android doc in activity life cycle about onPause() and onResume()
Because this state can transition often, the code in these two methods should be fairly lightweight in order to avoid slow transitions that make the user wait.

Poor performance until orientation change

I have a MainActivity that extends SherlockActivityFragment. This activity holds some fragments and a menu. Each menu item leads to new SherlockActivities. One particular SherlockActivity when it is loaded contains a carousel, that moves extremely slow.
However, once the orientation changes this carousel performs perfectly. I know that the Activity is reloaded on orientation change. But I have no idea what could start this to begin with, or even where to start looking.
Has anyone come across any similar issues? What did you do to profile the issue and what was your fix?
If you can think of relevant parts of the code (eg onCreate etc) please ask and I'll post it. Each activity has about 150 - 200 LoC)
Edit:
Here is the intent that I am using to start the SherlockActivity in question:
Intent rankIntent = new Intent(context, RankActivity.class);
rankIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(rankIntent);
break;
I've read that on orientation change onDestory() is called followed by onCreate. This makes me think that maybe some resource is freed that wasn't initially available. But the flag in the intent is intended to clear the backstack and any resources with it.
I've also tested with using the finish() method just before loading the new activity with no improvements.
This seems like a far reach but I recently had a problem I'd say could be similar.
I learnt that Android doesn't handle scaling images particularly well - could it be that the images are scaled before you change the orientation and not scaled once you do?
Answering the 2nd part of your question: since my app doesn't perform any resource-needy logic operations and is based on its UI, what I did was comment out some of its elements one at a time to see if it helps; that's how I found out an ImageView that was scaled up in my case.

Android strict mode detects multiple activity instance violation, but I have no idea why

Code is probably too complex to post here in full, but here is the basic schema: I have two Activity subclasses, each of which hosts a ListView. Each ListView has an adapter of a custom class, which generates View instances also of a custom class. These lists are showing data items that are generated asynchronously in another thread; as it needs to know where to send updates to, the data objects it manipulates have WeakReference<> objects that are set to hold references to the adapters displaying their contents when they are initialised. When an object in the list of the first activity is selected, I start the second activity with an intent that instructs it to look up the item and display its contents. I then use the 'back' button to close the second activity and return to the first. For some reason when I run this with StrictMode checking enabled, it always crashes after a few iterations of switching between the two activities, complaining that there are too many instances of one of my Activity classes.
I have arranged for a heap dump to be written just prior to the crash (see Android StrictMode and heap dumps). These heap dumps always show that there is 1 instance of each of my two activities on the heap at the time of termination. First of all, is this not to be expected when I have recently switched between the two, and if that is so, why is StrictMode complaining about this? If it isn't expected, how can I arrange to avoid this? Examining the heap dump, both objects are referenced from the main thread stack, over which I don't seem to have any useful degree of control. Each also has a reference from android.app.ActivityThread$ActivityClientRecord, which I also do not seem to be able to control.
So, basically, any ideas how I avoid this situation? Does this actually represent an activity leak, or is StrictMode just being overly sensitive?
I know that this is old post. Just for guys who is looking for solution and explanation to this problem.
In case there is InstanceCountViolation exception it means that there is a real problem that Activity leak. Otherwise there can problem which is related to how detectActivityLeaks check is implemented in Android SDK.
To identify if this is a problem I can recommend the following post: Detecting leaked Activities in Android. If you will see that there are objects holding a reference to this activity which don't related to Android Framework then you have a problem which should be fixed by you.
In case there are no objects holding a reference to this activity which don't related to Android Framework than it means that you encountered with the problem related to how detectActivityLeaks check is implemented. In this case to fix the problem with failed activity without turning off detectActivityLeaks you can simply run System.gc() before starting activity in debug configuration like in the following example:
if (BuildConfig.DEBUG)
{
System.gc();
}
Intent intent = new Intent(context, SomeActivity.class);
this.startActivity(intent);
More information are available in this answer.

Android Game Leaking memory because of GLThread reference

Right now I'm developing a game in Android (OpenGL ES 1.1) and I'm seeing that whenever I create a new SurfaceView (GLView) its thread is created. That's ok. The problem comes when I want to finish the Activity that holds the SurfaceView (and go back to the menu). It seems that the activities are not released because each GLThread is referencing it. This may finish with an OOM error.
Some MAT pictures:
The first picture: the MarkitActivity represents each single instance of the Activity that deals with SurfaceView.
The second picture: The list of all the activities in memory.
The Third Picture: What is holding the Activities from GC.
If any code is needed I will post it. Nevertheless I have already tried the following things:
->Weak reference of the Activity Context to the renderer and to the surfaceview.
->Application Context instead of Activity Context (in normal and weak mode).
->Trying to stop (in a hard way) the thread (interrupt) and waiting for join (Which the program does it, but the thread does not care, it is still there...)
->Trying without debugging, just in case in debugger mode the values changes (the MAT pictures are without debugger).
->Trying the Activity as singleInstance mode. Weird results and errors everywhere.
->onPause and onResume are correctly controlled for the view.
Any hint, idea, question or help will be really appreciated. Thanks in advance!
Carlos.
I had a similar problem with threads (but not using OpenGL), and end up solving it using a simple trick.
Before exting activity (in onPause() or onStop(), try nulling the thread like this:
myThread = null;
It seems that it makes the Thread GC collectable, and therefore you activity becomes also collectable.
It worked for me, as well as for some people with similar problems to whom I gave the same suggestion.
Regards.

Categories

Resources