はじめに

今回の勉強会では、いよいよロジックを実装していきます。

今回の勉強会が一通り実践できるようになると、下記のようなことができるようになります!

  • ボタンを押したら何かが起こるという、アプリの基本機能を作れるようになる!
  • Kotlinの基本文法と、ロジック実装に必要な概念を理解できるようになる

今回のキーポイント

  • ロジック実装の考え方
  • Android開発におけるKotlinの基本文法(変数の宣言、メソッドの定義)
  • リスナについて

前回の勉強会で、文字を入力するフォームを作成しました。今回の勉強会でロジックを実装し、ボタンを押したら入力した文字が表示されるアプリを作ってみましょう!

前回の内容はこちら

前回作成したアプリを開こう!

今回は、前回のアプリを引き続き使用しましょう。

AndroidStudioのWelcome画面から前回作成したアプリ(DisplayProfile)を選択してエディタを開きましょう。

今回のゴール

今回も先にゴールをお見せします。
今回のゴールはロジック部分を完成させることです。そして、ロジック部分は、Kotlinファイル(〇〇.kt というファイル)が担っています。
つまり、ロジック部分を決定しているKotlinファイルを作ることが今回のゴールです。

以下のファイルが、今回の完成形です。
activity_main.xmlについては、前回作成したファイルに以下のコードを追加しましょう。この部分は前回学んだ知識で実装できるので、今回の勉強会では省略します。そのままコピペしてください。

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:id="@+id/tvDisplayName"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="100dp"
      android:layout_marginEnd="8dp"
      android:textSize="30sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/etLanguage" />

  <TextView
      android:id="@+id/tvDisplayLanguage"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="8dp"
      android:textSize="30sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.0"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/tvDisplayFrom" />

  <TextView
      android:id="@+id/tvDisplayFrom"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="8dp"
      android:textSize="30sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.0"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/tvDisplayName" />

</androidx.constraintlayout.widget.ConstraintLayout>

今回XMLファイルに追加したコードは、入力フォームの余白部分に置かれた3つのラベルを表しています。
それぞれ、名前・出身・学習中の言語のフォームに入力した文字列を表示させるためのものです。

今回のメインはMainActiity.ktです。完成品は以下のとおりです。このファイルに、今回の勉強会で実装するロジック部分が詰め込まれています。

これ以降の作業でエラーが発生したり予期せぬ状態になった場合は、こちらのファイルと比較していただければと思います。

今回の勉強会を通して、このファイルを一緒に作り上げていきましょう!

MainActiity.kt

package com.example.displayprofile

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity(), View.OnClickListener {

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

        val btDisplay = findViewById<Button>(R.id.btDisplay)
        btDisplay.setOnClickListener(this)
        val btClear = findViewById<Button>(R.id.btClear)
        btClear.setOnClickListener(this)

    }

    override fun onClick(v: View) {
        val tvDisplayName = findViewById<TextView>(R.id.tvDisplayName)
        val tvDisplayFrom = findViewById<TextView>(R.id.tvDisplayFrom)
        val tvDisplayLanguage = findViewById<TextView>(R.id.tvDisplayLanguage)
        val etName = findViewById<EditText>(R.id.etName)
        val etFrom = findViewById<EditText>(R.id.etFrom)
        val etLanguage = findViewById<EditText>(R.id.etLanguage)
        
        when (v.id){
            R.id.btDisplay -> {
                tvDisplayName.text = "氏名:" + etName.text
                tvDisplayFrom.text = "出身:" + etFrom.text
                tvDisplayLanguage.text = "学習中の言語:" + etLanguage.text
            }
            R.id.btClear -> {
                etName.setText("")
                etFrom.setText("")
                etLanguage.setText("")
                tvDisplayName.text = ""
                tvDisplayFrom.text = ""
                tvDisplayLanguage.text = ""
            }
        }
    }
}

ファイルはどこにある?

今回も前回と同じく、編集対象の

  • MainActivity.kt

を探して表示させるところから始めます。

Android Studio の左側、Projectツールウィンドウ上部のドロップダウンリストからAndroidを選択し、appをクリックしてください。
今回編集するファイルは、この中のjavaフォルダにあります。

