본문 바로가기
안드로이드 공부 노트/Compose(컴포즈)

[Android-Compose] 안드로이드 컴포즈 rememberLauncherForActivityResult(registerForActivityResult)사용법

by 지게요 2023. 9. 27.
728x90
반응형

이번 포스팅은 XML에서 액티비티끼리 데이터를 주고받을 때 사용하는 registerForActivityResult를 Compose에서 사용하는 방법을 공부해 보겠다!

만약 프로젝트 구성을 Compose Only면 필요 없을지도 모르지만 XML + Compose을 혼합해서 사용한다면 Compose -> Acltitly -> 원래 Compose로 데이터를 전달해야 할 경우가 생긴다. 이럴 경우 어떤 식으로 해결하는지 아래 예제로 알아보자!

# 사용법

공식 문서에서 보면 이미지를 가져오는 예제가 있다. 보통 예제는 권한을 확인하거나 공식 문서처럼 이미지를 가져오는 예제이다.

여기서는 간단한 데이터를 가져오는 예제를 할 것이다.

예제의 순서를 설명하자면

1. Composable 함수인  A Screen에서 Activity인 B Activity로 이동

2. B Activity에서 A Screen로 값 전달 

이렇게 하면 예제는 끝난다.

 

## A Screen.kt (Composable)

@Composable
fun AScreen(){
    var userName by remember {
        mutableStateOf("")
    }
    var userAge by remember {
        mutableStateOf("")
    }

    //// rememberLauncherForActivityResult로 생성
    val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { result ->
        //// 넘어온 값이 RESULT_OK이면 getStringExtra로 값 가져오기
        if (result.resultCode == Activity.RESULT_OK) {
            val data = result.data
            userName = data?.getStringExtra("NAME")?:""
            userAge = data?.getStringExtra("AGE")?:""
        }
    }
    val context = LocalContext.current

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ){
        Text(
            text = "유저 이름은? ${userName.ifBlank {"빈값"}}",
            fontSize = 24.sp,
            fontWeight = FontWeight.W700,
            textAlign = TextAlign.Center
        )
        Spacer(modifier = Modifier.height(20.dp))
        Text(
            text = "유저 나이는? ${userAge.ifBlank {"빈값"}}",
            fontSize = 24.sp,
            fontWeight = FontWeight.W700,
            textAlign = TextAlign.Center
        )
        Spacer(modifier = Modifier.height(20.dp))
        Button(onClick = {
            //// 위에서 만든 launcher를 이용해 launch후 실행할 Intent를 만들어준다.
            launcher.launch(Intent(context, BActivity::class.java))
        }) {
            Text(
                text = "B액티비티로 이동"
            )
        }

    }
}

## B Activity.kt

class BActivity : AppCompatActivity() {
    private lateinit var binding: ActivityBactivityBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityBactivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.btnSave.setOnClickListener {
            val resultIntent = Intent()
            val name = binding.inputName.text.toString()
            val age = binding.inputAge.text.toString()

            //// 위에서 가져온 Intent를 이용해 putExtra로 값을 보냄
            resultIntent.putExtra("NAME",name)
            resultIntent.putExtra("AGE",age)

            //// setResult를 사용해 RESULT_OK 코드와 만든 resultIntent를 넘겨준다
            setResult(Activity.RESULT_OK, resultIntent)
            finish()
        }

    }
}

위는 전체적인 코드이다 이 코드에서 볼 것은 주석 부분을 보면 된다. 이제 하나씩 살펴보자! 

##1단계 Composable에서 rememberLauncherForActivityResult을 생성

액티비티끼리 통신에서는 registerForActivityResult를 사용했는데 위에서 설명한 
rememberLauncherForActivityResults는 컴포즈용 registerForActivityResult라고 보면 된다.
이제 rememberLauncherForActivityResults가 뭔지 알아보자!

공식 홈페이지: https://developer.android.com/reference/kotlin/androidx/activity/compose/package-summary#rememberLauncherForActivityResult(androidx.activity.result.contract.ActivityResultContract,kotlin.Function1)

 우선 첫 번째 인자로는 공식문서의 사진으로 보시는 거와 같이 ActivityResultContract 객체를 넣어야 한다. 

ActivityResultContract객체로는 아래 사진과 같이 공식문서 가면 나와있으니 참조 바람

우리는 저 많은 객체 중 ActivityResultContracts.StartActivityForResult()를 사용할 것이다. 그래서 첫 번째 인자로는 ActivityResultContracts.StartActivityForResult() 넣어주고, 두 번째 인자로는 onResult라고 반환함수가 들어온다 이 부분은 이제 우리가 익숙하던 방식으로 getStringExtra, getIntExtra로 값을 가져와 처리해주면 된다.

참고로 넘어온 값은 onResult에 반환된 값. data후 getStringXXX를 해줘야 하는 점을 기억해야 한다.

##2단계 rememberLauncherForActivityResult로 만든 객체를 launch후 실행할 Intent를 만들어준다

  Button(onClick = {
            //// 위에서 만든 launcher를 이용해 launch후 실행할 Intent를 만들어준다.
            launcher.launch(Intent(context, BActivity::class.java))
        }) {
            Text(
                text = "B액티비티로 이동"
            )
        }

위 예제에서는 rememberLauncherForActivityResult로 만든 객체이름을 launcher로 해줬기 때문에 launch를 해준다.
첫 번째 인자로 실행하고 싶은 액티비티를 인텐트로 만들어서 넣어 준다!
이러면 2단계 작업은 끝이다.

##3단계 넘어간 액티비티에서 하고 싶은 작업이 끝나면 Intent를 가져온 후 putExtra를 이용해 값을 넘겨주고 setResult를 사용

    binding.btnSave.setOnClickListener {
            val resultIntent = Intent()
            val name = binding.inputName.text.toString()
            val age = binding.inputAge.text.toString()

            //// 위에서 가져온 Intent를 이용해 putExtra로 값을 보냄
            resultIntent.putExtra("NAME",name)
            resultIntent.putExtra("AGE",age)

            //// setResult를 사용해 RESULT_OK 코드와 만든 resultIntent를 넘겨준다
            setResult(Activity.RESULT_OK, resultIntent)
            finish()
        }

위 예제에서는 btnSave라는 버튼을 클릭하면 name, age해당 EditText에 있는 text를 기존 액티비티끼리 값 전달 하는 것처럼 putExtra와 setResult를 사용해 넘기면 된다.
여기서 기존 액티비티는 어떤 식으로 처리하는지가 궁금하다면 클릭하길 바란다! 

##4단계 돌아온 Composable 함수에서 1단계의 rememberLauncherForActivityResult의 콜백으로 넘어온 값을 확인

val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { result ->
        //// 넘어온 값이 RESULT_OK이면 getStringExtra로 값 가져오기
        if (result.resultCode == Activity.RESULT_OK) {
            val data = result.data
            userName = data?.getStringExtra("NAME")?:""
            userAge = data?.getStringExtra("AGE")?:""
        }
    }

이 예제에서는 넘어온 콜백 값 중 resultCode가 RESULT_OK이면 result의 data를 호출해 getStringExtra로 가져오는 로직이다!
그래서 이렇게 모든 단계를 차례대로 하다 보면 값 전달이 된다!

 
반응형