Passing Activity's context (prevent memory leak) - java

I have a non-activity class which creates a number of views like ImageView and TextView in my activity class.
To do this, I need to pass my activity context from activity class to non-activity class. Here is the code of my non-activity class -
public class Create {
Activity activity;
Create(Activity act){
activity = act;
}
}
Is this a good practise? Should I use getApplicationContext() instead like this? What's the difference between the two methods? -
public class Create {
Context context;
public Create(Context context){
this.context = context.getApplicationContext();
}
}
Will there be a memory leak if I use the above methods? Which method is better? How to destroy the context after use to prevent memory leak?
Is there any advantage of declaring the Activity/Context as final or protected like this -
protected Context context;
or
final Context context;

It depends on how you're using your Create object. If you're using it like:
public class MyActivity extends Activity {
public void someMethod() {
Create mCreate = new Create(this);
mCreate.doSomething();
}
}
It'll be fine. If you do something like use an inner class that does some stuff in the background, and the activity is closed, you might end up leaking context if the inner class hasn't finished processing yet.
In the case of use of context.getapplicationcontext vs passing the activity (which is a context), the latter is better in this situation, because I'm assuming your create class is only creating views for the activity it's associated with; once the activity is finished, the lifecycle for those views is presumably over.

Android Activity extends ContextThemeWrapper.
ContextThemeWrapper ultimatley extends Context.
So think of Context as the superclass and Activity as a subclass. For example, Context has 10 methods and Activity has the same 10 methods plus 20 other methods.
In terms of memory leaks, that all depends on how you're using it. Make sure you destroy all unused objects in onDestroy() to prevent memory leaks. See http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of-2/
I prefer the first method. That way you still get access to the other methods that Activity provides which Context might not have.
You can do this:
public class Create extends SomethingThatRequiresASuper {
Activity activity;
Create(Activity act){
this.activity = act;
super (act.getApplicationContext())
}
}
You can declare Context protected if you want. That just means that the scope of that object is limited.
Don't declare it final. If you do that, you won't be able to change Context later.

i think it would be fine to past the context through. And if you develop in android framework you could directly use attribute 'mContext' in View, but this is not work in SDK.

Related

Is an Activity equal to a Context?

I've been wondering about something in android development.
I have a class for requesting permissions to the device in an easier way for me, this class name is PermissionRequester
public class PermissionRequester{
int sdk;
Context context;
public PermissionRequester(Context context) {
this.context = context;
sdk = Build.VERSION.SDK_INT;
}
}
In a beginning, I was requesting a Context in my constructor for checking if the permission was allowed or denied by the user. Using Context didn't work, so I change "Context" to "Activity" and it worked.
public class PermissionRequester {
int sdk;
Activity activity;
public PermissionRequester(Activity activity) {
this.activity = activity;
sdk = Build.VERSION.SDK_INT;
}
}
In my MainActivity, I instanciate like this
PermissionRequester requester = new PermissionRequester(MainActivity.this);
So my question is the next:
Why didn't I get a compile error in both cases using Context and Activity?
Context is the Base Object. To be more precise an Activity is a specialization of Context. That's why you Activity works in your case.
Take a look at this architecture of an Activity:
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.view.ContextThemeWrapper
↳ android.app.Activity
Add to DEX7RA's answer.
Another important Context is Appication, which is base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's tag, which will cause that class to be instantiated for you when the process for your application/package is created.
I usually do application wide initialization in Application's OnCreate event, like creating database, log file, etc.

nullPointerException Crash On Call after App Minimized Long Time

there is Class Named "Configs.java" contains :
public Contect context;
public Activity currentActivity;
On Global Class Named "App.java" :
public static Configs configs = new Configs();
On Main Activity Java Class Oncreate :
App.configs.context = getApplicationContext();
App.configs.currentActivity = this;
On Products Activity Java Class Oncreate (Main Activity Not Finished And Must Work In Background):
App.configs.currentActivity = this;
After Long Time Minimized , it shows An Error On Bellow Line From Products Activity Java Class :
App.configs.currentActivity = this;
NullPointerException
Unable To Use "Bundle savedInstanceState" Because It's Activity Valiable
Try moving this code to onResume() instead of onCreate() and see if the error still exists.
Using static variables on Android is no good. This post explains that Android is very likely to kill your app (kills your Application instance, hence the static variable becomes null when your app is recreated and the class loader reinstantiates your vars) to save memory. The post also refers to Saving Activity state in Android which offers an alternative to save stuff with Bundles.
Anyway, if you need a quick solution, make your Configs class a singleton, and use getters and setters instead of making it public. Make the getter check if your singleton is null, and in this case, instantiate a new and return it. You won't get NPEs but it is very risky since it won't restore the previous state.

How to get the Context from anywhere? [duplicate]

