← Назад к вопросам

Какие плюсы и минусы подхода Single Activity?

2.0 Middle🔥 171 комментариев
#Android компоненты#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Single Activity архитектура: плюсы и минусы

Single Activity (одна Activity на приложение) — это архитектурный паттерн, когда всё приложение использует одну Activity и управляет навигацией через Fragments. Это стандарт в современной Android разработке, особенно с Navigation Component.

Архитектура Single Activity

// MainActivity — единственная Activity
class MainActivity : AppCompatActivity() {
    private lateinit var navController: NavController
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController
    }
}

// nav_graph.xml определяет навигацию между Fragments
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/nav_graph">
    
    <fragment android:id="@+id/homeFragment" android:name=".HomeFragment" />
    <fragment android:id="@+id/detailFragment" android:name=".DetailFragment" />
    
    <action android:id="@+id/action_home_to_detail"
        app:destination="@id/detailFragment" />
</navigation>

ПЛЮСЫ Single Activity

1. Управление состоянием проще

// Состояние приложения централизовано в ViewModel'е
class AppViewModel : ViewModel() {
    private val _appState = MutableLiveData<AppState>()
    val appState: LiveData<AppState> = _appState
    
    // Все экраны используют один ViewModel
    // Состояние сохраняется при navigation
}

// Во фрагментах
class HomeFragment : Fragment() {
    private val appViewModel: AppViewModel by activityViewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        appViewModel.appState.observe(viewLifecycleOwner) { state ->
            // Всегда видим актуальное состояние
            updateUI(state)
        }
    }
}

2. Более простой back stack

// Back stack управляется NavController, не Activity Manager
navController.navigate(R.id.action_home_to_detail)  // Добавляет в back stack
navController.popBackStack()  // Удаляет из back stack

// Жизненный цикл более предсказуем
// onPause/onResume вызываются один раз

3. Переходы между экранами без запуска новой Activity

// Нет overhead на создание новой Activity
// Быстрее и меньше памяти

// ❌ Multi-Activity подход
startActivity(Intent(this, DetailsActivity::class.java).apply {
    putExtra("user_id", userId)  // Передача данных через Intent
})

// ✅ Single Activity подход
val action = HomeFragmentDirections.actionHomeToDetail(userId)
navController.navigate(action)  // Type-safe navigation

4. Улучшенная навигация с Deep Links

<fragment android:id="@+id/detailFragment"
    android:name=".DetailFragment">
    <deep-link app:uri="app://detail/{userId}" />
    <argument android:name="userId" app:type="integer" />
</fragment>
// Deep link автоматически создаёт правильный back stack
val deepLink = "app://detail/123"
navController.navigate(deepLink.toUri())

5. Сохранение состояния при rotation

class HomeFragment : Fragment() {
    private val viewModel: HomeViewModel by viewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // ViewModel сохраняет состояние при rotation
        viewModel.items.observe(viewLifecycleOwner) { items ->
            adapter.submitList(items)
        }
    }
}
// При rotation Fragment пересоздаётся, но ViewModel остаётся

6. Единая точка входа для всех переходов

class AppNavigator(private val navController: NavController) {
    fun navigateToHome() = navController.navigate(R.id.homeFragment)
    fun navigateToDetail(id: Int) = navController.navigate(
        HomeFragmentDirections.actionHomeToDetail(id)
    )
    fun navigateToSettings() = navController.navigate(R.id.settingsFragment)
}

МИНУСЫ Single Activity

1. Более сложное управление transition анимациями

// ❌ Multi-Activity проще с ActivityOptions
startActivity(
    Intent(this, DetailActivity::class.java),
    ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
)

// ✅ Single Activity требует более явного управления
navigator.navigateToDetail(id) { transitionDuration = 300 }

// Нужно настраивать в fragment transaction
val options = FragmentNavigatorExtras(
    sharedView to "shared_element_name"
)
navController.navigate(action, options)

2. Все Fragments конкурируют за ресурсы

// ❌ Проблема: оба Fragment'а видны
class HomeFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // Может быть скрыт, но всё ещё обновляет UI
        startObservingData()  // Работает в фоне
    }
}

// ✅ Решение: pause/resume наблюдения
class HomeFragment : Fragment() {
    override fun onPause() {
        super.onPause()
        viewModel.pause()  // Остановить обновления
    }
    
    override fun onResume() {
        super.onResume()
        viewModel.resume()  // Возобновить обновления
    }
}

3. Более сложное управление Dialogs и PopUps

// ❌ Multi-Activity: можно легко открыть Dialog Activity
startActivityForResult(Intent(this, DialogActivity::class.java), REQUEST_CODE)

// ✅ Single Activity: нужно использовать DialogFragment
class MyDialogFragment : DialogFragment() {
    interface OnResultListener {
        fun onResult(result: String)
    }
    
    private var listener: OnResultListener? = null
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.button_ok).setOnClickListener {
            listener?.onResult("Result")
            dismiss()
        }
    }
}

4. Сложность с background задачами

// ❌ Multi-Activity: можно запустить Service
startService(Intent(this, MyService::class.java))

// ✅ Single Activity: нужно использовать WorkManager или Coroutines
class HomeFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.data.collect { data ->
                    updateUI(data)
                }
            }
        }
    }
}

5. Отладка back stack может быть сложнее

// ❌ Сложно понять, какие Fragment'ы в back stack'е
navController.currentBackStackEntry?.destination?.label

// ✅ Нужно логировать явно
navController.addOnDestinationChangedListener { _, destination, _ ->
    Log.d("Navigation", "Navigated to: ${destination.label}")
}

6. Может быть сложнее с модульной архитектурой

// ❌ Сложно: у каждого модуля свой Activity
module_auth::AuthActivity
module_profile::ProfileActivity
module_shop::ShopActivity

// ✅ Решение: shared navigation module
module_navigation::NavigationGraph
// Все модули используют одну Activity и один graph

Когда использовать Single Activity

  • Большинство современных приложений
  • Если нужна гибкая навигация между экранами
  • Если используется Material Design
  • Если нужно делиться состоянием между экранами

Когда использовать Multi-Activity

  • Отдельные экраны с кардинально отличающимся UI
  • Отдельные приложения в составе multi-app
  • Legacy приложения

Вывод: Single Activity + Navigation Component — стандарт современной Android разработки, рекомендуемый Google.

Какие плюсы и минусы подхода Single Activity? | PrepBro