onActivityResult для фрагмента

Предположим, вас занесло в чудный мир программистов для Андроид. Вы прониклись туториалами и описаниями об Активностях и Фрагментах. Начали красиво писать первые скромные поделки… Хорошо? Благодать? Уже расслабились и получаете удовольствие? А вот тут раз и из-за угла вам лопатой!

Дело было так. Вы написали Активность, а в неё чудесно вписали красивый Фрагментик. Но вы же захотели большего — вызвать из этого Фрагментика на экран другую Активность! Эка наглость… Не просто вызвать, а вызвать для результата. То есть, она для вас должна вернуть полезные данные.

Кусок текста Фрагмента:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class LittleFragment: Fragment() {
  …
    // На нажатие волшебной кнопки
    fun onClick() {
        // Формируем запрос и отправляем его, ожидая в ответ полезные данные
        val intent =
        startActivityForResult(intent, REQUEST_DATA)
    }
  …
    // Ловушка для полезных данных
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "onActivityResult(requestCode = $requestCode, resultCode = $resultCode)")
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                REQUEST_DATA ->
                    updateSomething()
                else ->
                    Log.e(TAG, "onActivityResult: wrong request code!")
            }
        }
    }
  …
}

Начинаете эксперименты… Продолжаете эксперименты… Продолжаете… Но ловушка просто так работать отказывается. После недолгих скитаний от кофемашины до компуктера, от балкона до кота, становится ясно, что ответ получает ловушка, расположенная у родительской Активности! Вот ведь… Чего ж нас раньше в детском садике не предупредили? Тупо копируем нашу ловушку в Активность — в ответ граблями по наглой морде:

Родительская активность получает ответ немного другой формы. Хуже того, у родительской Активности могут быть свои котлеты и перемешивать их с кодами запросов нашего фрагмента — как-то не по-джентельменски. Возвращаем ловушку обратно, а у родительской Активности пишем закленания:

Код родительской Активности:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MainActivity : AppCompatActivity() {
  …
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "onActivityResult(requestCode = $requestCode, resultCode = $resultCode)")
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                REQUEST_DATA1_FOR_MAIN_ACTIVITY -> {
                    // …
                }
                REQUEST_DATA2_FOR_MAIN_ACTIVITY -> {
                    // …
                }
                else -> {
                    // Если ожидаемые коды не подходят — пытаемся определить дочерний Фрагмент,
                    // инициировавший происходящие события. requestCode в старших разрядах содержит индекс:
                    val fragmentIndex = requestCode.shr(16)
                    if (fragmentIndex>0) {
                        // Надо передать дочернему фрагменту
                        val fragments = supportFragmentManager.fragments
                        if (fragmentIndex>fragments.size)
                            Log.e(TAG, "onActivityResult: wrong request code!")
                        else {
                            Log.i(TAG, "onActivityResult: transfer result to fragment.")
                            fragments[fragmentIndex-1].onActivityResult(
                                    requestCode.and(0xFFFF),
                                    resultCode, data)
                        }
                    }
                }
            }
        }
        super.onActivityResult(requestCode, resultCode, data)
    }

Такому в Хогвардсе не учат. Это жизнь, детка!