【kotlin】超簡単なMVPを実装してみた、⑤recyclerviewとの連携

# はじめに
今回はMVP(アーキテクチャ)に沿って、recyclerviewとの連携を実装していきたいと思います。

# 実装内容
・追加ボタンを押した時にrecyclerviewにアイテム(✖︎マークのセル)を追加し表示する。
・✖︎マークのセルを押した際に押したセルを削除し、反映させる。

![Screenshot_1644046349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784089/a77055b6-5fb4-098d-7dcf-d3d395712231.png)

# 実装
**[レイアウト]**
①addButton
②recyclerView
![Screenshot_1644046349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784089/244a451c-dd00-b6ce-4466-2d17ff52ef72.png)

**[コード]**
**・準備**
①BasePresenter,BaseViewを作成。

```kotlin:BasePresenter
interface BasePresenter {
　    //起動処理のメソッド
    fun start()
}
```

```kotlin:BaseView
interface BaseView<T> {
    var presenter: T
}
```
**・Contract設定**
①Contractを作成。
②View、Presenterのインターフェースを作成
③View、Presenterで使用するメソッドを作成。

```kotlin:MainContract
interface MainContract {

    interface View: BaseView<Presenter> {
        //③RecyclerViewを初期化するメソッド
        fun setRecyclerView (rvList: ArrayList<String>)
        //③RecyclerViewを更新するメソッド
        fun updateRecyclerView (rvList: ArrayList<String>)
        //③✖︎ボタンクリックされた際にview側に渡すメソッド
        fun onClickCellDeleteButton (position: Int)
    }

    interface Presenter: BasePresenter {
        //③Activity側のaddButoonをクリックされた際に使用するメソッド
        fun onClickAddButton ()
        //③RecyclerViewの✖︎Butoonをクリックされた際に使用するメソッド
        fun onClickCellDeleteButton (position: Int)
    }
}
```
**・Presenter設定**
①Presenter作成。
②Contract.Viewを引数に追加。
③Contract.presenter(MainContract.Presenter)を戻り値に追加。
④view.presenter = thisに設定。
⑤Contractで作成したメソッドが色々出てくるので設定。

```kotlin:MainPresenter
class MainPresenter(private val view: MainContract.View): MainContract.Presenter {
    var rvList = ArrayList<String>()

    //④view.presenter = thisに設定。
    init {
        view.presenter = this
    }

    //⑤追加ボタンが押された時の処理
    override fun onClickAddButton() {
        rvList.add("✖️")
        view.updateRecyclerView(rvList)
    }

    //⑤✖︎ボタンが押された時の処理
    override fun onClickCellDeleteButton(position: Int) {
        rvList.removeAt(position)
        view.updateRecyclerView(rvList)

    }

    //⑤起動時の処理
    override fun start() {
        view.setRecyclerView(rvList)
    }
}
```



**・Adapter設定**
①Adapter作成。
②MainContract.Viewを引数に設定。
③MainContract.Viewのメソッドを呼び出す。

```kotlin:RvAdapter
//②MainContract.Viewを引数に設定。
class RvAdapter(private val litner: MainContract.View,
                private val List: ArrayList<String>,
                private val context: Context): RecyclerView.Adapter<RvAdapter.ViewHolder>(){

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val cellDeleteButton: TextView

        init{
            cellDeleteButton  = view.findViewById<TextView>(R.id.cellDeleteButton)
        }

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvAdapter.ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.cell, parent, false)
        view.layoutParams.height= 150
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: RvAdapter.ViewHolder, position: Int) {
        holder.cellDeleteButton.setOnClickListener {
            //③view側に渡すpositionを渡すメソッド
            litner.onClickCellDeleteButton(position)
        }
    }

    override fun getItemCount(): Int {
        return List.size
    }
}
```

**・View設定**
①Activityの戻り値にContract.Viewを追加。
②overrideしたContract.presenter(MainContract.Presenter)を追加。
③Contract.View で作成したメソッドが色々出てくるので設定。
④presenterのメソッドを呼び出す。


```kotlin:MainActivity
//①戻り値にContract.Viewを追加。
class MainActivity : AppCompatActivity(), MainContract.View {

    //②overrideしたContract.presenter(MainContract.Presenter)を追加。
    override lateinit var presenter: MainContract.Presenter
    lateinit var addButton : Button
    lateinit var recyclerView : RecyclerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        addButton = findViewById(R.id.addButton)
        recyclerView = findViewById(R.id.recyclerView)
        initPresenter()
        presenter.start()
        addButton.setOnClickListener {
            presenter.onClickAddButton()
        }
    }

    //③RecyclerViewをセットする
    override fun setRecyclerView(rvList: ArrayList<String>) {
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.setPadding(10,20,10,0)
        val dividerItemDecoration = DividerItemDecoration(this, LinearLayoutManager(this).getOrientation())
        getDrawable(R.drawable.divider)?.let { dividerItemDecoration.setDrawable(it) }
        recyclerView.addItemDecoration(dividerItemDecoration)
        var adapter = RvAdapter(this, rvList, applicationContext)
        recyclerView.adapter = adapter
    }

    //③RecyclerViewを更新する
    override fun updateRecyclerView(rvList: ArrayList<String>) {
        var adapter = RvAdapter(this, rvList, applicationContext)
        recyclerView.adapter = adapter
    }
    //③✖︎ボタンが押された時呼び出される
    override fun onClickCellDeleteButton(position: Int) {
        presenter.onClickCellDeleteButton(position)
    }

    fun initPresenter() {
        if (::presenter.isInitialized) {
            return
        }
        presenter = MainPresenter(this)
    }
}
```

以上、recyclerviewとの連携との連携でした。
AdpterとPresenterで直接やり取りするではなくて、
Viewを経由してpresenterに送るイメージです。

# 関連記事
[【kotlin】超簡単なMVPを実装してみた、①Presenterの実装](https://qiita.com/Na0yaKub0/items/d688c440dfa9c3a49a7f)
[【kotlin】超簡単なMVPを実装してみた、②LocalRepository設定(ローカルデータに保存、読み込み)](https://qiita.com/Na0yaKub0/items/7209258a0d7b084d276a)
[【kotlin】超簡単なMVPを実装してみた、③RemoteRepository設定(APIのやり取り)](https://qiita.com/Na0yaKub0/items/57358d689b6552ad7d75)
[【kotlin】超簡単なMVPを実装してみた、④異なるレイアウト(Fragment)との連携](https://qiita.com/Na0yaKub0/items/76854a1dfc79dc978c3e)


# 参考資料
[Android アプリ設計パターン入門](https://peaks.cc/books/architecture_patterns)
[テストが書けない人のAndroid MVP](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E3%81%8C%E6%9B%B8%E3%81%91%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AEAndroid-MVP-%E6%8A%80%E8%A1%93%E3%81%AE%E6%B3%89%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%EF%BC%88NextPublishing%EF%BC%89-%E9%AB%98%E7%95%91-%E5%8C%A1%E7%A7%80/dp/4844398717)
[todo-mvp](https://github.com/android/architecture-samples/tree/todo-mvp-kotlin/todoapp)