DeadObjectException в GMS::LocationClient (Android)

В Android у нас есть класс, который упаковывает объект LocationClient из GMS (Google Mobile Services). (Обратите внимание, что LocationClient реализует com.google.android.gms.common.GooglePlayServicesClient).

К сожалению, у объекта LocationClient есть привычка генерировать DeadObjectExceptions (например, когда мы вызываем locationClient.getLastLocation ()), который мы обнаруживаем с помощью нескольких наших механизмов ведения журнала. Что странно, однако, это то, что LocationClient не задокументирован как выбрасывающий DeadObjectExceptions, и, кроме того, я могу только отследить указанные DeadObjectExceptions ~ 1/40 времени их появления o_0. У нас нет репродукции для этой проблемы, и я лично никогда не видел ее, однако это происходит для большого числа наших пользователей.

Другие заметки:

[a] о чем говорит строка "Вызвано: java.lang.IllegalStateException: android.os.DeadObjectException"? Эти два типа исключений не имеют отношения предок-потомок

[b] Я отправил сообщение на форум Android, но, конечно, они отклонили мое сообщение как "неправильный форум", и там нет форума GMS, так что мне совершенно не повезло.

Таким образом, вопрос заключается в следующем: GMS вызывает это странное неуловимое исключение, так что с этим и что я могу сделать?

Here's a stack trace:
com.myapp.android.service.AsyncExecutionException
     at com.myapp.android.service.AsyncService$ExceptionThrower.run(MyApp:120)
     at android.os.Handler.handleCallback(Handler.java:615)
     at android.os.Handler.dispatchMessage(Handler.java:92)
     at android.os.Looper.loop(Looper.java:137)
     at android.app.ActivityThread.main(ActivityThread.java:4794)
     at java.lang.reflect.Method.invokeNative(Method.java)
     at java.lang.reflect.Method.invoke(Method.java:511)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
     at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: java.lang.IllegalStateException: android.os.DeadObjectException
     at com.google.android.gms.internal.ey.getLastLocation()
     at com.google.android.gms.internal.ez.getLastLocation()
     at com.google.android.gms.location.LocationClient.getLastLocation()
     ***at com.myapp.GoogleLocationProvider.getLastLocation(MyApp:92)***
     at com.myapp.LocationProducer.getLocation(MyApp:183)
     at com.myapp.LocationProducer.getLocationHeader(MyApp:194)
     at com.myapp.API.onExecute(MyApp:344)
     ...
     at java.lang.Thread.run(Thread.java:856)
Caused by: android.os.DeadObjectException
     at android.os.BinderProxy.transact(Binder.java)
     at com.google.android.gms.internal.ex$a$a.a()
     at com.google.android.gms.internal.ey.getLastLocation()
     at com.google.android.gms.internal.ez.getLastLocation()
     ***at com.google.android.gms.location.LocationClient.getLastLocation()***
     at com.myapp.GoogleLocationProvider.getLastLocation(MyApp:92)
     at com.myapp.LocationProducer.getLocation(MyApp:183)
     at com.myapp.LocationProducer.getLocationHeader(MyApp:194)
     ...
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
     at java.lang.Thread.run(Thread.java:856)

------------ ADDENDUM ------------- Вот наш актуальный код. Вы заметите, что мы всегда проверяем заранее mLocationClient.isConnected (), так что проблема не в этом. Возможно, нам очень не повезло, и mLocationObject умирает между вызовами isOnConnected () и getLastLocation (), однако это кажется мне невероятным. Я полагаю, что могу начать входить до, между и после звонков и выяснить это.

LocationClient mLocationClient; // populated somewhere

public Location getLastLocation() {
    if (!mLocationClient.isConnected()) {
        return null;
    }
    Location location = null;
    try {
        location = mLocationClient.getLastLocation();
    } catch (Exception e) {
        if (!handleDeadObjectException(e)) {
            throw e;
        }
    }
    return location;
}

// logs, attempts to handle depending on user configuration
private boolean handleDeadObjectException(Exception e);

1 ответ

Из документации DeadObjectException:

Объект, который вы вызываете, умер, потому что процесс его размещения больше не существует.

Это значит, что вы пытаетесь достичь объекта в другом процессе, который больше не доступен. Например, если вы связываетесь со службой, которая выполняется в другом процессе (например, с Google Mobile Services), используемый вами IBinder является локальным объектом, который "представляет" объект в удаленном процессе. Когда удаленный объект больше не доступен и вы пытаетесь использовать локальный объект IBinder, вы получите исключение DeadObjectException.

Так...

a] Что такое строка "Вызывается: java.lang.IllegalStateException: android.os.DeadObjectException" о? Эти два типа исключений не имеют отношения предок-потомок

Два исключения никак не связаны. IllegalStateException является фактическим исключением, а DeadObjectException является корневым исключением.

Поскольку gms.location.LocationClient.getLastLocation() не хочет объявлять элементы throw, которые предоставляют внутренние реализации - работают с связывателями и тому подобным, - этого просто нет. Но когда возникает исключение, такое как DeadObjectException, оно все еще хочет выбросить, и поэтому оно использует исключение времени выполнения IllegalStateException (которое не требует объявления броска).

[b] Я отправил сообщение на форум Android, но, конечно, они отклонили мое сообщение как "неправильный форум", и там нет форума GMS, так что мне совершенно не повезло.

:(

Таким образом, вопрос заключается в следующем: GMS вызывает это странное неуловимое исключение, так что с этим и что я могу сделать?

При работе с GMS LocationClient необходимо проверить, если LocationClient.isConnected(), прежде чем взаимодействовать с клиентом. Обратите внимание, что иногда LocationClient.isConnected() будет возвращать true, но после вызова LocationClient.getLastLocation () может по-прежнему генерировать исключение java.lang.IllegalStateException: android.os.DeadObjectException, и причиной этого являются проблемы с потоками и условия гонки, когда клиент был подключен когда вы проверили, но затем соединение было потеряно до вашего фактического действия.

Что вы должны сделать, это: а) Проверьте, подключен ли клиент

if ( mLocationClient != null && mLocationClient.isConnected() ) {   
    mLocationClient.getLastLocation();
}

б) поймать исключение IllegalStateException (а не DeadObjectException)

if ( mLocationClient != null && mLocationClient.isConnected() ) {   
    try {
        mLocationClient.getLastLocation();
    } catch (IllegalStateException ex) {
        // This will catch the exception, handle as needed
    }
}
Другие вопросы по тегам