Kotlinを使う場合であっても、javaフォルダにファイルが置かれることに気をつけてください。
javaフォルダの中に、PackageName(今回はcom.example...) と同じ名前のフォルダがあります。 その下にMainActivityファイルがあります。

同じ名前のフォルダで、(androidTest), (test)と後ろに書かれているフォルダもありますが、これらは無視して構いません。

ここからMainActivityを選択し、エディタに表示させましょう!

ロジック実装の考え方

前回の勉強会では、ビュー (画面部品) の配置方法について学びました。
実は、ロジック実装も部品配置と同じイメージで実装することができます。
前回学んだ画面部品の配置と比較すると、以下のように対応付けることができます

画面部品の配置ロジック実装
部品の種類ビュークラス
(TextView, Button)
クラス
(String, Int)
部品そのものビュー
(tvName, btDisplay)
インスタンス
(name, age)

クラスと聞くと、以下の基本的な型を思い浮かべる方が多いかと思います。

  • Int:整数
  • Float:小数
  • Double:小数
  • String:文字列
  • Array:配列
  • Boolean:真偽値(TrueかFalseか)

今回のロジック実装で扱うのはAndroidアプリに関係するクラスになりますが、上記のようなクラスと同じ概念のものです。ビューを配置したときと同じような流れで、ロジックを構成する部品を配置しましょう。

具体的には、

  1. クラスを指定してインスタンスを作る
  2. 演算子を用いてインスタンスに関する計算をする
  3. インスタンスに対する命令を定義する

という作業を一緒に行っていきます。

※この勉強会に参加されているほとんどの方は他の言語を学ばれているはずなので、クラスの詳細な説明は省略します。

ビューのインスタンスを作成する

ここから早速、手を動かしながら学んでいきます。

今回のゴールの章で示した、activity_main.xml の追加部分は事前に実装しておいてください。これ以降、activity_main.xmlは完成済とみなして進めます。

MainActivity.ktには既にある程度コードが書かれています。このコードに追記する形で実装していきます。

以下のように、1文追加してください。

class MainActivity : AppCompatActivity() {

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

