I have 3 activities A,B,C. In all the 3 activities i'm using Async task. Is it possible to run all the Async task under a single Async task(Common code).
If possible
1. How to check which task called from which activity?
2. How to check whether the task got completed or not?
May be you want to have a Common async task for that can used to perform long running taks and you want a callback machanism to it use this,
You can implement the same by taking async task class a separate abstract and by implementing a callback interface.
Async Class with callback
Yes it is possible.
Add a Parameter that is used to indicate the calling Activity
Look at JavaDoc of AsyncTask method onPostExecute()
Create your AsyncTask class
public class MyTask extends AsyncTask<Void, Void, Void>
{
// Use a WeakReference instead of holding the Activity object
private WeakReference<Activity> mActivity;
public MyTask(Activity activity)
{
mActivity = new WeakReference<Activity>(activity);
}
#Override
protected Void doInBackground(Void... params)
{
// do common work
return null;
}
public Activity getActivity()
{
return mActivity.get();
}
public void setActivity(Activity activity)
{
mActivity = new WeakReference<Activity>(activity);
}
}
And in each Activity:
MyTask t = new MyTask(YourActivity.this)
{
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
// do some work when finished
}
};
Related
I am starting an AsyncTask from an Activity. When, the AsyncTask completes its execution I need to send a broadcast which needs to call Activity method to update the UI.
Any good approach to achieve this.
Yes.
If the AsyncTask is an inner class of your Activity then it has access to any member variables and your Activity methods. If it isn't then you can simply pass variables to its constructor or even a reference to the Activity to call Activity methods from onPostExecute(). Without any code its hard to say much else.
To pass an instance of your Activity and use its methods if its a separate class then you can create a constructor and do something like
public class MyTask extends AsyncTask<...> // add your params
{
private MyActivity activty;
public MyTask (MyActivity act)
{
this.activty = activty;
}
// ...
}
and in onPostExecute() add something like
activity.myMethod();
and call the task like
MyTask task = new MyTask(this); // pass a reference of the activity
task.execute(); // add params if needed
If the AsyncTask is a separate file from the Activity then you can see this answer on how to use an interface for a callback
Please use Interface.
interface INotifyChange {
void notifyChange(); // You can use params to transfer data :D
}
In Activity you should implements this interface.
YourActivity extends Activity implements INotifyChange {
#Override
public void notifyChange() {
// Right here, you can Update UI.
}
}
When you create new instance of AsyncTask
Example:
YourAsyncTask mTask = new YourAsyncTask(this); // You put INotifyChange
In YourAsyncTask
private INotifyChange iNotifyChange;
public YourAsyncTask(INotifyChange iNotifyChange) {
this.iNotifyChange = iNotifyChange;
}
// When you complete doInBackground or anywhere you want to Update UI please use iNotifyChange.notifyChange()
Example:
#Override
public void onPostExecute(ResultType mResult) {
iNotifyChange.notifyChange();
}
By this way I often use to update progress bar. In this case, I use parameter in my method:
Example:
iNotifyChange.notify(progress);
Have you considered overwriting the onPostExecute() method of the AsyncTask to update the UI? Try something like this:
AsyncTask<String, Void, Bitmap> task = new AsyncTask<String, Void, Bitmap>(imageView)
{
private ImageView imageView;
public AsyncTask(ImageView imageView)
{
this.imageView = imageView;
}
#Override
protected Bitmap doInBackground (String... params)
{
if(params.length > 0)
{
String filePath = params[0];
// Load Bitmap from file
return bitmap;
}
}
#Override
protected void onPostExecute(Bitmap result)
{
imageView.setImageBitmap(result);
}
}
task.execute(filePath);
I have utility class with static methods. Assuming that these methods can fire background task, something like below:
class ExampleAsyncUtil {
public static void doSomeAsyncJob() {
new AsyncTask<Void, Void, Void> () {
#Override
protected Void doInBackground (Void... params) {
//do heavy job here ...
return null;
}
}.execute();
}
}
if then i call the util class method inside activity which then becomes destroyed:
class ExampleActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExampleAsyncUtil.doSomeAsyncJob();
}
#Override
protected void onDestroy() {
//should i stop async task in util on destroy ?
super.onDestroy();
}
}
Does it do any harm? (assuming that the background thread does not keep any refrence to activity which called the utility method)
Yes, you should cancel the AsyncTask from your UI. You can leak the AsyncTask otherwise (talking from experience). And, who knows, maybe even block another from being started on the same thread: they keep changing the implementation: http://developer.android.com/reference/android/os/AsyncTask.html. Or, contrary, multiple onCreate() could create duplicate "zombie" AsyncTask's. Anyway, it's not an intended use of AsyncTask: they are supposed to be short-lived and properly controlled. So, there seems to be no real gain in that static business.
I think you should either start a Service and spawn a tread from it or just use AsyncTask traditionally, within the life cycle of your Activity.
There is a good tutorial on asynchronous handling here: http://www.vogella.com/articles/AndroidPerformance/article.html.
This question already has answers here:
How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
(17 answers)
Closed 6 years ago.
I have the following asynctask class which is not inside the activity. In the activity I'm initializing the asynctask, and I want the asynctask to report callbacks back to my activity.
Is it possible? Or does the asynctask must be in the same class file as the activity?
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
caller.sometextfield.setText("bla");
}
Something like this?
You can create an interface, pass it to AsyncTask (in constructor), and then call method in onPostExecute()
For example:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted();
}
Your Activity:
public class YourActivity implements OnTaskCompleted{
// your Activity
}
And your AsyncTask:
public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted listener){
this.listener=listener;
}
// required methods
protected void onPostExecute(Object o){
// your stuff
listener.onTaskCompleted();
}
}
EDIT
Since this answer got quite popular, I want to add some things.
If you're a new to Android development, AsyncTask is a fast way to make things work without blocking UI thread. It does solves some problems indeed, there is nothing wrong with how the class works itself. However, it brings some implications, such as:
Possibility of memory leaks. If you keep reference to your Activity, it will stay in memory even after user left the screen (or rotated the device).
AsyncTask is not delivering result to Activity if Activity was already destroyed. You have to add extra code to manage all this stuff or do you operations twice.
Convoluted code which does everything in Activity
When you feel that you matured enough to move on with Android, take a look at this article which, I think, is a better way to go for developing your Android apps with asynchronous operations.
I felt the below approach is very easy.
I have declared an interface for callback
public interface AsyncResponse {
void processFinish(Object output);
}
Then created asynchronous Task for responding all type of parallel requests
public class MyAsyncTask extends AsyncTask<Object, Object, Object> {
public AsyncResponse delegate = null;//Call back interface
public MyAsyncTask(AsyncResponse asyncResponse) {
delegate = asyncResponse;//Assigning call back interfacethrough constructor
}
#Override
protected Object doInBackground(Object... params) {
//My Background tasks are written here
return {resutl Object}
}
#Override
protected void onPostExecute(Object result) {
delegate.processFinish(result);
}
}
Then Called the asynchronous task when clicking a button in activity Class.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
Button mbtnPress = (Button) findViewById(R.id.btnPress);
mbtnPress.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {
#Override
public void processFinish(Object output) {
Log.d("Response From Asynchronous task:", (String) output);
mbtnPress.setText((String) output);
}
});
asyncTask.execute(new Object[] { "Youe request to aynchronous task class is giving here.." });
}
});
}
}
Thanks
IN completion to above answers, you can also customize your fallbacks for each async call you do, so that each call to the generic ASYNC method will populate different data, depending on the onTaskDone stuff you put there.
Main.FragmentCallback FC= new Main.FragmentCallback(){
#Override
public void onTaskDone(String results) {
localText.setText(results); //example TextView
}
};
new API_CALL(this.getApplicationContext(), "GET",FC).execute("&Books=" + Main.Books + "&args=" + profile_id);
Remind: I used interface on the main activity thats where "Main" comes, like this:
public interface FragmentCallback {
public void onTaskDone(String results);
}
My API post execute looks like this:
#Override
protected void onPostExecute(String results) {
Log.i("TASK Result", results);
mFragmentCallback.onTaskDone(results);
}
The API constructor looks like this:
class API_CALL extends AsyncTask<String,Void,String> {
private Main.FragmentCallback mFragmentCallback;
private Context act;
private String method;
public API_CALL(Context ctx, String api_method,Main.FragmentCallback fragmentCallback) {
act=ctx;
method=api_method;
mFragmentCallback = fragmentCallback;
}
I will repeat what the others said, but will just try to make it simpler...
First, just create the Interface class
public interface PostTaskListener<K> {
// K is the type of the result object of the async task
void onPostTask(K result);
}
Second, create the AsyncTask (which can be an inner static class of your activity or fragment) that uses the Interface, by including a concrete class. In the example, the PostTaskListener is parameterized with String, which means it expects a String class as a result of the async task.
public static class LoadData extends AsyncTask<Void, Void, String> {
private PostTaskListener<String> postTaskListener;
protected LoadData(PostTaskListener<String> postTaskListener){
this.postTaskListener = postTaskListener;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (result != null && postTaskListener != null)
postTaskListener.onPostTask(result);
}
}
Finally, the part where your combine your logic. In your activity / fragment, create the PostTaskListener and pass it to the async task. Here is an example:
...
PostTaskListener<String> postTaskListener = new PostTaskListener<String>() {
#Override
public void onPostTask(String result) {
//Your post execution task code
}
}
// Create the async task and pass it the post task listener.
new LoadData(postTaskListener);
Done!
I am developing an application in which i need to send the value of the asynctask's onPostExecute method's result in to the previous activity , ie the activity in which the aync task is being called.pls put some codes. Anyhelp is appreciated
Two ways:
Declare class extending AsyncTask as private class in parent Activity
Pass Handler or Activity itself as param of class extending AsyncTask
If I were you, I'd follow the first option.
Look at DOCS:
class MyActivitySubclass extends Activity {
function runOnPostExecute(){
// whatever
}
private class MyTask extends AsyncTask<Void, Void, Void> {
void doInBackground(Void... params){
// do your background stuff
}
void onPostExecute(Void... result){
runOnPostExecute();
}
}
}
Note 1
Code placed in body of function onPostExecute is already run on Activity thread, you should just mention that this keywords leads to MyTask.this and not MyActivitySubclass.this
Well if your AsyncTask is an inner class, you could simply call a method in your activity from onPostExecute():
public class MyActivity extends Activity {
public void someMethod(String someParam) {
// do something with string here
}
public class InnerTask extends AsyncTask<...> {
protected void onPostExecute(result) {
someMethod(Send parameters);
}
}
}
The onPostExecute method is fired on the main UI thread, so anything done there is already on the AsyncTasks caller.
http://developer.android.com/reference/android/os/AsyncTask.html
Fire an event in the OnPostExecute.
Its an add on to the answer by Marek Sebera, he pointed to use a handler. To keep the code simple and intuitive use an interface. This isn't alien concept, we use it all the time for callback functions (eg: OnClickListner etc..). The code would look some thing like this.
public class InnerTask extends AsyncTask<...>
{
interface ResultHandler
{
void gotResult(<> result);
}
private ResultHandler myResult;
//constructor
public InnerTask(....params...,ResultHandler callback)
{
...
this.myResult = callback;
}
protected void onPostExecute(<>result)
{
...
myResult.gotResult(result);
}
}
public class MyActivity extends Activity implements InnerTask.ResultHandler
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
//do something
//if you want the InnerTask to execute here
InnerTask i = new InnerTask(....params...,this); //send 'this' as parameter
i.execute();
}
#Override
public void gotResult(<> result)
{
//from onPostExecute
}
}
If we want to use the same AsynTask class at multiple sites we can use this type of implementation instead of using nested classes implementation.
I am launching a activity, and once a user is logged in, i want to refresh the main activity. To load the data from the logged in user.
Such as the image and name. I have all of this set up already.
I just need to know is it possible to launch another activity and run its async task again.From an launching an intent from inside another activity?
It's not clear what exactly your design is, but if you need to use the same AsyncTask from two different activities, it should be a separate class, not tied to a particular activity. You can have the two activities implement a common interface, so that the AsyncTask doesn't need to know which activity it is updating. Then instantiate the task by passing a reference to the enclosing activity, and start it as needed. There is no need for one activity to start the other.
Something like:
public interface UserActivity {
void updateUserData(UserData userData);
}
public class Activity1 implements UserActivity {
public void onStart() {
UpdateUserDataTask task = new UpdateUserDataTask(this);
task.execute();
}
public void updateUserData(UserData userData) {
// update
}
}
public class UpdateUserDataTask extends AsyncTask<Void, Void, UserData> {
UserActivity userActivity;
public UpdateUserDataTask(UserActivitiy userActivity) {
this.userActivity = userActivity;
}
// doInBackground, etc implementation.
protected void onPostExecute(UserData userData) {
userActivity.updateUserData(userData);
}
}
As far as I'm aware, AsyncTasks aren't supposed to be reused. They're supposed to be run once and then you can create a new one if you need it.
Once an AsyncTask is executed once, you cannot execute it again. What you can do, though, is control it's "refresh" using onProgressUpdate() and publishProgress() as follows. Note that this will only work for a one-time refresh. If you wanted to be more semantically correct, you might do the "normal" operation in onProgressUpdate() and use onPostExecute() for your resfresh.
public class MyAsyncTask extends AsyncTask<Void, String, Void> {
private boolean isRefresh = false;
#Override
protected Void doInBackground(Void... arg0) {
while (!isRefresh){
//Perform your normal operation
}
//When isRefresh is true, you want to refresh.
this.publishProgress(values);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
// Refresh code here
super.onProgressUpdate(values);
}
public void refreshTask(){
this.isRefresh = true;
}
}
You could then maintain a reference to the object of MyAsyncTask and invoke refreshTask() on it whenever you want to refresh it.