Files
AndroidAisMap/UI_HANG_FIX_SUMMARY.md
T
Grigo b5aee265bc feat: новая архитектура UI и расширенная визуализация AIS
Архитектурные улучшения:
- Внедрен 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
2025-10-02 09:15:33 +03:00

4.8 KiB
Raw Blame History

Анализ и исправление зависаний 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);
    }
}

Ожидаемый результат:

  1. Значительное снижение нагрузки на главный UI поток
  2. Устранение блокировок от setLayoutParams()
  3. Throttling обновлений control panel до безопасного уровня
  4. Улучшенная диагностика для понимания проблем в рантайме
  5. Автоматическое восстановление при превышении лимитов

Мониторинг:

Следите за логами:

  • "Control panel updates count: X за последние 10 сек" - количество обновлений
  • "UI WATCHDOG: Handler status" - состояние всех handler'ов
  • "Control panel updated: top=X, bottom=Y" - фактические обновления

Если проблема остается:

  1. Проверьте количество вызовов updateControlPanelPosition
  2. Рассмотрите полную отключение тестового обновления coordinatesWidget
  3. Увеличьте CONTROL_PANEL_UPDATE_DELAY до 500мс
  4. Добавьте дополнительный throttling для BottomSheet обновлений