1

我正在创建一个使用该FusedLocationProviderClient.requestLocationUpdates()方法的位置跟踪应用程序。它的一个论点需要一个Looper对象,我不完全确定它是如何工作的。现在我只是传递null给它,它按预期工作。

经过研究,我了解到 UI Thread 基本上是一个HandlerThread已经有自己的 Looper 对象(我知道基本的东西,但意识到有点晚)。所以Looper.myLooper(这次我使用 ) 而不是 null ,它仍然有效。

private void getLocationUpdates(){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper());
}

文档说传递null在调用线程上执行 locationCallback。那么当我使用Looper.myLooper(). 从字面上的任何线程调用时两者是否具有相同的效果,或者我错过了什么?

4

2 回答 2

4

从文档中添加更多信息: Callbacks for LocationCallback will be made on the specified thread, which must already be a prepared looper thread.

null在你理解传递和作为第三个参数的区别之前looper,你需要知道的是:looper// handlerHandlerThread因为你提到了HandlerThread,所以我把它和其他两个放在一起)。

有很多关于这些概念的文章,这里有一些仅供参考:


所以我希望我能尽量简单地回答。

当你说: I'm creating a location tracking app for which I'm using the FusedLocationProviderClient.requestLocationUpdates() method. One of its argument requires a Looper object and I'm not completely sure how it works. Right now I'm just passing null to it and it works as expected.

我假设您当时没有启动任何新线程(例如: nonew Thread()或 no new HandlerThread()),如果是这样,那么您很可能getLocationUpdates()在 Android 主线程中调用该方法,即:默认线程,您可以在其上更新视图(例如默认情况下你可以textView.setText("xx")毫无问题地运行,这是因为你在主线程 - 也就是 UI 线程,默认情况下),所以传递null将在 上执行回调calling thread,即:主线程。现在你需要知道,主线程有一个looper,我们可以称它为main looper。

然后你说: After researching I learned that the UI Thread is basically a HandlerThread which already has its own Looper object (I know basic stuff but realized a bit late). So I used Looper.myLooper() instead of null this time and it still works.

我假设你做了如下的事情:

HandlerThread handlerThread = new HandlerThread();
getLocationUpdates();

private void getLocationUpdates(){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper());
}

这次你Looper.myLooper()作为第三个参数传递。

是的,通过这种方式,您提供了一个looper, 并将locationCallback在其特定线程上执行looper(稍后再谈一下 looper)。

但是,因为很有可能您getLocationUpdates()再次在主线程中调用,所以Looper.myLooper仍然在主线程中返回 looper,是的,您可以认为callback它仍在主 looper 处运行,与您在null上面设置的相同。

但是,如果您像这样更改代码:

HandlerThread handlerThread = new HandlerThread();
handlerThread.start();
getLocationUpdates(handlerThread.getLooper());

private void getLocationUpdates(Looper looper){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest, locationCallback, looper);
}

callback在指定的looper线程上执行,即:您从中获得的looper对象handler.getLooper()

那么地球有什么不同呢?

当您创建一个 newHandlerThread并启动它时,您将启动一个 new Thread,并且默认情况下将在处理程序线程创建一个 new 的位置handlerThread.start()调用该 looper ,并且该 looper 已准备好,与您刚刚创建的绑定。HandlerThread#run()looperhandlerThread

如果您尝试在回调中更新 UI 元素(例如更新 textview 或 mapview),您将看到真正的区别。因为 UI 更新只允许在 UI 线程上进行,如果你设置了,handlerThread.getLooper()那么你在尝试更新 UI 时会遇到异常;而且从主线程null设置还是没有问题的,之所以强调是因为,在不同线程上运行时会引用不同的looper对象。Looper.myLooper() main threadLooper.myLooper

谈谈looper:使用looper对象,您可以新建一个处理程序并将looper传递给它,例如:Handler handler = new Handler(looper),然后当您调用时handler.post(new Runnable(...)),runnable将在您在处理程序上设置的looper线程上执行,我认为这就是API 在幕后做了。

我认为阅读更多关于handler//的文章会有所帮助looperHandlerThread

于 2019-06-24T10:29:29.040 回答
1

如果您在主线程中调用getLocationUpdates方法,则locationCallback也将在主线程中执行。如果您在后台线程中调用getLocationUpdates并将 null 作为循环器传递,您的回调将在后台线程中执行。这取决于您的需要,您是否需要指定在哪个线程中执行回调。

于 2019-06-24T09:22:20.150 回答