在 FusedLocationProviderClient.requestLocationUpdates() 中使用 Looper.myLopper() 或 null 是一回事吗?
Is using Looper.myLopper() or null in FusedLocationProviderClient.requestLocationUpdates() the same thing?
我正在创建一个使用 FusedLocationProviderClient.requestLocationUpdates()
方法的位置跟踪应用程序。它的一个参数需要一个 Looper
对象,我不完全确定它是如何工作的。现在我只是将 null
传递给它,它按预期工作。
经过研究,我了解到 UI 线程基本上是一个 HandlerThread
,它已经有自己的 Looper 对象(我知道基本的东西,但意识到有点晚)。所以这次我使用 Looper.myLooper(
) 而不是 null 并且它仍然有效。
private void getLocationUpdates(){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper());
}
文档说传递 null
会在调用线程上执行 locationCallback。那么当我使用 Looper.myLooper()
时会发生什么?从字面意义上的任何线程调用时,两者是否具有相同的效果,还是我遗漏了什么?
如果您在主线程中调用 getLocationUpdates 方法,那么 locationCallback 也会在主线程中执行。
如果您在后台线程中调用 getLocationUpdates 并将 null 作为循环程序传递,您的回调将在后台线程中执行。
这取决于您的需要,您是否确实需要指定在哪个线程中执行回调。
从 document 添加更多信息:
Callbacks for LocationCallback will be made on the specified thread, which must already be a prepared looper thread.
在理解传递 null
和 looper
作为值 3rd 参数之间的区别之前,您需要了解的是:looper
/ handler
/ HandlerThread
(因为你提到了HandlerThread,所以我把它和其他两个放在一起)。
关于这些概念的文章很多,这里仅供参考:
Understanding Android Core: Looper, Handler, and HandlerThread
Explanation of handler, looper and related android thread classes
Looper/Handler vs. Executor
所以我希望我能尽量简单地回答。
当你说:
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.
我假设你当时没有启动任何新线程(例如:没有 new Thread()
或没有 new HandlerThread()
),如果是这样,很可能你正在调用方法 getLocationUpdates()
in Android main thread,即:默认线程,可以更新视图的线程(比如默认情况下你可以 运行 textView.setText("xx")
没有任何问题,这是因为你在主线程中 - a.k.a。UI 线程,默认情况下),所以传递 null
将在 calling thread
上执行回调,即:主线程。现在你需要知道,主线程有一个循环器,我们可以称之为主循环器。
然后你说:
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()
作为第 3 个参数。
是的,通过这种方式,你提供了一个looper
,locationCallback
将在那个looper
的特定线程上执行(稍后再谈一下looper)。
但是,因为很有可能又在主线程调用getLocationUpdates()
,所以Looper.myLooper
还是returns主线程的looper,可以考虑callback
仍然 运行ning 在主循环器中,与上面设置的 null
相同。
但是,如果您像这样稍微更改代码:
HandlerThread handlerThread = new HandlerThread();
handlerThread.start();
getLocationUpdates(handlerThread.getLooper());
private void getLocationUpdates(Looper looper){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest, locationCallback, looper);
}
callback
会在指定的looper线程上执行,即:你从handler.getLooper()
.
得到的looper对象
那到底有什么区别呢?
当您创建一个新的 HandlerThread
并启动它时,您将启动一个新的 Thread
,而 handlerThread.start()
将默认调用 HandlerThread#run()
,在处理程序线程创建一个新的 looper
,并且此循环器已准备就绪,与您刚才创建的 handlerThread
绑定。
如果您尝试在回调中更新 UI 元素(例如更新 textview 或 mapview),您将看到真正的区别。因为 UI 更新仅允许在 UI 线程上进行,如果您设置 handlerThread.getLooper()
那么您将 运行 在尝试更新 UI 时进入异常;从主线程设置null
或Looper.myLooper()
都没有问题,之所以强调main thread
是因为,Looper.myLooper
运行在不同线程上连接时将引用不同的循环对象。
谈谈循环器:使用 looper
对象,您可以新建一个处理程序并将循环器传递给它,例如:Handler handler = new Handler(looper)
,然后当您调用 handler.post(new Runnable(...))
时, 运行nable 将在您在处理程序上设置的循环线程上执行,我认为这就是 API 在幕后所做的。
阅读更多关于 handler
/ looper
/ HandlerThread
的文章我认为会有帮助。
我正在创建一个使用 FusedLocationProviderClient.requestLocationUpdates()
方法的位置跟踪应用程序。它的一个参数需要一个 Looper
对象,我不完全确定它是如何工作的。现在我只是将 null
传递给它,它按预期工作。
经过研究,我了解到 UI 线程基本上是一个 HandlerThread
,它已经有自己的 Looper 对象(我知道基本的东西,但意识到有点晚)。所以这次我使用 Looper.myLooper(
) 而不是 null 并且它仍然有效。
private void getLocationUpdates(){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper());
}
文档说传递 null
会在调用线程上执行 locationCallback。那么当我使用 Looper.myLooper()
时会发生什么?从字面意义上的任何线程调用时,两者是否具有相同的效果,还是我遗漏了什么?
如果您在主线程中调用 getLocationUpdates 方法,那么 locationCallback 也会在主线程中执行。 如果您在后台线程中调用 getLocationUpdates 并将 null 作为循环程序传递,您的回调将在后台线程中执行。 这取决于您的需要,您是否确实需要指定在哪个线程中执行回调。
从 document 添加更多信息:
Callbacks for LocationCallback will be made on the specified thread, which must already be a prepared looper thread.
在理解传递 null
和 looper
作为值 3rd 参数之间的区别之前,您需要了解的是:looper
/ handler
/ HandlerThread
(因为你提到了HandlerThread,所以我把它和其他两个放在一起)。
关于这些概念的文章很多,这里仅供参考:
Understanding Android Core: Looper, Handler, and HandlerThread
Explanation of handler, looper and related android thread classes
Looper/Handler vs. Executor
所以我希望我能尽量简单地回答。
当你说:
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.
我假设你当时没有启动任何新线程(例如:没有 new Thread()
或没有 new HandlerThread()
),如果是这样,很可能你正在调用方法 getLocationUpdates()
in Android main thread,即:默认线程,可以更新视图的线程(比如默认情况下你可以 运行 textView.setText("xx")
没有任何问题,这是因为你在主线程中 - a.k.a。UI 线程,默认情况下),所以传递 null
将在 calling thread
上执行回调,即:主线程。现在你需要知道,主线程有一个循环器,我们可以称之为主循环器。
然后你说:
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()
作为第 3 个参数。
是的,通过这种方式,你提供了一个looper
,locationCallback
将在那个looper
的特定线程上执行(稍后再谈一下looper)。
但是,因为很有可能又在主线程调用getLocationUpdates()
,所以Looper.myLooper
还是returns主线程的looper,可以考虑callback
仍然 运行ning 在主循环器中,与上面设置的 null
相同。
但是,如果您像这样稍微更改代码:
HandlerThread handlerThread = new HandlerThread();
handlerThread.start();
getLocationUpdates(handlerThread.getLooper());
private void getLocationUpdates(Looper looper){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest, locationCallback, looper);
}
callback
会在指定的looper线程上执行,即:你从handler.getLooper()
.
那到底有什么区别呢?
当您创建一个新的 HandlerThread
并启动它时,您将启动一个新的 Thread
,而 handlerThread.start()
将默认调用 HandlerThread#run()
,在处理程序线程创建一个新的 looper
,并且此循环器已准备就绪,与您刚才创建的 handlerThread
绑定。
如果您尝试在回调中更新 UI 元素(例如更新 textview 或 mapview),您将看到真正的区别。因为 UI 更新仅允许在 UI 线程上进行,如果您设置 handlerThread.getLooper()
那么您将 运行 在尝试更新 UI 时进入异常;从主线程设置null
或Looper.myLooper()
都没有问题,之所以强调main thread
是因为,Looper.myLooper
运行在不同线程上连接时将引用不同的循环对象。
谈谈循环器:使用 looper
对象,您可以新建一个处理程序并将循环器传递给它,例如:Handler handler = new Handler(looper)
,然后当您调用 handler.post(new Runnable(...))
时, 运行nable 将在您在处理程序上设置的循环线程上执行,我认为这就是 API 在幕后所做的。
阅读更多关于 handler
/ looper
/ HandlerThread
的文章我认为会有帮助。