[안드로이드] fragment의 startActivityForResult() 고찰

1 minute read

activity 에서 startActivityForResult를 할 경우는 직관적으로 해당 activity의 onActivityResult()를 바로 진입함을 알 수있다.

그런데 activity 안의 fragment 에서 startActivityForResult를 실행할 경우 onActivityResult()를 해당 activity 에서 처리를 해줘야 할까? 아니면 fragment에서 처리를 해줘야 할까?

androidx.fragment.app.FragmentActivity 의 startActivityForResult << not this case
androidx.fragment.app.Fragment의 startActivityForResult << this case

정석적으로는 fragment에서 받아주는게 맞다. 그러나 activity에서도 처리를 할 수 있긴하다.

test requestCode는 111

logcat을 보면

                                                                requestCode/resultCode/data.getIntExtra()
D/TestActivity:     >>  onActivityResult:  ####  up super       65647 -1 100  
D/BlankFragment0:   >>  onActivityResult:  ####  up super       111 -1 100
D/BlankFragment0:   >>  onActivityResult:  ####  bottom super   111 -1 100 
D/TestActivity:     >>  onActivityResult:  ####  bottom super   65647 -1 100 

즉 fragment 에서 startActivityForResult()을 호출할 경우 이 순서로 실행되고 requsetCode는 해당 fragment에서만 같다. 그러나 resultCode나 data는 동일하게 이동하는것을 볼 수 있다.

좋은 방법은 아니지만 특별한 경우(어쩔수 없는 경우)에는 activity의 onActivityResult에서 처리를 해주어도 될것 같다.

(in activity)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?){
        //1 (순서)
        super.onActivityResult(requestCode, resultCode, data)--->@
        //4
}

(in fragment)
@--->override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?){
        //2
        super.onActivityResult(requestCode, resultCode, data)
        //3
}
//activity의 super.onActivityResult(requestCode, resultCode, data) 을 호출하면 
//아래 코드를 지나고 여기서 (*) onActivityResult를 호출함을 볼 수 있다.
Fragment targetFragment = mFragments.findFragmentByWho(who);
if (targetFragment == null) {
    Log.w(TAG, "Activity result no fragment exists for who: " + who);
} else {
    //(*)
    targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);
}
return;

여기서 activity의 requestCode는 65647로 나오는데 이는 (Fragment)startActivityForResult()가 맨처음 호출되고 바로 host인 그 내부에서 바로

mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options);

를 호출한다. 여기서 또

ActivityCompat.startActivityForResult(
                    this, 
                    intent, 
                    ((requestIndex + 1) << 16) + (requestCode & 0xffff), 
                    options);

을 호출하는데 여기서 위의 (activity의 onActivityResult)1번이 호출되고 위의 shift연산이 65647을 생성하게 된다. 그리고 (FragmentActivity) 내부의 onActivityResult()에서 이 65647를 다시 (requestCode & 0xffff) 으로 원래 requestCode로 변경해 놓고 fragment의 onActivityResult에서 제대로 된 requestCode를 넘겨준다.

shift 연산이 친숙하진 않는데 위의 계산대로 해보면 이렇게 나오는걸 보면 대충 이해할 수 있을듯 하다.

println(Integer.toBinaryString(65647))      10000000001101111
println(Integer.toBinaryString(111))                  1101111
println(Integer.toBinaryString(0xffff))      1111111111111111

전부를 디버깅 ((F7)step into로 )하는것은 좀 아니지만 끊어가면서 한번은 해볼 가치가 있을 듯 하다.



디버깅하면서 느낀점

  • cpu의 속도를 새삼 느끼고
  • android sdk 개발자들의 레벨을 어느정도 느끼고
  • 가야할 길이 멀다는것을 느낌

Leave a comment