본문 바로가기
안드로이드 코틀린

[Kotlin][Android] ActivityResultAPI 사용해서 액티비티 간 데이터 주고 받기

by teamnova 2023. 8. 30.

안드로이드 개발을 진행하다 보면 단순히 액티비티를 전환하고 끝! 이 아니라

이후 발생한 액티비티에서 작업을 하고 원래 액티비티에 돌아와서 사용하고 싶은 경우가 있습니다. 

 

이럴때 이전까진 startActivityForResult() onActivityResult() 함수를 사용해서 처리해 주곤 했습니다. 그렇지만, 이미 onActivityResult는 Deprecated 된 함수입니다.

최근엔 새로운 Activity Result API 사용을 권장하고 있습니다. 다양한 Activity Result API 중 Activity 간의 Result 처리에는 ActivityResultContracts.StartActivityForResult를 사용해야 합니다.

 

오늘은 간단한 예제를 통해 전환된 액티비티에서 작업한 데이터를 받아오는 작업을 해보겠습니다.

 

다음은 전체 코드 입니다.

 

activity_test_activity_result.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActivityTestActivityResult">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="화면 이동"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.897" />

    <TextView
        android:id="@+id/data_TV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="받은값 없음"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/sendData_ET" />

    <EditText
        android:id="@+id/sendData_ET"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="text"
        android:text="보낼 데이터"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_get_data.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActivityGetData">


    <EditText
        android:id="@+id/getData_ET"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="받은 데이터"
        android:inputType="text"
        app:layout_constraintBottom_toTopOf="@+id/text_view"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="데이터를 수정하고 확인을 눌러주세요"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.367" />

    <Button
        android:id="@+id/submit_BTN"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="확인"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

ActivityTestActivityResult.kt

package com.example.stickcodepost

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import com.example.stickcodepost.databinding.ActivityTestActivityResultBinding

class ActivityTestActivityResult : AppCompatActivity() {

    // ActivityResultLauncher 인스턴스를 선언합니다.
    private lateinit var getResult: ActivityResultLauncher<Intent>

    // 전역 변수로 바인딩 객체 선언
    private var mBinding: ActivityTestActivityResultBinding? = null

    // 매번 null 체크를 할 필요 없이 편의성을 위해 바인딩 변수 재 선언
    private val binding get() = mBinding!!
    // !!는 Kotlin에서 Nullable 타입을 강제로 Non-nullable 타입으로 변환하는 것을 의미

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 자동 생성된 뷰 바인딩 클래스에서의 inflate라는 메서드를 활용해서
        // 액티비티에서 사용할 바인딩 클래스의 인스턴스 생성
        mBinding = ActivityTestActivityResultBinding.inflate(layoutInflater)
        // getRoot 메서드로 레이아웃 내부의 최상위 위치 뷰의
        // 인스턴스를 활용하여 생성된 뷰를 액티비티에 표시합니다.
        setContentView(binding.root)

        // ActivityResultLauncher를 초기화합니다.
        getResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            // 결과 처리 콜백 함수입니다.
            if (result.resultCode == RESULT_OK) {
                // 결과가 OK일 경우 처리합니다.
                val getData = result.data?.getStringExtra("returnValue")

                // 화면에 결과 데이터를 표시합니다.
                binding.dataTV.text = getData
            }
        }

        // 버튼 클릭 리스너를 설정합니다.
        binding.button.setOnClickListener {
            val strData = binding.sendDataET.text.toString()
            val mIntent = Intent(getApplicationContext(), ActivityGetData::class.java)

            // 입력한 데이터를 인텐트에 추가합니다.
            mIntent.putExtra("strData", strData)

            // getResult를 사용하여 다른 액티비티를 실행하고 그 결과를 처리합니다.
            getResult.launch(mIntent)
        }
    }
}

ActivityResultLauncher 객체를 이용해서 Callback 함수를 만들어 줍니다. 

예제에선 결과값을 result 에 담았습니다. 

해당 콜백 함수의 result 를 체크해서 RESULT_OK 값을 체크해주고

result.data? 에서 결과값을 받아올 수 있습니다. 

 

예제의 경우 getStringExtra 로 결과값을 받아오도록 했습니다. 

 

만들어진 Callback 함수를 이용해 Intent 를 실행시켜 줍니다.

 

ActivityGetData.kt

package com.example.stickcodepost

import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.stickcodepost.databinding.ActivityGetDataBinding

class ActivityGetData : AppCompatActivity() {

    // 전역 변수로 바인딩 객체 선언
    private var mBinding: ActivityGetDataBinding? = null

    // 매번 null 체크를 할 필요 없이 편의성을 위해 바인딩 변수 재 선언
    private val binding get() = mBinding!!
    // !!는 Kotlin에서 Nullable 타입을 강제로 Non-nullable 타입으로 변환하는 것을 의미

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 자동 생성된 뷰 바인딩 클래스에서의 inflate라는 메서드를 활용해서
        // 액티비티에서 사용할 바인딩 클래스의 인스턴스 생성
        mBinding = ActivityGetDataBinding.inflate(layoutInflater)
        // getRoot 메서드로 레이아웃 내부의 최상위 위치 뷰의
        // 인스턴스를 활용하여 생성된 뷰를 액티비티에 표시합니다.
        setContentView(binding.root) // < 기존의 setContentView는 주석 처리해 주세요!

        // 인텐트로부터 전달된 데이터를 가져옵니다.
        val strData = intent.getStringExtra("strData")

        // 가져온 데이터를 EditText에 설정합니다.
        binding.getDataET.setText(strData.orEmpty())

        // 리스너 초기화 메서드를 호출합니다.
        initListener()
    }

    private fun initListener() {
        // 버튼 클릭 리스너를 초기화합니다.

        binding.submitBTN.setOnClickListener {
            // 결과를 담을 인텐트를 생성합니다.
            val intent = Intent()
            // EditText에서 데이터를 가져와서 인텐트에 추가합니다.
            val data = binding.getDataET.text.toString()
            intent.putExtra("returnValue", data)
            // 결과 코드와 인텐트를 설정하고 현재 액티비티를 종료합니다.
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
}

이동한 액티비티 에서 변경된 데이터를 돌려 줄때 성공여부에 대해 setResult() 에서 첫번째 파라미터 값이 값 을 주면  원래 액티비티에서 돌아갔을때  해당 값을 처리해줄 수 있습니다. 

예제 실행 화면

 

예제를 실행시켜 보겠습니다. 

 

최초에 testData 를 작성해서 다음 액티비티로 보내줍니다.

이동한 액티비티에서 받은 testData 를 modifydata 로 변경해주고 확인 버튼을 누르면 본래 Activity 로 돌아오고 

변경 된 값을 받아온것을 볼 수 있습니다.