This Field leaks context object - android

I am using Context object inside non-Activity, it is working perfectly but the problem is it shows warning
That is where I am using the context object
Here is the result of inspection

You can use WeakReferences for this case. something like this:
public class ContactsTask {
private WeakReference<Context> weakContext;
public ContactsTask(Context context){
weakContext = new WeakReference<>(context);
}
public void doSomething(){
if (weakContext!=null) weakContext.get() ... //return context without leaks
}
}

Related

Is storing static application class a memory leak?

In the below example code from my project, android studio warns me that this is a memory leak. Is Android Studio right?
Application class is singleton thus i thought that it is good to store it in my class. What is your suggestions?
public class MyApi {
private static MyApi instance ; // Compiler gives the following warning: Do not place Android context classes in static fields (static reference to MyApi which has field context pointing to Context); this is a memory leak
private Context context; // i need this context inside MyApi class.
public static MyApi getInstance() {
return instance;
}
public static void init(Context context) {
instance = new MyApi(context);
}
private MyApi(final Context context) {
this.context = context;
}
}
public class App extends Application{
#Override
public void onCreate() {
MyApi.init(this);
}
}
Lint sees you store a Context in a static. It does not know which kind of context it is.
If it was an activity context, then it would be super easy to leak. Application context is an application-scoped singleton and it does not cause a leak. You can ignore or suppress this warning if you want to.
static state is kind of an anti-pattern so most of the time you're better of avoiding it though.

Using context without any static reference

I am trying to access application resources, (string resources to be specific) from a Singleton class. Being Singleton, this class cannot hold any reference to Context objects (to prevent memory leak). While I was looking for other implementations on the net, I came across this two implementation:
Create a static context in Application class and use it across the app.
Pass context as a parameter to the method that requires it.
I don't want to use the fist one as it also uses a static reference to Context object. I understand that it's ok to have it statically in the Application class of android, but still it looks like a hack.
The second implementation is useless since i don't have any instance of context which I can pass to the someOtherMethod of the singleton.
So I came up with following implementation where I make my Singleton abstract to override its context requiring methods (for ex. getString(int resId) in the code below) when I initialize the singleton instance.
I am curious to know if this can lead to any memory leaks now?
Where am I confused with this approach:
--> The reference to context in the Overridden getString is final. I am not sure if that can cause a memory leak or not.
public abstract class SingletonClass{
.
.
.
private static SingletonClass sInstance;
private SingletonClass(Context paramContext) {
// constructor code
}
public static SingletonClass getInstance(final Context context) {
if (sInstance == null) {
sInstance = new SingletonClass(context){
#Override
public String getString(int resId) {
return context.getString(resId);
}
};
}
return sInstance;
}
public abstract String getString(int resId);
.
.
.
private void someOtherMethod(){
//uses above getString()
}
}
Your approach does have a memory leak. The first context passed into getInstance will never be garbage collected, since your anonymous class holds a reference to it. (and there is a static reference to the anonymous class). e.g., if you call getInstance(Activity), that activity will remain in memory until the process is killed!
Fortunately there is a pretty easy fix to get rid of the memory leak. You can safely hold onto the application context (context.getApplicationContext), which is basically a singleton context for lifetime of the app.
public static SingletonClass getInstance(Context c) {
if (sInstance == null) {
sInstance = new SingletonClass(c.getApplicationContext());
}
return sInstance;
}
You can depend on activity lifecycle, and require activities to pass reference to your singleton object in onResume method, and clean it in onPause.
protected void onResume() {
super.onResume();
Singleton.getInstance().onResume(this);
}
protected void onPause() {
super.onResume();
Singleton.getInstance().onPause();
}
Also, you can refresh the instance of Context and hold it in WeakReference:
class Singleton {
private WeakReference<Context> mContext;
private boolean hasContext() {
return mContext != null && mContext.get() != null;
}
public static Singleton getInstance(Context c) {
//do your singleton lazy
if (!sInstance.hasInstance()) {
sInstance.mContext = new WeakReference<>(c);
}
return sInstance;
}
}
Second case could hold a reference to finishing activity, so i don't suggest it.

Access Context from another activty in Android

