Добавьте немного больше информации из документа : 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.
Я предполагаю, что вы не запустили ни одного нового потока (например: нет new Thread()
или нет 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()
в качестве 3-го параметра.
Да, таким образом, вы предоставили 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
, который вы только что создали.
Вы увидите реальную разницу, если попытаетесь обновить элементы пользовательского интерфейса (такие как обновление textview или mapview) в обратном вызове.Поскольку обновление пользовательского интерфейса разрешено только в потоке пользовательского интерфейса, если вы установите handlerThread.getLooper()
, то при попытке обновления пользовательского интерфейса вы столкнетесь с исключением;и не будет проблем, если вы установите null
или Looper.myLooper()
из основного потока , причина для акцента на main thread
заключается в том, что Looper.myLooper
будет ссылаться на другой объект петлителя при работе на другомпотоки.
Поговорим немного о лупере: с помощью объекта looper
вы можете создать новый обработчик и передать ему лупер, например: Handler handler = new Handler(looper)
, тогда при вызове handler.post(new Runnable(...))
исполняемый объект будетвыполненный в потоке петлителя, который вы установили в обработчике, я думаю, что именно это API делал за кулисами.
Прочитайте больше статей о handler
/ looper
/ HandlerThread
, я думаю, будет полезно.