Android

Androidアプリ開発方法について (その1)

Androidアプリは、ユーザーの操作を受け取ったり、バックグラウンドで処理をしたり、画面間で情報を受け渡したりと普段使う上では気にも留めない要素が詰め込まれています。そこで、Androidアプリ開発を始めるにあたり、Androidのアプリケーションではどういったコンポーネントが使われているのかを書いていきたいと思います。

Androidを構成するコンポーネント

Andoridアプリでは4つのコンポーネントが使われています。自分が作りたいアプリによってどのコンポーネントを組み合わせればいいかを設計することが重要です。

1. アクティビティ
2. サービス
3. ブロードキャストレシーバー
4. コンテンツプロバイダ

アクティビティとは、画面を構成するためのコンポーネントです。ユーザーインターフェースを構成するために必要となり、基本的には1画面につき1アクティビティとなります。

サービスとはアクティビティとは反対でユーザーインターフェースを構成しないコンポーネントになります。Andoroid OSは画面上には1つの画面しか表示できません。そのため、バックグラウンドで何か処理を行う際にはこのサービスを使います。

ブロードキャストレシーバーとはAndoroid OS⇔アプリケーション、アプリケーション同士間でイベントの通知を行う際に使うコンポーネントです。例えば、アプリケーション同士間では、通常はデータの共有はできないため、このブロードキャストレシーバーを使ってデータの受け渡しをします。

コンテンツプロバイダとは、予めアプリケーション同士間でデータを共有することのできるコンポーネントです。Andoroid端末に標準でインストールされている「ギャラリー」なんかがそうです。どのアプリケーション(カメラアプリやSNSアプリなど)からでも権限さえあれば、「ギャラリー」へアクセスすることができます。

アクティビティ

ここからはAndroidアプリ開発において欠かせない、アクティビティについて詳細に説明したいと思います。

アクティビティとは

アクティビティとはアプリケーションの画面を構成する上で欠かせないコンポーネントです。このアクティビティ上にボタンやテキストボックス、ラベルなどを配置することによってユーザー操作を支援しています。

スマホを使われていればお分かりだと思いますが、表示できる画面は1つだけです。そのため、一般的なアプリケーションは複数の画面で構成されており、各画面ごとにできる機能を定めています。画面が切り替わるたびにバックグラウンドに行ったり、フォアグランドへ戻ってきたりします。

アクティビティの作り方

アクテビティは「ソースコード(.java)」と「レイアウトリソース(.xml)」、「マニフェストファイル(.xml)」の3つから構成されています。
新規で作成するには、画面右上にある「ファイル」 -> 「新規」 -> 「アクテビティ」 -> 「空のアクテビティ」を選択します。

アクテビティを作成すると「ソースコード(.java)」と「レイアウトリソース(.xml)」が出来上がります。ソースコードはその名の通り、プログラムの処理ロジックを記述するためのファイルで、レイアウトリソースは画面上のコンポーネントの配置を記述したファイルです。

それぞれ、以下の場所に作成されます。
・”プロジェクト名” -> “java” -> “com~のパッケージ名” ->”アクテビティ名.java”
・”プロジェクト名” -> “res” -> “layout” ->”activity_アクテビティ名.xml”

アクテビティを実装する上での注意点

アクティビティでは次の3つ事を必ず実装する必要があります。

・AndroidManifest.xmlに追加したアクティビティを登録

・アクティビティのライフサイクルの関数を記述

・レイアウトリソースととアクティビティを関連付け

AndroidManifest.xmlに追加したアクティビティを登録

AndroidManifestとは、Androidアプリの定義を記述したファイルです。アプリケーションがどんなアクティビティで構成されているか、データの受け渡しはどうするか、パーミッション(セキュリティ保護のために必要)などが書かれています。

下記、AndroidManifest.xmlの赤下線がアクティビティの記述です。新たにアクテビティを追加する場合は同じようにアクティビティの記述を登録します。

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.example.helloworld.helloworld”>

<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round”
android:supportsRtl=”true”
android:theme=”@style/AppTheme”>
<activity android:name=”.HelloWorld”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>

</manifest>

アクティビティのライフサイクルの関数を記述

前回でも説明した通り、Androidアプリにはライフサイクルがあり、コンポーネントでもあるアクテビティにもライフサイクルがあります。例えば、アクティビティが生成されるときに呼び出されるonCreateや再び画面が表示された場合に呼び出されるonRestartなどがあります。