I have a Main class and another two classes named WebServicesClass and DynamicHeightAdpater.
I am creating an instance of DynamicHeightAdpater in WebServicesClass for which I need the context of MainActivity but I am not sure how to point it. The way by which I am calling throws a NullPointerException.
CODE :
MainActivity :
static Context context;
context = this.context;
WebServicesClass :
new DynamicHeightAdapter(MainActivity.context, 1, rowItems);
But it throws a null pointer exception and I am sure that it is due to the context cause I tried to print it and it threw NullPointer.
I would suggest you to take a look at the Android application class. You can store context there and retrieve it, when needed:
public class TestApplication extends Application {
private static Context mAppContext;
#Override
public void onCreate() {
super.onCreate();
mAppContext = getApplicationContext();
}
/**
* Returns the application's context. Useful for classes that need a Context
* but don't inherently have one.
*
* #return application context
*/
public static Context getAppContext() {
return mAppContext;
}
I suggest passing the Context to the WebServicesClass object in it's constructor, and having a member variable to keep it... something like
public class WebServicesClass
{
private Context mContext;
...
public WebServicesClass(Context c) // constructor
{
mContext = c;
}
void someOtherFunction()
{
new DynamicHeightAdapter(mContext, 1, rowItems);
}
}

Android: Maintaining Global Application State

Android documentation for Application states:
There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality [i.e. maintain global application state] in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.
My request is: Can you explain, and provide code sample that implements the above suggestion for maintaining global state.
Note that there is already a suggestion that recommends subclassing Application:
How to declare global variables in Android?
Thank you.
Correction to StinePike's answer regarding context in the ApplicationState. In the code posted the context passed in to the application state is held on to. If the context passed in is an activity or similar unit then the activity would be leaked and prevented from being garbage collected.
The android documentation for the Application class states you should "internally use Context.getApplicationContext() when first constructing the singleton."
public class ApplicationState {
private Context applicationContext;
private static ApplicationState instance;
private ApplicationState(Context context) {
this.applicationContext = context.getApplicationContext();
}
public static ApplicationState getInstance(Context context) {
if(instance == null) {
instance = new ApplicationState(context);
}
return instance;
}
}
If I am not wrong your are trying to save global variables without extending Application. If so you can do two things
if you don't need any context then you ca simply use a class with static members like this
public class ApplicationState {
public static boolean get() {
return b;
}
public static void set(boolean a) {
b = a;
}
private static boolean b;
}
And if you need a context but you don't want to extend Application you can use
Public class ApplicationState {
private Context context;
private static ApplicationState instance;
private ApplicationState(Context context) {
this.context = context;
public static ApplicationState getInstance(Context context) {
if (instance == null) {
instance = new ApplicationState(context);
}
return instance;
}
public void someMethod(){}
}
So you can call some method like this
ApplicationState.getInstance(context).somemethod();

Using Application context everywhere?

In an Android app, is there anything wrong with the following approach:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
and pass it everywhere (e.g. SQLiteOpenHelper) where context is required (and not leaking of course)?
There are a couple of potential problems with this approach, though in a lot of circumstances (such as your example) it will work well.
In particular you should be careful when dealing with anything that deals with the GUI that requires a Context. For example, if you pass the application Context into the LayoutInflater you will get an Exception. Generally speaking, your approach is excellent: it's good practice to use an Activity's Context within that Activity, and the Application Context when passing a context beyond the scope of an Activity to avoid memory leaks.
Also, as an alternative to your pattern you can use the shortcut of calling getApplicationContext() on a Context object (such as an Activity) to get the Application Context.
In my experience this approach shouldn't be necessary. If you need the context for anything you can usually get it via a call to View.getContext() and using the Context obtained there you can call Context.getApplicationContext() to get the Application context. If you are trying to get the Application context this from an Activity you can always call Activity.getApplication() which should be able to be passed as the Context needed for a call to SQLiteOpenHelper().
Overall there doesn't seem to be a problem with your approach for this situation, but when dealing with Context just make sure you are not leaking memory anywhere as described on the official Google Android Developers blog.
Some people have asked: how can the singleton return a null pointer?
I'm answering that question. (I cannot answer in a comment because I need to post code.)
It may return null in between two events: (1) the class is loaded, and (2) the object of this class is created. Here's an example:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Let's run the code:
$ javac A.java
$ java A
x:X#a63599 y:Y#9036e
x:null y:null
The second line shows that Y.xinstance and X.yinstance are null; they are null because the variables X.xinstance ans Y.yinstance were read when they were null.
Can this be fixed? Yes,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
and this code shows no anomaly:
$ javac A.java
$ java A
x:X#1c059f6 y:Y#152506e
x:X#1c059f6 y:Y#152506e
BUT this is not an option for the Android Application object: the programmer does not control the time when it is created.
Once again: the difference between the first example and the second one is that the second example creates an instance if the static pointer is null. But a programmer cannot create the Android application object before the system decides to do it.
UPDATE
One more puzzling example where initialized static fields happen to be null.
Main.java:
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
And you get:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Note that you cannot move the static variable declaration one line upper, the code will not compile.
Application Class:
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context mContext;
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getAppContext() {
return mContext;
}
}
Declare the Application in the AndroidManifest:
<application android:name=".MyApplication"
...
/>
Usage:
MyApplication.getAppContext()
You are trying to create a wrapper to get Application Context and there is a possibility that it might return "null" pointer.
As per my understanding, I guess its better approach to call- any of the 2
Context.getApplicationContext() or Activity.getApplication().
It is a good approach. I use it myself as well. I would only suggest to override onCreate to set the singleton instead of using a constructor.
And since you mentioned SQLiteOpenHelper: In onCreate () you can open the database as well.
Personally I think the documentation got it wrong in saying that There is normally no need to subclass Application. I think the opposite is true: You should always subclass Application.
I would use Application Context to get a System Service in the constructor. This eases testing & benefits from composition
public class MyActivity extends Activity {
private final NotificationManager notificationManager;
public MyActivity() {
this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
}
public MyActivity(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
// onCreate etc
}
Test class would then use the overloaded constructor.
Android would use the default constructor.
I like it, but I would suggest a singleton instead:
package com.mobidrone;
import android.app.Application;
import android.content.Context;
public class ApplicationContext extends Application
{
private static ApplicationContext instance = null;
private ApplicationContext()
{
instance = this;
}
public static Context getInstance()
{
if (null == instance)
{
instance = new ApplicationContext();
}
return instance;
}
}
I'm using the same approach, I suggest to write the singleton a little better:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
but I'm not using everywhere, I use getContext() and getApplicationContext() where I can do it!
I know the original question was posted 13 years ago, and this is the Kotlin version of getting context everywhere.
class MyApplication : Application() {
companion object {
#JvmStatic
private var instance: MyApplication? = null
#JvmStatic
public final fun getContext(): Context? {
return instance
}
}
override fun onCreate() {
instance = this
super.onCreate()
}
}

Categories

Resources