generated from Grigo/AndroidTemplate
b5aee265bc
Архитектурные улучшения: - Внедрен UIRenderingCoordinator с централизованным throttling - Решены проблемы зависания UI через батчинг операций карты - Добавлен VesselPathController для отслеживания маршрутов - Реализован MapLibreMapImpl как альтернатива Яндекс.Картам Визуализация AIS: - Добавлены векторные иконки для всех типов судов - Разделение Class A/B судов с соответствующими иконками - Иконки навигационных статусов (anchor, moored, engine, sail) - Улучшенный CursorOverlay с информацией о судах Производительность: - Throttling UI обновлений (vessel: 500ms, AIS: 1s, paths: 2s) - Устранение утечек Handler объектов - Оптимизация GeoJSON операций в MapLibre
4.8 KiB
4.8 KiB
Анализ и исправление зависаний UI в MainActivity
Выявленные проблемы:
1. Основная причина зависания: updateControlPanelPosition()
- Функция вызывается слишком часто (7+ мест вызова)
- Выполняет дорогие операции в главном потоке:
- Множественные
getHeight()вызывают layout pass setLayoutParams()- одна из самых дорогих операций в Android UI- Множество логирования в главном потоке
- Множественные
- Вызывается каждые несколько секунд из-за автоматических обновлений
2. Цепочка блокировок:
coordinatesWidget.updateVessel()
→ invalidate()
→ onDraw()
→ getHeight()
→ onDockResize callback
→ updateControlPanelPosition()
→ setLayoutParams() ← BLOCKING!
3. Множественные UI обновления:
messageAgeRunnable- каждую секундуbottomSheetUpdateRunnable- каждую секундуtimeUpdateRunnable- каждую секунду- Все в главном UI потоке без throttling
Внесенные исправления:
1. Throttling для updateControlPanelPosition:
// Добавлены переменные для throttling
private android.os.Handler controlPanelUpdateHandler;
private Runnable controlPanelUpdateRunnable;
private boolean controlPanelUpdatePending = false;
private static final long CONTROL_PANEL_UPDATE_DELAY = 200; // 200ms throttling
// Переработана функция с оптимизациями
private void updateControlPanelPositionSafe() {
// Проверки на нулевые размеры (избегаем layout pass)
if (compassHeight <= 0) return;
if (coordinatesHeight <= 0) return;
// Изменения только если отличаются от текущих
if (params.topMargin != topMargin || params.bottomMargin != bottomMargin) {
// Применяем изменения
}
}
2. Безопасные UI обновления:
private void updateVesselPositionUI(Vessel vessel) {
if (isFinishing() || isDestroyed()) return; // Защита
runOnUiThread(() -> {
try {
updateUIActivity(); // Обновляем watchdog
// ... безопасные операции
} catch (Exception e) {
Log.e(TAG, "Ошибка в updateVesselPositionUI: " + e.getMessage(), e);
}
});
}
3. Дополнительная диагностика:
// Добавлен счетчик вызовов updateControlPanelPosition
private int controlPanelUpdateCount = 0;
// Улучшен UI Watchdog с диагностикой handler'ов
Log.i(TAG, "UI WATCHDOG: Handler status - " +
"watchdog=" + watchdogActive +
", controlPanelCount=" + controlPanelUpdateCount);
// Принудительная остановка при превышении лимита
if (controlPanelUpdateCount > 50) {
// Останавливаем слишком частые обновления
}
4. Очистка ресурсов:
@Override
protected void onDestroy() {
// Добалена очистка throttling handler'а
if (controlPanelUpdateHandler != null) {
controlPanelUpdateHandler.removeCallbacks(controlPanelUpdateRunnable);
}
}
Ожидаемый результат:
- Значительное снижение нагрузки на главный UI поток
- Устранение блокировок от
setLayoutParams() - Throttling обновлений control panel до безопасного уровня
- Улучшенная диагностика для понимания проблем в рантайме
- Автоматическое восстановление при превышении лимитов
Мониторинг:
Следите за логами:
"Control panel updates count: X за последние 10 сек"- количество обновлений"UI WATCHDOG: Handler status"- состояние всех handler'ов"Control panel updated: top=X, bottom=Y"- фактические обновления
Если проблема остается:
- Проверьте количество вызовов updateControlPanelPosition
- Рассмотрите полную отключение тестового обновления coordinatesWidget
- Увеличьте CONTROL_PANEL_UPDATE_DELAY до 500мс
- Добавьте дополнительный throttling для BottomSheet обновлений