Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Development: Having an AsyncTask in a separate class file

I have been playing around with various examples trying to familiarize myself with AsyncTask. So far all the examples I have seen have had the AsyncTask included into the onCreate method of the main activity. Which I don't like very much, so I was wanting to see how hard it would be to separate it into its own class. So far I have this:

the main activity

package com.example.asynctaskactivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.example.asynctaskactivity.ShowDialogAsyncTask;

public class AsyncTaskActivity extends Activity {

 Button btn_start;
 ProgressBar progressBar;
 TextView txt_percentage;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn_start = (Button) findViewById(R.id.btn_start);
        progressBar =  (ProgressBar) findViewById(R.id.progress);
        txt_percentage= (TextView) findViewById(R.id.txt_percentage);
        Log.v("onCreate","Attempt set up button OnClickListener");
        btn_start.setOnClickListener(new View.OnClickListener() 
        { 
           @Override
           public void onClick(View v) {
               btn_start.setEnabled(false);
               new ShowDialogAsyncTask().execute();
           }
        });

        Log.v("onCreate","Success!"); 
    }
}

the new seperate AsyncTask class

package com.example.asynctaskactivity;

import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class ShowDialogAsyncTask extends AsyncTask<Void, Integer, Void>{
int progress_status;

@Override
    protected void onPreExecute() {
    // update the UI immediately after the task is executed
    Log.v("onPreExecute","1");
    super.onPreExecute();
    Log.v("onPreExecute","2");
    //Toast.makeText(AsyncTaskActivity.this,"Invoke onPreExecute()", Toast.LENGTH_SHORT).show();
    progress_status = 0;
    Log.v("onPreExecute","3");
    txt_percentage.setText("downloading 0%");  
    Log.v("onPreExecute","4");
    }

    @Override
    protected Void doInBackground(Void... params) {
        Log.v("doInBackground","1");
        while(progress_status<100){

            progress_status += 2;

            publishProgress(progress_status);
            SystemClock.sleep(300);

        }
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);

    progressBar.setProgress(values[0]);
    txt_percentage.setText("downloading " +values[0]+"%");   
    }

    @Override
    protected void onPostExecute(Void result) {
    super.onPostExecute(result);

    //Toast.makeText(AsyncTaskActivity.this,"Invoke onPostExecute()", Toast.LENGTH_SHORT).show();

    txt_percentage.setText("download complete");
    btn_start.setEnabled(true);
    }
}

Originally this was all in the main activity, hence the mentions to the elements that the asynctask should in theory update. Obviously at present this is causing runtime errors, which then got me thinking. How can I have the file seperate but still update the UI thread.

Sorry if this is a stupid question, quite new to android development and background threads in particular.

like image 369
cosmicsafari Avatar asked Mar 18 '13 22:03

cosmicsafari


3 Answers

How can I have the file seperate but still update the UI thread.

Okey. So at first you know that main advantage of AsyncTask added in Activity as inner class is that you have direct access to all UI elements and it makes possible pretty "lightweight" UI updates.

But if you decided to make AsyncTask separated from Activity(which also have some benefits e.q. code is more clean and app logic is separated from appearance) class you can:

  • You can pass UI elements via constructor of class
  • You can create various setters
  • You can create some interface that will hold callbacks. Look at Android AsyncTask sending Callbacks to UI

This is all what you need i guess.

like image 191
Simon Dorociak Avatar answered Nov 17 '22 10:11

Simon Dorociak


Add a callback interface, and let your Activity implement it.

public interface MyAsyncTaskCallback{
    public void onAsyncTaskComplete();
}

In the postexecute:

myAsyncTaskCallback.onAsyncTaskComplete();

In the constructor of your AsyncTask you could pass the instance of MyAsyncTaskCallback (your Activity).

like image 43
nhaarman Avatar answered Nov 17 '22 08:11

nhaarman


Your best way of handling this is via a Handler. Instantiate one in the activity and override the method handleMessage(). When you create ShowDialogAsyncTask class just pass in the handler and maintain a reference to it. On postExecute you can construct a message and send it via the handler method sendMessage().

A previous answer mentioned using an interface and a callback paradigm. This will work, however, there is a chance that the activity can be destroyed and won't be present when the postExecute method is executed so you would need to test for this.

like image 32
BrianPlummer Avatar answered Nov 17 '22 08:11

BrianPlummer