3

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?

Nate
  • 31,017
  • 13
  • 83
  • 207
Raz Cohen
  • 79
  • 1
  • 7
  • Praise the lord that someone wants to do the same thing as me. I really hope you get some answers. I want to have a class that I can reuse my network function as well, and I cannot for the life of me figure out how to display the loading dialog. – boltup_im_coding Mar 03 '13 at 08:07

2 Answers2

3

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.

Community
  • 1
  • 1
2

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") });
Nate
  • 31,017
  • 13
  • 83
  • 207
  • Here's where personally this doesn't work for me (not sure about OP) but the line that is right after `task.execute` will start executing immediately afterwards while the tasks `doInBackground` is running. How can I hold off on it executing until it's 100% done? I just want to have the progressDialog up. – boltup_im_coding Mar 03 '13 at 08:49
  • @unexpected62, If you want something to run **after** the task completes, then you put it inside the `onPostExecute()` method. Or at least, *trigger* it from within that method. – Nate Mar 03 '13 at 08:50
  • Gah - that's what I keep reading, but I feel like I'd put the rest of my app in `onPostExecute`. I must be missing a design principal here. – boltup_im_coding Mar 03 '13 at 08:51
  • @unexpected62, Can you tell me what you're doing *after* the task? Is it just a UI operation? Is it another download? Something else? I can be more helpful if you're specific about what comes *after* this task. – Nate Mar 03 '13 at 08:52
  • 2
    @unexpected62 You can pass a callback to your AsyncTask subclass, and then call it in the onPostExecute(). or I think If I get you right just not to use AsyncTask, because you dont want async behaviour – RCB Mar 03 '13 at 08:54