I'm creating a module (a group of classes to perform functionality) where I need the context object to perform some operations like secure setting read and others.
I do not like to create multiple objects for my classes which ideally is not needed in my case even so i'm doing something like this,
class MyModuleFactory {
private static final String TAG = MyModuleFactory.class.getSimpleName();
public Context mContext;
private static HashMap<Context, MyModuleFactory> myInstance = new HashMap<>();
private MyModuleFactory(Context context) {
mContext = context;
}
public static synchronized MyModuleFactory getInstance(Context mContext) {
if(mContext == null) {
Log.i(TAG, "Context cannot be null");
return null;
}
if(myInstance.get(mContext.getApplicationContext()) != null) {
return myInstance.get(mContext.getApplicationContext());
} else {
MyModuleFactory myModuleFactory = new MyModuleFactory(mContext);
myInstance.put(mContext.getApplicationContext(), myModuleFactory);
}
}
}
My worry here is since I'm holding the context of application here I'm afraid that I could cause memory leak - the reason is because Android can clear up application object and recreate it at anytime. So holding the context behind the application's lifecycle and not allowing to clear the context here could cause memory leak.
What is the better way to force singleton for my module here and also avoiding memory leak.
There won't be any memory leak if you are holding a reference to Application context. Application context lives as long as the app is running. It gets destroyed when the app is killed. In that case, even your singleton will be destroyed, so no memory leak will happen.
Just make sure you are holding reference only to the Application context in the singleton, not Activity context.
Check this post for detailed information:
If you have to create a singleton object for your application and that
object needs a context, always pass the application context.
If you pass the activity context here, it will lead to the memory leak
as it will keep the reference to the activity and activity will not be
garbage collected.
Related
I'm in a little bit of a dilemma and I hope you guys can help me with it.
As you can see I have an AsyncTask in which I have some code to save Bitmap objects as .jpg file to the gallery. In the AsyncTask I'm also using a Context, but as I understand using a context of an Activity in this inner class can cause memory leak, so I changed it to a WeakReference<Context> weakContext; so the garbage collector can collect it.
But by using the Application context that I get from the passed View from the constructor I should archive the same effect as the weak context reference
So is any better to use than the other in this case?
public class ViewToBitmap {
private View view;
private WeakReference<Context> weakContext;
public ViewToBitmap(#NonNull View view) {
this.view = view;
}
// This?
private WeakReference<Context> getContext() {
weakContext = new WeakReference<>(view.getContext());
return weakContext;
}
// Or This?
private Context getContext() {
return view.getContext().getApplicationContext();
}
private class AsyncSaveBitmap
extends AsyncTask<Void, Void, Void>
implements MediaScannerConnection.OnScanCompletedListener {
#Override
protected Void doInBackground(Void... params) {
//TODO: Save bitmaps to gallery
//CONTEXT IS USED HERE
getContext().get()
return null;
}
}
Since the View object has explicit references to Context which was used upon view's inflation, you are effectively keeping a "transitive" hard reference to Context in instances of ViewToBitmap by keeping a hard reference to View.
Also, since AsyncSaveBitmap is not static, instance of this class has implicit reference to the enclosing instance of ViewToBitmap.
The net result is that as long as AsyncSaveBitmap exists, there is a chain of hard references to Activity that will prevent GC of that Activity.
So, the answer is: neither approach is good enough.
The best approach would be to refactor the logic in such a way that no long running code has references to Context, Activity, View, etc.
The most straightforward way of achieving this is to use Observer design pattern or Publish-Subscribe design pattern - this way you could "unregister" in life-cycle methods (e.g. onStop()), thus removing the potentially dangerous reference and preventing memory leaks.
EDIT:
For library purposes, where you don't necessarily need a specific Context and application's Context will suffice, the following patterns can be used (depending on whether your library exposed as Singleton or not):
// Use this approach if clients will use your library as Singleton
private static Context sAppContext;
public static void init(Context context) {
sAppContext = context.getApplicationContext();
}
// Use this approach if clients will instantiate your library's object on each use
private final Context mAppContext;
public MyLibraryEntryClass(Context context) {
mAppContext = context.getApplicationContext();
}
Let's assume we have a custom App extends Application.
I understand that wherever possible getApplicationContext() method should be used, but it's only applicable if you're within a scope that provides this method. Sometimes you need to access it outside of it and that's why I started wondering.
Here's the sample code
public class App extends Application
{
private static App instance = null;
public static App getInstance()
{
return instance;
}
public static Context getContext()
{
return instance;
}
#Override
public void onCreate()
{
instance = this;
super.onCreate();
}
}
Does App.getContext() return the same context getApplicationContext() would return in an appropriate scope? Is it safe to bind the App context like this?
Lifetime of statics is practically the same as your Application. It's safe in the sense that there won't be a memory leak and it will always refer to the correct Application.
getApplicationContext() returns the Application object which also is-a Context.
However, static data like this is a design smell you should try to avoid. It adds unnecessary coupling to your code, making components harder to test in isolation. Instead, consider passing a Context as a parameter where one is needed.
For a good article about what a particular kind of Context such as Application is good for, read http://www.doubleencore.com/2013/06/context/
I have a singleton, typical design with a static 'mInstance' to hold the global state. I notice that sometimes, while switching between activities, the mInstance variable becomes null and requires to be re-instantiated, causing all data to go empty.
Is this expected or am I doing something wrong? Is there really a chance that the static variables of a singleton would be nullified in such a scenario? I seriously doubt it and would like to hear some opinions.
Code is pasted:
public class RuleManager extends ArrayAdapter<Rule>
{
private static RuleManager mInstance;
private final Context context;
public RuleManager(Context context, List<Rule> r)
{
super(context,R.layout.main_menu_options_list_item);
if(r==null)r=new ArrayList<Rule>();
this.context=context;
}
public static RuleManager getInstance(Context context,List<Rule> r)
{
if (mInstance == null)
mInstance = new RuleManager(context, r);
return mInstance;
}
}
I just learned that storing Context like this would never let it being Garbage Collected and hence may cause a big leak.
You need to make your constructor private. I guess you may be calling a new on the constructor. Also make your getInstance synchronized.
A Service may be better than a Singleton if you want to hook into the LifeCycle. Here's more information from a related stackoverflow question.
I've read that it is a mistake and a source of memory leaks in Android application to keep a long-lived references to a Context.
But I don't understand if it is ok to create a class that looks like this one:
public class HelperClass {
private Context context;
public HelperClass(Context context) {
this.context = context;
}
public void myHelperMethod() {
// uses this.context
}
}
And call it from an Activity:
public class MyActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
HelperClass h = new HelperClass(this);
h.myHelperMethod();
}
...
}
This is fine, and will not cause a memory leak.
As soon as onCreate finishes executing, h will be out of scope and become eligible for garbage collection. If h was static, then you would run into problems. Only when the reference to the context outlives the lifecycle of the context itself will a memory leak occur. A few helpful hints:
Use Context.getApplicationContext() when possible. This context will live as long as your application is alive.
Be careful when using static fields and inner classes.
Run your application through a profiler to check for leaks.
The scope of the HelperClass is only within your onCreate function, so once onCreate executed, your "h" object is no longer needed and subject to garbage collection.
It would be a different story if "h" was a static member - THAT would be a great way to leak memory.
I'm considering creating a singleton wrapper for a Context so my model objects, if necessary, can open and read from a database connection. My model objects do not have access to a Context, and I'd like to avoid needing to pass a reference to a Context from object to object.
I was planning to place into this singleton a reference to the Context returned by Application.getApplicationContext(). This singleton object would be initialized in my custom Application instance before anything else would need to or have a chance to use it.
Can anyone think of a reason to not do this?
I would urge you to think about what reasons you have for not passing a reference of the application context into your model objects.
There are various well-documented disadvantages of using singletons. I won't go into detail here but you might want to consider:
How singletons limit your ability to properly unit-test your application.
Singletons hide dependencies between different entities in the code- you cannot determine dependecies from inspecting the interfaces.
You have no real control over the lifetime of a singleton, it could exist for the lifetime of your application. Do you really want to potentially hold a DB connection for the lifetime of your app?
The thread safety of your singleton.
If you valid reasons for not passing a reference to a context to other parts of your application then perhaps you should consider some other pattern- a factory might be one possible solution, a service another.
I'm not sure I get your idea, but here's what's been working for me:
public class MyApp extends Application {
private static MyApp instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
// ...
}
public static MyApp getInstance(){
return instance;
}
// misc helper methods
}
Pasted here to preserve formatting.
public class ContextContainer
{
private static boolean initialized;
private static Context context;
private ContextContainer()
{
//
}
public static synchronized void setApplicationContext(Context context)
{
if (!initialized) {
ContextContainer.context = context;
initialized = true;
} else {
throw new RuntimeException("ApplicationContext has already been set!");
}
}
public static synchronized Context getApplicationContext()
{
return context;
}
}