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

Как вернуть значение из Activity при навигации назад

1.7 Middle🔥 172 комментариев
#Android компоненты#Жизненный цикл и навигация

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Возврат значения из Activity при навигации назад

Возвращение значения из Activity при ее закрытии (навигации назад) — это распространенная задача, требующая передачи данных от дочерней активности к родительской. Существует несколько ключевых подходов, каждый с разными сценариями использования, преимуществами и ограничениями.

Основные подходы и их реализация

1. Использование startActivityForResult() и onActivityResult() (до API 29)

Это классический, но теперь устаревший метод (в AndroidX Activity 1.0+ он заменен на ActivityResult API). Однако он важен для понимания исторического контекста.

Механизм работы:

  • В родительской Activity запускаете дочернюю с помощью startActivityForResult(intent, requestCode).
  • В дочерней Activity устанавливаете результат с помощью setResult(resultCode, intent) перед закрытием.
  • Родительская Activity получает данные в методе onActivityResult(requestCode, resultCode, intent).

Пример реализации:

// Родительская Activity
class MainActivity : AppCompatActivity() {
    private val REQUEST_CODE_EDIT = 101

    fun openEditActivity() {
        val intent = Intent(this, EditActivity::class.java)
        startActivityForResult(intent, REQUEST_CODE_EDIT)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_EDIT && resultCode == RESULT_OK) {
            val resultText = data?.getStringExtra("RESULT_TEXT")
            // Используем полученное значение
            resultText?.let { updateUI(it) }
        }
    }
}

// Дочерняя Activity
class EditActivity : AppCompatActivity() {
    fun finishWithResult() {
        val resultIntent = Intent()
        resultIntent.putExtra("RESULT_TEXT", "Новое значение")
        setResult(RESULT_OK, resultIntent)
        finish()
    }
}

2. Использование современного ActivityResult API (Activity 1.0+ / AndroidX)

Это рекомендуемый подход, предоставляющий более декларативный, тестируемый и удобный для обработки жизненного цикла механизм. Он основан на контрактах (ActivityResultContract).

Механизм работы:

  • Регистрируете обработчик результата (ActivityResultLauncher) в родительской Activity.
  • Запускаете дочернюю Activity через этот лаунчер.
  • Дочерняя Activity устанавливает результат стандартным способом (setResult).
  • Обработчик вызывается автоматически с полученным результатом.

Пример реализации:

// Родительская Activity с использованием ActivityResult API
class MainActivity : AppCompatActivity() {
    // Регистрируем лаунчер для получения результата
    private val editResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            val data = result.data
            val resultText = data?.getStringExtra("RESULT_TEXT")
            resultText?.let { updateUI(it) }
        }
    }

    fun openEditActivity() {
        val intent = Intent(this, EditActivity::class.java)
        editResultLauncher.launch(intent)
    }
}

Для простых данных (например, строки) можно использовать специализированный контракт ActivityResultContracts.PickContact(), но для собственной Activity базовый StartActivityForResult() универсален.

3. Использование Shared ViewModel (для связанных в стеке Activity)

Если обе Activity находятся в одном процессе и логически сильно связаны, можно использовать ViewModel, разделяемую между ними. Это особенно актуально в архитектуре MVVM или при использовании Navigation Component.

Механизм работы:

  • Создается общий ViewModel, доступный через владельца (например, область активности родителя).
  • Дочерняя Activity записывает данные в эту ViewModel.
  • Родительская Activity наблюдает за изменениями данных в той же ViewModel.

Пример реализации:

// Общая ViewModel
class SharedResultViewModel : ViewModel() {
    private val _resultLiveData = MutableLiveData<String>()
    val resultLiveData: LiveData<String> = _resultLiveData

    fun setResult(result: String) {
        _resultLiveData.value = result
    }
}

// Родительская Activity
class MainActivity : AppCompatActivity() {
    private val viewModel: SharedResultViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Наблюдаем за изменениями результата
        viewModel.resultLiveData.observe(this) { result ->
            updateUI(result)
        }
    }

    fun openEditActivity() {
        val intent = Intent(this, EditActivity::class.java)
        startActivity(intent)
    }
}

// Дочерняя Activity
class EditActivity : AppCompatActivity() {
    // Получаем тот же экземпляр ViewModel, используя родительскую Activity как owner
    private val viewModel: SharedResultViewModel by viewModels(
        ownerProducer = { requireActivity() } // или this.activity
    )

    fun finishWithResult() {
        viewModel.setResult("Новое значение из EditActivity")
        finish()
    }
}

4. Использование Callback-интерфейсов или событий (через систему событий)

Подход с использованием интерфейсов или широковещательных событий (например, через LocalBroadcastManager, который также считается устаревшим, или через RxJava, Kotlin Flow, EventBus) менее стандартен и может усложнить архитектуру.

Пример через интерфейс (осторожно, может создавать утечки контекста):

interface OnResultCallback {
    fun onResultReceived(value: String)
}

class MainActivity : AppCompatActivity(), OnResultCallback {
    override fun onResultReceived(value: String) {
        updateUI(value)
    }

    fun openEditActivity() {
        val intent = Intent(this, EditActivity::class.java)
        intent.putExtra("CALLBACK_EXTRA", this as OnResultCallback) // Потенциально опасно!
        startActivity(intent)
    }
}

Ключевые рекомендации и выбор подхода

  • Для стандартной задачи: Используйте современный ActivityResult API. Он интегрирован с жизненным циклом, избегает проблем с onActivityResult при повторном создании Activity и является официальной рекомендацией Google.
  • Для сложных или постоянных данных: Если передаваемые данные сложны или требуют сохранения состояния между несколькими экранами, рассмотрите Shared ViewModel (в сочетании с Jetpack Navigation это часто оптимальный выбор).
  • Устаревшие методы: startActivityForResult и LocalBroadcastManager следует избегать в новых проектах, но знать их важно для поддержки старого кода.
  • Архитектурные соображения: Передача данных назад часто является сигналом к необходимости пересмотра архитектуры. Возможно, стоит использовать один Activity с несколькими Fragment или полностью реактивную архитектуру (например, с Flow в ViewModel), где навигация и данные управляются централизованно.

Вывод: Наиболее правильным и современным ответом является реализация через ActivityResult API, предоставляющий надежный, тестируемый и интегрированный в Jetpack компонент для обработки результатов между Activity.

Как вернуть значение из Activity при навигации назад | PrepBro