행복한 가족, 패밀리그램

개발/안드로이드

Activity와 Fragment간의 데이터 전달, 그리고 Parcelable

패밀리그램 2016. 12. 1. 23:50

Android App 개발을 하는데 Fragment는 특정 UI 들을 하나로 묶고, 다양한 UI 구현에 엄청난 효자 노릇을 한다.

(Fragment를 잘 사용함으로, 반복된 UI 구현을 줄일 수 있고, 좀 더 다양하고 깔끔하게 정리된 UI 개발을 할 수 있다.)

하지만 단순한 앱을 개발하는데, Fragment를 자유자제로 사용 할 능력이 없다면 그냥 사용하지 않고 개발하는 것을 권한다.

(Fragment 사용으로 발생하는 Side effects 들을 감당하기 어려울 수 있기 때문이다)


 Android개발에서 Fragment를 사용 할 경우에 Activity와 Fragment 간에 데이터를 전달이 필요한 경우가 많이 생긴다.

Activity <-> Fragment간의 데이터 전달 방법에 대해서 알아보겠다.


1. Fragment 에서 Activity로 데이터를 전달 하는 방법


Fragment 에서 특정 interface callback 을 정의하여 Activity 로 Fragment에서 Runtime 으로 운용되는 데이터를 전달 할 수 있다.


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
public class MyFragment extends Fragment{
    
    public interface OnMyListener{        
        void onReceivedData(Object data);
    }
 
    private OnMyListener mOnMyListener;
 
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if(getActivity() != null && getActivity() instanceof OnMyListener){
            mOnMyListener = (OnMyListener) getActivity();
        }
 
    }
    
 
    ......
    //데이터 혹은 특정 Callback
    {
        if(mOnMyListener != null){
            mOnMyListener.onReceivedData(obj);    
        }
    }
    
}
cs


이 부분을 적용하기위해서는 먼저 Activity에 Fragment에 정의한 Interface 를 구현해야 한다.


1
2
3
4
5
6
7
8
public class MyActivity extends Activity implements OnMyListener{
    
    ....
    public void onReceivedData(Object data){
        
    }
 
}

cs


위 방법은 Google Developer 사이트에서도 설명하는 방법이다.

* Support Library에 에 있는 v4 Fragmnet를 사용한다면 onAttatch(Context context)가 호출 되지만, Android Framework 의 기본 Fragment를 사용한다면,

이미 Deprecated된 onAttatch(Activity activity) 가 호출 될 수 있다.



2. Activity 에서 Fragment로 데이터를 전달 하는 방법


Fragment가 Activity에 부착되는 시점에서 특정 Activity의 객체를 받아와 Fragment에서 불러와 사용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyFragment extends Fragment{
    
    private Object mMyData;
 
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if(getActivity() != null && getActivity() instanceof MyActivity){
            mMyData = ((MyActivity)getActivity()).getData();
        }
 
    }    
}
cs


이것 또한 부모가되는 Activity에 관련 Method 혹은 변수가 선언되어있어야 한다.


1
2
3
4
5
6
7
8
public class MyActivity extends Activity implements OnMyListener{
    
    ....
    public Object getData(){
        return obj;
    }
 
}
cs


이 부분이 가장 편리하긴 하지만, Fragment를 서로 다른  Activity에서 사용하기가 어려워 지며, 코드가 복잡해 질 수 있다.


3. Parcelable객체를 Fragment Argument로 전달 하는 방법


Activity에서 Fragment로 데이터를 전달 할 경우 Parcelable이 구현된 Class의 객체를 Argument로 전달하는 것을 추천한다.

우선 Parcelable 이 구현된 객체가 필요하다.

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
public class MyData implements Parcelable{
 
        public String name;
        public String address;
 
        protected MyData(Parcel in) {
            name = in.readString();
            address = in.readString();
        }
 
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeString(address);
        }
 
        @Override
        public int describeContents() {
            return 0;
        }
 
        public static final Creator<MyData> CREATOR = new Creator<MyData>() {
            @Override
            public MyData createFromParcel(Parcel in) {
                return new MyData(in);
            }
 
            @Override
            public MyData[] newArray(int size) {
                return new MyData[size];
            }
        };
    }
cs


MyData란 Class를 만들었다 그리고 Fragment argument에 넣어 Activity에서 Fragment 생성 시 원하는 객체를 전달해 준다.


1
2
3
4
5
6
7
8
9
10
11
public class MyFragment extends Fragment{
    
     public static Fragment newInstance(MyData data) {
        Fragment f = new MyFragment();
        Bundle b = new Bundle();
        b.putParcelable(MyData.class.getName(), data);
        f.setArguments(b);
        return f;
    }
    
}
cs


Parcelable은 Android에서 대표적으로 사용되는 Mashalling 방법이다.

보통 ContextWrapper간에 Mashaling을 이용하여 객체를 전달하면, 특정 객체가 단순히 복사되어 전달된다.

하지만 Fragment는 독립적으로 이용 될 수 없는 특성이 있기 떄문에 항상 Activity위에 존재 해야한다.

그렇기 때문에 조금만 더 생각해보면, Fragment로 전달되는 Parcelable 객체는 과연 CallByValue 인가 CallByReference인가 궁금증을 갖는 게 좋다.

Activity에서 Fragment에 전달하는 객체들은 CallByReference로 전달 된다.

즉 Observer와 같은 기법을 사용한다면, Fragment 내에서 객체가 변경되었을 때, 같은 객체를 참조하는 Activity는 충분히 변경된 객체를 통해 UI 를 업데이트 할 수 있다.

이 부분은 직접 확인하길 바란다.