Intent & Bundle

강현성·2023년 5월 1일
0

android

목록 보기
15/18

1. Intent & Bundle

Android 애플리케이션에서 Activity, Service, Broadcast Receiver, Content Provider컴포넌트 간에 통신을 하려면 Intent를 사용해야 한다. Intent 객체는 컴포넌트 간에 통신을 위한 메시지를 전달하는 역할을 하고 Bundle 객체는 통신할 때 전달할 메시지를 저장하는 역할을 한다. 즉 Bundle에 데이터를 저장해서 Intent로 데이터를 전달한다.

1-1. Intent

Intent는 Android 애플리케이션의 컴포넌트 간에 작업 요청을 전달하는 메시지 객체로 Intent를 이용해 다른 애플리케이션의 컴포넌트를 호출하거나, 자신의 컴포넌트를 호출할 수 있다. Intent는 명시적 호출과 암시적 호출로 구분된다.

명시적 호출
호출하려는 컴포넌트를 직접 지정하는 방법으로 호출하려는 컴포넌트의 패키지명과 클래스명을 지정해야 한다.

Intent intent = new Intent(this, MyActivity.class);
startActivity(intent);

암시적 호출
호출하려는 컴포넌트의 패키지명과 클래스명을 모르는 경우 사용하는 방법으로 호출하려는 작업의 내용을 지정하고, 시스템이 이 작업을 처리할 수 있는 컴포넌트를 찾아서 호출한다.

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.naver.com"));
startActivity(intent);

1-2. Bundle

Bundle은 Android에서 다양한 데이터를 저장하고 전달하기 위한 객체이다. Bundle 객체는 Map 인터페이스를 구현하므로, 키-값 쌍으로 데이터를 저장하고 추출할 수 있다.

2. Intent & Bundle 사용법

2-1. Intent.putExtra()

데이터 전달

class MainActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val intent = Intent(this, MainActivity2::class.java)
            intent.putExtra("key", "kang")
            startActivity(intent)
        }
    }
}

데이터 받기

class MainActivity2 : AppCompatActivity() {

    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        val key = findViewById<TextView>(R.id.key)

        key.text = intent.getStringExtra("key");

    }
}

Intent.putExtra() 메서드 내부 코드는 다음과 같다.

public @NonNull Intent putExtra(String name, @Nullable String value) {
    if (mExtras == null) {
        mExtras = new Bundle();
    }
    mExtras.putString(name, value);
    return this;
}

Bundle객체가 null이라면 Bundle객체를 생성한 뒤 name:value 값을 저장하고 데이터를 보낸다. 즉 Intent.putExtra() 메서드를 사용하면 Bundle객체를 생성하지 않아도 내부적으로 알아서 Bundle객체를 생성해서 값을 저장한 뒤 데이터를 보낸다.

2-2. Bundle

데이터 전달

class MainActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val intent = Intent(this, MainActivity2::class.java)
            val bundle = Bundle()
            bundle.putString("key", "kang")
            intent.putExtra("bundle", bundle)
            startActivity(intent)
        }
    }
}

데이터 받기

class MainActivity2 : AppCompatActivity() {

    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        val bundle = intent.getBundleExtra("bundle")
        val key = findViewById<TextView>(R.id.key)

        if (bundle != null) {
            key.text = bundle.getString("key")
        }
    }
}

3. Serializable & Parcelable

만약 Intent에 객체를 전달해야 한다면, Serializable이나 Parcelable을 구현한 클래스를 통해 객체를 직렬화 한 뒤 보내야 한다.

직렬화(Serialization)란 객체를 바이트 스트림으로 변환하여 전송하거나 저장하는 것을 말한다. 직렬화를 통해 객체를 전송하거나 저장할 수 있으며, 이를 역직렬화(Deserialization)하여 다시 객체로 변환할 수 있다.

3-1. Serializable

Serializable은 Java의 표준 인터페이스로 구현이 아주 간단하다. 아래 코드와 같이 class 형태에서 Serializable만 구현하면 된다.

data class User(
    val name: String?,
    val age: Int
) : Serializable

단점으로는 Parcelable보다 속도가 느리다. 왜냐하면 Serializable 인터페이스를 구현한 클래스는 직렬화될 때 reflection을 사용하여 객체의 모든 필드를 검색하고, 이를 일련의 바이트로 변환하는 방식으로 직렬화한다. (reflection은 자바에서 객체를 생성하고, 해당 객체의 메소드나 멤버 변수 등의 정보를 알아내는 기술) 때문에 런타임에 데이터를 직렬화/역직렬화하는 과정에 많은 객체를 생성하기 때문에 GC가 할 일이 많아지므로 Serializable을 사용하는 객체가 많아지면 많아질수록 성능에 안좋은 영향을 미치게 된다.

Serializable로 객체 전달

class MainActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val intent = Intent(this, MainActivity2::class.java)
            val bundle = Bundle()
            bundle.putSerializable("userData", User("kang", 27))
            intent.apply {
                this.putExtra("bundle", bundle)
            }
            startActivity(intent)
        }
    }
}

data class User(
    val name: String?,
    val age: Int
) : Serializable

객체 받기

class MainActivity2 : AppCompatActivity() {

    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        val bundle = intent.getBundleExtra("bundle")
        val name = findViewById<TextView>(R.id.name)
        val age = findViewById<TextView>(R.id.age)

        if (bundle != null) {
            val userData = bundle?.getSerializable("userData") as User
            name.text = userData.name
            age.text = userData.age.toString()
        }
    }
}   

3-2. Parcelable

Parcelable은 Java가 아닌 Android SDK의 인터페이스로 Serializable과는 다르게 reflection 과정이 없고 직렬화/역직렬화를 하는 과정을 개발자가 모두 구현한다. (kotlin에서는 plugins {id 'kotlin-parcelize'}를 통해 쉽게 구현할 수 있슴) 이렇게 구현된 코드가 미리 컴파일되어 런타임에 빠르게 처리되기 때문에 Serializable보다 빠르게 객체를 전달할 수 있다.

Parcelable 쉽게 구현하기 위해 'kotlin-parcelize' 추가

plugins {
    id 'kotlin-parcelize'
}

객체 전달

class MainActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            // bundle 안쓰고 Parcelable
            val intent = Intent(this, MainActivity2::class.java)
            intent.putExtra("userData", User("Kang", 27))
            startActivity(intent)
        }
    }
}

@Parcelize
data class User(
    val name: String?,
    val age: Int
) : Parcelable

객체 받기

class MainActivity2 : AppCompatActivity() {

    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        
        val name = findViewById<TextView>(R.id.name)
        val age = findViewById<TextView>(R.id.age)

        // bundle 안쓰고 parcelable
        val userData = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            intent.getParcelableExtra("userData", User::class.java)
        } else {
            intent.getParcelableExtra<User>("userData")
        }

        if (userData != null) {
            name.text = userData.name
            age.text = userData.age.toString()
        }
    }
}
profile
Hello!

0개의 댓글