EditTextに入力された値を一括で取得できるようにする

#前提条件
SDKバージョン：　30
Androidバージョン：　9.0

#一般的なEditTextに入力された値を取得する方法
おそらく皆さんこんな感じかと思います。

```kotlin
var name = binding.editTextName.text.toString()
var height = binding.editTextHeight.text.toString()
var weight = binding.editTextWeight.text.toString()
```
私の場合は[ViewBinding](https://qiita.com/mi_iroha/items/dbc07737e81776e05f8d)を使用しているのでこんな感じでよく書きますが、`findViewById()`や`Kotlin extension`を利用していたとしてもさほどやり方は変わらないかと思います。要するに、取得したいeditTextのidを一つ一つ取得して、そのeditTextに入力された文字を受け取り、String型に直すという流れですね。「Android editText　値　取得」などで検索するといくらでも出てきます。

さて、入力されるeditTextが10個になったらこの作業を10回するのでしょうか。100個になったら100回するのでしょうか。一気に取得したくないですか？

#EditTextに入力された値を一回で全て取得する
まず今回実現したいことは、画面に入力された３つのeditTextを一気に取得してcsvファイルに書き込むぞ！という処理です！
画面はこんな感じです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/3e42cb43-822b-fe11-9abc-9c11944455ae.png" width=70%>

```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"
    android:background="@color/background_color"
    tools:context=".InputDataActivity">

    <LinearLayout
        android:id="@+id/container_for_toolbar"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"></LinearLayout>

    <LinearLayout
        android:id="@+id/container_for_edit_text"
        android:layout_width="400dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <EditText
            android:id="@+id/edit_text_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="名前"
            android:inputType="textPersonName"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_text_height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="身長"
            android:inputType="textPersonName"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_text_weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="体重"
            android:inputType="textPersonName"
            android:textSize="24sp" />

        <Button
            android:id="@+id/btn_send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="8dp"
            android:paddingBottom="8dp"
            android:text="送信する"
            android:textColor="#393e46"
            android:textSize="24sp"
            android:textStyle="bold"
            app:backgroundTint="@color/light_green"
            app:rippleColor="@color/dark_green" />

    </LinearLayout>

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

入力して、送信ボタンを押すと、入力された値が一気に取得されてCSVファイルに書き込まれます。

以下のように書くと実現できます

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // bindingの初期化とsetContentViewを行う
        binding = ActivityInputDataBinding.inflate(layoutInflater)
            .apply { setContentView(this.root) }

        // 送信ボタンをクリック
        binding.btnSend.setOnClickListener {
            // 引数にeditTextを格納しているコンテナのidを入れる
            val patientsDataList = getAllInputData(binding.containerForEditText)
            createFile(patientsDataList)
        }    
}


// ===== editTextに入力された値を全て取得する =====
    private fun getAllInputData(group: ViewGroup): MutableList<String> {
        val count = group.childCount
        var editDataList = mutableListOf<String>()
        for (i in 0 until count) {
            val view = group.getChildAt(i)
            if (view is EditText) {
                Log.d("TAG", view.text.toString())
                editDataList.add(i, view.text.toString())
            }
        }
        return editDataList
    }

// ===== ファイルを作成して書き込み =====
private fun createFile(patientsDataList: MutableList<String>) {
        // 出力ファイルの作成
        val file = File(applicationContext.filesDir, fileName)
        val fw = FileWriter(file, false)
        val pw = PrintWriter(BufferedWriter(fw))

        // ヘッダーの指定
        pw.print("名前")
        pw.print(",")
        pw.print("身長")
        pw.print(",")
        pw.print("体重")
        pw.println()

        // データを書き込む
        val listSize = patientsDataList.size
        for (i in 0 until listSize) {
            if(i == listSize-1) {
                pw.print(patientsDataList[listSize - 1])
                pw.println()
            } else {
                pw.print(patientsDataList[i])
                pw.print(",")
            }
        }
        // ファイルを閉じる
        pw.close()
    }
```
上記のように書くと、`getAllInputData()`メソッドにて`editText`に入力された値が一気に取得されて、`List`に入ります。`List`に入ったデータは`createFile()`メソッドに渡されて、csvファイルに書き込みが行われ、内部ストレージに保存されます。このようにしてeditTextに入力された文字を一気に取得し、メソッドに一気に渡して処理してあげることができます。

`getAllInputData()`での処理ですが、これは単純に`editText`をfor文で回して一つ一つ取得しているようなイメージです。試しに`Log.d("TAG", view.text.toString())`の部分にブレークポイントを貼って、Logcatで`TAG`と検索し、ログを逐一確認してみましょう。入力された値が一つ一つ取得されているのが確認できます。

#比較
もし今回のこの処理ですが、`getAllInputData()`を作成せずに書いたらどうなるのでしょうか

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // bindingの初期化とsetContentViewを行う
        binding = ActivityInputDataBinding.inflate(layoutInflater)
            .apply { setContentView(this.root) }

        // 送信ボタンをクリック
        binding.btnSend.setOnClickListener {
            // この部分が増える
            var name = binding.editTextName.text.toString()
            var height = binding.editTextHeight.text.toString()
            var weight = binding.editTextWeight.text.toString()
            val patientsDataList = mutableListOf(name, height, weight)

            createFile(patientsDataList)
        }    
}

