KotlinでAndroidの Button アプリを簡単に作ってみました。
findViewByIdの代わりにAndroid Kotlin Extensions プラグインを使っていましたが、現在では ViewBinding が推奨されています。
2021.1.1
Button
JavaでのButtonアプリを下のように作成しましたが、
その作り方をそのままKotlinに変えるとどうなるか試してみます。
1. Kotlinプロジェクトの作成
1.1 プロジェクト構成ファイル
1.2 MainActivity.kt
1.3 activity_main.xml
2. View Binding
3. サンプルコード
Kotlinプロジェクトの作成
プロジェクトをJavaで開発するのか、KotlinなのかはLanguageの切り替えで簡単にできます。
プロジェクトを作成するときに、プロジェクト名を設定するステップで
Languageで Kotlin を選択します。
これだけでプロジェクトがKotlin仕様になり、クラスファイル名が MainActivity.kt などと色々と変更されます。
プロジェクト構成ファイル
プロジェクトを作ると幾つかのファイルが既にできています。
- MainActivity.kt
- アプリのエントリポイントで、Kotlin の主なコーディングをするところ
- activity_main.xml
- レイアウトを定義する XML ファイル
- AndroidManifest.xml
- マニフェストにはアプリの各コンポーネントが定義されていて、セキュリティ上ユーザーに許可を得るための記述などがされています。
- build.gradle
- 同じ名前のファイルが2つあり、プロジェクト用(Project: xxx)とモジュール用(Module: xxx.app)で、もっぱらモジュール用を使用します。ターゲットのAPIレベルやライブラリーの情報が設定されます。
MainActivity.kt
アプリをビルドして実行するとこの Activity のインスタンスが起動し、そのレイアウトが読み込まれます。
Empty Activityを選んだので、ある程度の基本的なコードは既に入っています。
1 2 3 4 5 6 7 8 9 10 11 |
//package your.package.name import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } |
activity_main.xml
Activity のユーザー インターフェース(UI)のレイアウトを定義する XML ファイルで、ここにコードを記述あるいは「Design」タグからレイアウトエディタでも作成が可能です。
やり方としては、
- 「Design」を使って画面上にUIパーツを配置する
- 「Code」で全てコードで記述
「Design」ではレイアウトの配置全体をデザイン的に決めていくには便利です。
右上の3つ並んだアイコンで「Code」「Split」「Design」の切り替えができます。
「Code」は並んだアイコンの左端です。
微調整も含めた細かな設定はコーディングがいいでしょう、またネットにある開発情報の多くがコードです。
actvity_main.xml のコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
View Binding
以前は findViewById を使ってXMLレイアウトファイルからIDを読みだしていたのを
Kotlin Android Extensionsのプラグインにある kotlinx.android.synthetic を使って簡略化していました。
1 2 3 4 5 |
import kotlinx.android.synthetic.main.activity_main.* ... button.setOnClickListener{ ... } |
ただ、kotlinx synthetics には問題点があり、非推奨となっています。
Kotlin Android Extensions の未来
代わりに View Binding が推奨されています。
Migrate from Kotlin synthetics to Jetpack view binding
View Binding:
セットアップとして、build.gradle ファイルに viewBinding 要素を追加します。
build.gradle
1 2 3 4 5 6 7 |
android{ ... buildFeatures { viewBinding true } } |
プロジェクトのXML レイアウトファイルが
activity_main.xml
の場合は、そのレイアウトファイル毎にViewBinding Class を作成します。
1 2 3 |
package com.example.testbutton ... import com.example.testbutton.databinding.ActivityMainBinding |
[package name].databinding.[XMLレイアウトファイル名から]Binding
ActivityMainBindingはXMLファイルの名前(activity_main)を
キャメルケースに変換して、末尾に「Binding」という単語を追加することで生成します。
例)
activity_main.xml | >> | ActivityMainBinding |
sub_layout.xml | >> | SubLayoutBinding |
main.xml | >> | MainBinding |
Viewのidでは
text_view | >> | textView |
textview | >> | textview |
button | >> | button |
Activityでの使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// ViewBinding Class のインスタンス // lateinit で宣言し初期化タイミングを onCreate() まで遅らせる private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // bindingのイニシャライズ // Binding Classに含まれる静的 inflate() メソッドを呼び出す binding = ActivityMainBinding.inflate(layoutInflater) // root view への参照を取得 val view = binding.root // view をsetContentView()にセット setContentView(view) binding.button.setOnClickListener { ... } } |
Kotlin Android Extensionsに比べると、いえいえfindViewIdに比べても記述が増えてしまうのですが
findViewIdの問題点の改善もあるのでいたしかたないということでしょうか
サンプルコード
まとめてみます。
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//package com.example.testbutton import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.testbutton.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // Button切り替え用のフラグ var flag = false binding.button.setOnClickListener { if (flag ) { // flagがtrueの時 binding.textview.text = getString(R.string.hello) flag = false } else { // flagがfalseの時 binding.textview.text = getString(R.string.world) flag = true } } } } |
XMレイアウトファイル
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?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"> <TextView android:id="@+id/textview" android:text="@string/hello" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button" android:text="@string/button" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5" /> </androidx.constraintlayout.widget.ConstraintLayout> |
文字列をコードにリテラル(直書き)するのではなく、strings.xml に記述して引用するのがお行儀のよい記述とされています。
直に書いていると後でハマることになります。(と理解してけっこうやっていましたが)最近はうるさくワーニングが出るのでちゃんとしてみました。
strings.xml
1 2 3 4 5 6 |
<resources> <string name="app_name">Test Button</string> <string name="hello">Hello</string> <string name="world">World</string> <string name="button">Button</string> </resources> |
app_name はプロジェクトの名前なのでそのままでも、書き換えてもいいでしょう。
strings.xml のファイルは以下の場所にあります。
次にbuild.gradleですが2つあるので注意してください。
build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
plugins { ... } android{ compileSdk ... defaultConfig { ... } buildTypes { release { ... } } compileOptions { ... } kotlinOptions { ... } buildFeatures { viewBinding true } } ... |
android { } の中にbuildFeatures{ } を追加します。
記述後には Sync が必要です(エディタ上部に表示が出ます)
反映に多少時間がかかる場合もあります(MainActivityのエラーの赤線が消えるまで時間がかかる数十秒?)
実行アイコンをクリックします。
「No Device」となっていた場合はエミュレータを作成します
以下を参考にエミュレータを作成してください。
できあがったら実行させてみましょう。
デフォルトでエミュレータがAndroid Studio内に表示されるようになりました
設定を変えれば独立させることも可能ではあります。
デフォルトではちょっと見栄えがわるいので、フォントを大きくしたりレイアウトを変更してみます。
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?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"> <TextView android:id="@+id/textview" android:text="@string/hello" android:textSize="50sp" android:textColor="#ff00ff" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button" android:text="@string/button" android:textSize="30sp" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.6" /> </androidx.constraintlayout.widget.ConstraintLayout> |
Kotlinでは生産性が上がるという意見もありますが、どうでしょう。今後のGoogleにおけるJavaの扱いがどうなるか、どうなっても対応できるようにしておいた方がいいのかもしれませんね。
References:
ボタン | Android デベロッパー
Kotlin and Android | Android Developers
Kotlin Programming Language
Kotlin Android Extensions の未来
Use view binding to replace findViewById