Is it at all possible, from within an AsyncTask that is NOT an inner class of the calling Activity class, to get a reference to the instance of Activity that initiated execution of the AsyncTask?
I am aware of this thread, however it doesn't exactly address how to reference the calling Activity. Some suggest passing a reference to the Activity as a parameter to the AsyncTask constructor, however, it's reported that doing so will always result in a NullPointerException.
So, I'm at a loss. My AsyncTask provides robust functionality, and I don't want to have to duplicate it as an inner class in every Activity that wants to use it. There must be an elegant solution.
The "elegant solution" is to actually try passing it as a parameter (to the constructor or execute()) and see if it works, rather than assuming the person who asked that previous question (then answered his own question twice) knows what he is doing. I can think of nothing intrinsic to AsyncTask that would cause Activity to be a bad constructor parameter and every other object be just fine.
Now, I haven't passed an Activity (or other Context) as a parameter to an AsyncTask, because my AsyncTasks are always private inner classes. In fact, the fact that you want a public AsyncTask to me is a code smell, suggesting these tasks should be mediated by a Service or some other control point. But, that's just me.
UPDATE
A better answer for handling this pattern can be found here: Background task, progress dialog, orientation change - is there any 100% working solution?
My AsyncTasks always live in a separate package while still bound to a particular type of Activity. They accept it's instance in constructor and store in a local variable.
Try thinking in terms of creating an abstract Activity class that encapsulates AsyncTask-related stuff and is extended by other activities.
Like so:
public abstract RemoteListActivity<T> extends ListActivity{
// calls AsyncTask, shows spinning progress dialog, etc
protected abstract T someConcreteMethod();
}
public final class CustomerListActivity extends RemoteListActivity<Customer>{
protected final Customer someConcreteMethod();
}
Alternatively, if things don't fit in a single hierarchy, have an interface:
interface LazyLoadable {
void setLoadingState();
void setDefaultState();
}
public class MyActivity extends Activity implements LazyLoadable{
}
public final class AsyncTask extends AsyncTask<Void, Void, Void>{
private final LazyLoadable lazyLoadable;
public MyAsyncTask(Context ctx, LazyLoadable lazyLoadable){
super(ctx);
this.lazyLoadable = lazyLoadable;
}
}
Related
I'm wondering where I should place my AsyncTask in my android project. As of right now I'm implementing an AsyncTask as a private class of my activity its running under. What I am going to do is in each activity that has a network call I will implement its own private class of AsyncTask. I have a few questions though
In The preexecute method it says I can interact with the activity and place a spinner or progress bar. I do this by using My_Activity_Class_Name.this. So my question is does that line of code reference the activity the AsyncTask is called from? If so I believe that will be a static method. How do i actually pass in the instance of the class so I can interact with non static functions?
I want to place all my Async code into one class for its respective needs. My quesiotn though is if i need to return a type back to the class that calls the Async method how can I return a value? Also is this the best practice?
You should make your inner private AsyncTask class - static. This is because otherwise it will have implicit reference to your Activity - this means that if your Activity will be recreated - ie. due to config change - then your AsyncTask will still hold your activity reference causing reference leak. This means you should pass reference to your activity to AsyncTask in ie. constructor of AsyncTask, and keep it in WeakReference (WeakReference/AsyncTask pattern in android).
So my question is does that line of code reference the activity the ASYNC Task is called from?
yes, but only if your AsyncTask class is non static
If so I beleve that will be a static method. How do i actually pass in the instance of the class so i can interact with non static functions?
its not a static method, with My_Activity_Class_Name.this you can access non static methods of your Activity class.
My quesiotn though is if i need to return a type back to the class that calls the Async method how can I return a value? Also is this the best practice?
You can call a method on your Activity class, there is nothing wrong with that. Remember that you cannot access UI widgets from non UI thread. So update your Activity widgets from onPostExecute which is called on UI thread.
How do I call the functions provided by Activity class from a class that does not extend Activity? Theoretically, yes, if I don't extend Activity I cannot directly use the functions provided by it. But is there a workaround provided for this? If not, are there replacements or alternative ways for these functions?
For example,
If my class extends Activity, I can call setContentView() to instantiate my layout xml file. But if my class extends some other class and doesn't extend Activity, then I can use the LayoutInflater to do the task. But what about other functions like registerReceiver() ? How do I get the functionality of 'registerReceiver()' from any other class , obviously I wouldn't want every such class to extend Activity. Static access by "Activity.function_name" is also not possible as these functions are not static.
Certain services can be accessed from anywhere. For example 'println()' or Log.e(),System functions can be called from anywhere, whenever needed. Is there a similar way for other critical functions?
Conclusion:
Pass Context to destination class. For accessing some functions however, type-casting the passed Context to Activity is required.
Both Changdeo's and BT's answers are correct.
Thanks.
Although I have not found any documentation explicitly stating why, in every case where I have ever needed to do this, simply passing the Activity's Context is sufficient.
For a Context called contextActivity passed into any function, the following will allow access to these member functions you require:
((Activity) contextActivity).<anyMemberFunction>
Or if you need these functions in multiple cases it might be simplest just to do the following:
Activity myActivity = (Activity) contextActivity;
From there you can access these Activity member functions whenever you like by using:
myActivity.<desiredFunction>;
As I mentioned, I have never found any case where this hasn't worked, but also no solid documentation saying this will always work. This is the trick I have seen consistently used though. If anyone has more to add, please do.
For Ex
Class XYZActivity extends Activity
{
......
......
MyClass myClass = new MyClass(this);
// OR you can pass just context
// MyClass myClass = new MyClass(getContext());
}
Class MyClass
{
Context context;
Myclass(Context context)
{
this.context = context;
context.registe....//Or any function
}
}
I was trying to use the managedquery() in android to get back a cursor when working with a content provider. I used this because it was mentioned that this will handle the closing of the cursor by itself when the activity is paused or resumed.
But however this works on the Activity class only. But I have more than one background threads using the asynctask in android. I do a same fetch of list in more than one thread. So its repetitive code. This is because i cant call a function of one thread class from other thread dobackground(). Is there a easy and safe way to avoid this repetitive code. Kindly advice. Thank you for your help and time.
Can't you have an abstract asynctask class which implements this db query code (if that's all you're doing in the background thread, then put it in doInBackground(), otherwise put it in a private method), and then have your concrete child classes which extend this abstract class call super.doInBackground or call that private method?
E.G.
private abstract AbstractQueryTask extends AsyncTask<Long, Void, Long> {
protected Cursor querycode{
//put your query code here
}
}
public ConcreteQueryTask extends AbstractQueryTask {
//put the doInBackground and onPostExecute implementations here
}
I have some classes within my application that need to call Android functions that require the Context as a parameter.
I don't have it as the class is not a subclass of the Activity class.
What is the correct way to tackle this problem?
Pass it as a parameter on each call?
Pass it at class instantiation and keep it?
It depends on the role of the class. But anyway pass ApplicationContext but not Activity one. If you pass Activity context gc can't remove it from the memory when after you don't need activity anymore. But application context is used while application was not finished by OS.Refer Avoid Memory Leaks
Pass it as a parameter. Or better yet, get the application context to avoid memory leaks.
public class Example {
protected Context context;
public Example(Context context){
this.context = context.getApplicationContext();
}
}
I'm pretty much always going with a constructor parameter approach. I pass it in the instantiation and keep a private reference in the instantiated class.
You have to think about one important thing. If the class you pass the Context will exist longer than the Activity instantiating it then you should use the application context. If that class is doing UI stuff you will need an activity context.
Make sure that the class you are passing an activity context to won't last longer than the Activity or you'll leak the entire activity.
If you don't do UI stuff then go with the application context.
I pass it as a parameter, i think its de best form to do it
Pass it at class instantiation and keep it.
One typical example is when you create a db helper. See this link
I've answered this question here also.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
}
and use that class as it were Context
The best way is to follow Bean approach:
public class Example {
protected Context getContext() {
...
}
...
}
Then it depends on possibilities to access context. If class is fully independent then constructor parameter and private field seems best approach.
But that bean property way shields you from further code changes.
This function runs on the UiThread, but it seems that doesnt mean it also has access to the activity context. Shall I implement to my AsyncTask a public Setter to pass the activity (as reference)?
protected void onPostExecute( Bitmap bitmap ) {
//following is underlined red due to missing context
(ImageView)findViewById(ResId)).setImageBitmap(bitmap);
}
I can think about two options.
If the AsyncTask is an inner class of you activity you can use getApplicationContext() to get the Context object, without passing the activity object.
If you have to access the ImageView object from different methods or if the task handled by the AsyncTask class can run multiple times you might think about storing the ImageView object as a member of your activity class, so you can don't need a context to access it.