Добавьте дополнительную информацию из документ: Callbacks for LocationCallback will be made on the specified thread, which must already be a prepared looper thread.
Прежде чем вы сможете понять разницу между передачей null
и looper
в качестве значения 3-го параметра, вам нужно знать следующее: 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.
Я предполагаю, что вы не запускали какой-либо новый поток (например: no new Thread()
или no new HandlerThread()
) в то время, если это так, вполне возможно, что вы вызываете метод getLocationUpdates()
в основном потоке Android, то есть: поток по умолчанию, тот, который вы можете обновить представление (например, по умолчанию вы можете запускать 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()
, где поток обработчика создает новый looper
, и этот петлитель подготовлен, привязан к handlerThread
, который вы создали только что Теперь.
Вы увидите реальную разницу, если попытаетесь обновить элементы пользовательского интерфейса (например, обновить текстовое представление или отображение карты) в обратном вызове. Поскольку обновление пользовательского интерфейса разрешено только в потоке пользовательского интерфейса, если вы установите handlerThread.getLooper()
, вы столкнетесь с исключением при попытке обновить пользовательский интерфейс; и не возникнет проблем, если вы установите null
или Looper.myLooper()
из основного потока, причина для акцента на main thread
заключается в том, что Looper.myLooper
будет ссылаться на другой объект петлителя при работе в разных потоках.
Поговорим немного о петлителе: с помощью объекта looper
вы можете создать новый обработчик и передать ему петлитель, например: Handler handler = new Handler(looper)
, тогда, когда вы вызовете handler.post(new Runnable(...))
, runnable будет выполняться в потоке петлителя, который вы установили на обработчике, я думаю это то, что API делал за кулисами.
Думаю, вам будет полезно прочитать больше статей о handler
/ looper
/ HandlerThread
.
person
LiuWenbin_NO.
schedule
24.06.2019