개요

코틀린을 사용하여 안드로이드 앱을 개발할 때, 액티비티(Activity)는 화면을 구성하는 기본 단위입니다.
이 포스트에서는 액티비티 간의 화면 전환 방법, 데이터 전달, 그리고 여러 액티비티를 거쳐 최종 액티비티로 돌아오는 방법을 설명합니다.

서브 액티비티 만들기

먼저 새로운 서브 액티비티를 만들어야 합니다.

프로젝트에 새로운 액티비티 추가하기

  • Android Studio에서 패키지 이름을 우클릭한 후, New > Activity > Empty Views Activity를 선택합니다.
  • Activity Name을 적당한 이름으로 설정합니다 (예: SubActivity).
  • Finish를 눌러 생성합니다.

기본 액티비티 구성

먼저, 메인 액티비티와 서브 액티비티를 설정해보겠습니다.
메인 액티비티에서는 서브 액티비티를 시작하고, 서브 액티비티에서는 사용자가 입력한 데이터를 다시 메인 액티비티로 반환하는 구조를 갖습니다.

Main Activity

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    // ActivityResultLauncher 선언
    private val activityResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.getStringExtra("returnValue")?.let { message ->
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }
    }

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

        binding.btnStart.setOnClickListener {
            val intent = Intent(this, SubActivity::class.java)
            intent.putExtra("from1", "hello Bundle")
            intent.putExtra("from2", 12345)
            activityResultLauncher.launch(intent)  // startActivityForResult 대신 사용
        }
    }
}

Sub Activity

class SubActivity : AppCompatActivity() {

    private val binding by lazy { ActivitySubBinding.inflate(layoutInflater) }

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

        with(binding) {
            to1.text = intent.getStringExtra("from1")
            to2.text = "${intent.getIntExtra("from2", 0)}"

            btnClose.setOnClickListener {
                val returnIntent = Intent()
                val message = editMessage.text.toString() // 사용자 입력
                returnIntent.putExtra("returnValue", message) // 결과 데이터 설정
                setResult(Activity.RESULT_OK, returnIntent) // 결과 코드 및 데이터 설정
                finish() // 서브 액티비티 종료
            }
        }
    }
}

화면 전환 및 데이터 전달 방법

서브 액티비티 호출하기

  • MainActivity에서 버튼 클릭 시 Intent를 사용하여 SubActivity를 호출합니다. 이때, putExtra 메서드를 사용하여 서브 액티비티로 전달할 데이터를 설정합니다.
binding.btnStart.setOnClickListener {
    val intent = Intent(this, SubActivity::class.java)
    intent.putExtra("from1", "hello Bundle") // 문자열 데이터
    intent.putExtra("from2", 12345) // 정수 데이터
    activityResultLauncher.launch(intent)  // 서브 액티비티 호출
}

서브 액티비티에서 데이터 수신하기

  • SubActivity에서는 intent 객체를 통해 메인 액티비티에서 전달받은 데이터를 수신합니다.
    to1은 문자열을, to2는 정수 데이터를 보냈기에 getStringExtragetIntExtra 메서드를 사용하여 데이터를 가져옵니다.
to1.text = intent.getStringExtra("from1") // 문자열 데이터 표시
to2.text = "${intent.getIntExtra("from2", 0)}" // 정수 데이터 표시

서브 액티비티에서 메인 액티비티로 데이터 반환하기

  • 사용자가 입력한 데이터를 Intent에 담아 메인 액티비티로 반환합니다.
    setResult 메서드를 사용하여 결과 코드를 설정하고, finish()를 호출하여 서브 액티비티를 종료합니다.
btnClose.setOnClickListener {
    val returnIntent = Intent()
    val message = editMessage.text.toString() // 사용자 입력
    returnIntent.putExtra("returnValue", message) // 결과 데이터 설정
    setResult(Activity.RESULT_OK, returnIntent) // 결과 코드 및 데이터 설정
    finish() // 서브 액티비티 종료
}

메인 액티비티에서 서브 액티비티의 결과 처리하기

  • MainActivity에서는 ActivityResultLauncher를 사용하여 서브 액티비티의 결과를 처리합니다.
    서브 액티비티에서 반환된 데이터는 onActivityResult 메서드에서 확인할 수 있습니다.
private val activityResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.getStringExtra("returnValue")?.let { message ->
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show() // 반환된 데이터 표시
        }
    }
}

이러한 방법으로 메인 액티비티와 서브 액티비티 간에 데이터를 전달하고, 사용자 입력에 따라 메인 액티비티로 데이터를 반환하는 기능을 구현할 수 있습니다.
각 단계에서 Intent를 활용하여 간편하게 데이터를 주고받을 수 있으므로, 여러 화면 간의 원활한 데이터 처리가 가능합니다.

Q&A

startActivity(intent)activityResultLauncher.launch(intent)의 차이점

startActivity(intent)

  • 용도: 새로운 액티비티를 시작할 때 사용합니다.
  • 장점
    • 간단하게 새로운 액티비티를 시작할 수 있습니다.
    • 결과를 받지 않고 단순히 화면 전환만 필요할 때 적합합니다.
  • 단점
    • 이전 액티비티로부터의 결과를 받을 수 없습니다.

activityResultLauncher.launch(intent)

  • 용도: 새로운 액티비티를 시작하고, 그 액티비티에서 결과를 반환받기 위해 사용합니다.
  • 장점
    • 시작한 액티비티에서 반환된 결과를 쉽게 처리할 수 있습니다.
    • 결과 코드와 데이터를 직접 받아올 수 있어, 보다 유연한 처리가 가능합니다.
  • 단점
    • 모든 액티비티에 대해 결과가 필요하지 않을 때 사용하기엔 다소 복잡할 수 있습니다.

정리

  • 만약 서브 액티비티에서 결과를 메인 액티비티로 보내야 한다면activityResultLauncher.launch(intent)를 사용하는 것이 좋습니다.
  • 반면에 단순히 화면을 전환하고, 결과가 필요하지 않을 경우에는 startActivity(intent)를 사용하는 것이 더 간단하고 효율적입니다.

finish()는…

메인 액티비티에서 서브 액티비티로 이동할 때는 val intent = Intent(this, SubActivity::class.java) 라고 확실히 지정을 해줬는데, 돌아올때는 메인 액티비티로 간다는 명령이 없는 이유가 무엇때문인지 궁금할 수 있습니다.

이 부분은 안드로이드 액티비티의 생명주기인텐트의 흐름을 이해하는 데 중요한 개념입니다.
간단히 설명하자면, 서브 액티비티에서 finish() 메서드를 호출할 때, 이전 액티비티(즉, 메인 액티비티)로 돌아가는 것입니다.

finish() 메서드는 현재 액티비티를 종료하는 역할을 합니다.
이 메서드를 호출하면 현재 액티비티의 생명주기가 종료되고, 다시 이전 액티비티로 돌아가게 됩니다.