Я работаю над программной клавиатурой, и многие клиенты жаловались, что приложение (клавиатура) зависает в какой-то момент, и они больше не могут его использовать, пока не убьют приложение.
После выполнения дампа обработчика, связанного с главным петлителем, я заметил, что MessageQueue
содержит более двух тысяч сообщений, и первое (которое, очевидно, блокирует обработку) - barrier
.
Вот как выглядит файл дампа:
MainHandlerPrefixHandler (android.os.Handler) {3ff4640} @ 263606865
MainHandlerPrefix Looper (main, tid 2) {989979}
MainHandlerPrefix Message 0: { when=-6m23s60ms barrier=79218 }
MainHandlerPrefix Message 1: { when=-6m23s60ms callback=my.package.MyService$6 target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix Message 2: { when=-6m23s60ms callback=my.package.-$$Lambda$MyService$1$ubKmTRTmp1KgOJNPNWqMqGvEn4w target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix Message 3: { when=-6m23s60ms callback=my.package.-$$Lambda$MyService$j8NCLWjGRK01foVLc7iUIBP0CK4 target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix Message 4: { when=-6m22s762ms callback=my.package.-$$Lambda$MyService$3PQrgbrUtIie519YhF12lIH8KUQ target=android.os.Handler }
MainHandlerPrefix Message 5: { when=-6m22s761ms callback=my.package.MyService$5 target=android.os.Handler }
...
MainHandlerPrefix Message 2232: { when=-32ms callback=my.package.-$$Lambda$MyService$3PQrgbrUtIie519YhF12lIH8KUQ target=android.os.Handler }
MainHandlerPrefix Message 2233: { when=0 callback=my.package.-$$Lambda$MyService$ct9EhzRGhNjeTqThcka4z4DVWy0 target=android.os.Handler }
MainHandlerPrefix (Total messages: 2234, polling=true, quitting=false)
Как видно из дампа, "барьерное" сообщение находилось в очереди более шести минут.
Вот как инициализируется основной обработчик:
private void initMainHandler() {
mainHandler = new Handler(this.getMainLooper());
}
А вот как Runnable
отправляется основному обработчику:
private void runOnUiThread(Runnable r, String message) {
try {
if (Thread.currentThread() == getMainHandler().getLooper().getThread()) {
r.run();
} else {
getMainHandler().post(r);
}
} catch (Exception e) {
Log.d(TAG, "", e);
}
}
Пример Использование:
public void loadKeyboard() {
runOnUiThread(() -> {
containerFacade.requestLayout();
containerFacade.layoutOverlay();
}, "example");
}
К сожалению, я не могу воспроизвести эту проблему, я только что получил журнал от клиента, который пожаловался на это.
Есть ли у вас какие-либо идеи, что может вызвать эту блокировку? Заранее спасибо.
ОБНОВЛЕНИЕ
Кажется, что Looper.removeSyncBarrier(int token)
, где token
- это значение сообщения (barrier
) из MessageQueue
с индексом '0' (из дампа) никогда не вызывается, поэтому поток, связанный с l oop, заблокирован, а приложение зависает.