onCreate アクティビティ生成時に呼び出される
onRestart アクティビティが再度表示される直前に呼び出される
onStart アクティビティがユーザーに対して表示される直前に呼び出される
onResume ユーザから操作を受ける直前に呼び出される
onPause 別のアクティビティを起動しようとするときに呼び出される
onStop アクティビティがユーザに対して非表示になったときに呼び出される
onDestroy アクテビティを破棄する前に呼び出される
レイアウトリソースととアクティビティを関連付け

アクテビティにはボタンやラベル、テキストボックスなどのコンポーネントを配置します。アクテビティと各コンポーネントを紐づけるためにsetContentViewをソースコード(.java)に記述する必要があり、普通はonCreateの中に書きます。

package com.example.helloworld.helloworld;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class HelloWorld extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello_world);
}
}

おまじないのようにActivity系のクラスを継承し、onCreate関数の中にsetContenViewを書きます。R.layout.activity_hello_wordはレイアウトリソースを指しています。レイアウトリソースはアクティビティに乗せるボタンやテキストボックスなどのコンポーネントの設定情報を持っています。

<?xml version=”1.0″ encoding=”utf-8″?>
<android.support.constraint.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=”com.example.helloworld.helloworld.HelloWorld”>

<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” />

</android.support.constraint.ConstraintLayout>

ライフサイクルの動き

アクテビティのライフサイクルの処理について上述しましたが、ライフサイクルは複雑です。ここで、アプリを開いた状態でホームキーを押して一度ホーム画面に戻ったのちに、アプリを再開するライフサイクルの流れについて説明します。

上図は、スマホからアプリのアイコンをタップして起動(初期・生成済・開始中)し、アプリが表示された(表示中)あと、ホームボタンを押し(一時停止、停止)、再度アプリのアイコンをタップしてアプリを起動した例です。

一度表示されたアプリはホームボタンを押し、前面から消えてもアクテビティ自体はなくなっておらず、停止状態で背面に残っています。そのため、再度アプリのアイコンをクリックしても初期・生成済の状態を経由せずに表示されます。

停止状態ではなく、破棄状態(onDestroy())の場合、アプリのアイコンをタップすると初期状態からスタートします。停止状態から破棄状態に移行する際にonDestroy()関数が呼び出されますが、必ずしもonDestroyが実行されるとは限りません。例えば、Androidの設定から強制終了をするとこの関数は実行されません。そのため、onDestroy()にアプリの終了処理(ファイルクローズなど)を書くと、実行されないケースが出てきてしまうので、アプリの終了処理はサービスに書くとよいです。

アクテビティの画面遷移

複数の画面(複数のアクテビティ)があると必ずと言っていいほど、画面が切り替えることが出来ます。しかし、アクテビティ間で共有したデータを持っていないため、インテントという仕組みを使ってアクテビティから別のアクテビティにデータの受け渡しをします。インテントには明示的インテントと暗黙的インテントがあります。

明示的インテント

明示的インテントとは、”どのアクティビティを起動するか”を予め、ソースコード(.java)に記載します。その際には呼び出す処理(IntentクラスのsetClass)に宛先のアクティビティを指定します。

暗黙的インテント

暗黙的インテントとは、どのアクティビティで起動するかをユーザに選択してもらうようにAndroid OSに促します。例えば、スマホでURLのリンクをタップしたときにAndroidからどのアプリケーションで開くか選択させる画面が表示されたことがないでしょうか。メーラー、ブラウザなどからどのアプリケーション(アクティビティ)を起動するかをユーザに任せているのです。明示的インテントと違ってソースコード(.java)には予めAndroid OSで用意しているアクションを指定します。Android OSはそのアクションをもとにユーザへ候補として表示するアプリを決めています。

ちなみにAndroid OSが判断に使っている情報はintent-filterです。AndroidManifest.xmlにはintent-filterのタグがあり、その中にactionタグがあります(本稿のAndroidManifestサンプルの背景色が黄色の箇所)Andoroid OSはその記述内容を見てそのアプリを表示するかを決めています。

まとめ

Android開発のまとめ

・4つのコンポーネントがある(アクティビティ、サービス、ブロードキャストレシーバー、コンテンツプロバイダ)
・アクティビティとはアプリケーションの画面を構成する上で欠かせないコンポーネント
・ライフサイクルが定義されており、ライフサイクルごと関数がある
・アクティビティ間の遷移にはインテントをつかう

お薦め書籍