1

I have this code. I don't know why postDelay make UI frozen in this case. I want the Runnable will run after 100 miliseconds deley and run in 4000 miliseconds.

package com.delaythread;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class MyNeedActivity extends Activity implements OnClickListener {

    private ProgressBar progressBar;
    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(final Message msg) {
            super.handleMessage(msg);
            progressBar.setVisibility(ProgressBar.INVISIBLE);
        }
    };

    @Override
    public void onClick(final View v) {
        if(v.getId() == R.id.button1) {
            /* This call doesn't make ProgressBar frozen.
            final Thread t = new Thread(new MyRunnable());
            t.start();
            progressBar.setVisibility(ProgressBar.VISIBLE);
             */

            // This makes ProgressBar frozen in 4000 miliseconds.
            final boolean b = handler.postDelayed(new MyRunnable(), 100);
            if(b) {
                progressBar.setVisibility(ProgressBar.VISIBLE);
            }
        }
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((Button)findViewById(R.id.button1)).setOnClickListener(this);
        progressBar = (ProgressBar)findViewById(R.id.progressBar1);
    }

    private class MyRunnable implements Runnable {
        @Override
        public void run() {
            sleep();
        }

        private void sleep() {
            try {
                Thread.sleep(4000);
                handler.sendEmptyMessage(0);
            } catch (final InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

Update: Actually what I want is AsyncTask executes after a delay time, so I do as this answer Java/android how to start an AsyncTask after 3 seconds of delay?. He said I should use Handler and Runnable.

Community
  • 1
  • 1
emeraldhieu
  • 9,380
  • 19
  • 81
  • 139
  • Can you explain in a bit more detail what is happening and what you want to happen? – Martyn Aug 12 '11 at 10:05
  • I want Runnable do long time calculations but after a delay time. So I have to use Handler::postDelay. When Runnable calculates, the ProgressBar visible. When it finishes, the Runnable invisible. – emeraldhieu Aug 12 '11 at 10:09
  • Ok, and what is actually happening? – Martyn Aug 12 '11 at 10:11
  • Actually I want to do something like this question. http://stackoverflow.com/questions/4177409/java-android-how-to-start-an-asynctask-after-3-seconds-of-delay but the ProgressBar freeze. :( – emeraldhieu Aug 12 '11 at 10:12
  • what are you trying to do? Why do you need a delay in a background thread? – Ron Aug 12 '11 at 10:34

6 Answers6

3

The following should suit your need according to the post

private final Handler handler = new Handler() {
    @Override
    public void handleMessage(final Message msg) {
        super.handleMessage(msg);
        //start Asyntask here. progress show/hide should be done in asynctaswk itself.
    }
};

@Override
public void onClick(final View v) {
    if(v.getId() == R.id.button1) {

        final boolean b = handler.postDelayed(new MyRunnable() , 1000);

    }
}

private class MyRunnable implements Runnable {
    @Override
    public void run() {
        handler.sendmessage(0);
    }
}

}
Ron
  • 24,175
  • 8
  • 56
  • 97
  • oh yeah, perfect. >_< I think my question make you all confused. Sorry for my not good English. :D I didn't think that Handler can do with AsyncTask like this. :) – emeraldhieu Aug 12 '11 at 10:55
2

You probably want to run your MyRunnable on other thread than main UI one, so you need to start a regular thread for this, like

new Thread(new MyRunnable()).start();

instead of using Handler for this, which queues your runnable to be executed on main UI thread.

BTW, for this purpose Timer with TimerTask would suit better.

ernazm
  • 9,208
  • 4
  • 44
  • 51
2

The Android Reference for the class Handler points out:

"[...] When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it [...]"

So your Handler, created on instantiation of the Activity, should be running on the UI thread causing it to block when your Runnable is executed.

Try creating a new Thread class in which your Handler is instantiated. Then pass the Runnable to it from your onClick() method. To pass messages back (such as updating the progress bar) you can use another Handler that is running on the UI thread.

You could also save yourself a lot of pain by taking a look at the AsyncTask class.

PS: Delaying the execution could be done in the AsyncTaskdoInBackground() via a Thread.sleep(100) call. To delay execution on UI thread level you could do the same in AsyncTask.onPreExecute().

Rekhyt
  • 76
  • 5
1

As far as I understand it you ask your MyRunnable to run on the GUI thread (of which there is only one); but the only this it does is sleep, effectively causing the GUI thread to freeze waiting for it.

You shouldn't do complicated calcultaions (or, sleep) in the GUI thread.

You may want to read the documentation on threads and the UI thread for a more elaborate description.

Joubarc
  • 1,206
  • 10
  • 17
  • No, I want the the Runnable do complicated calculations after a delay time, not in UI thread. That's why I create a Runnable. – emeraldhieu Aug 12 '11 at 10:01
  • @ernazm is right, using a Handler for this may not be the best choice if what you do in your Runnable isn't UI related. – Joubarc Aug 12 '11 at 10:09
1

Your progress bar isn't updating because you aren't updating it! Try using an AsyncTask, (it runs on a different thread but allows you to update UI elements) and setting the state of the progress bar from within the onProgress method in the Async task.

OR

Just follow this example on the Android Progress Bar page

Martyn
  • 16,432
  • 24
  • 71
  • 104
  • How to start AsyncTask after a delay time? The answer in this question points me to use Handler with Runnable. http://stackoverflow.com/questions/4177409/java-android-how-to-start-an-asynctask-after-3-seconds-of-delay – emeraldhieu Aug 12 '11 at 10:20
  • Best way to start something delayed is to use a `Handler`, like you have in your example. So I would add the `AsyncTask` `execute` method in your handler, and then start the handler in 100 ms. – Martyn Aug 12 '11 at 10:43
0

Try this:

new Handler().postDelayed(new Runnable() {

                @Override
                public void run() {
                    //Code to be executed after desired seconds
                }
            }, seconds*1000);

This would freeze the UI for given number of seconds and the execute the code inside the run()

Ilario
  • 5,979
  • 2
  • 32
  • 46
SalmaanKhan
  • 811
  • 7
  • 4