Is it safe to bind Application context in its onCreate? - android

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/

Related

Android: Change language android N, application instance not updated

I follow Android N change language programmatically to changed language of my app in android N and above. However, I still have the problem with the application context instance.
In my Application class:
private static Application mInstance;
public static Context getApplication() {
return mInstance;
}
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
The language is changed, but Resources get from the Application context is not changed. For example:
MyApplication.getApplication().getResources().getString(stringId);
With return the wrong language string.
Can I update the application instance in this situation? I stuck to this problem for several hours. Because the MyApplication.getApplication() have used in many places throughout my app. So I can't convert to the Activity context.
Many thanks.
I have the same issue with one of my apps, because I do love my managers and utilities that doesn't require the context being passed every time.
My solution involves two separate contexts, one application context and one locale context. This doesn't solve all issues like inflating with correct locale using the correct style, for this you need to use the activity context. However, if you need to get the correct string or image from the resources based on the current locale, then this solution will work.
public class MainApplication extends Application {
private static Context applicationContext;
private static Context localeContext;
public static Context getAppContext() {
return applicationContext;
}
public static Context getLocaleContext() {
return localeContext;
}
#Override
public void onCreate() {
super.onCreate();
setTheme(R.style.AppTheme);
applicationContext = getApplicationContext();
updateLocaleContext();
}
public static void updateLocaleContext() {
localeContext = LocaleHelper.wrapContext(applicationContext);
}
}
The LocaleHelper.wrapContext should use a similar solution as the accepted answer on Android N change language programmatically and all activites need to implements attachBaseContext. Every time the language changes MainApplication.updateLocaleContext needs to be called. Note: the localeContext do not retain the style set in the onCreate function
Now you can use the MainApplication.getLocaleContext() for resources that depend on correct locale, while using MainApplication.getAppContext() for, e.g., inflating views that do not depend on the locale. Note: you could also place the localeContext in LocaleHelper to reduce the coupling

Use of static member in Android Application bad?

I've stumpled upon an Android Application Class which implements the Singleton pattern and bind a static object to it.
public class App extends Application
{
public static BigObject myObj;
private static App instance;
public static App getInstance()
{
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
myObj = new BigObject(this);
}
}
Are there any problems with this implementation, regarding performance, memory leaks or maybe Exceptions, when getInstance().myObj.something() is called form BroadcastReceiver or Service?
The only drawback I see is somewhat ugly code, using dependency injection would be better. I don't know, but if OS guarantees that all other components will be launched after Application::onCreate than there is no issues. Even non-main threads will not cache value of bigObject. But if you want set value of bigObject after onCreate, or it's creation takes long time you can face issues with data racing or slow startup.
I don't see any problems with this implementation. The Application object is basically a singleton.

Should I use a WeakReference<Context> or Application Context in my AsyncTask?

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();
}

How to obtain AssetManager without reference to Context?

I have a class that needs to obtain a reference to it's application's AssetManager. This class does not extend any sort of android UI class, so it doesn't have a getContext() method, or anything similar. Is there some sort of static Context.getCurrentApplicationContext() type of method?
To clarify: my class is intended to be used like a library, for other applications. It has no associated AndroidManifest.xml or control over the context which is calling it.
Create a subclass of Application, for instance public class App extends Application {
Set the android:name attribute of your <application> tag in the AndroidManifest.xml to point to your new class, e.g. android:name=".App"
In the onCreate() method of your app instance, save your context (e.g. this) to a static field named app and create a static method that returns this field, e.g. getApp():
This is how it should look:
public class App extends Application{
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = this;
}
public static Context getContext(){
return mContext;
}
}
Now you can use: App.getContext() whenever you want to get a context, and then getAssetManager() (or App.getContext().getAssetManager()).
I am not sure of the best answer to the OP question. However, I do know that you have to be very careful when using a static context as suggested in Android developer resources:
In the onCreate() method of your app instance, save your context (e.g. this) to a static field named app and create a static method that returns this field, e.g. getApp():
Using static contexts can leak to leaked memory issues, especially if the static context is used for references to views.

Singleton wrapper for Context

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;
}
}

Categories

Resources