빙수왕의 개발일지

Activity에서 Activity로 값 전달하기 본문

개발/Android

Activity에서 Activity로 값 전달하기

빙수킹 2020. 8. 6. 02:00

Q) MainActivity에서 DestinationAcitivity로 "value1"과 "value2"를 전달하자.

 -> 결론은 맨밑에 있음,,

 

1. 그저그런 방법

 

- 코틀린 허접인 나는 자바에서 많이 쓰던 방식을 그대로 사용했는데 .. 더 발전할 방향이 많다. 이렇게는 쓰지말자.. 흑흑

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intent: Intent = Intent(applicationContext, DestinationActivity::class.java)
        // 다른 곳의 companion object의 값들 쓸 떄 임포트 하지말자.
        // 이유는 가독성 때문에! 어디서 온 앤지 한눈에 알기 힘들다..
        intent.putExtra(DestinationActivity.VALUE_ONE, "value1")
        intent.putExtra(DestinationActivity.VALUE_TWO, "value2")
        startActivity(intent)
        
        // 더 자세히 공부할 것 ::에 대하여..
        // ::는 그 클래스의 클래스..(?)라는데 찾아보자.
}

 

DestinationActivity.kt

class DestinationActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_destination)
        val value1 = intent.getStringExtra(VALUE_ONE)
        val value2 = intent.getStringExtra(VALUE_TWO)
    }

    // 선언 위치는 주체가 되는 쪽. 값을 받아서 사용하는 쪽. 호출하는 쪽에서보단 받는쪽이 좋다!
    companion object {
        const val VALUE_ONE = "value1"
        const val VALUE_TWO = "value2"
    }
}

 

 

2. 세련된 방법

 

*  Kotlin의 스코프 함수를 사용했다. apply와 run

- 뭔가 코틀린스러워졌고 멋있어보인다. 왠지모르게 가독성이 좋다고 해야할 것 같다.

- apply는 주로 초기화 목적으로 사용되는 스코프 함수이고, 반환값이 수신 객체 자신이다.

- run은 이미 생성된 객체에 뭔가 작업이 필요할 때 사용하고, 반환값이 실행의 결과다. (받은 객체가 아님!)

 

* bundleOf를 사용하여 내용을 보냈다.

- bundleOf의 파라미터는 가변인자로 된 Pair형태다. 그래서 Pair 친구들을 보내야 하는데 여기서는 Pair(key,  value) 이렇게 쓰기보다 "key to value" 와 같이 쓰는 방법을 사용했다. 이건 확실히 가독성이 더 좋은 것 같다.

- bundleOf의 장점은 Parcelable을 기본으로 사용하는 것이라고 한다. (Serializable보다 Parcelable이 성능이 좋음. 왜?)

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Intent(applicationContext, DestinationActivity::class.java).apply {
            putExtras(bundleOf(
                DestinationActivity.VALUE_ONE to "value1",
                DestinationActivity.VALUE_TWO to "value2"
            ))
        }.run { 
            startActivity(this)
        }
}

 

DestinationActivity.kt

class DestinationActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_destination)
        val value1 = intent.extras?.get(VALUE_ONE)
        val value2 = intent.extras?.get(VALUE_TWO)
    }

    // 선언 위치는 주체가 되는 쪽. 값을 받아서 사용하는 쪽. 호출하는 쪽에서보단 받는쪽이 좋다!
    companion object {
        const val VALUE_ONE = "value1"
        const val VALUE_TWO = "value2"
    }
}

 

 

3. 더 나은 방법

 

* Extension을 추가했다.

- startActivity라는 확장함수를 추가해서 액티비티에 value를 실어보내는 일련의 코드들을 완전 많이 줄였다. 한 번 선언해놓으면 훌륭하게 쓰일 것 같다.

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        startActivity<DestinationActivity>(
            DestinationActivity.VALUE_ONE to "value1",
            DestinationActivity.VALUE_TWO to "value2"
        )
}

 

MyExtensions.kt

- extension이라는 패키지를 따로 만들고 그 안에 "MyExtensions.kt" 파일을 만들어서 추가해주었다. 

