Raz Cohen
Raz Cohen

Reputation: 79

Calling multiple functions with Asynctask for network connection

II want to build a class that every time I want to do a network connection, I'll use it. I want to open a dialog first and then make the network connection (or get something from SQL or download something from the web or update the SQL) and then close the dialog.

I need to wait for the function to end before I can continue.

I wanted to use AsyncTask, but I can't figure out a way to determine in the AsyncTask which function to use. I found two solutions, switch-case or trying to send a function with java reflection. Both solutions are not too good.

Does someone have another idea or another way to do this?

Upvotes: 3

Views: 2394

Answers (2)

Alexander Sukharev
Alexander Sukharev

Reputation: 807

Consider using the Command design pattern. Here is Java example. You can extend it by callbacks to do something after finishing background work.

public abstract class Command {

    protected AsyncTaskCallback callback;

    public Command(AsyncTaskCallback callback) {
            this.callback = callback;
    }

    public abstract void execute();

    public AsyncTaskCallback getCallback() {
        return callback;
    }

    public interface AsyncTaskCallback {
        public void onPreExecute();
        public void onPostExecute();
    }

}

Invoker:

public class Invoker extends AsyncTask<Void, Void, Void> {

    private Command command;

    public static void execute(Command command) {
            new Invoker(command).execute();
    }

    private Invoker(Command command) {
            this.command = command;
    }

    @Override
    protected Void doInBackground(Void... params) {
            return command.execute();
    }

    @Override
    protected void onPreExecute() {
            if (command.getCallback() != null) {
                    command.getCallback().onPreExecute();
            }
    }

    @Override
    protected void onPostExecute(Void result) {
            if (command.getCallback() != null) {
                    command.getCallback().onPostExecute();
            }
    }

}

So, your AsyncTask doesn't know which command it is executing and thus can be used throughout the app. Now you can implement interface AsyncTaskCallback in your Activity and handle there all UI-related things you need.

Example:

public class MyActivity extends Activity implements AsyncTaskCallback {

...

public void onPreExecute() {
    showProgress();
}

public void onPostExecute() {
    hideProgress();
    doOtherThings();
}

...

Command myCommand = new Command(this) {
    @Override
    public void execute() {
        // Do specific background work
    }
}
Invoker.execute(command);

Also you need to handle orientation changes.

Upvotes: 3

Nate
Nate

Reputation: 31045

The Android docs have good examples of how to use AsyncTask. There's one here. If you want to add some code to show dialogs, then maybe something like this:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

     // Constant for identifying the dialog
     private static final int LOADING_DIALOG = 1000;
     private Activity parent;

     public DownloadFilesTask(Activity parent) {
         // record the calling activity, to use in showing/hiding dialogs
         this.parent = parent;
     }

     protected void onPreExecute () {
         // called on UI thread
         parent.showDialog(LOADING_DIALOG); 
     }

     protected Long doInBackground(URL... urls) {
         // called on the background thread
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         // called on the UI thread
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         // this method is called back on the UI thread, so it's safe to 
         //  make UI calls (like dismissing a dialog) here
         parent.dismissDialog(LOADING_DIALOG);
     }
 }

Before performing the background work, onPreExecute() will be called back. This is an optional method to override in your AsyncTask subclass, but it gives you a chance to throw up a UI before the network/database work starts.

After the background work completes, you have another opportunity to update the UI (or remove a dialog) in onPostExecute().

You'd use this class (from within an Activity) like so:

DownloadFilesTask task = new DownloadFilesTask(this);
task.execute(new URL[] { new URL("http://host1.com/file.pdf"), 
                         new URL("http://host2.net/music.mp3") });

Upvotes: 2

Related Questions