drcarter의 DevLog

안드로이드에서 onActivityResult는 이전 activity에서의 결과를 intent를 통해서 받을 수 있습니다. 개발문서 참고

당연히 Fragment안에서도 onActivityResult가 있고, fragment안에서 startActivityForResult를 통해서 해당 결과를 받을 수 있습니다.


/**
     * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's
     * containing Activity.
     */
    public void startActivityForResult(Intent intent, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode);
    }

이와 같이 fragment에서 startActivityForResult를 하기 위해선 fragment가 activity에 attach되어 있어야 합니다.

fragment에서 startActivityForResult를 Activity에서 보낸 것처럼 할려면

getActivity().startActivityForResult(.......)

로 해서 보내면 됩니다. 이렇게 해서 보내면 onActivityResult로 받게 되는 결과가 fragment에서 바로 받는 것이 아니라 activity에 있는 onActivityResult에서 받게 되어서 이 결과를 바로 fragment에 전달해 줘야 하죠.... 이 부분이 조금 껄끄러운 면이 있습니다. Lollipop에서 material design을 적용하여 Activity Transition이나 Fragment Transition을 적용할려면, onStartActivityForResult의 호출지점이 fragment가 아닌 activity에서 하는 것처럼 보내야 합니다.

그럼 Activity의 onActivityResult로 받은 결과를 어떻게 fragment에 전달하는 것이 좋을까요?

여러가지 방법이 있을 듯 합니다. 가장 쉬운 방법으로는 Activity에서 해당 fragment의 instance를 두고서 전달할 public method를 만들어 전달 할 방법이 있을 것 같습니다. 

제가 이번에 소개해볼 방법은 event bus[Otto - An event bus by Square]를 이용한 방법을 소개해 볼까 합니다. 

ActivityResultEvent.java 로 만든 class 입니다.


public class ActivityResultEvent {

    private int requestCode;
    private int resultCode;
    private Intent data;

    public static ActivityResultEvent create(int requestCode, int resultCode, Intent intent) {
        return new ActivityResultEvent(requestCode, resultCode, intent);
    }

    private ActivityResultEvent(int requestCode, int resultCode, Intent data) {
        this.requestCode = requestCode;
        this.resultCode = resultCode;
        this.data = data;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public int getResultCode() {
        return resultCode;
    }

    public Intent getData() {
        return data;
    }
}

이건 단순히 onActivityResult로 받는 requestCode, resultCode, intent정보를 가지고 fragment에 전달해 주는 용도 입니다.

EventBus.java


public class EventBus extends Bus {

    private static EventBus instance;

    public static EventBus getInstance() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    private Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    EventBus.super.post(event);
                }
            });
        }
    }
}

이건 ActivityResultEvent를 보내줄 Bus입니다.. 이 Bus의 이용 방법은 위에 링크 걸린 홈페이지에 자세히 설명 되어 있어요 

해당 EventBus를 Singleton으로 만들었습니다. 


이 부분의 사용 방법은

activity의 onActivityResult에서


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        EventBus.getInstance().post(ActivityResultEvent.create(requestCode, resultCode, data));
    }

이와 같이 호출하면 되고,

fragment에서는 

    @SuppressWarnings("unused")
    @Subscribe
    public void onActivityResultEvent(@NonNull ActivityResultEvent event) {
        onActivityResult(event.getRequestCode(), event.getResultCode(), event.getData());
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case Constants.RequestCode.REQUEST_CODE_NAME_INPUT: {
                if (resultCode == Activity.RESULT_OK) {
                    String text = data.getStringExtra(KeySets.KEY_NAME_INPUT);
                    if (!TextUtils.isEmpty(text)) {
                        textResult.setText(text);
                    }
                }
                break;
            }
        }
    }

이와 같이 Bus를 통해 받은 정보를 fragment의 onActivityResult로 전달하면 됩니다.

Bus를 통해서 정보 공유는 이요할 곳이 참 많아 보입니다. Service에서 activity나 fragment에 결과의 내용을 전달 할 때 사용해도 되구요.

결과를 만들어 내는 방법에는 여러 방법이 있지만, 사용하는건 개발자의 선택인 듯 합니다. 방법에는 정답이 없으니까요.

source : https://github.com/drcarter/RetriveActivityResult

샘플 소스는 제 git에 올려둡니다.