【问题标题】:Why does Handler::postDelay make UI frozen为什么 Handler::postDelayed 使 UI 冻结
【发布时间】:2011-08-12 09:56:47
【问题描述】:

我有这个代码。我不知道为什么 postDelay 在这种情况下使 UI 冻结。我希望 Runnable 将在延迟 100 毫秒后运行并在 4000 毫秒内运行。

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

}

更新:实际上我想要的是 AsyncTask 在延迟时间后执行,所以我按照这个答案 Java/android how to start an AsyncTask after 3 seconds of delay? 执行。他说我应该使用 Handler 和 Runnable。

【问题讨论】:

  • 您能否更详细地解释正在发生的事情以及您希望发生的事情?
  • 我希望 Runnable 进行长时间计算,但需要延迟一段时间。所以我必须使用 Handler::postDelay。当 Runnable 计算时,ProgressBar 可见。完成后,Runnable 不可见。
  • 好的,实际发生了什么?
  • 其实我想做类似这个问题的事情。 stackoverflow.com/questions/4177409/… 但 ProgressBar 冻结。 :(
  • 你想做什么?为什么后台线程需要延迟?

标签: android multithreading


【解决方案1】:

根据帖子,以下应该适合您的需要

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

}

【讨论】:

  • 哦,是的,完美。 >_
【解决方案2】:

您可能希望在主 UI 之外的其他线程上运行您的 MyRunnable,因此您需要为此启动一个常规线程,例如

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

而不是为此使用Handler,它将您的runnable排队以在主UI线程上执行。

顺便说一句,为此,TimerTimerTask 更适合。

【讨论】:

    【解决方案3】:

    类 Handler 的 Android 参考指出:

    "[...] 当你创建一个新的 Handler 时,它会绑定到创建它的线程的线程/消息队列中[...]"

    因此,在 Activity 实例化时创建的 Handler 应该在 UI 线程上运行,导致它在执行 Runnable 时阻塞。

    尝试创建一个新的 Thread 类,在其中实例化您的 Handler。然后将 Runnable 从您的 onClick() 方法传递给它。要回传消息(例如更新进度条),您可以使用在 UI 线程上运行的另一个 Handler。

    您还可以通过查看AsyncTask 课程来为自己省去很多痛苦。

    PS: 可以通过 Thread.sleep(100) 调用在 AsyncTaskdoInBackground() 中延迟执行。要延迟 UI 线程级别的执行,您可以在 AsyncTask.onPreExecute() 中执行相同操作。

    【讨论】:

      【解决方案4】:

      据我了解,您要求您的MyRunnable 在 GUI 线程(其中只有一个)上运行;但它唯一做的就是休眠,实际上导致 GUI 线程冻结等待它。

      您不应该在 GUI 线程中进行复杂的计算(或休眠)。

      您可能需要阅读the documentation on threads and the UI thread 以获得更详细的说明。

      【讨论】:

      • 不,我希望 Runnable 在延迟时间后进行复杂的计算,而不是在 UI 线程中。这就是我创建 Runnable 的原因。
      • @ernazm 是对的,如果您在 Runnable 中执行的操作与 UI 无关,则为此使用 Handler 可能不是最佳选择。
      【解决方案5】:

      您的进度条没有更新,因为您没有更新它!尝试使用AsyncTask,(它在不同的线程上运行,但允许您更新 UI 元素)并在异步任务的 onProgress 方法中设置进度条的状态。

      只需在 Android Progress Bar page 上按照此示例进行操作即可

      【讨论】:

      • 延迟时间后如何启动AsyncTask?这个问题的答案指向我将 Handler 与 Runnable 一起使用。 stackoverflow.com/questions/4177409/…
      • 开始延迟的最好方法是使用Handler,就像你在你的例子中一样。所以我会在你的处理程序中添加AsyncTaskexecute方法,然后在100毫秒内启动处理程序。
      【解决方案6】:

      试试这个:

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

      这将冻结 UI 给定的秒数并在 run() 中执行代码

      【讨论】:

      • 在这种情况下如何避免 UI 冻结
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 2023-03-31
      相关资源
      最近更新 更多