Является ли использование Looper.myLopper () или null в FusedLocationProviderClient.requestLocationUpdates () одним и тем же? - PullRequest
0 голосов
/ 24 июня 2019

Я создаю приложение отслеживания местоположения, для которого я использую метод FusedLocationProviderClient.requestLocationUpdates().Один из аргументов требует объекта Looper, и я не совсем уверен, как он работает.Прямо сейчас я просто передаю ему null, и он работает как положено.

После исследования я узнал, что поток пользовательского интерфейса - это, по сути, HandlerThread, который уже имеет свой собственный объект Looper (я знаю основные вещино понял немного поздно).Поэтому я использовал Looper.myLooper() вместо null на этот раз, и он все еще работает.

private void getLocationUpdates(){
//checkSelfPermissions
fusedLocationProviderClient
.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper());
}

В документации сказано, что передача null выполняет locationCallback в вызывающем потоке.Так что же происходит, когда я использую Looper.myLooper().Имеют ли оба одинаковый эффект при вызове буквально из любого потока, или я что-то упустил?

Ответы [ 2 ]

1 голос
/ 24 июня 2019

Добавьте немного больше информации из документа : 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, я думаю, будет полезно.

1 голос
/ 24 июня 2019

Если вы вызываете метод getLocationUpdates в главном потоке, тогда locationCallback также будет выполняться в главном потоке.Если вы вызываете getLocationUpdates в фоновом потоке с пропущенным нулем в качестве петлителя, ваш обратный вызов будет выполнен в фоновом потоке.В зависимости от ваших потребностей, вам точно нужно указать, в каком потоке будет выполняться ваш обратный вызов.

...