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

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.

Related

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.

Activities on stack after backpressed, Memory usage

I have a few specific Questions.
I´m developing a touristic app. It works great, but after a long time launching new activities it crashes. I used the debug and i realized it uses a lot of memory, it is like the activities don´t closes altought I call.
#Override
public void onBackPressed() {
super.onBackPressed();
this.finish();
}
after removing some static variables and using in every new activity this flag
Intent.FLAG_ACTIVITY_CLEAR_TOP
memory space is relieved. App performance looks good, altought it uses a lot of images and listviews because i used Holders
However, in the main activity i placed the same onBackPressed code, but after pressing it the app is not closed, the memory usage is decreased but i have my doubts
Here is my Questions
Is the app really closing?
It still there because is a recent app?
The memory usage decreasing means that the activity FLAG_ACTIVITY_CLEAR_TOP and onBackPressed() is Working?
Is this the
right way to manage the activities to finish() ?
http://developer.android.com/training/articles/memory.html Check this out it may help you with the memory issue.
Secondly, if your app makes use of internet connection, do check out your code for checking the internet connection to be present or not.
Thirdly, it seems that you have written all the code in the onCreate() method, hence the app is taking a long time. Make use of AsyncTask.
Fourthly, whenever you call finish() method, the app closes. So it is the right way.

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.

Activities not destroyed by the system before out of memory on Galaxy Nexus

I have a problem in some devices like Galaxy Nexus, where if you keep opening activities, you hit out of memory error. I thought I had some memory leaks which prevent activities from collected, but I couldn't find it. So I wrote this small activity (purely for test purpose.)
public class Test extends Activity {
private byte[] imageData = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button iv = new Button(this);
imageData = new byte[1024 * 1024 * 2];
iv.setText("Open");
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(Test.this, Test.class));
}
});
setContentView(iv);
}
}
So basically, it allocates 2MB of memory, and you can open another instance of the same activity. On Galaxy S and Kindle Fire, if you keep opening, memory usage increases to a certain point, and then it starts destroying old activities for new activities.
However on Galaxy Nexus, it just goes up until 64MB and crashes with out of memory error.
So is there something I do not know about android memory management, or is this a bug on some devices? If it's a bug, how can I work around it?
Thank you.
I asked Dianne Hackborn about this (one of the Android framework engineers), and here's the advice she gave:
The point at which old activities are destroyed is an arbitrary
number, based on the total number of activities across the entire
system. This has always been the case. Relying on activities being
destroyed to reclaim memory like that is never going to be stable; the
activity manager doesn't know anything about the amount of RAM in a
process or the limit on its RAM or how much RAM a new activity is
going to take to actually have an idea when it should try to destroy
activities in each process.
In other words: You can't rely on the system destroying Activities as a means of memory management within your own app. You still need to be frugal about memory usage, and have your activities clean up their own memory usage when possible.
In this case, it might be wise to deallocate your memory once onStop() or onPause() is called.
As far as I know, Android Provides specific Memory to each Application, if you try to run more than that you'll get VMBudgetOutOfMemory error. Nexus Series uses generic Build of Android OS with minimum customization, and it totally depends OEM that how much they customize their device OS and hardware (in your case along with Memory Management). So it's better to handle control of Activities by yourself,if not then Android will handle it.The behaviour will totally depend on particular Device Specification.

WebView memory leak

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.

Categories

Resources