출처: https://www.edwith.org/boostcourse-android/lecture/17066/



1. Serializable & Parcelable


부가데이터

부가데이터는 시스템에서 건드리지 않고 전달만 되며 인텐트 안에 번들(Bundle) 객체가 들어가 있어 

그 안에 데이터를 넣을 때는 putExtra() 메서드, 데이터를 가져올 때는 getExtra() 메소드를 사용한다.


배경

Integer, String과 같은 기본 자료형들이 아닌 아래의 Person과 같이 직접 정의하는 객체가 있다.

1
2
3
4
5
6
public class Person {
    String name;
    int age;
    String phoneNumber;
    String address;
}
cs

Person과 같이 여러 개의 속성이 들어가 있는 객체의 정보들을 전달하려 할 때 Person 클래스 자체를 putExtra(), getExtra()할 수 없다.

즉, 기본 자료형이 아닌 객체는 전달할 수 없기 때문에, 속성마다 일일이 putExtra(), getExtra()를 나누어 넣어야 하는 불편함이 있다. 

그렇기 때문에 이 경우에는 Person 클래스 객체를 바이트 코드로 변환하는 직렬화(Serialization) 작업을 거쳐야 한다.

직렬화: http://qlyh8.tistory.com/97 


직렬화 방법

표준 자바 인터페이스인 Serializable 객체를 이용해 부가데이터로 넣어 전달할 수 있다.

Serializable보다 좀 더 메모리 용량을 적게 차지하는 Android 전용 인터페이스인 Parcelable 객체를 만들어 전달할 수도 있다.


사용방식

ArrayList와 같은 객체들은 이미 Serializable 인터페이스를 구현하고 있으므로 그대로 부가데이터로 추가할 수 있으며, 

그 외에 Person과 같이 직접 정의하는 객체들은 Parcelable 인터페이스를 구현한 후 부가데이터로 추가한다.


성능

Parcelable는 안드로이드 개발에 최적화 되어 있기 때문에 Serializable 보다 속도가 더 빠르다.

Serializable은 Reflection 방법을 사용하여 직렬화를 하는데, Parcelable 은 프로그래머가 직접 직렬화를 구현하기 때문에 빠르다.


** Reflection

Java Class 파일은 Byte code로 컴파일되며, 실행시간에 이 Byte code가 해석되어 실행된다. 

이 Byte code에는 Class에 대한 모든 정보를 포함하고 있다.

Reflection은 구체적인 Class 타입을 알지 못해도, 컴파일된 바이트 코드를 통해 역으로 클래스에 정보를 알아내어

클래스를 사용할 수 있는 기법을 말한다.



2. 실행 결과 화면

    



3. MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.tistory.qlyh8.pracitice;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
 
import java.util.ArrayList;
 
public class MainActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), SubActivity.class);
 
                // Serializable 객체 이용
                ArrayList<String> names = new ArrayList<>();
                names.add("aaa");
                names.add("bbb");
                intent.putExtra("names", names);
 
                // Parcelable 객체 이용
                SimpleData data = new SimpleData(100"ccc");
                intent.putExtra("data", data);
 
                startActivityForResult(intent, 101);
            }
        });
    }
}
 
cs



4. SubActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.tistory.qlyh8.pracitice;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
import java.util.ArrayList;
 
public class SubActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
 
        Intent intent = getIntent();
        if(intent != null){
            // ArrayList 와 같은 객체들은 이미 Serializable 인터페이스를 구현하고 있어 그대로 부가데이터로 추가할 수 있다.
            ArrayList<String> names = (ArrayList<String>) intent.getSerializableExtra("names");
            if(names != null){
                Toast.makeText(getApplicationContext(), "리스트 개수: " + names.size(), Toast.LENGTH_LONG).show();
            }
 
            // Parcelable 객체는 Serializable 보다 좀 더 메모리 용량을 적게 차지한다.
            // SimpleData 와 같이 직접 정의하는 객체들은 Parcelable 인터페이스를 구현한 후 부가데이터로 추가한다.
            SimpleData data = intent.getParcelableExtra("data");
            if(data != null){
                Toast.makeText(getApplicationContext(), "SimpleData: " + data.number + ", " + data.message, Toast.LENGTH_LONG).show();
            }
        }
    }
}
 
cs



5. SimpleData.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.tistory.qlyh8.pracitice;
 
import android.os.Parcel;
import android.os.Parcelable;
 
// Parcel 은 SimpleData 안에 데이터를 다른 곳에 전달할 때 사용되는 객체이다.
public class SimpleData implements Parcelable {
 
    int number;
    String message;
 
    public SimpleData(int number, String message) {
        this.number = number;
        this.message = message;
    }
 
    // Parcel 에서 SimpleData 안에 들어가 있는 변수를 read 로 복원한다.
    public SimpleData(Parcel src){
        number = src.readInt();
        message = src.readString();
    }
 
    // 역직렬화(바이트 스트림을 원래 데이터 객체로 변환)할 때 사용되어진다.
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator(){
        // 필수 메서드. parcel된 데이터를 다시 원래대로 만들어 준다.
        public SimpleData createFromParcel(Parcel src){
            return new SimpleData(src);
        }
 
        // 필수 메서드. Parcel.createTypeArray()를 호출했을때 불린다.
        public SimpleData[] newArray(int size){
            return new SimpleData[size];
        }
    };
 
    // Parcel의 내용을 기술한다. 
    // FileDescriptor 같은 특별한 객체가 들어가면 이 부분을 통해서 알려줘야한다. 
    // 보통은 0을 리턴해준다.
    @Override
    public int describeContents() {
        return 0;
    }
 
    // SimpleData 를 Parcel 로 바꾼다. (Parcel 안에 데이터를 넣는다.)
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(number);  //number 값을 write
        dest.writeString(message);  // message 값을 write
    }
}
cs



+ Recent posts