Warning: do not place Android context classes in static fields; this is a memory leak (and also aborts Instant Run)

Android Studio:

Do not place Android context classes in static fields; this is a memory leak (and also aborts Instant Run)

So, 2 questions:

# 1 How do you call startService from a static method without a static variable for context?
# 2 How do you send localBroadcast from a static method (same)?

Examples:

 public static void log(int iLogLevel, String sRequest, String sData) { if(iLogLevel > 0) { Intent intent = new Intent(mContext, LogService.class); intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW"); mContext.startService(intent); } } 

or

  Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT); intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest)); intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData); intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel); LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); 

What would be the correct way to do this without using mContext ?

NOTE. I think that my main question may be how to pass the context to the class from which the calling method lives.

+76
Jun 08 '16 at 18:12
source share
6 answers

Just pass it as a parameter to your method. It makes no sense to create a static instance of Context exclusively to run Intent .

Here's what your method should look like:

 public static void log(int iLogLevel, String sRequest, String sData, Context ctx) { if(iLogLevel > 0) { Intent intent = new Intent(ctx, LogService.class); intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW"); ctx.startService(intent); } } 

Update from comments to the question: cascade the context from the initiating activity (via the constructor parameters or method parameters) up to the point you need.

+49
Jun 08 '16 at 18:15
source share

Just make sure you pass context.getApplicationContext () or call getApplicationContext () in any context that is passed through the methods / constructor to your singleton if you decide to save it in any member field.

An example of an idiot proof (even if someone passes it into action, it will capture the application context and use it to instantiate the single):

 public static synchronized RestClient getInstance(Context context) { if (mInstance == null) { mInstance = new RestClient(context.getApplicationContext()); } return mInstance; } 

getApplicationContext () according to the docs: "Return the context of a single global application object of the current process."

This means that the context returned by getApplicationContext () will go through the whole process, and therefore it doesn’t matter if you store a static link to it anywhere, because it will always be present at the time your application is running (and survive any objects / singles created by him).

Compare this with the context inside representations / activities containing large amounts of data, if you are running a context occupied by activity, the system will not be able to free this resource, which is clearly not suitable.

A link to an activity according to its context should live in the same life cycle as the activity itself, otherwise it will keep the context hostage causing a memory leak (which is the reason for the lint warning).

EDIT: For the guy who is beating up an example from the above documents, there is even a comment section in the code about what I just wrote:

  // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. 
+49
Oct 25 '16 at 9:08
source share

This is just a warning. Do not worry. If you want to use the application context, you can save it in the "singleton" class, which is used to save the entire singleton class in your project.

+4
Mar 06 '17 at 3:18
source share

In your case, it does not make sense to have this as a static field, but I do not think this is bad in all cases. If you do now, you can have a static field that has a context, and then null. I am creating a static instance for my main model class, in which there is a context inside, its application context, and not an activity context, and I also have a static field for an instance of a class containing Activity, in which I am null in on destroy. I do not see that I have a memory leak. Therefore, if any smart guy thinks I'm wrong, feel free to comment ...

Also Instant Run works here great ...

+2
01 Oct '16 at 18:33
source share

In general, avoid using context fields defined as static. The warning itself explains why: this is a memory leak. The instant launch gap may not be the biggest problem on the planet, though.

Now there are two scenarios in which you will receive this warning. For the instance (most obvious):

 public static Context ctx; 

And then there the bit is more complex, where the context is wrapped in a class:

 public class Example{ public Context ctx; //Constructor omitted for brievety } 

And this class is defined as static somewhere:

 public static Example example; 

And you will get a warning.

The solution itself is quite simple: Do not place context fields in static instances , be it a packaging class or declare it static.

And the solution to the warning is simple: don't put the field statically. In your case, pass the context as an instance of the method. For classes in which multiple context calls are made, use the constructor to pass context (or activity on the subject) to the class.

Please note that this is a warning, not an error. If for some reason you need a static context, you can do this. Although you create a memory leak when you do this. Sub>

+1
Dec 22 '17 at 12:36 on
source share

If you make sure this is the application context. It matters. Add this

 @SuppressLint("StaticFieldLeak") 
0
Jul 29 '19 at 9:49
source share



All Articles