回调是否发生在主(UI)线程上?

时间:2010-10-12 21:16:52

标签: android

有很多Android SDK API注册了回调处理程序。举一个具体的例子,使用MediaPlayer可以设置onCompletionListener回调。这些回调是否会从主(UI)线程调用?如果答案是“它取决于”,那么我正在寻找一些关于从主线程与另一个线程调用回调的一般规则。 SDK文档似乎没有拼写出来。 (也许我错过了。)

重要的是要知道,因为如果我保证主线程回调,那么我可以跳过代码中不同位置之间共享的数据的一些线程同步。如果我因无知而被迫悲观,那么我必须编写额外的同步块代码并担心死锁,数据完整性和性能降低。

7 个答案:

答案 0 :(得分:19)

如有疑问,可以使用Log.i("TAG", Thread.currentThread().getName());并查看:)

答案 1 :(得分:11)

如果您创建一个通过AIDL公开的远程服务,Android将在其他某个线程上调用您的代码的一种情况是 - 将在绑定器线程上调用这些AIDL方法,而不是主应用程序线程。

然而,这是个例外。正如其他人所指出的那样,绝大多数这些都是在主应用程序线程上调用的。

答案 2 :(得分:3)

根据我的经验,这些回调总是回到非UI线程上。您是否尝试Activity.runOnUiThread()以确保您的代码在UI线程上运行?您仍然会受到性能影响,因为此代码运行需要更长时间,但您可以避免线程同步的一些常见问题。

答案 3 :(得分:2)

通常,回调将发生在运行事件的线程上。如果您注册了一个回调并开始在非UI线程上播放,那么回调将在非UI线程上发生。但是,Android不会自己在后台创建新线程。

所有与UI相关的事件必须在UI线程上发生,因此您可以预测在UI线程上将发生单击处理程序回调等。

正如Aaron C指出的那样,你可以使用Activity.runOnUiThread强制在那里发生事情。

此外,AsyncTask对于快速后台工作非常有用,您需要一些完成步骤才能保证在uI线程上。

编辑:评论中的示例。

public void MyWorker {
   private OnCompleteListener onCompleteListener;

   public void setOnCompleteListener(OnCompleteListener onCompleteListener) {
     this.onCompleteListener = onCompleteListener;
   }

   public void doWork() {
     // do lots of work here
     onCompleteListener.onComplete();
   }
}

// somewhere in my Activity

public void onCreate() {
   final MyWorker worker = new MyWorker();
   worker.setOnCompleteListener(new OnCompleteListener() { ... });

   new Thread(new Runnable() {
       public void run() {
          worker.doWork();
       }
   }).start();
}

在此示例中,将从非UI线程运行onComplete“回调”。线程将在onComplete完成后退出。

答案 4 :(得分:1)

另一个例外是当您使用WebView时。当javascript调用Java函数时,主线程

中不会发生这样的调用

答案 5 :(得分:0)

当我在使用Location API时出现了类似的东西。我们知道,我们为位置服务提供回调,以便在获得位置后得到通知。 所以我在回调中做了一些事情,这花了很长时间,比如使用Geocoder API。

之前我的印象是,这个回调将从其他线程调用,因此不会在主UI线程上执行。但我可以看到,事实并非如此。

那么我在这个监听器中编写的代码将在主线程上执行。

现在我不明白他们是如何设法做到的,是通过使用标准函数runOnUIThread() ???

答案 6 :(得分:0)

前几天我在Tasks上遇到了这个问题。您可以检查this链接

  

默认情况下,附加到线程的侦听器在应用程序主(UI)线程上运行。附加侦听器时,还可以指定用于安排侦听器的执行器。

// Create a new ThreadPoolExecutor with 2 threads for each processor on the
// device and a 60 second keep-alive time.
int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(numCores * 2, numCores *2,
        60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

task.addOnCompleteListener(executor, new OnCompleteListener<AuthResult>() {
    @Override
    public void onComplete(@NonNull Task<AuthResult> task) {
        // ...
    }
});