This question already has answers here:
Using Application context everywhere?
(10 answers)
Closed 8 years ago.
In Android, is there any way to get the context of the application of a static way? For example to retrieving it from a background thread.
Thanks
The easiest (and correct) way is:
Define a new class
public class MyApp extends Application {
private static MyApp instance;
public static MyApp getInstance() {
return instance;
}
public static Context getContext(){
return instance;
// or return instance.getApplicationContext();
}
#Override
public void onCreate() {
instance = this;
super.onCreate();
}
}
Then in your manifest you need to add this class to the "Name" field at the "Application" tab. Or edit the xml and put
<application
android:name="com.example.app.MyApp"
android:icon="#drawable/icon"
android:label="#string/app_name"
.......
<activity
......
and then from anywhere you can call
MyApp.getContext();
Basically you have 2 types of Context - the Activity Context and the Application Context.
It's not necessary to use only one Context for everything. There's problems if you use one Context in every case you need Context.
It's best to follow something like this - use Activity Context inside the Activity and the Application Context when passing a context beyond the scope of an Activity, which will help you to avoid memory leaks.
If you read this article you can see the difference between to the two Context.
The Application context will live as long as your application is alive
and does not depend on the activities life cycle. If you plan on
keeping long-lived objects that need a context, remember the
application object.
Instead the Activity Context is associated with the activity and could be destroyed as many times as the activity is destroyed - changing screen orientation, back button etc.

How to retrieve a context from a non-activity class?

I have found one answer that appears to say I should create a separate class and make a static MyApplication object and make a get method. Then any class can call MyApplication.get() to retrieve the context.
Is there any other cleaner way? This is my situation:
I have a class A and a class B. Class A contains an object from class B (let's call the object b). In class A I call, "b.play()". However, I get a null pointer exception because class B needs to pass a context to the MediaPlayer.create() method.
Until now I threw together a hack and from class A I called.... "b.play(this)" and simply passed the context to B. However that is pretty ugly and looks like a bad use of OOP.
Any thoughts?
This problem seem to arise a lot in Android development. One solution to obtaining a reference to a specific Context is subclassing the Application and grab a reference to the Context which you want.
public class MyApplication extends Application {
private Context context;
#Override
public onCreate() {
super.onCreate();
this.context = getApplicationContext() // Grab the Context you want.
}
public static Context getApplicationContext() { return this.context; }
}
This solution however requires that you specify the name of your subclass in your manifest.
<application
android:name=".MyApplication"
</application>
You can then use this anywhere in your application like this in non-activity classes.
MyApplication.getContext(); // Do something with the context! :)
If class B requires a Context to operate, then I don't see any problem having class A provide that to it (through a parameter on the play method, a parameter in a constructor, etc).
I don't think you are doing any poor OOP by providing class B the dependencies that it needs to do it's job.
Passing this around is a viable way of doing things, especially if this is the activity that creates the object in need of a Context. Sometimes, I'll put the Context into the constructor (like public MyObject(Context context){this.context = context;}), so that you don't need to send it every time. However, if your object is shared across multiple Activities, you should probably update the context it is looking at with the new Activity, though I haven't tested what happens if you use the old activity.
I've answered also here.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
public void someMethod() {
// MediaPlayer.create(this, ...)
}
}

Accessing Resources without a Context

I'm trying to put configuration, such as URLs/etc, into a resource folder for a utility class to use. However, I don't want to pass the Context from the activities everywhere. I would like to be able to access a resource via a path name (seems like assets/ was designed for this use), without using a context to access the resource.
In this particular case, I want a singleton to use something in configuration when it's instantiated. It has no need for anything from resources besides that one time during instantiation. Therefore, having to pass in a Context every time getInstance() is called would be a complete waste.
Also, this is specific to the App's configuration, and should not be in stored in a shared system file or anything like that.
Use
Resources.getSystem().getString(android.R.string.someuniversalstuff)
You can use it ABSOLUTELY EVERYWHERE in your application, even in static constants declaration! But for system resources only.
For local resources use that solution.
You could extend the main application class and provide universal helpers there to access resources. This relieves the need for context as the application would provide the context instead of the caller. The application class is singleton style and should always be available while any portion of your application is running (including services).
public class MyApplication extends Application {
protected static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static Resources getResources() {
return instance.getResources();
}
}
This provides you access to:
MyApplication.getResources()....
Be sure to declare your custom application in your manifest to gain access to this. Assuming your custom application is in the root of your application's namespace:
<application
android:name=".MyApplication"
... >
I would recommend doing the following:
Rather than passing context everywhere make your activity class a singleton class with a public function that returns the context:
private static ActivityMain instance;
Initialize inside onCreate() before super.onCreate():
instance = this;
Then add these public functions to your activity:
/** Get singleton instance of activity **/
public static ActivityMain getInstance() {
return instance;
}
/** Returns context of this activity **/
public static Context getContext(){
return instance.getApplicationContext();
}
Now you can use the following anywhere in any class:
Context context = AntiMorphActivity.getContext();
String packageName = context.getPackageName();
int id = context.getResources().getIdentifier("web_page", "raw", packageName);
Unfortunately I don't think there is a real way around this. I lay mine out something like this, and also pass in the getApplicationContext() instead of the activity context.
public static AppController getAppController(Context context){
if(self == null) {
//Create instance
self = new AppController();
}
return self;
}
And then:
appController = AppController.getAppController(getApplicationContext());
The stackoverflow answer to the question below shows how to use POJO to obtain a stream to a resource, if you supply its path. This might be useful in cases you need to select a specific resource from one of many.
Is it possible to read a raw text file without Context reference in an Android library project

Categories