38

I have an application that does some long calculations, and I would like to show a progress dialog while this is done. So far I have found that I could do this with threads/handlers, but didn't work, and then I found out about the AsyncTask.

In my application I use maps with markers on it, and I have implemented the onTap function to call a method that I have defined. The method creates a dialog with Yes/No buttons, and I would like to call an AsyncTask if Yes is clicked. My question is how to pass an ArrayList<String> to the AsyncTask (and work with it there), and how to get back a new ArrayList<String> like a result from the AsyncTask?

The code of the method looks like this:

String curloc = current.toString();
String itemdesc = item.mDescription;

ArrayList<String> passing = new ArrayList<String>();
passing.add(itemdesc);
passing.add(curloc);

ArrayList<String> result = new ArrayList<String>();

new calc_stanica().execute(passing,result);

String minim = result.get(0);
int min = Integer.parseInt(minim);

String glons = result.get(1);
String glats = result.get(2);

double glon = Double.parseDouble(glons);
double glat = Double.parseDouble(glats);

GeoPoint g = new GeoPoint(glon, glat);
String korisni_linii = result.get(3);

So, as you see, I would like to send the string array list "passing" to the AsyncTask, and to get the "result" string array list back from it. And the calc_stanica AssycTask class looks like this:

public class calc_stanica extends AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
    ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(baraj_mapa.this);
        dialog.setTitle("Calculating...");
        dialog.setMessage("Please wait...");
        dialog.setIndeterminate(true);
        dialog.show();
    }

    protected ArrayList<String> doInBackground(ArrayList<String>... passing) {

        //Some calculations...

        return something; //???
    }

    protected void onPostExecute(Void unused) {
        dialog.dismiss();
    }

So my question is how to get the elements of the "passing" array list in the AsyncTask doInBackground method (and use them there), and how to return an array list to use in the main method (the "result" array list)?

RHA
  • 3,677
  • 4
  • 25
  • 48
Bojan Ilievski
  • 1,272
  • 2
  • 14
  • 22

5 Answers5

66

Change your method to look like this:

String curloc = current.toString();
String itemdesc = item.mDescription;
ArrayList<String> passing = new ArrayList<String>();
passing.add(itemdesc);
passing.add(curloc);
new calc_stanica().execute(passing); //no need to pass in result list

And change your async task implementation

public class calc_stanica extends AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(baraj_mapa.this);
        dialog.setTitle("Calculating...");
        dialog.setMessage("Please wait...");
        dialog.setIndeterminate(true);
        dialog.show();
    }

    protected ArrayList<String> doInBackground(ArrayList<String>... passing) {
        ArrayList<String> result = new ArrayList<String>();
        ArrayList<String> passed = passing[0]; //get passed arraylist

        //Some calculations...

        return result; //return result
    }

    protected void onPostExecute(ArrayList<String> result) {
        dialog.dismiss();
        String minim = result.get(0);
        int min = Integer.parseInt(minim);
        String glons = result.get(1);
        String glats = result.get(2);
        double glon = Double.parseDouble(glons);
        double glat = Double.parseDouble(glats);
        GeoPoint g = new GeoPoint(glon, glat);
        String korisni_linii = result.get(3);
    }

UPD:

If you want to have access to the task starting context, the easiest way would be to override onPostExecute in place:

new calc_stanica() {
    protected void onPostExecute(ArrayList<String> result) {
      // here you have access to the context in which execute was called in first place. 
      // You'll have to mark all the local variables final though..
     }
}.execute(passing);
Konstantin Burov
  • 68,980
  • 16
  • 115
  • 93
  • Thank you for your answer, but I have one more thing to ask. If I define int min = Integer.parseInt(minim); for example, in the AsyncTask class onPostExecute(), how can I access it from my main class method? When I change it like this, I get "min cannot be resolved" error in the main class method. – Bojan Ilievski Nov 16 '10 at 16:35
  • 2
    @Bojan Ilievski: Just make your min variable global. – Wroclai Nov 16 '10 at 16:55
  • I get the following error when I pass an `ArrayList` on `AsyncTask.execute`: **Type safety: A generic array of ArrayList is created for a varargs parameter.** – VansFannel Apr 17 '12 at 06:08
  • Thanks so much for posting this! – Jared Burrows Jun 06 '12 at 18:48
  • I've got a similar question, but for me the result is important. I don't see in your example how `result` gets back to the main method. I just don't get it. Could you please explain? – JohnK Jul 05 '12 at 19:58
  • @JohnK in essense, result never get's to the original method.. it is only available when onPostExecute method runs, usually when the original method returns already. That's why it's called async task. – Konstantin Burov Jul 09 '12 at 15:33
  • @KonstantinBurov, thanks for your reply! Just to be clear: by "main method" I mean the module/method that initiated `doInBackground`, in your example, the first block of code, specifically the line `new calc_stanica().execute(passing);`. So you pass in data, via `passing`; how do you get data back? If I wanted to get a result back, it sounds like I'd have to store it in a field (or some kind of global variable if the main method is static)... is that right? – JohnK Jul 12 '12 at 19:30
12

Why would you pass an ArrayList?? It should be possible to just call execute with the params directly:

String curloc = current.toString();
String itemdesc = item.mDescription;
new calc_stanica().execute(itemdesc, curloc)

That how varrargs work, right? Making an ArrayList to pass the variable is double work.

Leander
  • 612
  • 7
  • 8
4

I sort of agree with leander on this one.

call:

new calc_stanica().execute(stringList.toArray(new String[stringList.size()]));

task:

public class calc_stanica extends AsyncTask<String, Void, ArrayList<String>> {
        @Override
        protected ArrayList<String> doInBackground(String... args) {
           ...
        }

        @Override
        protected void onPostExecute(ArrayList<String> result) {
           ... //do something with the result list here
        }
}

Or you could just make the result list a class parameter and replace the ArrayList with a boolean (success/failure);

public class calc_stanica extends AsyncTask<String, Void, Boolean> {
        private List<String> resultList;

        @Override
        protected boolean doInBackground(String... args) {
           ...
        }

        @Override
        protected void onPostExecute(boolean success) {
           ... //if successfull, do something with the result list here
        }
}
Stijn Bollen
  • 386
  • 4
  • 9
1

I dont do it like this. I find it easier to overload the constructor of the asychtask class ..

public class calc_stanica extends AsyncTask>

String String mWhateveryouwantToPass;

 public calc_stanica( String whateveryouwantToPass)
{

    this.String mWhateveryouwantToPass = String whateveryouwantToPass;
}
/*Now you can use  whateveryouwantToPass in the entire asynchTask ... you could pass in a context to your activity and try that too.*/   ...  ...  
j2emanue
  • 60,549
  • 65
  • 286
  • 456
0

You can receive returning results like that: AsyncTask class

@Override
protected Boolean doInBackground(Void... params) {
    if (host.isEmpty() || dbName.isEmpty() || user.isEmpty() || pass.isEmpty() || port.isEmpty()) {
        try {
            throw new SQLException("Database credentials missing");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    try {
        Class.forName("org.postgresql.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    try {
        this.conn = DriverManager.getConnection(this.host + ':' + this.port + '/' + this.dbName, this.user, this.pass);
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return true;
}

receiving class:

_store.execute();
boolean result =_store.get();

Hoping it will help.

gevorg
  • 4,835
  • 4
  • 35
  • 52
Michael
  • 317
  • 6
  • 11