1

If I take the results given from an AsynkTask class from one another like this:

Register.java:

public void onClick(View v) {
    LoadFermate backgroundFermate = new LoadFermate(Register.this);
    ArrayList<HashMap<String, String>> fermate;
    try{
        fermate = backgroundFermate.execute().get();
        for (HashMap<String, String> fermata:fermate){
            Toast.makeText(Register.this , fermata.get("Nome"), Toast.LENGTH_SHORT).show();
        }
    }catch (InterruptedException e){
        e.printStackTrace();
    }catch (ExecutionException e){
        e.printStackTrace();
    }
}

the ProgressDialog is not shown. If instead I do all this stuff in the onPostExecute method, it is shown. How is that possible?

I learned the way for getting the value from the othe class in that question.

Here I post the class where I use the ProgressDialog:

LoadingFermate.java:

package com.PacchettoPrincipale.app;

import [...]

public class LoadFermate extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>> {

    private Context context;

    public LoadFermate(Context context){
        this.context = context;
    }

    private ProgressDialog pDialog;

    private JSONArray mComments = null;
    private ArrayList<HashMap<String, String>> mCommentList;

    //testing on Emulator:
    private static final String DOWNLOAD_FERMATE_URL = "http://10.0.2.2/PrimaAppAndroid/fermate.php";



    //JSON IDS:
    private static final String TAG_COD = "CodFermata";
    private static final String TAG_POSTS = "posts";
    private static final String TAG_NOME = "Nome";

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(context);   //HERE I START THE PDIALOG, and in the onPostExecute method I dismiss it
        pDialog.setMessage("Download fermate...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    @Override
    protected ArrayList<HashMap<String, String>> doInBackground(Void... voids) {
        updateJSONData();
        return mCommentList;
    }

    @Override
    protected void onPostExecute(ArrayList<HashMap<String, String>> hashMaps) {
        super.onPostExecute(hashMaps);

        pDialog.dismiss();
    }

    private void updateJSONData() {

        mCommentList = new ArrayList<HashMap<String, String>>();

        JSONParser jParser = new JSONParser();
        JSONObject json = jParser.getJSONFromUrl(DOWNLOAD_FERMATE_URL);

        try {

            mComments = json.getJSONArray(TAG_POSTS);

            for (int i = 0; i < mComments.length(); i++) {
                JSONObject c = mComments.getJSONObject(i);

                int CodFermata = c.getInt(TAG_COD);
                String Nome = c.getString(TAG_NOME);


                HashMap<String, String> map = new HashMap<String, String>();

                map.put(TAG_COD, String.valueOf(CodFermata));
                map.put(TAG_NOME, Nome);

                mCommentList.add(map);

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }  
    }
}
Community
  • 1
  • 1
giacomotb
  • 607
  • 4
  • 10
  • 24

2 Answers2

2

It's because your application's UI thread is blocked while you're waiting for the task to complete. Your program is blocked at this line:

ermate = backgroundFermate.execute().get();

Documentation says that "get(): Waits if necessary for the computation to complete, and then retrieves its result." (You can read it here: http://developer.android.com/reference/android/os/AsyncTask.html#get())

In Android, UI elements (such as a progress dialog) cannot be manipulated by multiple threads. (It means you can't call any method of them, or you'll end up with an exception.) They can only be manipulated by the thread they were created by. This thread is the main thread (or UI thread, in other words) of your application.

But we need to do work on a separate thread, and still want to update the UI!

This problem can be solved in several ways. Either by using Handlers and Runnables, but that may be complex sometimes. The conception of AsyncTask is to do this work instead of you. OnPreExecute() is executed on UI thread before executing the task on a separate thread, and onPostExecute() is also executed on main thread.

I'm sorry if you know this. Returning to your problem: Because you block the UI thread by calling get() on the AsyncTask, onPreExecute() and onPostExecute() cannot run on UI thread! They're posted to main thread, but they will run only after the main thread finishes what it's doing. That's, after get() returns. Then a dialog will be shown and closed immediately, this's why you can't see it.

Don't wait for the result in this way. Process the result in onPostExecute(), because it was designed for this purpose.

Aron Lorincz
  • 1,677
  • 3
  • 19
  • 29
1
this is just a test, later I'll need this HashMap in the calling class for making a graph(fermate are the liefs). Can I retrieve it in another way? 

marcin_j has answered about the get() part. Calling get() blocks the ui thread making it asynchronous no more.

Yes there is a way. You can use a interface as a callback to the activity.

Check the answer by blackbelt

How do I return a boolean from AsyncTask?

Instead of boolean its HashMap in your case.

You can also make your Asynctask an inner class of activity

Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • I decided not to do an inner class of activity because I need 3 or more AsynkTask. In the question it's passed the result to an interface, but I would send this data to a Graph class, because I'll also send Edges and the class will be quite big. How can I send it to the other class from the interface? – giacomotb Jan 04 '14 at 18:42
  • @giacomotb no you get the data from asynctask to the activity class. Once you get the data in activity class decide to do whatever you want – Raghunandan Jan 04 '14 at 18:44
  • but I can use them just on the method of the interface, or I'm wrong? – giacomotb Jan 04 '14 at 18:45
  • @giacomotb if you get a string in the method implemented. You can declare a `String s` as a instance variable and then initialize it in the implemented method. Then you can use `s` else where. I hope i do understand that is what you need – Raghunandan Jan 04 '14 at 18:47
  • @giacomotb you wanted the data outside the implemented interface method right? – Raghunandan Jan 04 '14 at 18:59
  • Yes, I understood. So in the implemented method I do all the assignment, all right – giacomotb Jan 04 '14 at 19:01
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/44511/discussion-between-giacomotb-and-raghunandan) – giacomotb Jan 04 '14 at 19:10