Android Kotlin日本語チュートリアル-①環境構築とAndroid基礎
Android Kotlin日本語チュートリアル
本連載記事はこれからAndroidアプリ開発を始める人に向けたチュートリアルです。
コンセプトは
- プログラミングをあまり知らない人でも完走できる
- プログラミングにある程度詳しい人にも満足できる
- 実用的な知識を提供する
- とにかくわかりやすく
で、全9回と長めですが頑張っていきましょう。
このチュートリアルを終える頃には、Android開発の土台が形成されているだけでなくアプリケーションアーキテクチャの知識が出来上がっているはずです。
作成するのは以下のようなメモアプリです。
完成品は HiroshiARAKI/AndroidKotlinTutrialで公開していますので適宜参考にしてください。
第1回 : 環境構築とAndroid基礎
さて第1回は初歩の初歩から始めます。
とりあえずやりながら逐一解説していきますので、できるだけ飛ばさずに進めてください。
もしこれから知らない単語で解説されていないものがあれば、Android開発用語集【初学者向け】などを別タブで開いて、都度参考にしてみてください。
【準備】Android Studioをインストールする
まずは開発環境からです。
Download Android Studio and SDK tools | Android Developersから最新版をダウンロードしましょう。
その後のインストール手順は、公式ドキュメントを参考にするのが良いです。
捕捉ですが、Android Developersというサイトは公式のドキュメントがたくさん載っていて、今後みなさんもずっとお世話になるページになります。
とりあえず困ったら、ここを参照して、それでもわからなかったら他の方の解説記事で補足する、というのが良いでしょう。
プロジェクトを作成する
Android Studioの準備ができたら早速チュートリアルを始めます。
Android Studioを立ち上げたら、「+ Create New Project」を選択します。
次に、デフォルトで「Phones and Tablet」が選択されていると思うので、その中の「Empty Activity」を選んでNext。
「Activityってなんですか?」と思われるかもしれませんが、後で解説しますので安心してください。
最後に、アプリの名前(プロジェクト情報)を決めましょう。
今回はアプリ名(Name)を「Smart Memo」としてみます。
「Package Name」は、正直今はなんでも良いのですが、基本的に他のアプリや他の方が作ったライブラリと被らないようにしないといけないので、自分が所持しているドメインを逆順で書いたりします。
例えば「example.com」を持っていて今回の「Smart Memo」というアプリを作る場合は「com.example.smartmemo」のようになります。
もし迷うのであれば、今回は「com.[あなたのハンドル名].smartmemo (例: com.araki.smartmemo)」で良いです。
「Save Location」もどこでも良いですが、おすすめはホームディレクトリに「AndroidProjects」や「AndroidStudioProjects」のようなディレクトリを作成しそこで管理するのが良いです。
「Language」はKotlinにします。
JetBrains社が開発している言語であるKotlinはJavaの完全互換言語で、簡潔に書けるだけでなく、安全なコーディングが可能です。
Androidアプリは昔はJavaで書いていましたが、最近はKotlinが主流です。
ちなみにAndroid StudioのベースとなるIDE (統合開発環境)「IntelliJ IDEA」はJetBrais社が開発しています。
最後に「Minimum SDK」は「API 30: Android 11.0 (R)」にしておきます。
これは、このアプリが動作する最低保証OSバージョンです。
AndroidのバージョンはR (API 30)やQ (API 29)のようにアルファベット1文字で省略したりします。
あとは「Finish」でアプリのベースが自動生成されます。
Android Studioを簡単に触ってみる
プロジェクトが立ち上がると上記のような画面になると思います。
立ち上がった直後はライブラリの読み込み等が走るので、少し待ちましょう。
左サイドバーにプロジェクトのディレクトリツリーが表示されれば、OKです。
早速、実行してみましょう。
右上に、実行エミュレータの情報と実行ボタン▶︎があると思います。
もし、「Available devices」に何も端末がなければ、仮想デバイスを作成して管理する | Android Developersを参考にしてください。(端末はなんでもOKで、OSバージョンは30をダウンロードし選択してください。そのほかはデフォルトで良いです。)
Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.
のようなエラーが出た場合は「他の方が書いたこの記事」が参考になるかもしれません。
実行▶︎してみると、アプリがビルドされ、しばらくするとエミュレータが起動し、アプリがインストールされると思います。
上記画像のように「Hello World!」と表示されます。
このように、初期状態で既に超簡易的なアプリが出来上がっています。
ちなみに、下ウィンドウの「▶︎ 4: Run」というタブでは、アプリのデバッグを行うためのログを表示させたりします。
もしアプリが所望の挙動をしなくなったら、ここのログを見てデバッグすることになります。
■でAndroid Studioから実行しているアプリを強制終了させます。
出力されている文字を変えてみる
少しだけアプリをいじってみましょう。
「activity_main.xml」を開いてみます。
.src/
├── androidTest
├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── tech.araki.smartmemo
│ │ └── MainActivity.kt
│ └── res
│ ├── drawable
│ ├── layout
│ │ └── activity_main.xml
│ ├── values
│ └── values-night
└── test
もし閉じてしまった場合は、左のサイドバーから「app > res > layout」の中にあります。
開くと、先ほどエミュレータで表示された「Hello World!」が見えますね。
このGUIウィンドウで要素を直接クリックして編集、ツールバーから要素をドラッグして並べる、などできるのですが、GUIウィンドウでのレイアウトデザインは私はお勧めしません。
おすすめは、右上の切り替えタブにある「Code」「Split」「Design」のうち、「Code」もしくは「Split」が良いでしょう。
レイアウトファイルも、元となるのは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">
<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>
こんな感じです。
最初はちょっと複雑そうに見えるかもしれませんが、最適なコーディングでアプリを作るためにも、直接コードを触ってレイアウトを作成するのに慣れていきましょう。
activity_main.xmlをよく見てみると、大まかには以下のような構造になっていることがわかります。
<ConstraintLayout>
<TextView/>
</ConstraintLayout>
ConstraintLayout
の中に、TextView
が入っています。
ConstraintLayout
はレイアウトの大枠でありコンテナのような要素で、他にもLinearLayout
などありますが基本的にはConstraintLayout
を使いましょう。
理由は、ConstraintLayout
を使った方が描画パフォーマンスが上がるからです。
さて、話が少し逸れましたが、「Hello World!」の実体はTextView
です。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Android Kotlin!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
のようにandroid:text
を変えれば表示されている文字も変わります。
さて、その他にも色々な要素があると思うのですが、app:layout_constraint*
以外を一旦解説します。
android:layout_width
/ android:layout_height
にはその名前の通り、その要素の幅と高さを指定します。
指定できるものはいくつかあって、
wrap_content
… 要素の中身によって動的に変化します。例えば、TextViewの文字が長ければ長いほど、行数が多ければ多いほど大きくなります。その名の通り、中身 (content)を包む (wrap)だけです。match_parent
… 親要素 (上記のXMLレイアウトだとConstraintLayout) の高さ / 幅と同じになります。〇〇dp
/sp
/in
/px
/pt
… 具体的な数値と単位で指定します。基本的に、Viewにはdp、テキストサイズにはspが使われます。@dimen/〇〇
… リソースファイル (このあと解説します)から指定するIDを元に参照して決定します。
と大きく4種類あります。
どれもよく使われるので、今はなんとなく把握しておきましょう。
リソースファイルで文字列を管理する
activity_main.xmlを見ているとどうやらWarning (警告)が出ていますね。
内容としては「文字列のハードコードは非推奨で、@stringで参照できるリソースファイルで管理しましょう」というものです。
リソースファイルは「app > res」ディレクトリ以下で管理され、文字列はさらにその下の「app > res > values > string.xml」で一括管理します。
せっかく「Extracting string resource」とあるのでそれをクリックしても良いですし、string.xmlを開いて以下のように追記ます。
<resources>
<string name="app_name">SmartMemo</string>
<string name="main_text">Hello Android Kotlin!</string> <!-- 追記 -->
</resources>
そうしたら、activity_main.xmlのTextView
内、android:name
を以下のように変更します。
android:text="@string/main_text"
これで、Stringリソースのmain_textというIDを参照して文字列を取ってくるようになります。
なぜハードコードがダメでわざわざリソースファイルで管理するのでしょう?
主な理由は2つあって、DRY (Don’t repeat yourself: 二度同じものを書かない) 原則とローカライズです。
DRYは、同じ文字列を繰り返し書くことになれば、またハードコードしなくてはいけなくなり変更の柔軟性がなくなる、というわかりやすい理由です。
もう一つのローカライズは、作成しているアプリケーションを日本に止まらず世界に公開したい、となったときにリソースファイルで管理していれば、参照するリソースファイルを変えるだけで、一発でローカライズが完了できるようになります。
もしそうしなかったら、国ごとにハードコード部分を手作業で書き換えなくてはなりませんし、同じようなXMLレイアウトファイルがたくさん出来上がってしまいます。
ある意味DRY原則と言っていることは同じかもしれませんね。
ボタンを追加してみる
さて解説ばかりになってしまったので、本格的にアプリを作っていきましょう。
まずはactivity_main.xmlにボタンを追加してみます。
同時にボタンの文字もstring.xmlで定義します。
string.xml
<resources>
<string name="app_name">SmartMemo</string>
<string name="main_text">Hello Android Kotlin!</string>
<string name="main_add_button">メモを追加</string> <!-- 追記 -->
</resources>
activity_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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_add_button"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
まだボタンは位置が定まっておらず、エラーも出ていますので解消してあげます。
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_add_button"
app:layout_constraintTop_toBottomOf="@id/main_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
良い感じにボタンが配置されました。
さて、ここでandroid:id
とapp:layout_constraint*
というプロパティを解説します。
まず、android:id
はそのままの意で、Viewに一意のIDを付与してそのIDで識別できるようになります。
そして、app:layout_constraint*
はConstraintLayout
の子要素専用プロパティで要素同士の位置関係を決定します。
指定できるのは、
- parent … 親要素
- @id/〇〇 … そのIDが割り振られたView
の2つです。
例えば、
app:layout_constraintTop_toBottomOf="@id/main_text"
は「自身の上辺 (Top)は main_textのIDが割り当てられたView (ここではTextView)の下辺 (Bottom)の間に制約 (constraint) を儲ける = 結びつける」と言う意味です。
ボタンクリックの処理を実装する
今のままではボタンはあるだけで、押しても何も反応しません。
具体的な操作は、MainActivity.ktに記述していきます。
package tech.araki.smartmemo
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はAndroidアプリのベースとなるViewで、全ての土台はActivityになります。
Activityを起点に別のActivityに移行したり、Fragment (第2回で解説します)と呼ばれるViewを呼び出したりします。
まずは、自動生成された上記コードを簡単に理解していきましょう。
// ActivityはAppCompatActivityクラスを継承して作成する
class MainActivity : AppCompatActivity() {
// Activityが生成されたときに呼ばれるメソッド
override fun onCreate(savedInstanceState: Bundle?) {
// 親クラスAppCompatActivity()の同名メソッドを呼ぶ
super.onCreate(savedInstanceState)
// res > layout > activity_main.xmlを元にViewを生成する
setContentView(R.layout.activity_main)
}
}
簡単にコメントを加筆するとこんな感じでしょうか。
最初のうちは完全に理解できなくてOKです。
まずは見様見真似で作っていきましょう。
そうしたら、先ほどのレイアウトファイルで構築したTextView
とButton
をMainActivityから参照します。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// findViewById<T>()の <T>は型推論できるので省略可能
// activity_main.xmlで割り当てたIDからViewを探す
val mainTextView: TextView = findViewById(R.id.main_text)
val addButton: Button = findViewById(R.id.add_button)
}
}
レイアウトファイルからViewを取得するには、findViewById<T>()
メソッドを使用します。
Kotlinの型推論は柔軟なので、val mainTextView: TextView
と定義していれば<TextView>
は省略可能です。
逆に、以下のように書くことも可能です。
val mainTextView = findViewById<TextView>(R.id.main_text)
さて、そうしたら以下の操作を実装してみましょう。
- ボタンを押したら、「Hello Android Kotlin!」が「ボタンが押された!」に変わる
「メモを追加」とはかけ離れた処理ですが、今は目を瞑ってください。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// findViewById<T>()の <T>は型推論できるので省略可能
// activity_main.xmlで割り当てたIDからViewを探す
val mainTextView: TextView = findViewById(R.id.main_text)
val addButton: Button = findViewById(R.id.add_button)
addButton.setOnClickListener {
mainTextView.text = "ボタンが押された!"
}
}
}
うまく動作していそうですね。
addButton.setOnClickListener {
mainTextView.text = "ボタンが押された!"
}
だけで実装できてしまうのですが、ここにはKotlinの色々な機能が詰まっています。
それについては、ラムダやSAMを関数の引数に取っているからなのですが、「Android KotlinのonClickListnerを紐解く【初学者向け】」で解説しているので、余裕があれば見てみてください。
第1回のまとめ
- レイアウトの実体はXMLファイル
- できるだけ直接書いてデザインする
- レイアウトは
ConstraintLayout
を使うようにする ConstraintLayout
は他のViewの辺と自身の辺を指定して結びつける
- ActivityはAndroidアプリの土台となるView
おわりに
第1回はここで終わりになります。
今回は、Androidアプリ開発の基礎の基礎から解説しました。
次回は、Activityと同じく重要なView「Fragment」を絡めて解説していきます。