【Kotlin】RecyclerViewはリサイクルされる夢を見られるか？

#はじめに
AndroidStudioで使われるRecyclerViewに複数のレイアウトを持たせててアダプターを1つで済ませる実験です。これが汎用的になればファイル数が減らせます（多分）

#準備

文字列を設定

```strings.xml
<resources>
    <string name="app_name">RecyclerViewSample2</string>
    <string name="btRow1">row1.xmlの反映</string>
    <string name="btRow2">row2.xmlの反映</string>
</resources>
```

切り替えるためのボタン2つとRecyclerViewを配置

```actibity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="btClick1"
                android:text="@string/btRow1" />

            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="btClick2"
                android:text="@string/btRow2" />

        </LinearLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rvMain"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
```

リサイクルするレイアウトとして row1.xml row2.xmlを作ります。違いを出すためレイアウトを変えています。

```row1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvRow1Main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tvRow1Sub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
```

```row2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tvRow2Main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tvRow2Sub"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>
```

メインのプログラムはこんな感じ
生成時の引数違いで2つのアダプターを作ってボタンクリックリスナーでそれを切り替えます。

```MainActivity.kt

class MainActivity : AppCompatActivity() {
    val viewAdapter1 = RecyclerviewTest(0)
    val viewAdapter2 = RecyclerviewTest(1)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        show(1)
    }
    fun show(mode : Int){
        val review : RecyclerView? = findViewById<RecyclerView>(R.id.rvMain)
        val layout = LinearLayoutManager(this)
        review?.layoutManager = layout
        when(mode){
            0    ->  review?.adapter = viewAdapter1
            else ->  review?.adapter = viewAdapter2
        }
    }

    fun btClick1(view : View){
        show(0)
    }
    fun btClick2(view : View){
        show(1)
    }
}
```

2つを別々にしたので結局if文が出来てますが配列にする事も出来るでしょう。
これをうまく処理する。RecyclerViewTest.ktを作っています。

```onCreateViewHolder.kt
class RecyclerviewTest(private val mode : Int)  : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var rowLayout : Int? = null
        when(mode){
            0    ->  rowLayout = R.layout.row1
            else ->  rowLayout = R.layout.row2
        }
        val view = LayoutInflater.from(parent.context).inflate(rowLayout!!, parent, false)
        return RecyclerListViewHolder(view!!,mode)
    }
```

生成時に引数 modeを使うようにしてその値をクラス内保存するとともに参照するレイアウトをR.layout.row1由来かR.layout.row2由来かを切り替えます。ここまでは順調です。

```RecyclerListViewHolder.kt
    private  class RecyclerListViewHolder(itemView : View,mode : Int) : RecyclerView.ViewHolder(itemView){
        var tvRowMain : TextView
        var tvRowSub : TextView

        init {
            when(mode){
                0 ->{
                    tvRowMain     = itemView.findViewById<TextView>(R.id.tvRow1Main)
                    tvRowSub = itemView.findViewById<TextView>(R.id.tvRow1Sub)
                }
                else ->{
                    tvRowMain     = itemView.findViewById<TextView>(R.id.tvRow2Main)
                    tvRowSub = itemView.findViewById<TextView>(R.id.tvRow2Sub)
                }
            }
        }
    }
```

ViewHolderとして参照されるレイアウト内のTextView参照を切り替えます。
tvRowMainとtvRowSubという変数に参照させるのですが
TextViewのIDが同じには出来ないのでR.id.tvRow1Main、やR.id.tvRow1Subなどの定義になって、リサイクルする意味があるのかわからなくなってきました。

```onBindViewHolder.kt
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when(mode){
            0 ->{
                holder.itemView.tvRow1Main.setText("%d".format(position))
                holder.itemView.tvRow1Sub.setText("%d".format(position * 2))
            }
            else ->{
                holder.itemView.tvRow2Main.setText("%d".format(position))
                holder.itemView.tvRow2Sub.setText("%d".format(position * 2))
            }
        }
    }
```

描画時の処理を実装します。
先ほどvar tvRowMain : TextViewとして定義したんですけどね。これをGlobal変数にすれば良いとかそういう問題ではないらしい。
結局holder.itemView.tvRow1Main.setTextと、レイアウトもTextViewのIDもひっくるめた参照になってしまいました。

#結果
RecyclerViewはリサイクルできなくも無いがリサイクルしてまで再利用するほどのものではない。との結論になりました。異論は認めます。
ファイル数を減らすのは難しそうです。

#ソース全体

```RecyclerViewTest.kt
class RecyclerviewTest(private val mode : Int)  : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var rowLayout : Int? = null
        when(mode){
            0    ->  rowLayout = R.layout.row1
            else ->  rowLayout = R.layout.row2
        }
        val view = LayoutInflater.from(parent.context).inflate(rowLayout!!, parent, false)
        return RecyclerListViewHolder(view!!,mode)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when(mode){
            0 ->{
                holder.itemView.tvRow1Main.setText("%d".format(position))
                holder.itemView.tvRow1Sub.setText("%d".format(position * 2))
            }
            else ->{
                holder.itemView.tvRow2Main.setText("%d".format(position))
                holder.itemView.tvRow2Sub.setText("%d".format(position * 2))
            }
        }
    }

    override fun getItemCount(): Int {
        return 16
    }

    private  class RecyclerListViewHolder(itemView : View,mode : Int) : RecyclerView.ViewHolder(itemView){
        var tvRowMain : TextView
        var tvRowSub : TextView

        init {
            when(mode){
                0 ->{
                    tvRowMain     = itemView.findViewById<TextView>(R.id.tvRow1Main)
                    tvRowSub = itemView.findViewById<TextView>(R.id.tvRow1Sub)
                }
                else ->{
                    tvRowMain     = itemView.findViewById<TextView>(R.id.tvRow2Main)
                    tvRowSub = itemView.findViewById<TextView>(R.id.tvRow2Sub)
                }
            }
        }
    }
}
```