Использует ли Looper.myLopper () или null в FusedLocationProviderClient.requestLocationUpdates () одно и то же?

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

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

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

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


person Syed Ahmed Jamil    schedule 24.06.2019    source источник


Ответы (2)


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

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

person Dmytro Batyuk    schedule 24.06.2019