본문 바로가기
안드로이드 공부 & 앱

[안드로이드/코틀린] activityResultLauncher(ActivityForResult 대체)

by 문톰 2022. 2. 2.

오늘은 코틀린에서는 ActivityForResult가 deperated 되어 있어서 이를 대체할 ActivityResultLanuncher

소개하겠습니다.

ActivityResultLanuncher를 사용하는 이유

-엑티비티에서 데이터를 받아오기 위해서 입니다.

엑티비티 A와 B가 있으면 A에서 B엑티비티를 생성 후에 B엑티비티에서 A엑티비티로 데이터를 받아오고 싶을 때 사용합니다.

ex)  -현재 실행중인 앱의 엑티비티A에서  갤러리 앱의 엑티비티 B로부터 사진을 갖고오고 싶을 때 

ActivityForResult가 Deperated된 이유

1)AndroidX Activity와 Fragment에 도입된 ActivityResult API 를 안드로이드 공식문서에서 적극 권장함

 

2)결과를 얻기 위해 엑티비티를 시작할 때 메모리 부족으로 인해 프로세스와 엑티비티가 소멸될 수 있음.

(특히 카메라 사용과 같이 메모리를 많이 사용하는 작업의 경우 소멸 확률이 매우 높음)

 -기존 방법은 Activity에서 startActivityResult를 통해서 콜백을 등록하고 onActivityResult에서 콜백을 처리하므로 

두 메서드가 같은 곳에서 구현을 해야하는데 메모리 부족으로 제대로 동작이 안될 수 있다.

ActivityResultLauncher와 ActivityForResult의 차이점

1)Activity ResulAPI는 다른 엑티비티를 실행하는 코드에서 결과 콜백을 분리한다.

-원래 기존의 startActivityForResult 메서드를 사용하면 항상 onActivityResult에서

콜백을 받아서 처리했지만 이렇게 할 경우 메모리가 부족해져서 Activity가 사라질

수 있다. 이 것을 방지하기 위해서 Activity를 실행하는 부분과 Result Callback 부분을

분리해서 만들어 주었다.

-registerForActivityResult() 메서드는 콜백을 등록하는 역할을 해준다.

 

2)RequestCode가 사라짐

-Result Callback 부분을 분리해서 구현했기 때문에 requestCode도 필요 없음.

 

3)Activity가 종료되었다가 다시 만들어져도 Result값을 기다리게 할 수 있음. 

3-1)A 액티비티와 B 액티비티가 있을 때,

startActivityResult메서드와 onActivityResult메서드를 사용해서 구현할 경우

  1. A -> B 실행, 메모리가 부족해서 A가 소멸됨.
  2. B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
  3. A가 소멸됐다가 다시 생성돼서 B에게 결과값을 요청한 줄 모름.

3-2)ActivityResultLauncher객체와 registerForActivityResult()를 사용한 경우

  1. A -> B 실행, 메모리가 부족해서 A가 소멸됨.
  2. B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
  3. A가 다시 생성돼도 registerForActivityResult() 메서드가 다시 콜백을 등록해 줘서 결과값을 받아온다.

 

-아직 정확하게는 이해가 아직 잘 안되지만 onCreate()에서 registerActivityResult를

사용해서 콜백메서드를 등록해주면 엑티비티가 메모리부족으로 소멸되었다가 

재생성되어도 결과값을 받아올 수 있는 것 같다.

예제

MainActivity.kt

class MainActivity : AppCompatActivity(), View.OnClickListener {
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    //ActivityResultLauncher<T>객체를 생성해주고 초기화 해준다.
    //T는 내가 호출할 엑티비티에서 결과값으로 받아올 자료형을 말한다.
    lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
    val TAG = "MainActivity"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.btnMain.setOnClickListener(this)

        //RegisterActivityResult(Contract자료형, 콜백메서드)를 이용해서
        //ActivityResultLauncher를 초기화 해준다.
        activityResultLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult())
            {//Result 매개변수 콜백 메서드
                //ActivityResultLauncher<T>에서 T를 intent로 설정했으므로
                //intent자료형을 Result 매개변수(콜백)를 통해 받아온다
                //엑티비티에서 데이터를 갖고왔을 때만 실행
                if (it.resultCode == RESULT_OK) {
                    //SubActivity에서 갖고온 Intent(It)
                    val myData: Intent? = it.data
                    val address = it.data?.getStringExtra("KEY1") ?: ""
                    Log.e(TAG, address)
                }
            }


    }


    override fun onClick(v: View?) {

        when (v?.id) {
            //버튼을 누르면 메뉴 엑티비티가 실행되게 하였다.
            //launch메서드를 이용해 intent를 실행하고 새 엑티비티로부터 응답을받는다.
            //그리고 RequestCode가 사라졌다.
            binding.btnMain.id -> {
                val intent = Intent(applicationContext, SubActivity::class.java)
                activityResultLauncher.launch(intent)
            }

            else -> {


            }
        }


    }


}

SubActivity.kt

class SubActivity : AppCompatActivity(), View.OnClickListener {
    val binding by lazy { ActivitySubBinding.inflate(layoutInflater) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.btnSub.setOnClickListener(this)
    }


    //버튼 클릭 리스너 메서드
    override fun onClick(v: View?) {
        when (v?.id) {
            binding.btnSub.id -> {
                val intent = Intent(applicationContext, MainActivity::class.java).apply {
                    //엑티비티에서 갖고올 데이터
                    putExtra("KEY1", "bbbbb")
                    //데이터 전달이 성공했을 때의 변수 값 저장
                    // Result_ok = -1 일 때 엑티비티에 전달된다.

                }
                setResult(RESULT_OK, intent)
                //엑티비티 종료
                if (!isFinishing) finish()
            }
            else -> {
            }
        }
    }

}

 

참고

https://kimyunseok.tistory.com/40

 

[Android] startActivityForResult Deprecated된 이유와 해결책

startActivityForResult()가 Deprecated되었다. 활동에서 결과 가져오기  | Android 개발자  | Android Developers 개발자 앱 내의 활동이든 다른 앱의 활동이든 다른 활동을 시작하는 것이 단방향 작업일 필요..

kimyunseok.tistory.com

https://kimyunseok.tistory.com/39?category=1035300 

 

[Android] 화면 여러개 만들어서 화면 전환하기 - onActivityResult, startActivityForResult Deprecated. registerForAc

화면 전환은 액티비티를 전환하는 것으로 이루어진다. (물론 요즘은 프래그먼트를 이용해서 많이 전환한다.) 그렇다고 액티비티만 안다고 안드로이드 앱을 잘 구성할 수 있는 것은 아니다. 안드

kimyunseok.tistory.com

https://stickode.com/detail.html?no=2415 

 

https://stickode.com/detail.html?no=2415

 

stickode.com

 

댓글