From my understanding, Application in Android is a singleton (correct me if I'm wrong) and we always have just one application Context instance.
So, from this perspective, is it a bad practice to save the application Context in my Application class?
Can it lead to a massive memory leak?
Here is an example:
public class MyApp extends Application {
private static Context appContext = null; // <-- here is the thing!
#Override
public void onCreate() {
appContext = this;
}
public static Context getApplicationContextSingleton () {
return MyApp.appContext;
}
}
The reason to do this is globally accessed classes, like PreferencesManager, that mostly have static methods always need a context. So, instead of passing it everytime (or even storing it in an instance, which can be bad), I thought about storing the app context. What are the drawbacks I'm not seeing?
is it a bad practice to save the application Context in my Application class?
It is a code smell.
Can it lead to a massive memory leak?
Having the static data member will not lead to a massive memory leak. Whether your over-use of the Application object will lead to a massive memory leak depends upon where and how you use it.
What are the drawbacks I'm not seeing?
Not all Contexts are created equal. Generally speaking, only use Application when you know specifically why you need the Application context, not for everything.
Dave Smith of DoubleEncore has an awesome blog post covering the differences between types of Context and when to use one over another.
Related
I created a custom Application class for my app. This class onCreate sets a static variable of itself like this
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static ChattyApp getInstance() {
return mInstance;
}
Then I use App.getInstance() method to get application context to a nonactivity/fragment class like API Controller or something. Can it cause a memory leak?
I setup leak canary and it is showing memory leak on an instance variable of Application class. This variable keeps socket.io's socket ref so that I can use it anywhere in the app.
It is a good question that you have asked and people on SO have had extensive discussions on this. Have a look at this and this
Although this seems to be an okay way to store the Context in Application class as per the discussion in the first link, there can be better ways to deal with this.
Ideally for each logic unit you should have a separate class to deal with it rather than polluting your application class. You application class can however initialize or setup those other classes. This will create a separation of concern.
Another way is to use Dagger2, which is a dependency injection framework, to inject your socket ref to wherever you want.
Dagger 2 has a steep learning curve and but a very important tool to learn as an Android developer
I have a class which has a static variable which holds Context reference.
public static Context context;
Android studio gives a warning saying that static references to the
Context class leads to memory leaks
If I remove the static keyword, it does not give any warning.
Similar scenario with ContextWrapper class as well.
My understanding is, if we hold a reference to the classes which are related to Context will lead to memory leak. But, Why Android studio does not give any warning for non-static Context references?
I have seen some code examples where they have extended the ContextWrapper class. Whenever they needed the Context, they are accessing through the class which was extended `ContextWrapper'. Will this approach does not lead to Memory leak?
Also, Will memory leaks happens for non-static Context references at runtime? Did I understand it in wrong way? Am I missing something here?
Can anyone give explanation for this?
Thanks in advance.
First things first, let's know about memory leaks and why it happens exactly
Memory leaks occur if there is any data in memory which can't be garbage collected ,Having said that, static variables can't be garbage collected as they stays live in memory throughout the Application life where as non-static variables can be garbage collected once it's enclosing parent is no longer referenced, keeping this in mind we'll see example to explain your question.
Consider class A with a static and non static Variable
Class A{
private static Context iCanNeverBeDestroyed;
// Scope -> Application life, so memory leak can occur
private Context iCanBeDestroyedWithA;
// Scope -> A
private static int itWontMatterWhetherImDestroyedOrNot;
//Even though the scope is Application, due to low memory usage , memory leak is negligible in this case
}
Leakage is calculated based on scope of variable and size in memory together, high memory and greater scope has greater chances of leak, example like Context,Bitmap etc
With this question the main concern is what could be best approach. In my android app an Application class is subclassed mainly for two reasons,
1), Maintaining the global state across the app,
2), Ability to initialise and use SharedPreferences in non-activity classes.
The code is somewhat like this,
public class GlobalApp extends Application {
private static GlobalApp instance;
private Bitmap bitmap;
#Override
public void on create(){
super.on create();
instance = this;
}
public static GlobalApp getInstance() {
return instance;
}
public void setBitmap(Bitmap b) {
this.bitmap = b;
}
}
As you can see, to have access of application context in non-activity class, it has been taken as the static whereas other fields are simply instance variables, in which we are storing Bitmaps, will it cause the memory leak ?
And above approach is best? Or it can be made even better than this?
Please help.
I don't see anything there that could cause a memory leak. However, you needn't store and retrieve the instance like that, you can just do this:
GlobalApp app = ((GlobalApp)this.getApplication());
Just make sure to add the application class name to the manifest. Keep in mind also that just because there isn't a memory leak doesn't mean there isn't a memory problem. If you hold on to too much memory in that Application object, your app could crash with an OutOfMemoryError. Depending on your exact needs you may need to use weak references to avoid that. More info about using the Application class: Using the Android Application class to persist data
I'm part of an Android project that uses a global class that contains public static variables, like the example below:
public class Globals {
public static MyObject variable = "this is a test";
}
In the middle of using the application, this global variable's value will be changed let's say:
#Override
public void onCreate(Bundle savedInstanceState) {
Globals.variable = new MyObject(somethingHere);
}
And I came across using Headless Retained Fragments from these blog posts:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
http://www.vogella.com/tutorials/AndroidFragments/article.html#headlessfragments
Problem:
I need to have a reference of an initialized object all over the application.
Question:
which is better to implement, a good practice, and practical? Or is there another way I could store a reference of an object all over the application?
The global class has been used over the project, and works fine, but are there any downsides of this implementation?
are there any downsides of this implementation?
Memory leaks, depending on what you are storing there. Leaks are why static data members are considered poor form in classic Java, even if we tend to use them more in Android app development.
Also, this data needs to be considered a cache, one that has to be able to be lazy-created on first access. Your process can be terminated at any point (wiping out the static data member) and the user can return to any activity in your app (courtesy of the recent-tasks list). If you want this data to survive process termination, the most likely solution will be to persist it in a file, database, or SharedPreferences.
All that being said, a retained fragment is a per-activity solution, not a per-application solution, and so it is not a valid alternative for your scenario AFAICT.
I am looking for how to share functions and data across multiple activities within a single application. I researched the daylights out of it and find some ideology war between overriding the extend for the application and doing a singleton, neither of which I can find examples sufficient to make me understand. Basically I want to share data and share functions. All activities need the same functions and data so this is not one activity sharing data with another activity. It is all activities needing to have access to the same functions and data.
What I want to know is what is the way to go and how do I do it. I need to see what I need to do in my 34 activities, what the class that is going to be common looks like, and what the Manifest entry needs to be. I also need to be sure the common data area will not be closed by the OS.
This is my first Android - Java program and now find my 15,000 line, 34 activity application needs some structure. I know, should have done things differently but the app works really well with two exceptions. One is that it is structurally a mess. Two is that the fact it is a mess is making it hard to fix one behavior I would like to fix.
This is a GPS based application for racing sailboats. It is timing critical and every activity basically runs a once a second loop inside the location manager onLocationChanged function. That part is fine and I do not want to put the GPS code in one place. The problem is that most activities need to filter the data so a lot of code is copied and pasted to the activities. The filter needs history so it needs to remember a state. There are other functions that are used by several activities so these have been copied as well. Think of a function that averages the last three GPS speed readings. It needs to save some history, do its thing, and give a result. All activities need to do the exact same thing. All this works but the problem is that the averaging starts over every time I switch activities because every activity has its own filter. That gives a glitch in the data that I need to get rid of. I need common place to save the data and hopefully a common place to run the filtering and other functions that are common. If every activity can call the filter function that is using common state data, there will be no glitch across activity changes.
I would appreciate some guidance.
Why you don't just make a Class with only static functions, passing needed Parameters? An example if you want to show an ErrorDialog
public class SharedHelper{
public static Dialog showErrorDialog(Context ctx, String message, String title, DialogInterface.OnClickListener okListener, DialogInterface.OnClickListener cancelListener){
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setMessage(message).setTitle(tilte);
if (okListener != null){
builder.setPositiveButton(R.string.button_positive, okListener);
}
if (cancelListener != null){
builder.setNegativeButton(R.string.button_negative, cancelListener);
}
return builder.show();
}
}
Singletons are (from my point of view) one of the uglyest design pattern and will bite you sooner or later. Putting anything in Application requires you to cast it everytime to the Special Application class you designed. A class with only statics however is very flexible in its usage and doesn't need an instance to work.
For the storage-issue:
lookup "SharedPreferences" & "SQLite" and decide afterwards which storage-type suits your needs more.
For the methods-issue:
This question is a bit more complex and there are different ways to do it. For example you could write a parent-class that implements all your globally needed questions and you let all your activity-classes inherit from it.
public class MyParentActivity extends Activity {
public void myMethod() {
}
}
and:
public class Activity1of34 extends MyParentActivity {
myMethod();
}
I think what this comes down to is not an Android problem but an Object-Oriented Programming problem. If I understand the situation correctly, I'm betting the best solution would be to take your shared filter and create a new Filter class that is instantiated within each Activity (this is likely more manageable than a singleton, but not having seen your use case, it's hard to say for sure). If you need to centrally track the averaging, you can simply create a static variable within the Filter class that maintains the same value during the life of the application. If you really want to maintain that average (even past the application's current lifecycle), you can persist it in a database or other local data options. However, I don't see any reason to put everything in a singleton just to maintain that average. Singletons (and all static data structures) can be potentially troublesome if used incorrectly.
I, for one, do not mind the singleton pattern. Of course as everything else it should not be abused.
This is the construction I use for my shared objects. My app is divided into modules this way but can just as well be used in your case.
public class SharedDataObject {
private Context context;
private static SharedDataObject instance;
public static SharedDataObject getInstance() {
if (instance == null) throw new RuntimeException("Reference to SharedDataObject was null");
return instance;
}
public static SharedDataObject createInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new SharedDataObject(context.getApplicationContext());
}
// notice the constructor is private
private SharedDataObject(Context context) {
this.context = context;
}
...
public void myMethod() {
// do stuff
}
}
Notice that it uses the application context, that means among other things, means that the context owned by SharedDataObject cannot be used for GUI operations. But, the context will live for the entire lifetime of the application, which is nice.
Furthermore I hate having to pass a context everytime I wish to call methods on my SharedDataObject, thus I have a splashscreen calling SharedDataObject.createInstance() on all my modules.
Once an instance is create, I can call:
SharedDataObject.getInstance().myMethod();
Anywhere in my code, regardless of a context being present or not (from the place calling this code that is).