Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+717новых вакансий за сутки·60 871вакансия открыта сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании5 951
РезюмеAIПодготовкаСтатьи
ТарифыТарифы
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 391 кандидат открыт к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python9 224
  • Облачные технологии4 076
  • QA вакансии1 588
  • Android1 322
  • Инженер данных805
  • Продакт-менеджер368

Разработка

  • Backend вакансии1 317
  • iOS1 239
  • AI вакансии608
  • Fullstack вакансии523
  • Frontend вакансии456
  • Mobile вакансии28

По стеку

  • Go5 445
  • Java3 175
  • Kotlin1 119
  • Node.js1 026
  • Rust949
  • .NET666
  • PHP311
  • C#210
  • C++204

DevOps и инфраструктура

  • DevOps вакансии2 713
  • Kubernetes2 308
  • Linux-инфраструктура1 890
  • Terraform / IaC1 406
  • CI/CD842
  • Мониторинг и Observability645
  • SRE226
  • Кибербезопасность84

Аналитика и данные

  • Аналитик данных483
  • Data Scientist469
  • Бизнес-аналитик349
  • Системный аналитик48

Другие направления

  • Проджект-менеджер139
  • UI/UX дизайн71
  • Ручное тестирование14

По регионам

  • Вакансии в США24 791
  • Вакансии в Европе9 439
  • Работа в России2 924
  • Вакансии в Канаде2 178

По формату

  • Удалённые вакансии43 505
  • Релокация в США24 791
  • Гибридная работа3 370
  • Офисная работа2 525

По уровню

  • Senior вакансии20 898
  • Middle вакансии12 438
  • Junior вакансии3 864

Сейчас нанимают

Все компании
  • Wise191 вакансия
  • Rakuten188 вакансий
  • ASML163 вакансии
  • Grab134 вакансии
  • Celonis48 вакансий
  • Spotify37 вакансий
  • Adyen28 вакансий
  • Infobip28 вакансий
  • Monzo20 вакансий
  • Darktrace17 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме Jetpack ComposeВсе вопросы
Jetpack ComposeSeniorПроектирование систем

Как поэтапно перенести существующий UI на основе View в Jetpack Compose?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Миграцию выполняют поэтапно: сначала встраивают Compose в существующие экраны через ComposeView, используют AndroidView для legacy-виджетов, разделяют ViewModel, и в конце переходят на Navigation Compose.

Фаза 1: Внедрение Compose в существующие View-экраны

Используйте ComposeView — специальный View, способный хостить composable-функции. Его можно добавить прямо в XML-лейаут или создать программно:

// В XML-лейауте
// <androidx.compose.ui.platform.ComposeView
//     android:id="@+id/compose_view"
//     android:layout_width="match_parent"
//     android:layout_height="wrap_content" />

// В Fragment/Activity
binding.composeView.apply {
  setViewCompositionStrategy(
    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
  )
  setContent {
    AppTheme {
      MyComposableComponent()
    }
  }
}

Стратегия DisposeOnViewTreeLifecycleDestroyed обязательна для Fragment, чтобы Compose-состояние корректно освобождалось при возврате в backstack.

Поэтапный перенос View UI в Jetpack Compose

Ключевой принцип миграции — не переписывать всё разом, а двигаться постепенно, используя механизмы взаимодействия между View-системой и Compose. Google рекомендует стратегию «снизу вверх» (leaf-first): начинать с атомарных компонентов (кнопки, текстовые поля, карточки), постепенно продвигаясь к экранам и навигации.

Фаза 2: Использование View внутри Compose

Если какой-то виджет сложно воссоздать в Compose (например, MapView, AdView, legacy custom view), используйте AndroidView:

@Composable
fun LegacyChartView(data: List<Float>) {
  AndroidView(
    factory = { context ->
      CustomChartView(context).apply {
        // начальная настройка
        setChartStyle(ChartStyle.LINE)
      }
    },
    update = { view ->
      // вызывается при каждой рекомпозиции
      view.setData(data)
    },
    modifier = Modifier
      .fillMaxWidth()
      .height(200.dp)
  )
}

// Для ViewGroup с дочерними элементами
@Composable
fun LegacyContainer() {
  AndroidViewBinding(MyLegacyBinding::inflate) {
    // доступ к binding внутри лямбды
    tvTitle.text = "Hello"
  }
}

Фаза 3: Общий ViewModel и состояние

Как View, так и Compose-компоненты могут разделять один ViewModel. Это ключ к постепенной миграции без переписывания бизнес-логики:

class ProfileViewModel : ViewModel() {
  private val _uiState = MutableStateFlow(ProfileUiState())
  val uiState: StateFlow<ProfileUiState> = _uiState.asStateFlow()

  fun onNameChanged(name: String) {
    _uiState.update { it.copy(name = name) }
  }
}

