0

I define this method in a RecordTable class, which is not an Activity.
I call it from the main UI thread and pass a valid UI thread context as parameter.
Of course, it does not work with the message:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

I saw in other post they recommend using runOnUiThread instead of new thread but since the class is not an activity runOnUiThread is not available.

Starting the Dialog outside the runnable() does not work either.

Has anyone got this problem and found how to solve it?

public synchronized void scrollUp(final Context context, final ArrayList<Record> list, final int count) {
    new Thread(new Runnable() {
        public void run() {
            setScrolling(true);
            ProgressDialog pd = ProgressDialog.show(context, "", context.getResources().getString(R.string.loading_msg), true);
            int n = Math.max(mViewStartIndex - count, 0);
            for(int i = mViewStartIndex - 1; i >= n; i--) {
                RecordTable.this.addFirstRow(list.get(i));
                RecordTable.this.removeViews(RecordTable.this.getChildCount() - 1, 1);
            }
            pd.dismiss();
            setScrolling(false);
        }
    }).start();
}
ilomambo
  • 8,290
  • 12
  • 57
  • 106
  • 1
    did you try context.runOnUiThread(new Runnable(etc..)) ? – Murat Nafiz Jun 06 '12 at 13:40
  • @MuratNafiz I just tried, `runOnUiThread` is not available under `context` – ilomambo Jun 06 '12 at 13:46
  • you can cast your context to your Activity. Like: ((YourActivityName) context).runOnUiThread(new Runnable() ... Where 'YourActivityName' is the activity which you are passing context – Murat Nafiz Jun 06 '12 at 14:33
  • @MuratNafiz I just tried it, and it does not give any error, but the Progress dialog is not shown and the app gets an ANR – ilomambo Jun 06 '12 at 14:58

2 Answers2

2

Given the code I would suggest use an AsyncTask. Take a look at the documentation for AsyncTask.

Carry out the work you want on a different thread in the doInBackground(....) function with periodic calls to progressUpdate, which always runs on the UI thread. Much simpler to implement and you don't have to worry about creating new threads. AsyncTask does it for you.

Orlymee
  • 2,349
  • 1
  • 22
  • 24
  • I am leaving your suggestion as a last resort. I am sure it will work, I use AsyncTask for other stuff.:::: But it really hurts me to have to create a new class to run 6 lines of code, just because I want to display a Progress dialog ... :-( – ilomambo Jun 06 '12 at 14:01
  • On second though, in this specific case I cannot use AsyncTask, because the `for` loop manipulates a TableLayout, adding and deleting TableRows. And doInBackground() cannot deal with UI elements. – ilomambo Jun 06 '12 at 16:06
  • yes indeed doInBackground does not have accesst to UI thread but onProgressUpdate does. so in your for loop when you want to manipulate the table layout make a call to progressUpdate instead and do the manipulation in there as it runs on the UI Thread. – Orlymee Jun 06 '12 at 16:09
  • I am not 100% sure, but I think that forfeits the whole purpose of using AsyncTask, which is not blocking the UI thread with background work. – ilomambo Jun 06 '12 at 16:20
  • this will not block the UI thread. read the documentation on AsyncTask. doInbackground is working on a seprate thread whilst, preExecute, postExecute, porgressupdate are on UI thread – Orlymee Jun 06 '12 at 16:23
  • You said it yourself, the onProgressUpdate does not run in a separate thread, only doInBackground. So if I follow your suggestion and do the TableLAyout work in onProgrssUpdate, I will not be using at all the separate thread. Moreover, I will need to keep the doInBackground() looping on empty until I finish the TableLayout update. – ilomambo Jun 06 '12 at 16:30
  • as a general rule if you want to do any time consuming tasks they should be in a separate thread. But if you want to do something to the UI then you need access to UI thread. I don;t know why you would run an empty loop in the other thread. Post your code please so I can uderstand – Orlymee Jun 06 '12 at 16:38
  • I posted the only code I have in the question. I did not move to AsyncTask because I don't see the point now. If you don't run an empty loop in doInBAckground() the AsyncTask finishes and excutes onPostExecute(). – ilomambo Jun 06 '12 at 16:49
0
ProgressDialog pd;
Context context;

public synchronized void scrollUp(Context context, final ArrayList<Record> list, final int count) {
this.context = context;
new Thread(new Runnable() {
public void run() {
    setScrolling(true);
    hand.sendEmptyMessage(0);                
    }
  }
}).start();

int n = Math.max(mViewStartIndex - count, 0);
for(int i = mViewStartIndex - 1; i >= n; i--) {
RecordTable.this.addFirstRow(list.get(i));
RecordTable.this.removeViews(RecordTable.this.getChildCount() - 1, 1);

pd.dismiss();
setScrolling(false);
}


Handler hand = new Handler() 
{
    @Override
    public void handleMessage(Message msg) 
    {
              pd = ProgressDialog.show(context, "", context.getResources().getString(R.string.loading_msg), true);
    }
}

try this it may help you.... if you want to create any dialog or Toast in a class handler will handle this...

kalandar
  • 793
  • 6
  • 13
  • the main reason I run a `runnable()` is to perform the for loop without blocking the UI thread. You put all the code outside the runnable. :::: I am also pretty sure the handle is only a solution if you are running inside some Activity. I am not. This is running from within the RecordTable class :::: The `pd.dismiss()` in your solution will not work, the same way `ProgressDialog.show()` did not work for me. – ilomambo Jun 06 '12 at 13:53