从文档中添加更多信息:
Callbacks for LocationCallback will be made on the specified thread, which must already be a prepared looper thread.
null
在你理解传递和作为第三个参数的区别之前looper
,你需要知道的是:looper
// handler
(HandlerThread
因为你提到了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()
looper
handlerThread
如果您尝试在回调中更新 UI 元素(例如更新 textview 或 mapview),您将看到真正的区别。因为 UI 更新只允许在 UI 线程上进行,如果你设置了,handlerThread.getLooper()
那么你在尝试更新 UI 时会遇到异常;而且从主线程null
设置还是没有问题的,之所以强调是因为,在不同线程上运行时会引用不同的looper对象。Looper.myLooper()
main thread
Looper.myLooper
谈谈looper:使用looper
对象,您可以新建一个处理程序并将looper传递给它,例如:Handler handler = new Handler(looper)
,然后当您调用时handler.post(new Runnable(...))
,runnable将在您在处理程序上设置的looper线程上执行,我认为这就是API 在幕后做了。
我认为阅读更多关于handler
//的文章会有所帮助looper
。HandlerThread