// В Fragment (View-мир)
fragment.viewModel.uiState
  .onEach { state -> binding.tvName.text = state.name }
  .launchIn(viewLifecycleOwner.lifecycleScope)

// В Compose-мире
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = viewModel()) {
  val uiState by viewModel.uiState.collectAsStateWithLifecycle()
  Text(text = uiState.name)
}

Фаза 4: Миграция навигации

Параллельное использование Navigation Component (Fragment) и Navigation Compose возможно через NavHostFragment, у которого один из пунктов навигации — ComposeNavHost фрагмент. Финальная цель — полная замена Navigation Component на Navigation Compose:

// Промежуточный вариант: Compose-экран как Fragment
class ProfileFragment : Fragment() {
  override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
  ) = ComposeView(requireContext()).apply {
    setViewCompositionStrategy(
      ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
    )
    setContent {
      AppTheme { ProfileScreen() }
    }
  }
}

// Финальный вариант: чистый NavHost
@Composable
fun AppNavHost(navController: NavHostController) {
  NavHost(navController, startDestination = "home") {
    composable("home") { HomeScreen() }
    composable("profile/{userId}") { backStackEntry ->
      val userId = backStackEntry.arguments?.getString("userId")
      ProfileScreen(userId = userId)
    }
  }
}

Рекомендуемый порядок миграции

  • Начните с листовых UI-компонентов (кнопки, иконки, теги) — они не имеют зависимостей
  • Перейдите к составным компонентам (карточки, list item'ы)
  • Перепишите целые экраны, оставив Fragment-оболочку временно
  • Мигрируйте навигацию на Navigation Compose в последнюю очередь
  • Удалите Fragment-оболочки и перейдите на Activity с единственным ComposeView

Подводные камни

  • Отсутствие setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed) в Fragment приводит к утечкам памяти: Composition живёт дольше, чем View Fragment'а при возврате из backstack.
  • AndroidView не поддерживает Preview в Android Studio — factory-лямбда требует реального Context, а Preview-контекст не даёт доступа к ресурсам.
  • Вызов View.invalidate() или View.requestLayout() из update-лямбды AndroidView может вызвать бесконечный цикл перекомпозиции.
  • Смешивание WindowInsets из View-мира и Compose — разные API. ViewCompat.setOnApplyWindowInsetsListener и WindowInsets.systemBars из Compose конфликтуют, если применяются одновременно.
  • Анимации View (ObjectAnimator, ValueAnimator) и Compose Animation API (animate*AsState, Transition) работают независимо — нельзя синхронизировать анимации разных миров без дополнительного оркестратора.
  • RecyclerView внутри AndroidView плохо работает с Compose-скроллингом: вложенный скролл требует настройки NestedScrollInteroperability через rememberNestedScrollInteropConnection().
  • Databinding-лейауты при AndroidViewBinding не реагируют на Compose-состояние автоматически — нужно вручную обновлять binding в update-блоке.
  • Тестирование: ComposeView в UI-тестах требует использования createAndroidComposeRule<Activity>, а не ActivityScenario напрямую — иначе Compose-узел не будет виден Espresso.

Частые вопросы на собеседовании

  • Что такое State в Jetpack Compose и как работает state hoisting?
  • Что такое recomposition и что её вызывает в Jetpack Compose?
  • В чём разница между remember и rememberSaveable?
  • Каковы лучшие практики производительности в Jetpack Compose (стабильность, пропускаемость)?

Типичные ошибки

  • Объяснять «миграция View UI на Compose» только как синтаксис и не описывать поведение runtime/compiler.
  • Игнорировать важный риск: Big-bang миграция без ownership и метрик создает два UI стека и замедляет поставку фич.
  • Давать пример без edge case: отмены, null, recomposition, platform boundary или ошибки.

Что проверяет интервьюер

  • Формулирует суть темы «миграция View UI на Compose» своими словами и связывает ее с кодом.
  • Называет механизм: Нужно определить interop boundaries, theme mapping, navigation, testing, performance baseline и стратегию удаления XML.
  • Видит production-последствие: Big-bang миграция без ownership и метрик создает два UI стека и замедляет поставку фич.

Как вы знаете этот вопрос?

Проверить себя по теме Jetpack Compose →

Источники

  • https://developer.android.com/develop/ui/compose/migrate/migrate-xml-views-to-jetpack-compose
  • https://developer.android.com/develop/ui/compose/migrate/interoperability-apis
←Предыдущий вопросКак обрабатывать темы и стили в Jetpack Compose с помощью Material3?Следующий вопрос→Как осуществлять навигацию между экранами в Jetpack Compose с помощью Navigation Compose?

Связанные темы

Jetpack Composemigrate-views-to-compose-reasoningui-state