Developing Myself Everyday
article thumbnail
Published 2023. 5. 30. 19:25
Serializable & Parcelable Android

안드로이드 앱을 개발할 때 데이터를 전달해야 하는 경우가 있다. 이 때 복잡한 클래스의 객체를 이동하려는 경우 Serializable 또는 Parcelable을 사용해 직렬화하여 데이터를 전달해야 한다. 이제부터 이 2가지에 대해서 알아보도록 하겠다.

 

※ 직렬화란?
메모리 내에 존재하는 정보를 보다 쉽게 전송 및 전달하기 위해 바이트 코드 형태로 나열하는 것 JVM의 메모리에 상주 되어있는 객체 데이터를 바이트 형태로 변환하는 기술

 

 

Serializable


자바에서는 Value Object를 쉽게 직렬화 하기위해 Android SDK가 아닌 표준 자바의 인터페이스인 Serializable 이라는 인터페이스가 있다. 이 인터페이스를 구현한 클래스는 다음과 같다.

 

 

 By Java

import java.io.Serializable;

public class Person implements Serializable {

    private String firstName;
    private String lastName;
    private int age;


    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

 

By Kotlin

import java.io.Serializable

class Person(val firstName: String, val lastName: String, val age: Int) : Serializable

 

코틀린에서는 Serializable의 구현은 매우 간단하다. Serializable은 해당 클래스가 직렬화 대상이라고 알려주기만 할뿐 어떠한 메서드도 가지지 않는 단순한 마커 인터페이스이므로, 사용자는 매우 쉽게 사용할 수 있다.

 

그런데 사용방법이 쉽다는 것은 시스템 적인 비용이 비싸다는 것을 의미한다.

 

Serializable는 내부에서 리플렉션을 사용해 직렬화를 처리한다.

 

 

Parcelable


Parcelable은 직렬화를 위한 또 다른 인터페이스이다. Parcelable는 Serializable과는 달리 표준 자바가 아닌 Android SDK의 인터페이스이다.

 

Parcelable는 Serializable과는 달리 리플렉션을 사용하지 않도록 설계되었다. Parcelable는 사용자가 직렬화 처리 방법을 명시적으로 작성하기 때문에 자동으로 처리하기 위한 리플렉션이 필요없다.

 

 

 By Java

import android.os.Parcel;
import android.os.Parcelable;

public class Person implements Parcelable {

    private String firstName;
    private String lastName;
    private int age;


    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.firstName);
        dest.writeString(this.lastName);
        dest.writeInt(this.age);
    }

    protected Person(Parcel in) {
        this.firstName = in.readString();
        this.lastName = in.readString();
        this.age = in.readInt();
    }

    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel source) {
            return new Person(source);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
}

 

 

By Kotlin

import android.os.Parcel
import android.os.Parcelable
import android.os.Parcelable.Creator

class Person : Parcelable {
    var firstName: String?
    var lastName: String?
    var age: Int

    constructor(firstName: String?, lastName: String?, age: Int) {
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
    }

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(firstName)
        dest.writeString(lastName)
        dest.writeInt(age)
    }

    protected constructor(`in`: Parcel) {
        firstName = `in`.readString()
        lastName = `in`.readString()
        age = `in`.readInt()
    }

    companion object {
        val CREATOR: Creator<Person> = object : Creator<Person?> {
            override fun createFromParcel(source: Parcel): Person? {
                return Person(source)
            }

            override fun newArray(size: Int): Array<Person?> {
                return arrayOfNulls(size)
            }
        }
    }
}

 

 

Parcelable을 사용하려면 구현해야 하는 필수 메서드가 존재한다. 때문에 클래스에 보일러 플레이트 코드가 추가되게 된다. 이는 클래스를 이해 하기 어렵고, 새로운 기능을 추가하기 힘들게 만든다. 또한 코드의 추가로 클래스가 복잡해 질수록 유지 보수가 어려워지는 원인이 된다.

 

이런 문제를 해결하는 방법이 있다. @Parcelize 어노테이션으로 Parcelable의 보일러 플레이트 코드를 구현하지 않아도 되게 해주는 코틀린 플러그인이 존재한다. 이를 구현하는 법은 다음과 같다.

 

플러그인에 다음의 코드를 추가하면 @Parcelize 어노테이션을 사용하기 위한 설정은 완료된다.

plugins {
   --
   id 'kotlin-parcelize'
}

 

By Kotlin with @Parcelize

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
class Person(val firstName: String, val lastName: String, val age: Int) : Parcelable

 

위의 코드를 보게 되면 확연히 코드가 간결해진것을 확인할 수 있다.

 

 

Parcelable VS Serializable


 

 

위의 그림을 보게 되면 Parcelable 이 Serializable 보다 훨씬 빠르고 좋다고 말하고 있다. 그렇다면 도대체 어떤 것을 사용해야 할까?

Parcelable 이 Serializable 보다 훨씬 빠르고 좋다는 장점이 존재하지만 보일러 플레이트 코드를 생성해야 한다는 문제가 발생한다. 하지만 코틀린에서는 이를 해결할 수 있는 플러그인이 존재한다. 

 

내 생각은 이런 단점이 해결되었다면 Parcelable을 사용하지 않을 이유가 없다고 생각한다.

 

 

Reference

 

Parcelable vs Serializable , 정말 Serializable은 느릴까?

원문 : “Parcelable vs Serializable”

medium.com

 

Parcelable vs Serializable

 

www.developerphil.com

profile

Developing Myself Everyday

@배준형

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!