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