3

In an activity I load rows of a listview which takes much time, therefore I put this task in a separate thread to allow displaying a progressDialog.

I do the following

private void doMyStuff() {
    listItems.clear();
    progressDialog.show();

    new Thread(new Runnable() {
        @Override
        public void run() {                
            for () {
                listItems.add(something to add);
            }
        handler.sendEmptyMessage(0);
        progressDialog.dismiss();
        }
    }).start();
}

private Handler handler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        if (msg.what == 0) {
            adapter.notifyDataSetChanged();
        }
    };
};

I have sometimes a bug which raises an IllegalStateException. First of all I was surprised, because programming thread like that is what I usually do in standard Java programs.

The bug appears only "sometimes" and it does not appear when doing step by step debugging.

This lead me to search around the web and I found some questions in SO related to this and I must admit that things are not clear to my mind.

As I call the notifyDataSetChanged() only when the thread finished why does it sometimes raises an exception.

Can someone confirm me that this way of doing is wrong, and that I MUST use async task and perhaps explain me why ???

I need to have a progressDialog displayed, can someone give me a simple example of AsyncTask populating a listview AND displaying a progressDialog of the populating progress.

Thanks

UPDATE

jtanveer gave me the answer to the asynctask question. Now the others pointed out that the dismiss is not in the handler, which I correct.

According to the article given by jtanveer on "Painless Threading" they say that

Android offers several ways to access the UI thread from other threads which one of them is HANDLER.

Does someone know why putting the dismissed in the handler did not solve my problem ? for me listItem.add has nothing to do with UI ? Am I wrong on that point ?

For me, in my code the only UI is adapter and progressdialog ? Any commentary or explanation is welcome.

FINAL ANSWER

stjom gave a working answer for my specific code. Running the runOnUiThread in the handler. It's working but I am surprised because I thought the handler was run in the Ui Thread ...

Thanx to all for all your answers.

HpTerm
  • 8,151
  • 12
  • 51
  • 67
  • 1
    I believe there are a lot of examples out there. Try searching the web for something like "android progressdialog asynctask example". – anon May 04 '12 at 20:11
  • 1
    Both of the answers you have now are correct. You do not need to use `AsyncTask`, though it does make operations like this clean. What you MUST do is all UI operations on the UI/Main thread, and this includes dismissing the progress dialog. You could either use the `AsyncTask` example below or just add `progressDialog.dismiss()` into your `Handler` callback. – devunwired May 04 '12 at 22:20
  • +1 to both of you for pointing out that mistake. Unfortunately it did not correct my problem but I don't understand why besause the handler is in the UI thread ! – HpTerm May 05 '12 at 07:53
  • I've update my question. why are your answers not working ? – HpTerm May 05 '12 at 08:12

3 Answers3

3

define an inner class like below:

private class LoadListTask extends AsyncTask<String, Void, Integer> {
    protected void onPreExecute() {
        progressDialog.show();
    }

    protected Integer doInBackground(String... params) {
        for () {
            listItems.add(something to add);
        }
        return 0;
    }

    protected void onPostExecute(Integer result) {
        progressDialog.dismiss();
        if (result == 0) {
           adapter.notifyDataSetChanged();
        }
    }
}

if you need, you can refer to this article.

jamael
  • 398
  • 1
  • 4
  • 13
  • Thank you to have taken the time to answer to the question. It is working fine and correct my bug. However I don't understand why the answers of the others are not working as putting the dismissed in the handler should have correct it. – HpTerm May 05 '12 at 07:59
  • you are trying to update UI from separate thread, which is strictly prohibited. UI update must have to be done from UI thread. Maybe that's why you are getting exception. – jamael May 06 '12 at 09:30
  • as I said I have corrected my code and do the dismiss in the "handler" that's why now I don't understand why I still get the error whereas your code is working fine – HpTerm May 06 '12 at 10:07
  • I'm not sure you can add items to a collection `listItems` linked with adapter in a background thread. Sometimes it can raise exception. So I usually create another list (collection), add items there. Then in UI-thread I add a collection to the adapter (adapter.addAll(newList); adapter.notifyDataSetChanged();). – CoolMind Aug 04 '16 at 15:45
2

You don't need to use AsyncTask, its just a convenience.

As far as why your current implementation doesn't work sometimes - You should dismiss your progress dialog from the UI thread, so that needs to go in your handler, not your background thread.

Splash
  • 1,310
  • 12
  • 20
  • +1 for pointing out the mistake. Unfortunately it did not correct my problem but I don't understand why because as you state it and as far as I understand it is just for "convenience" and as the handler is in the UI thread it is still not clear to my mind. – HpTerm May 05 '12 at 07:55
2

whenever you call adapter.notifyDataSetChanged(); it identifies any changes to your listItems object. if any change is found, it will update the UI accordingly which I think causes your problem. you can call

runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }  
});

inside your handler.

PinoyCoder
  • 1,112
  • 8
  • 13
  • 1
    +1 it is working !!! But you pointed something not understandable to me. How come the Handler is not executed in the UI thread ??? I thought the handler was run in the UI thread. – HpTerm May 09 '12 at 09:50