Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 回调是否发生在主(UI)线程上?_Android - Fatal编程技术网

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

Android 回调是否发生在主(UI)线程上?,android,Android,有很多Android SDK API都注册了回调处理程序。例如,使用MediaPlayer可以设置onCompletionListener回调。这些回调会从主(UI)线程调用吗?如果答案是“视情况而定”,那么我正在寻找一些关于从主线程调用回调与从另一个线程调用回调的一般规则。SDK文档似乎没有详细说明。(也许我错过了。) 知道这一点似乎很重要,因为如果保证主线程回调,那么我可以跳过代码中不同位置共享的数据上的一些线程同步。如果我因为无知而被迫悲观,那么我必须编写额外的同步块代码,并担心死锁、数据

有很多Android SDK API都注册了回调处理程序。例如,使用MediaPlayer可以设置onCompletionListener回调。这些回调会从主(UI)线程调用吗?如果答案是“视情况而定”,那么我正在寻找一些关于从主线程调用回调与从另一个线程调用回调的一般规则。SDK文档似乎没有详细说明。(也许我错过了。)


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

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

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

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

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

此外,对于快速完成后台工作非常有用,因为您需要一些完成步骤才能进入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();
}

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

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


然而,这是个例外。正如其他人所注意到的,其中绝大多数都是在主应用程序线程上调用的。

如果有疑问,可以使用
Log.i(“TAG”,thread.currentThread().getName())请参见:)

在我编写位置API时,出现了类似的情况。正如我们所知,我们为位置服务提供回调,以便在获得位置后得到通知。 所以我在这个回调中做了一些事情,这需要很长时间,比如使用GeocoderAPI

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

因此,我在这个侦听器中编写的任何代码都将在主线程上执行


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

另一个例外是当您使用WebView时。当javascript调用Java函数时,这样的调用不会发生在主线程中

前几天我在任务中遇到了这个问题。你可以查看链接

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

//创建一个新的ThreadPoolExecutor,该线程池上的每个处理器有2个线程
//设备和60秒的保持活动时间。
int numCores=Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor=新的ThreadPoolExecutor(numCores*2,numCores*2,
60L,TimeUnit.SECONDS,新LinkedBlockingQueue());
task.addOnCompleteListener(执行者,新的OnCompleteListener(){
@凌驾
未完成的公共void(@NonNull任务){
// ...
}
});

我不明白您描述的非UI案例是如何工作的。似乎非UI线程中运行的调度循环与UI线程中运行的调度循环不同。也就是说,UI线程中有一些代码调用UI事件、视图呈现、注册回调的方法。但是如果我只是用一个可运行的扩展类创建一些线程,我认为JVM只是启动线程并退出,没有Android SDK钩子将回调放在同一个线程上。也许你在描述其他的东西,“回调”不一定涉及调度循环。假设你有一个做复杂工作的班级。它有一个setOnCompleteListener函数和一个start函数。在一些非UI线程上,给它一个OnCompleteListener,然后调用start。它启动并执行它的操作,完成后将调用registeredOnCompleteListener.onComplete()。这将导致从运行对象的线程调用侦听器中的onComplete函数。在线程2上,run()方法内部调用setOnCompleteListener()。onComplete方法将在线程1或线程2中执行吗?不,没有“运行”。抱歉,我认为您把我的随机示例与java Runnable混淆了。在我的例子中,所有的事情都发生在一个线程上,而不是主UI线程。唯一的一点是不涉及派遣。您为类提供了侦听器的实现。当它感觉像这样时,它会调用侦听器上的方法。这些方法调用将发生在任何正在运行的线程上。我认为,除非涉及到调度机制,否则回调必然需要在与初始线程不同的线程上执行。为了使其具体化,假设我将setOnCompleteListener()和start调用放在可运行的扩展cla中
// 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) {
        // ...
    }
});