はじめに
今回はMVP(アーキテクチャ)に沿って、異なるレイアウト(Fragment)との連携を実装していきたいと思います。
実装内容
・Activity(親View)の下半分にFragment(子View)を重ねる。
・ACTIVITYボタン(紫文字)が押された際に双方ViewのTextViewに1を足し、表示する。
・FRAGEMENTボタン(赤文字)が押された際に双方ViewのTextViewに10を足し、表示する。
実装
[レイアウト]
Activity(親)側
①activityButton
②activityTextView
Fragment(子)側
③fragmentButton
④fragmentTextView
[コード]
・準備
①BasePresenter,BaseViewを作成。
interface BasePresenter {
//起動処理のメソッド
fun start()
}
interface BaseView<T> {
var presenter: T
}
・Contract設定
①Contractを作成。
②Activity、Fragment、Presenterのインターフェースを作成
③ActivityとFragmentとpresenterで使用するメソッドを作成。
interface MainContract {
interface Activity: BaseView<Presenter> {
//③Activity側のTextViewをテキストを表示するメソッド
fun showActivityTextView (text: String)
}
interface Fragment: BaseView<Presenter> {
//③Fragment側のTextViewをテキストを表示するメソッド
fun showFragmentTextView (text: String)
}
interface Presenter: BasePresenter {
//③Activity側のButoonをクリックされた際に使用するメソッド
fun onClickActivityButton ()
//③Fragment側のButoonをクリックされた際に使用するメソッド
fun onClickFragmentButton ()
}
}
・Presenter設定
①Presenter作成。
②Contract.Activityを引数に追加。
③Contract.Fragmentを引数に追加。
④Contract.presenter(MainContract.Presenter)を戻り値に追加。
⑤activity.presenter = thisに設定。
⑥fragment.presenter = thisに設定。
⑦Contractで作成したメソッドが色々出てくるので設定。
class MainPresenter(private val activity: MainContract.Activity,
private val fragment: MainContract.Fragment): MainContract.Presenter {
//数字をカウントする変数
var cnt = 0
//初期化
init {
//⑤activity.presenter = thisに設定。
activity.presenter = this
//⑥fragment.presenter = thisに設定。
fragment.presenter = this
}
//⑦Activity側のボタンが押された時の処理
override fun onClickActivityButton() {
cnt += 1
activity.showActivityTextView(cnt.toString())
fragment.showFragmentTextView(cnt.toString())
}
//⑦Fragment側のボタンが押された時の処理
override fun onClickFragmentButton() {
cnt += 10
activity.showActivityTextView(cnt.toString())
fragment.showFragmentTextView(cnt.toString())
}
override fun start() {
}
}
・Fragment(子View)設定
①Fragment作成。
②Fragmentの戻り値にContract.Fragmentを追加。
③fragmentを親Viewに渡す。
④overrideしたContract.presenter(MainContract.Presenter)を追加。
⑤Contractで作成したメソッドが色々出てくるので設定。
⑥presenterのメソッドを呼び出す
//②Fragmentの戻り値にContract.Fragmentを追加。
class MainFragment : Fragment(), MainContract.Fragment {
////④overrideしたContract.presenter(MainContract.Presenter)を追加。
override lateinit var presenter: MainContract.Presenter
lateinit var fragmentTextView :TextView
lateinit var fragmentButton :Button
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
fragmentTextView = view.findViewById(R.id.fragmentTextView)
fragmentButton = view.findViewById(R.id.fragmentButton)
//③fragmentを親Viewに渡す。
activity?.let {
if (it is MainActivity) {
it.initPresenter(this)
}
}
fragmentButton.setOnClickListener {
//⑥presenter.onClickFragmentButtonを呼び出す。
presenter.onClickFragmentButton()
}
}
//⑤FragmentTextViewに文字を表示させる
override fun showFragmentTextView(text: String) {
fragmentTextView.text = text
}
}
・Activity(親View)設定
①Activityの戻り値にContract.Activityを追加。
②overrideしたContract.presenter(MainContract.Presenter)を追加。
③Contractで作成したメソッドが色々出てくるので設定。
④presenterのメソッドを呼び出す。
//①戻り値にContract.Activityを追加。
class MainActivity : AppCompatActivity(), MainContract.Activity {
//②overrideしたContract.presenter(MainContract.Presenter)を追加。
override lateinit var presenter: MainContract.Presenter
//空の子Viewを用意する。
var mainFragment : MainFragment? = null
lateinit var activityTextView : TextView
lateinit var activityButton : Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//③Fragment設定(引数に自分を入れる)。
val transition = supportFragmentManager.beginTransaction()
transition.add(R.id.fragmentLayout, MainFragment())
transition.commit()
activityTextView = findViewById(R.id.activityTextView)
activityButton = findViewById(R.id.activityButton)
activityButton.setOnClickListener {
//⑤presenter.onClickActivityButtonを呼び出す。
presenter.onClickActivityButton()
}
}
//③ActivityTextViewに文字を表示させる
override fun showActivityTextView(text: String) {
activityTextView.text = text
}
fun initPresenter(main : MainFragment? = null) {
if (::presenter.isInitialized) {
return
}
main?.let {
this.mainFragment = it
}
//子Viewがnulじゃない場合、Presenterを起動する。
if (mainFragment != null) {
presenter = MainPresenter(this, mainFragment!!)
}
}
}
以上、異なるレイアウト(Fragment)との連携でした。
ロジカルな処理がpresenterに集まって、いい感じになったと思います。
Viewが一つだけ相違点をまとめると以下となっております。
・Viewの数だけContractでインターフェースを作成する。
・親Viewに子Viewを渡し、Presenterの初期化を行う。
関連記事
【kotlin】超簡単なMVPを実装してみた、①Presenterの実装
【kotlin】超簡単なMVPを実装してみた、②LocalRepository設定(ローカルデータに保存、読み込み)
【kotlin】超簡単なMVPを実装してみた、③RemoteRepository設定(APIのやり取り)
【kotlin】超簡単なMVPを実装してみた、⑤recyclerviewとの連携