- Anko라는 라이브러리에서 같은 기능을 제공했는데 이제는 deprecated 되었다고 한다. 참고하여 extension에 추가하면 된다고 함.

package com.example.lesson1.extension

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf


inline fun <reified T: AppCompatActivity> Context.startActivity (
    vararg extras: Pair<String, Any?>, // vararg는 가변인자. 원하는 갯수대로 넣기 가능 ~
    intentAction: Intent.() -> Unit = {} // 고차함수 사용. 
    // 이 파라미터를 받으므로 인해서 함수(){"후처리내용"} 이런식으로 사용 가능하다.
    // 스위프트의 후행클로저처럼..!
) {
    startActivity(Intent(this, T::class.java).apply {
        putExtras(bundleOf(*extras))
        intentAction()
    })
}
// 더 추가할 내용: 여기에 쓰인 inline, refied, 제너럴, <>, * 은 무엇인가?

 

DestinationActivity.kt

- 똑같쥬

class DestinationActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_destination)
        val value1 = intent.extras?.get(VALUE_ONE)
        val value2 = intent.extras?.get(VALUE_TWO)
    }

    // 선언 위치는 주체가 되는 쪽. 값을 받아서 사용하는 쪽. 호출하는 쪽에서보단 받는쪽이 좋다!
    companion object {
        const val VALUE_ONE = "value1"
        const val VALUE_TWO = "value2"
    }
}

 

 

4. 오지는 방법

 

- 오지는건 내 개인적인 판단기준이다. 1이 내 코드였으므로 비교하면 거의 원시인에서 현대인으로 진화하엿음.

* startActivity 함수를 DestinationActivity의 companion object에 만들었다.

- 이렇게 하면 좋은점이. startActivity()할 때 에러가 안나니까 추가한 내용들을 놓칠 수 있는데, 이런식으로 하게되면 빌드 시 에러가 나서 조금 더 안전한 코드를 짤 수 있다!!

 

MainActivity.kt

- 한줄밖에 안된다!! 대박

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DestinationActivity.startActivity(applicationContext, "value1", "value2")
}

 

MyExtensions.kt

- 3과 same same

package com.example.lesson1.extension

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf


inline fun <reified T: AppCompatActivity> Context.startActivity (
    vararg extras: Pair<String, Any?>, // vararg는 가변인자. 원하는 갯수대로 넣기 가능 ~
    intentAction: Intent.() -> Unit = {} // 고차함수 사용. 
    // 이 파라미터를 받으므로 인해서 함수(){"후처리내용"} 이런식으로 사용 가능하다.
    // 스위프트의 후행클로저처럼..!
) {
    startActivity(Intent(this, T::class.java).apply {
        putExtras(bundleOf(*extras))
        intentAction()
    })
}
// 더 추가할 내용: 여기에 쓰인 inline, refied, 제너럴, <>, * 은 무엇인가?

 

DestinationActivity.kt

- companion object에 함수를 만들어주었다.

class DestinationActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_destination)
        val value1 = intent.extras?.get(VALUE_ONE)
        val value2 = intent.extras?.get(VALUE_TWO)
    }

    // 선언 위치는 주체가 되는 쪽. 값을 받아서 사용하는 쪽. 호출하는 쪽에서보단 받는쪽이 좋다!
    companion object {
        const val VALUE_ONE = "value1"
        const val VALUE_TWO = "value2"
        
        // 여기에 start 함수를 만들어줌. 어디서 이 액티비티를 호출하든 전달인자 필수요건으로 붙이기 가능.
        // 이 안에 내용 적어서 MainActivity에서 DestinationActivity.start(this, "value1", "value2") 이렇게 호출한다.
        // 이렇게 하면 좋은점이. startActivity()할 때 에러가 안나니까 추가한 내용들을 놓칠 수 있는데, 이런식으로 하게되면 빌드 시 에러가 나서 조금 더 안전한 코드를 짤 수 있다!!
        fun startActivity(context: Context, value1: String, value2: String){
            context.startActivity<DestinationActivity>(
                VALUE_ONE to value1,
                VALUE_TWO to value2
            )
        }
    }
}