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
This commit is contained in:
2025-10-02 09:15:33 +03:00
parent 41432665ea
commit b5aee265bc
85 changed files with 7132 additions and 449 deletions
+116
View File
@@ -0,0 +1,116 @@
# Анализ и исправление зависаний 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`**:
```java
// Добавлены переменные для 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 обновления**:
```java
private void updateVesselPositionUI(Vessel vessel) {
if (isFinishing() || isDestroyed()) return; // Защита
runOnUiThread(() -> {
try {
updateUIActivity(); // Обновляем watchdog
// ... безопасные операции
} catch (Exception e) {
Log.e(TAG, "Ошибка в updateVesselPositionUI: " + e.getMessage(), e);
}
});
}
```
### 3. **Дополнительная диагностика**:
```java
// Добавлен счетчик вызовов updateControlPanelPosition
private int controlPanelUpdateCount = 0;
// Улучшен UI Watchdog с диагностикой handler'ов
Log.i(TAG, "UI WATCHDOG: Handler status - " +
"watchdog=" + watchdogActive +
", controlPanelCount=" + controlPanelUpdateCount);
// Принудительная остановка при превышении лимита
if (controlPanelUpdateCount > 50) {
// Останавливаем слишком частые обновления
}
```
### 4. **Очистка ресурсов**:
```java
@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 обновлений