        val btDisplay: Button = findViewById(R.id.btDisplay)

今追加した、

val btDisplay: Button = findViewById(R.id.btDisplay)

こちらの文には、Android開発のために必要な文法がたくさん詰まっています。この文がどのような意味を持つのか、少しずつ解きほぐしていきましょう。

変数の宣言

どの言語にも共通する流れですが、はじめに変数を宣言します。ここでは、あるクラスをもとにインスタンスを宣言することになります。
その時の文法がこちらです。

val name: String = "hogehoge" 

この文は、

「String型(クラス)で 名前がname、中身が "hogehoge"というインスタンスを作る」

という意味になります。

valは、一回宣言したら中身を変更することができません。途中で変更する場合はvarを頭につけます。
特別な事情がない限りなるべくvalを使い、中身を変更できない形式で宣言しましょう。

そして、Kotlinでは型推論が可能です。変数を宣言する際にクラスを指定しなくても、自動的に使用する型を決めてくれます。

val name = "hogehoge" 

と書くだけで、String型のnameという変数が作られます。Ruby, PHP等の動的型付け言語を使われていた方ならおなじみの機能ですね。

ここまで学んだことを踏まえると、

val btDisplay: Button = findViewById(R.id.btDisplay)

この文は、

「Button型(クラス)で 、名前がbtDisplay、中身が findViewById(R.id.btDisplay)というインスタンスを作る」

という意味になります。この文も型推論が可能です。やり方については後ほどご紹介します。

変数の名前について

先程定義した変数の名前は btDisplay でした。これは、前回作成した表示ボタンのビュー(btDisplay)と同じ名前です。
変数にどのような名前をつけても問題ないのですが、「変数名を見ただけで、どのような機能を持つ変数かがわかるようにする」のが基本です。
この変数は、表示ボタンのビューに結びつけて使う予定なので、表示ボタンビューと同じ名前を付けました。

findViewByIdとは

次に、findViewByIdについて説明します。先程おまじないのような形で書いていただきましたが、このfindViewByIdは、

layoutファイル(activity_main.xml)とkotlinファイル(MainActivity.kt)間のビューを結びつける機能を持つ、MainActivityクラスのメソッド

という意味です。
変数とビューの名前を同じにしましたが、それだけでは結びつけができません。findViewByIdを用いて、layoutファイルのビューとkotlinファイルのインスタンスを繋げる必要があります。

※findViewByIdの省略

プラグインを使えば、findViewByIdを使わずにビューとインスタンスの結びつけをすることができます。
kotlin-android-extensions
というプラグインを入れることで、layoutファイルで定義したidをそのまま変数名として使うことができます。
興味がある方はチャレンジしてみてください!

R.id とは

findViewByIdのカッコの中に、

R.id.btDisplay

という記述がありました。
このR.idを理解できれば、下記の文の全体がわかるようになります。

val btDisplay: Button = findViewById(R.id.btDisplay)

結論から述べると、R.id にはリソースIDを返す機能があります。

resフォルダに入っているもの(画像やlayoutファイル、画面部品)にはすべて、整数のIDが割り振られていいます。
このIDは他と被ることのない一意な値で決められています。人間でいうマイナンバーと同じイメージですね。
これらをロジック実装で使う際は、リソースIDを使って呼び出す必要があります。

表示ボタン(btDisplay)を呼び出すためにリソースIDが欲しかったので、R.id.btDisplayと書くことでbtDisplayのリソースIDを取得しました。

以上より、以下の文は、

val btDisplay: Button = findViewById(R.id.btDisplay)

「Buttonという型(クラス)で、名前がbtDisplayのインスタンスを作り、XMLファイルで定義したbtDisplayという画面部品をリソースIDを使って探し、画面部品とインスタンスを結びつける」

という意味だということがわかりました。

※型推論の利用

型推論について後回しにしていたので、ここでご説明します。

val btDisplay: Button = findViewById(R.id.btDisplay)

この文は、型推論を使うと

val btDisplay = findViewById<Button>(R.id.btDisplay)

このように書くことができます。結局findViewByIdのところで型を指定しなくてはならないので手間はあまり変わりませんが、どちらの書き方でも問題ないことを覚えておいてください。

インスタンスに命令を定義し、クリック処理を実装する

ボタンビューのインスタンスを作ることで、変数宣言に関する基本的な文法を学ぶことができました。
次に、「ボタンを押したら文字を表示させる」というクリック処理機能を実装していきます!

クリック処理を実装する手順がこちらです。

