开发者

Why does Handler::postDelay make UI frozen

开发者 https://www.devze.com 2023-03-27 21:04 出处:网络
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.

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. */开发者_如何学JAVA
    @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.


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);
    }
}

}


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.


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().


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.


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


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()

0

精彩评论

暂无评论...
验证码 换一张
取 消