Using context as a member variable in all classes - android

I am really new to Android development. In my app, I perform different async task and needed to save the result from those task to the database which requires context. Inspired from this answer I started using context in all my classes as a member variable. This seemed like a good method, but now ALL my background task and other classes which deal with preference have context as a member variable.
Code example -
public class Task extends AsyncTask<Void, Void, String> {
Context context;
public Task(Context context){
super();
this.context = context;
}
protected String doInBackground() {
//myAsyncTask
..
}
..
protected void onPostExecute(String response) { //response from the request
DbHelper helper = new DbHelper(context);
//save to db
}
I have about 3 or more of such tasks running consecutively at times. So whenever I need to do a background task, I first have to initialize the async task with the context and then initialize the DbHelper using that context. I feel like I'm doing it all wrong. This doesn't seem like a good method to me now (may lead to huge memory leaks imo). Plus it feels like duplication and that I can have access to the context in a better way.
Is it recommended to use context like this? Or does it actually have a disadvantage and I'm better off using some other method? Something like
public class MyApplication extends Application {
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
//use context as MyApplication.getAppContext();
}
}
Which one is better to use?

Neither is correct. Do NOT maintain a reference to Context anywhere, it gives memory leaks because then the VM cannot garbage-collect the Context. We also tried several solutions but all failed. There's no other solution than pass the Context whenever you need it (if you look at the Android API you will see that it also works this way, and it's for a reason).

Related

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

Singleton-Pattern for Toast, Database and other Utilities in Android

As I'm really annoyed of passing the Context for most of the operations in Android (Database, Toast, Preferences). I was wondering if it's a good way of programming to initialize these elements once (e.g. in Application-Class).
It works quite good, I don't have to pass the element from Class to class and I can't see any disadvantages. Thats the reason why I wanted to ask you guys. Why shouldn't I use this?
For the people who don't know what I mean:
MainApplication:
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
VolleySingleton.init(this);
Toaster.init(this);
PrefUtilities.init(this);
}
}
Toaster:
public class Toaster {
private static Toaster mInstance = null;
private Context context;
private Toast currentToast;
private Toaster(Context context) {
this.context = context;
}
public static void init(Context context) {
mInstance = new Toaster(context);
}
public static void toast(String message){
if (mInstance.currentToast != null){
mInstance.currentToast.cancel();
}
mInstance.currentToast = Toast.makeText(mInstance.context, message, Toast.LENGTH_SHORT);
mInstance.currentToast.show();
}
}
I'm also interested in the question, why the context for Toast or other stuff is needed? I can use the application context for the Toast and have access in every single Activity / Fragment. Why has the Android-Team implemented it this way?
So basically two questions:
1. Do I have any disadvantages with my implementation (memory, time) ?
2. Why do classes like Toast require a context at all?
1. Do I have any disadvantages with my implementation (memory, time) ?
Well, you are always initiating your db, even if you dont use it at all during that session, same goes for the other classes. Couldnt think of anything else, since you would use application context anyways, at least for database.
2. Why do classes like Toast require a context at all?
Toast requires a context since it touches the UiThread, so it needs a reference to access the thread.

Best practice to pass Context to non-activity classes?

So, my first major application is almost coded and I'm doing optimizations on my code. The app works fine, but I'm not sure about my way of passing the context to other classes. I don't want to do it the wrong way. I stumbled upon articles and questions here in Stackoverflow about contexts and which is the right way to pass it to non-activity classes. I read the documentation as well, but being a Finn makes complicated tech speak even harder to understand.
So, a simple question. Is my way of passing my main activity's context to other (helper) classes correct? If not, where can I read more about better practice on these situations.
For example:
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle sis){
super(sis);
new Helper(MyActivity.this).makeMyAppAwesome();
}
}
Helper.java
public class Helper {
Context context;
Helper(Context ctx){
this.context = ctx;
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(context);
}
}
Is this OK? It would be nice if someone could provide an easy to read article with examples on this subject.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(this);
}
}
And call the non activity class like this from an Activity
new MyContextWrapper(this);
It is usually in your best interest to just pass the current context at the moment it is needed. Storing it in a member variable will likely lead to leaked memory, and start causing issues as you build out more Activities and Services in your app.
public void iNeedContext(Context context) {...
Also, in any class that has context, I'd recommend making a member variable for readability and searchability, rather than directly passing or (ClassName.)this. For example in MainActivity.java:
Context mContext = MainActivity.this;
Activity mActivity = MainActivity.this;
I have passed context like this which solved my problem:
public class Utils extends ContextWrapper {
private final Context context;
public Utils(Context context) {
super(context);
this.context = context;
}
public void mymethod(){}
}
super(context); with ContextWrapper helped to make getBaseContext() and getApplicationContext() valid and this.context = context; captured context in variable which I can use wherever needed in methods.
Maybe alternatively you can just opt for using a constructor with this.context = context; and replace all occurrences of getApplicationContext() and getBaseContext().
Well, an even better way is to pass context directly to the method if using only few from a class for avoiding memory leaks.
You could also create a static instance reference to your MainActivity initialized in the onCreate() method
public class MainActivity extends AppCompatActivity {
public static MainActivity mMainActivity;
#Override
private onCreate(Bundle savedInstanceState){
//...
mMainActivity = this;
}
}
and call the context like this:
MainActivity.mMainActivity;
or write a method getInstanceOf() if it's clearer and/or you prefer using an accessor
MainActivity.getInstanceOf();
This strategy might provide you with some flexibility if you decide later that you would like to call an instance method contained in your main activity like so:
MainActivity.mMainActivity.myInstanceMethod();
Just a suggestion. Criticism is welcome and encouraged.

How to use SQLite DB from AsyncTask?

I've been using my Activity class to access my DB which made my program freeze sometimes.
So I decided to use AsyncTask instead to handle the DB.
My problem is I don't know how to instantiate my SQLite DB "TheDB" from AsyncTask's class
public class myClass extends AsyncTask<Void, Void, Void>{
private TheDB db;
any method() {
this.db = new TheDB(this); //<-- Error here
}
this worked fine on the Activity class, but it I dont know how to use it here
TheDB's constructor is TheDB(Context context) but this class is not a "context" so how can i use my DB here?
please provide examples if you can
and please do not give me links to google's references, am a newbie and i find them hard to follow
you need to pass the application context here
this.db = new TheDB(getApplicationContext());
import android.content.Context;
public class SuperTask extends AsyncTask<Void, Void, Void> {
private final Context mContext;
public SuperTask(Context context) {
super();
this.mContext = context
}
protected Void doInBackground(Void... params) {
// using this.mContext
}
}
public class MainActivity extends Activity {
// and run from Activity
public void onButtonClick(View view) {
new SuperTask(this.getApplicationContext()).execute();
}
}
There are two ways that i see:
Pass a context object to your AsyncTask constructor, then instantiate database like this this.db = new TheDB(context);
Or you probably can pass the actual database object to the constructor, but the first approach seems better.
An important part of learning to program is learning to read and understand documentation. As documentation goes, the Android docs are pretty detailed, so its really worth your time to understand how they work.
As you can see in the AsyncTask docs, there is no onCreate or onExecute method in an AsyncTask.
The docs clearly walk you through the 4 main functions of an AsyncTask, onPreExecute(), doInBackground(Params...), onProgressUpdate(Progress...), onPostExecute(Result).
The likely choices for your instance are onPreExecute() or doInBackground(Params...). The difference is whether or not you want the initializition to occur on the UI thread. If you don't, then do it in doInBackground(Params...).

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