[Android] MVP Architecture 정리

Android MVP Architecture

Posted by JungHoon-Park on May 22, 2019

MVP Pattern


MVP1

MVP2

구글에서 제공하는 샘플링크

MVP 패턴의 동작

  • 1. View에서 사용자의 이벤트 수신
  • 2. View에서 Presenter 이벤트 호출
  • 3. Presenter에서 Model에 데이터 요청
  • 4. Model에서 Presenter로 데이터 전달
  • 5. Presenter에서 전달받은 데이터를 기반으로 View 업데이트
  • 6. View에서 화면 업데이트

- Model

내부적으로 쓰이는 데이터를 저장하고, 처리하는 역할을 한다. 흔히 ‘Business Logic’ 이라고 부르는 부분이다. View, Presenter 등 다른 어떤 요소에도 의존적이지 않은 독립적인 영역이다.

1
2
3
4
5
6
7
8
9
10
11
public class ResultUrl {
    private String message;
    private String code;
    private ResultFormat result;

    public ResultUrl(String message, String code, ResultFormat result) {
        this.message = message;
        this.code = code;
        this.result = result;
    }
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class GetServerResponseImpl implements MainContractor.GetServerResponse {
    @Override
    public void getNoticeURL(final OnFinishedListener onFinishedListener, String url) {

        RetrofitService retrofit = RetrofitInstance.getRetrofitInstance().create(RetrofitService.class);

        retrofit.sendShortURL(url).enqueue(new Callback<ResultUrl>() {
            @Override
            public void onResponse(Call<ResultUrl> call, Response<ResultUrl> response) {
                if (response.isSuccessful()){
                    if (response.body() != null){
                        onFinishedListener.onFinished(response.body().getResult().getUrl());
                        Log.e("result url",""+response.body().getResult().getUrl());
                    }
                }
            }
            @Override
            public void onFailure(Call<ResultUrl> call, Throwable t) {
                onFinishedListener.onFailure(t);
                Log.e("shotURL Failure",""+t.toString());
            }
        });
    }
}

- View

실제 View 에 대한 직접적인 접근을 담당한다. 안드로이드에서 Activity/Fragment 는 View의 일부로 정의한다. View의 일부로 정의한다. View 에서 발생하는 이벤트는 직접 핸들링 할 수 있으나 Presenter 에 위임하도록 한다. 위임하는 방법은 Activity 가 View Interface 를 구현해서 Presenter 에서 코드를 만들 인터페이스를 갖도록 하면 된다. 이를 통해 특정 뷰와 결합되지 않고 가상 뷰를 구현해서 간단한 유닛 테스트를 실행할 수 있다.

1
2
3
4
5
6
7
8
9
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ButterKnife.bind(this);
    mainPresenter = new MainPresenter(this, new GetServerResponseImpl());
    mainPresenter.attachView(this);
}

- Presenter

본질적으로는 MVC의 컨트롤러와 같지만, 뷰에 연결되는 것이 아니라 Interface로 연결된다는 점이 다르다. 이에 따라 MVC가 가진 테스트 가능성 문제와 함께 모듈화/유연성 문제 역시 해결한다. Presenter의 역할을 정의한다면 View 와 Model 사이에서 자료 전달 역할을 합니다.

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 interface MainContractor {
    interface View {
        void showResult();

        void setResultURL(String url);

    }

    interface Presenter {

        void attachView(View view);

        void detachView();

        void loadURL(Context context, String url);
    }

    interface GetServerResponse {

        interface OnFinishedListener {
            void onFinished(String resultURL);
            void onFailure(Throwable t);
        }

        void getNoticeURL(OnFinishedListener onFinishedListener, String url);
    }
}
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 MainPresenter implements MainContractor.Presenter, MainContractor.GetServerResponse.OnFinishedListener{

    private MainContractor.View view;
    private MainContractor.GetServerResponse getNoticeIntractor;

    public MainPresenter(MainContractor.View view, MainContractor.GetServerResponse getNoticeIntractor) {
        this.view = view;
        this.getNoticeIntractor = getNoticeIntractor;
    }

    @Override
    public void attachView(MainContractor.View view) {
        this.view = view;
    }

    @Override
    public void detachView() {view = null;}

    @Override
    public void loadURL(Context context, String url) {
        getNoticeIntractor.getNoticeURL(this,url);
    }

    @Override
    public void onFinished(String resultURL) {
        view.setResultURL(resultURL);
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e("network onFailure",""+t.toString());
    }
}

MVC와 MVP의 차이

MVC 는 Model-View-Controller 로 코드를 구성하는 디자인 패턴이다.
Model과 View는 MVC,MVP가 역할이 같지만 Controller와 Presenter는 약간 다르다.
MVC에서는 사용자의 이벤트에 Controller가 먼저 반응한 후 View를 가져와 적절한 작업 후 반환한다.
MVP에서는 사용자의 이벤트에 View가 먼저 반응한 후 Presenter에 알리고 작업을 처리한 후 View한테 다시 알려준다.

왜 사용할까?
MVP와 같은 디자인 패턴은 앱을 구성하는 코드를 모듈화시킬 수 있다. 협업 시 각각 전문분야에서만 작업을 해도 된다. 소스파일을 관리하기 더 편해지고 유닛 테스트에 용이해진다는 장점이 있다. 즉, 전체적인 유지보수가 쉬워진다.

github 링크