// ===== ファイルを作成して書き込み =====
private fun createFile(patientsDataList: MutableList<String>) {
        // 出力ファイルの作成
        val file = File(applicationContext.filesDir, fileName)
        val fw = FileWriter(file, false)
        val pw = PrintWriter(BufferedWriter(fw))

        // ヘッダーの指定
        pw.print("名前")
        pw.print(",")
        pw.print("身長")
        pw.print(",")
        pw.print("体重")
        pw.println()

        // データを書き込む
        val listSize = patientsDataList.size
        for (i in 0 until listSize) {
            if(i == listSize-1) {
                pw.print(patientsDataList[listSize - 1])
                pw.println()
            } else {
                pw.print(patientsDataList[i])
                pw.print(",")
            }
        }
        // ファイルを閉じる
        pw.close()
    }
```

どうでしょうか。増えるのはこの4行です

```kotlin
// この部分が増える
var name = binding.editTextName.text.toString()
var height = binding.editTextHeight.text.toString()
var weight = binding.editTextWeight.text.toString()
val patientsDataList = mutableListOf(name, height, weight)
```
この4行が増えましたが、代わりに`private fun getAllInputData(...)`の処理が消えたので一見こっちの方が処理があっさりして見えますね。でも、今回は取得するeditTextがたったの３つでしたのでスッキリ見えますがこれが100個になったらどうでしょう。１００個分取得しないとダメです。

```kotlin
// この部分が増える
var name = binding.editTextName.text.toString()
var height = binding.editTextHeight.text.toString()
var weight = binding.editTextWeight.text.toString()
val patientsDataList = mutableListOf(name, height, weight)
```
つまりこのコードが100行になります。

一方`getAllInputData()`を使用する場合はeditTextがいくら増えようが`container_for_edit_text`のコンテナにeditTextが入っている限りは一回で取得できます。つまり途中でeditTextの数を増やしてもコードを変更する必要はないのです。


#追記
コメントでのご指摘を受けてeditTextに入力された値を一気に取得するコードを以下のように修正しました。

```kotlin
    // ===== editTextに入力された値を全て取得する =====
    private fun getAllInputData(group: ViewGroup): MutableList<String> {
        var editDataList = mutableListOf<String>()

        group.children.forEachIndexed { i, view ->
            if (view is EditText) {
                Log.d("TAG", view.text.toString())
                editDataList.add(i, view.text.toString())
            }
        }
        return editDataList
    }
```