【问题标题】:Can I do network operations (UI blocking) inside handlers/runnables?我可以在处理程序/runnables 中进行网络操作(UI 阻塞)吗?
【发布时间】:2013-09-25 15:17:43
【问题描述】:

在我的 mainActivity(我的应用程序的唯一活动)中,我正在创建下面的处理程序并在其中运行一个可运行文件。

我对处理程序及其运行位置有一些误解。

查看代码

Handler handler;

    @Override
    protected void onCreate(Bundle bundle)
    {
      handler = new Handler();
      handler.postDelayed(r , 5000);
    }

    Runnable r = new Runnable()
    {
         @Override 
         public void run() {
              FetchServerAndUpdateStatus(); //network stuff in here
              handler.postDelayed(r , 5000);
         }
    }
  • 我假设此代码仍将在 UI 线程中运行,我将无法在其中进行任何网络调用,不是吗?
  • 如果是,我该怎么办?创建和使用单独的线程?
  • 如果我创建了一个新线程,如何运行 postdelayed 方法?该线程没有延迟发布?
  • 不使用 handler/runnable 而是使用 TimerTask 和 Runnable 是更好的方法吗?或者,就像上面的 handler/runnable 一样,它也将在 UI 线程上运行,除非在单独的线程中创建。

【问题讨论】:

  • 我认为我遗漏了一些东西。 Handler 真的有可以运行的构造函数吗?
  • @joozek 不,他们没有。 postdelayed 需要你,我的坏。

标签: java android multithreading android-handler


【解决方案1】:

当你构造一个 Handler 时,它会绑定到构造它的线程。

onCreate() 在 UI 线程上运行,因此此处理程序将绑定到主线程上的 Looper,因此将在该线程上运行。

如果你想要一个处理程序,你可以在另一个线程上使用,你可以构造一个。 查看 looper 文档:https://developer.android.com/reference/android/os/Looper.html

哪个有这个块:

class LooperThread extends Thread {
  public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      synchronized (this) {
          this.notifyAll();
      }

      Looper.loop();
  }
}

添加此类,然后在您的 onCreate 中执行以下操作:

mLooperThread = new LooperThread();
mLooperThread.start();
synchronized (mLooperThread) {
  while (null == mLooperThread.mHandler) {
    mLooperThread.wait();
  }
}
mLooperThread.mHandler.postDelayed(r , 5000);

这将导致 runnable 不在 UI 线程上运行,这可能是您想要的。

对于需要与 UI 交互的任务,AsyncTask 可能会更好,因为它包含一种机制,当任务在 UI 线程上完成时,它会运行与视图相关的事情,因为任何与视图相关的事情都必须在 UI 上完成线程。

在 UI 线程上执行的其他机制是发布到视图本身:

https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable) 或者 [https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long)](https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long))

或者让 Activity 为你在 UI 上运行它:

https://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)

【讨论】:

  • 非常感谢。我想到目前为止你给出的解释是最精确和对新手友好的。我认为很多人认为在 onCreate() 或 onResume() 中创建处理程序时,他们是在单独的线程上启动它,但实际上并非如此。处理程序和线程之间存在很大的混淆,这让我迷失了方向。感谢您填写那里的空白。
  • 这将导致:尝试在空对象引用上调用虚拟方法 'boolean android.os.Handler.post(java.lang.Runnable)'
  • 是的,mHandler 的构造存在竞争,使用 LooperThread 上的监视器可以避免这种竞争。我更新了代码来解决这个问题。
【解决方案2】:
  1. 这取决于你用你的处理程序做什么,你没有显示,你想如何获得 m_handler。如果您使用new Handler(Looper.getMainLooper()) 创建它,它将在 UI 线程上运行。
  2. 如果你想在后台运行代码(网络操作)你应该使用AsyncTask

【讨论】:

  • 你能详细说明一下 Activty.getHandler() 的事情,除了活动我在哪里可以得到它?是的,我肯定会使用网络的东西,所以我需要它在后台运行。上面的代码,是运行在UI线程还是其他线程上?
  • 对不起,我把事情搞砸了。您可以通过调用Looper.getMainLooper() 获取主looper。 Looper 是在循环中运行代码的东西,您可以使用new Handler(looper) 将处理程序附加到它。无论如何我都会编辑我的答案
  • 如果我在没有任何东西的情况下创建它,就像上面一样,它在哪里运行?
  • Docs 表示它将在活套绑定到当前线程的情况下运行。如果您(或任何人)没有为当前线程创建循环器,则会引发异常
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 2016-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
相关资源
最近更新 更多