내용이 조금 어려울수 있습니다. 왜냐하면 여러 MVP 예제 프로젝트를 통해 저만의 방식대로 만들었기 때문입니다.
앞서서 기본적으로 MVP 의 구조와 간단하게 구현하는 방법들을 살펴 보았습니다. 이번에는 제가 만든 샘플 프로젝트를 통해서 Base 클래스
들을 어떻게 만들어 활용하고있는지 살펴볼 예정입니다.
샘플 프로젝트는 “MVP 로 작성된 Sample Project - GitHub” 이며, 같은 구조를 적용하여 만든 어플은 “모닝카페-기상알람,가계부,일기” 입니다.
BaseMvpView
interface BaseMvpView {
fun getActivity(): Activity
fun showLoadingDialog()
fun dismissLoadingDialog()
fun getCompositeSubscription(): CompositeSubscription // rxJava 의 subscribe 때문
}
BaseMvpFragment
abstract class BaseMvpFragment : BaseFragment(), BaseMvpView {
private var presenter: BasePresenter<BaseMvpView>? = null
@Suppress("UNCHECKED_CAST")
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter = getPresenter() as BasePresenter<BaseMvpView>
if (null != presenter)
presenter!!.attachView(this)
onViewCreated_afterAttachViewToPresenter()
}
protected abstract fun onViewCreated_afterAttachViewToPresenter()
override fun onDestroyView() {
super.onDestroyView()
if (null != presenter)
presenter!!.detachView()
}
protected abstract fun getPresenter(): BasePresenter<*>
}
BaseMvpFragment
는 추상 클래스로 만들어져 getPresenter() 를 구현하도록 해놓고, onViewCreated 에서 호출하여 presenter 의 인스턴스를 멤버변수로 가지고 있도록 해놓았습니다. 이렇게 한 이유는 presenter 를 DI 라이브러리를 통해 인젝션 받는데 구현하는 Fragment 에서 인젝션 후에 attachView() 하는 작업을 BaseMvpFragment 에 넣기 위함입니다. ( 제대로 이해가 됬을지 모르겠습니다 )
DI 라이브러리로 Dagger2 를 사용하였고, 추후에 관련 포스팅을 하도록 하겠습니다.
그리고 onDestroyView() 에서 detachView()
를 통해 presenter 에서 view 를 제거 합니다. 이는 조금있다 Presenter 에서 볼수있는데, presenter 에서 view 의 유무에 따라 작업을 중단해야할 일이 생길수 있기 떄문입니다.
BasePresenter
abstract class BasePresenter<VIEW : BaseMvpView> {
var view: VIEW? = null
private set
fun attachView(view: VIEW) {
this.view = view
}
open fun detachView() {
view = null
}
val isAttached: Boolean
get() = null != view
}
BasePresenter 는 Generic 을 이용하여 View interface 를 받을수 있도록 했습니다.
Fragment 에서
class TaskListFragment : BaseMvpFragment(), TaskListView {
// ...
/**
* Injection value & needed mvp
*/
@Inject
lateinit var presenter: TaskListPresenter
override fun getPresenter(): BasePresenter<*> = presenter
/**
* LifeCycle function
*/
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
val rootView = inflater!!.inflate(R.layout.fragment_task_list, container, false)
DaggerFragmentComponent.builder()
.applicationComponent((activity.application as MokaToyApplication).applicationComponent)
.fragmentModule(FragmentModule())
.build().inject(this)
return rootView
}
...
}
Fragment 에서 Presenter 를 Injection(주입) 하였고, BaseMvpFragment 를 상속 받았기 때문에 onCreateView() 에서 presenter 에 attachView 가 될것입니다.
Adapter
SeongUg Steve Jung 님의 Medium 포스팅 ‘Adapter, 누구냐 넌?’ 을 참고하여 구현하였습니다.
위의 포스팅처럼 adapter 를 interface 를 이용하여 View 가 할일, Model 이 할일로 구분하여 presenter 에서는 adapter 의 interface 를 통해서 adapter 를 컨트롤 하고있습니다.
다른 MVP 포스팅 보기 및 샘플 프로젝트
- Android - MVP, What is it? Why to use? MVP 가 무엇이고, 왜쓰는지 살펴봅니다.
- Android - MVP Presenter/View/Model Code Lab - 차근차근 MVP 구조를 구현해 해봅니다.
- Android - MVP in action Reference
- MVP 로 작성된 Sample Project - GitHub
- 동영상 설명 보기