  1. ボタンにリスナーを付ける
  2. 1でできるメソッド onClick の中に、やりたいことを書く

ちなみに今回やりたいことは、「入力フォームに記入した文字列を、下のラベルに表示させる」ことです。これらの作業を手順を追って進めていきます。

ボタンにリスナーを付ける

先程書いた文の下に

btDisplay.setOnclickListener

と打ってください。途中まで入力すると、予測変換のような候補が大量に出てきます。

これらがbtDisplayで使えるメソッドです。Buttonクラスのインスタンスに対して使えるメソッドの候補をAndroidStudioが自動的に表示してくれています。

この中から、

setOnClickListener(l: View.OnClickListener?)

を選んでください。カッコが出てきたら、

btDisplay.setOnClickListener(this)

と入力します。

setOnClickListenerは、「OnClickListenerというリスナをここに設定する」という意味のメソッドです。

アプリ側からすると、ボタンがいつ押されるかはわかりません。ユーザーがボタンを押す瞬間を今か今かと待っている機能があるのですが、それがリスナ(Listener)です。
今回は、クリックする瞬間を待つ機能であるOnClickListenerを設定します。

※ thisは自分自身という意味です。厳密には、OnClickListenerを定義しているMainActivityを意味するものですが、今はそこまで深く理解しなくても問題ありません。

ここまで入力すると、thisの部分に波線がかかっています。これは、「これだけだと不十分だ」という警告を意味しています。ここにカーソルを当てると下図のようにメッセージが出てくるので、
More actions... を開くために option + Enterを(Windowsの場合は、Alt + Enter)を押してください。

下図のメッセージが出てくるので、Let 'MainActivity' を選択してください。

選択すると、このようなダイアログボックスが出てきますが、そのままOKをクリックしてください。

以上の操作で、onClickメソッドが自動的に作成されました。このメソッドは、「ボタンが押されたときに、中に書かれていることを実行する」という役割を持つメソッドです。

この中に、入力した文字列を表示させる機能を入れていきます。

onClick の中に、やりたいことを書く

今回やりたいことは、「入力フォームに記入した文字列を、下のラベルに表示させる」ことです。
手始めに、名前フォームに入れた文字列を、下のラベルに表示させてみましょう。

この機能を実装する上で必要なビューは、名前入力フォームと名前表示ラベルです。この2つのインスタンスを先に作ります。先程作ったonClickメソッドの中に書いていきましょう。

override fun onClick(v: View?) {
    val tvDisplayName = findViewById<TextView>(R.id.tvDisplayName)
    val etName = findViewById<EditText>(R.id.etName)
}

インスタンスを宣言することができました。この下に、

tvDisplayNameラベル内に表示させる文字列 = 氏名:etNameに入力した文字列

という式を入れれば、今回やりたいことが実装できます。

「tvDisplayNameラベル内に表示させる文字列」はどのように表現すればいいでしょうか。実は、前回の勉強会で学んだことの中にヒントがあります。

前回の勉強会で、ラベルの中に入れる文字をstrings.xmlから選択しました。この作業の流れを振り返って見ましょう。

activity_main.xmlを開きDesignモードにしてください。名前を表示するラベル(tvDisplayName)を選択すると、右側にAttributesウィンドウが出てきます。

このラベルに文字を表示させたい場合、textの欄に文字を入力していました。Attributesウィンドウ右上の虫眼鏡マークから、'text'を選択し、text欄を探し、そこに文字を入力することで、下図のように文字を表示させることができます。

このtextが、実はtvDisplayNameのプロパティにあたります。textはTextViewクラスのインスタンスで表示させる文字列を格納するプロパティです。
したがって、

tvDisplayName.text

が「tvDisplayNameラベル内に表示させる文字列」という意味になります。

同様に、「etNameに入力した文字列」も

etName.text

と表現できます。文字列の足し算のやり方を踏まえると、

tvDisplayName.text = "氏名:" + etName.text

これをonClickメソッドの中の最後の行に追加しましょう。これで、名前入力フォームに関する機能が実装できました。

試しにアプリを動かしてみましょう。下図のように、名前入力フォームに文字を入力し、表示ボタンを押して名前が出てきたら成功です。

同じことを出身・学習中の言語フォームでもやってみましょう。

すべてできたら、onClickメソッドの中は以下のようになっているはずです。

    override fun onClick(v: View?) {
        val tvDisplayName = findViewById<TextView>(R.id.tvDisplayName)
        val tvDisplayFrom = findViewById<TextView>(R.id.tvDisplayFrom)
        val tvDisplayLanguage = findViewById<TextView>(R.id.tvDisplayLanguage)
        val etName = findViewById<EditText>(R.id.etName)
        val etFrom = findViewById<EditText>(R.id.etFrom)
        val etLanguage = findViewById<EditText>(R.id.etLanguage)
        tvDisplayName.text = "氏名:" + etName.text
        tvDisplayFrom.text = "出身:" + etFrom.text
        tvDisplayLanguage.text = "学習中の言語:" + etLanguage.text
    }

今回はここまでにして、続きは次回の後編でお話します。

おわりに

今回は、Androidアプリのロジック実装を行いました。

ロジック実装を通して、Androidアプリを開発する上での基本的な文法を学ぶことができました。
第1回から第3回を通して、Androidアプリ開発の大まかな流れを理解することができたかと思います。

次回は最終回です! 次回は、まだ説明しきれていない残りの部分

  • クリアボタンを押した時の挙動の実装(条件分岐)
  • onCreateとは何か
  • クラス継承、オーバーライドという概念
  • エミュレータで日本語を入力するための設定方法

あたりをご説明していきます。

今回の勉強会はここまでです。お疲れさまでした!

次回の内容はこちら

この記事が気に入ったら
フォローしよう

最新情報をお届けします

Twitterでフォローしよう

おすすめの記事