第03講 生まれた日を知るアプリ


本講義では、誕生日を入力すると誕生日に関する情報を表示する「生まれた日を知るアプリ」の作成を通して、Androidアプリケーション開発において大切な概念であるActivityとIntentに関する学習を行います。


本講義で作成するアプリの画面




AcitivityとIntent

コンポーネント

Androidアプリケーションは、コンポーネントと呼ばれるオブジェクトから構成されます。

コンポーネントには、以下の4種類のものがあります。

  • アクティビティ(Activity)
  • サービス(Service)
  • ブロードキャストレシーバ(Broadcast Receiver)
  • コンテントプロバイダ(Content Provider)

それぞれ、以下のような機能を持ちます。

Activity

アクティビティとは、画面を生成する機能を持っているコンポーネントです。ひとつのアクティビティは、ひとつの画面を生成します。したがって、複数の画面を持つアプリを作成する場合は、画面の数だけActivityを作成することとなります。


Androidアプリケーションを開発する際に、最も多く利用するコンポーネントです。アクティビティの仕組みについては、次章でもう少し詳しく説明します。

Service

サービスは、時間のかかる処理をバックグラウンドで(画面の背後で)実行し続けたい、という時に利用されるコンポーネントです。アクティビティは、そのアクティビティが生成した画面が表示されていない場合、アプリケーションの処理が中断させられてしまう可能性があります。


例えば、音楽再生を行うメディアプレイヤーアプリケーションを作っているとします。曲の再生を、アクティビティで行っているとそれとは違う画面が表示されているときに音楽の再生が中断されてしまう可能性がある、ということです。曲の再生を、サービスを使って行うことで、途切れることなく曲をバックグラウンドで再生し続けることができるようになります。

Broadcast Receiver

 ブロードキャストレシーバは、ブロードキャストの通知を受信し、対応する動作を行うコンポーネントです。例えば、充電池の状態の変化や電話の着信があった場合に、Androidシステムは全てのアプリケーションに対して通知を行います。ブロードキャストレシーバを用いることで、これらの通知を受け取った時の処理をアプリケーション内で記述することができます。


Content Provider

 コンテントプロバイダは、複数のアプリケーションでデータを共有したい、というときに使われるコンポーネントです。通常、アプリケーションのデータはそのアプリケーションのみでしか利用できませんが、コンテントプロバイダを利用することでデータを他のアプリケーションに公開し、データを他のアプリケーションから利用することができるようになります。

 例えば、Content Providerを利用したアプリケーションに,標準でインストールされている電話帳があります。電話帳は,それ自身でデータを保存せず,別途定義したContent Provider経由で連絡先データを管理しています。そのデータは,ユーザーが認めた他のアプリケーションからも参照できるようになっています。Androidアプリケーションマスターコースにおいても、コンテントプロバイダを介して電話帳の編集を行うアプリケーションの作成を行います。

Activityのライフサイクル

 Activityはandroidにおいて最も重要な要素の一つです。

 第1講でも触れたようにActivityは「一つの画面」を表します。(一部例外もあります。) 

 Activity(画面)は生成されて、表示され、別の画面が表示されると、画面上から消えます。この一連の流れをActivityのライフサイクルと呼び、次の図によって表されます。



  • onCreate()・・・Activityが生成された時に呼び出されるメソッド。
  • onStart()・・・Activityが開始する時に呼び出されるメソッド。
  • onResume()・・・Activityが最前面に表示された時に呼ばれるメソッド。
  • onPause()・・・別のActivityが最前面に表示される時に呼ばれるメソッド。
  • onStop()・・・Activityが画面上に表示されなくなった時に呼ばれるメソッド。
  • onDestroy()・・・Activityが破棄される時に呼ばれるメソッド。


今までのアプリはonCreate()の中に処理を書いていましたが、このonCreate()というのはActivityのライフサイクルの一番最初の項目です。


他の項目については、今までの講義では使用していませんが、今後の講義の中で出てきますので、随時解説していきます。


Activityは「一つの画面」を表し、これがandroidアプリの根幹となっていることを覚えておいて下さい。

また、Activityを追加した時は、追加した画面をAndroidManifest.xmlに追加する必要があることも併せて覚えておきましょう。(あとで実際に編集します!)

Intent

Intentは直訳すると「意図」(やりたいこと)です。先にあげたAndroidのコンポーネントのうち、アクティビティ、サービス、ブロードキャストレシーバを起動するためにはインテントを利用する必要があります。具体的には、

  • 別の画面(Activity)を呼びたい
  • 別のアプリを呼びたい
  • メールを送りたい
  • 電話をかけたい

等、別の画面やアプリを呼び出して「やりたいこと」がある時、androidにおいてはIntentが用いられます。


一番多く使われるパターンとしては一番上のパターン、すなわち画面(Activity)間の連携です。

今回のアプリでもこの画面間の連携にIntentを用いています。

生まれた日アプリにおけるActivityとIntent

生まれた日アプリは、2つのアクティビティ(TopActivityとResultActivity)から構成されます。左側の画像がTopActivity、右側の画像がResultActivityです。


まず、TopActivityで生年月日を選択します。そして、TopActivityからResultActivityに対してintentを発行して画面遷移を行います。画面遷移を行う際に、入力された生年月日をTopActivityからResultActivityに渡しています。


さらに、ResultActivityからはintentを利用することで、他のアプリケーションを起動することができます。このようにintentは、他のアクティビティの起動だけでなく他のアプリケーションの起動にも用いることができます。

プロジェクトの作成

eclipseを起動して、新規に「BirthDay」というプロジェクトを作成します。以下の情報にあわせて、各項目を入力して下さい。

<New Android Application(Create a new Android Application)画面入力項目>

 Application Name  BirthDay
 Project Name  BirthDay
 Package Name  com.rainbowapps.birthday
 Minimum Required SDK  API 7 : Android 2.1 (Eclair)
 Target SDK  API 7 : Android 2.1 (Eclair)
 Compile With  API 7 : Android 2.1 (Eclair)
 Theme  None


<New Android Application(Configure Project)画面入力項目>

※何も変更せずそのまま「Next >」ボタンをクリックしてください。

 Create custom launcher icon  チェックする
 Create activity  チェックする
 Mark this project as a library  チェックを外す
 Create Project in Workspace  チェックする
 LocationはデフォルトのままでOK
 Add project to working sets  チェックを外す

<New Android Application(Configure the attributes of the icon set)画面入力項目>

※何も変更せずそのまま「Next >」ボタンをクリックしてください。

 Foreground  Image
 Image File:  launcher_icon
 Trim Surrounding Blank Space  チェックする
 Foreground Scaling  Crop
 Shape  None

<Create Activity画面入力項目>

※何も変更せずそのまま「Next >」ボタンをクリックしてください。

 Create Activity  チェックする
 Activityの種類  Blank Activity


<Blank Activity画面入力項目>

 Activity Name  TopActivity
 Activityの種類  main
 Navigation Type  None 


まっさらな状態でアプリを実行し、エラーがでないことを確認します。

画面に「Hello World!」と表示されていればOKです。

Top画面の作成

strings.xmlの編集

まず、アプリ内で使用する文字列を定義しておきます。

strings.xmlは、resフォルダの中のvaluesフォルダの中にありますので、もし初期状態で表示されていない場合は左側の小さい三角形をクリックしましょう。




また、初期状態ではResourcesタブが全面に表示されていると思いますが、strings.xmlというタブをクリックしましょう。

strings.xmlを開き、以下の黄色の部分をコピー&ペーストして追加しておきます。


res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>


    <string name="app_name">BirthDay</string>

    <string name="action_settings">Settings</string>

    <string name="hello_world">Hello world!</string>

    <string name="message">Input your Birthday</string>

    <string name="btn_ok">OK</string>

    <string name="btn_mail">send mail</string>

</resources>


layoutファイルの編集

次にレイアウトファイルを編集します。まずは、main.xmlを開き、以下のように編集して下さい。グレーは背景の部分が削除する部分、黄色の部分がコピー&ペーストで追加する部分になります。


res/layout/activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".TopActivity" >


    <TextView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/hello_world" />


</RelativeLayout>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical" 

>

    <TextView  

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="@string/message"/>

    

    <DatePicker

    android:id="@+id/datepicker"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_marginTop="10dp"/>

    

    <Button

    android:id="@+id/btn01"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/btn_ok"

    android:layout_marginTop="10dp"/>

</LinearLayout>


ここまでできたら一度保存して実行してみて下さい。

以下のような画面が表示されたら成功です。




(実行する際は、main.xmlファイルを保存し、閉じてから実行するようにして下さい。設定によってはごくまれにmain.out.xmlというファイルが生成されエラーとなることがあります。こうなった場合は、main.out.xmlというファイルを削除し、main.xmlファイルを保存して閉じてから再度実行を試してみてください。)


TextViewとButtonといったウィジェットはこれまでのアプリでも使っていましたが、DatePickerは初めて使います。DatePickerはこのように、日時の選択を行う際に利用するウィジェットです。

ボタンが押されたときの処理を追加する

では、TopActivity.java(srcフォルダのcom.rainbowapps.birthday内)にボタンを押されたときの処理を追加していきましょう。先週の授業でやったように、以下の部分を追加します。


src/TopActivity.java

 public class TopActivity extends Activity implements OnClickListener{

先週と同じように、上位のImport ‘OnClickListener’ (android.view.View)を選択します。



さらに、”Add implemented methods”を選択します。



すると、onClick()メソッドがTopActivity.javaの下部に追加されます。


  @Override

public void onClick(View v) {

// TODO Auto-generated method stub

}


※赤くした文字の部分が「v」ではなく「arg0」となっている場合は「v」に書き換えます。


次にViewの宣言と初期化をします。

以下のオレンジ背景の部分を追加して下さい。それぞれViewの宣言とViewの初期化をしています。第1講でも少し触れましたが、Viewとは画面上に配置されたパーツのことです。この、宣言と初期化をすることで、プログラム内でViewを使うことができるようになります。


src/TopActivity.java

public class TopActivity extends Activity implements OnClickListener{

    private DatePicker datePicker;

    private Button okButton;


    

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        //Viewの初期化

        datePicker = (DatePicker)findViewById(R.id.datepicker);

        okButton = (Button)findViewById(R.id.btn01);

        okButton.setOnClickListener(this);

    }


上記のオレンジの部分を追加すると、以下のように5つエラーが検出されると思います。



エラーは5つ検出されていますが、下の図に表示されている2つを左側の赤い点線の箇所にカーソルをあわせて修正すれば、全てのエラーが消えます。その際は、Import ‘………’(android.widget)を選択しましょう。



上記の操作により、以下の2つのファイルがインポートされていることが確認できると思います。Androidでは、新しいウィジェットを利用する際に、対応するファイルをインポートする必要があり、上記の操作を行うことで簡単にインポートを行うことができます。覚えておきましょう。


import android.widget.Button;

import android.widget.DatePicker; 


続いて、onClick()メソッドの中に、ボタンがタップされたときの処理を記述します。


TopActivity.java#onClick()

    public void onClick(View v) {

    switch(v.getId()){

    case R.id.btn01:

    Toast.makeText(this, R.string.hello_world, Toast.LENGTH_LONG).show();

    break;

    }

    }


Toastの部分にまた赤い点線が表示されると思いますので、先ほどと同じように印をクリックして修正し、必要なファイルをインポートします。ここで一旦、保存し、アプリを実行してみましょう。


「OK」ボタンを押した時に以下のように画面下にトーストが表示されれば成功です。トーストは以下の画像下部のように、ユーザに対して文字列を短時間表示する際に利用するウィジェットです。




結果表示画面の作成

クラスの追加

次に、結果表示画面を作成します。新しいクラス、「ResultActivity.java」を作成します。「com.rainbowapps.BirthDay」を選択した状態で、右クリックを行い、「New」→「Class」と選択します。



すると、以下のようなクラス作成のダイアログが出現します。ここのName:の部分に、「ResultActivity」と入力し、SuperClassの部分に「android.app.Activity」と入力し、「Finish」ボタンを押せば新しいクラスが作成されます。



作成されたResultActivity.javaを開き、以下の文を追加して下さい。


src/ResultActivity.java

package com.rainbowapps.BirthDay;


import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;


public class ResultActivity extends Activity implements OnClickListener{

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.result);

}

@Override

public void onClick(View v) {

switch(v.getId()){

}

}

}


以上のようにすると、以下の部分にエラーが発生していますが、今後修正を行いますのでそのままで大丈夫です。


 setContentView(R.layout.result);


レイアウトファイルの追加

クラスが作成されたら、次に、レイアウトファイルを作成します。新しく作ったクラスにはレイアウトファイルは自動的に割当てられていないので、以下の手順にしたがって、XMLファイルを作成します。まず、「res」フォルダの下の「layout」フォルダを選択します。この状態で、右クリック→「New」→「Android XML File」を選択します。



※Android XML Fileが見つからない場合は、「New」→「Other」を選択し、表示されたダイアログの「Android」→「 Android XML File」を選択してください。



すると、以下のようなダイアログが出現します。



ここで、「File」の項目に「result.xml」と入力し、「Root Element」の項目には「LinerLayout」を選択し「Finish」ボタンを押すことで、作成が完了します。ファイルが作成されたのを確認した後、編集を行います。result.xmlをダブルクリックして開いて下さい。result.xmlに以下の文を追加します。


res/layout/result.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >


    <TextView

        android:id="@+id/birthday"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp" />


    <TextView

        android:id="@+id/age"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp" />


    <TextView

        android:id="@+id/youbi"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp" />


    <TextView

        android:id="@+id/wareki"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp" />


    <TextView

        android:id="@+id/eto"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp" />


    <Button

        android:id="@+id/btn_mail"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="10dp"

        android:text="@string/btn_mail" />


</LinearLayout>


AndroidManifest.xmlの編集

Activity(画面)を追加したらAndroidManifest.xmlファイルへ登録する必要があります。AndroidManifest.xmlはプロジェクト作成時に自動的に作られ、アプリケーション全体の様々な情報を管理しています。アプリケーションが保持するActivity(画面)の管理もAndroidManifest.xmlを用いて行なっており、Activity(やその他のコンポーネント)の追加時には忘れずに編集しなければなりません。


他には、アプリケーションに関するパーミッション(権限)の管理も行っています。Android Marketからアプリケーションをダウンロードする際に、アプリケーションが利用する機能や情報が一覧で表示されますよね。(HTTP通信や、プロフィール情報の利用、等)これも、AndroidManifest.xmlに記載されています。


AndroidManifest.xmlを開き、以下を追加して下さい。AndroidManifest.xmlは以下の図の矢印①が示す場所にあります。編集可能な画面になっていない場合は、以下の矢印②で示されている場所をクリックしてください。




AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.rainbowapps.BirthDay1"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk android:minSdkVersion="7" />


    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name" >

        <activity

            android:label="@string/app_name"

            android:name=".TopActivity" >

            <intent-filter >

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

       </activity>

        <activity android:name=".ResultActivity"

android:label="@string/app_name">

</activity>

    </application>


</manifest>


追加する場所に注意して下さい。android:nameには今回追加するアクティビティの名前の先頭に”.”をつけて、android:labelにはActivityの上部に表示される文字列(今回は、アプリケーションの名前)を記載します。

これで結果表示画面の作成が終わりました。

画面遷移の実装

Intentによる画面遷移

さて、いよいよ画面遷移ができるように変更しましょう。TopActivity.javaを開き、以下の文を追加して下さい。

グレー背景の部分は削除する部分です。


src/TopActivity.java#onClick()

@Override

public void onClick(View v) { 

switch(v.getId()){

case R.id.btn01:

Toast.makeText(this, R.string.hello, Toast.LENGTH_LONG).show();

Intent intent = new Intent(this,ResultActivity.class);

startActivity(intent);

break;

}

}


Intentのところでエラーが検出されると思うので、赤い印の上にカーソルを持って行き、import ‘Intent’をクリックしてください。



ここまで終わったら保存して実行してみましょう。「OK」ボタンを押した時に以下の画面に切り替われば成功です。



Intentを使ってActivity間で情報を渡す

さて次は2つの画面の間で情報を受け渡しましょう。Androidでは、intentに情報を付与することで、異なるActivity間でデータのやりとりを行う事ができます。


1つめの画面(TopActivity)で入力された情報(誕生日)を、次の画面(ResultActivity)に渡します。

では、まずTopActivityを以下のように修正して下さい。


src/TopActivity.java#onClick()

  @Override

public void onClick(View v) { 

switch(v.getId()){

case R.id.btn01:

int year = datePicker.getYear();

int month = datePicker.getMonth();

int day = datePicker.getDayOfMonth();

Intent intent = new Intent(this, ResultActivity.class);


intent.putExtra("extra_year", year);

intent.putExtra("extra_month", month);

intent.putExtra("extra_day", day);


startActivity(intent);

break;

}

}


getYear,getMonth,getDayOfMonth()はそれぞれ、datePickerから年月日を取得するメソッドです。このように取得した年月日を、Intentに付与することで、結果表示画面に渡します。Intentにデータを付与するには、putExtra()メソッドを利用します。


次に情報を受け取る画面、ResultActivityも修正します。


src/ResultActivity.java

public class ResultActivity extends Activity implements OnClickListener{

//View

private TextView txtBirthDay;


@Override

public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.result);

    

    //Viewの初期化

    txtBirthDay = (TextView)findViewById(R.id.birthday);


    //Activityからの情報(bundle)を受け取る

    Bundle bundle = getIntent().getExtras();

    

    if(bundle != null){

        int year = bundle.getInt("extra_year");

        int month = bundle.getInt("extra_month");

        int day = bundle.getInt("extra_day");

        

        txtBirthDay.setText(year + " " + (month + 1) + " " +  day + " うまれ");

    }

}


TextViewを利用するのに必要なファイルがインポートされていないので、これまでと同様にインポートしましょう。

まず最初に、Bundle bundle = getIntent().getExtras();で前の画面(Activity)からデータを受け取ります。そして、受け取ったデータから、bundle.getInt()メソッドを使って具体的な情報を取り出しています。


ここで一度保存し、実行してみましょう。

トップ画面で誕生日を入力し、「OK」ボタンを押すと、入力した誕生日が表示されていれば成功です。


機能追加

生まれた日から年齢、干支などを算出する

ResultActivityに和暦、年齢、干支、曜日を計算する機能をつけます。まずは、西暦から和暦を計算するメソッドを作りましょう。


src/ResultActivity.java

  @Override

public void onClick(View v) {

switch(v.getId()){

}

}

private static String getWareki(int year){


     }


このメソッドの中に、プログラムを記述します。前回作ったメソッドと大きく違う点は、このメソッドが引数(ひきすう)を持つ、という点です。

このメソッドは、


 String wareki = getWareki( 1989 );

のように利用します。int型の整数の形で西暦を投げると、String型の和暦が返ってきます。このように、メソッドに情報を渡すことを、メソッドに引数を渡す、といいます。


メソッドを呼び出す際に、呼び出し元からメソッド内になんらかの情報(値)を渡し、それに応じた処理を行う、ということができるのです。引数の型は、メソッド名のあとに記述します。


さらに、引数とはちょうど逆に、メソッドの呼び出し元にメソッド本体から特定の情報を渡す、ということもできます。メソッドから返される情報を、戻り値と呼びます。メソッドの戻り値の型は、メソッド名の前に記述します。


getWarekiメソッドは、整数型の引数をもち、文字列(String)型の値を戻り値として返すメソッドです。

例えば、西暦1989年は平成1年ですよね。(おおまかに言えば、ですが)つまり、西暦から1988を引くと、平成何年かがわかる、ということです。これは、以下のように記述できますので、先ほど作ったメソッドを書き換えましょう。


src/ResultActivity.java#getWareki()

  private static String getWareki(int year){

int toshi = 0;

String wareki= "";

if( year >= 1989 ){

toshi = year - 1988;

wareki = "平成";

}

wareki = wareki + toshi + "";

return wareki;

    }


戻り値は、returnのあとに記述します。


では次に、和暦を表示させるTextViewをつくります。既にレイアウトファイルにはwarekiというidでTextViewが配置されているので、今回はResultActivity.javaのみ編集を行います。さらに、そのTextViewに先ほど作ったgetWarekiの戻り値(和暦)を表示してみましょう。


src/ResultActivity.java

 public class ResultActivity extends Activity implements OnClickListener{

//View

private TextView txtBirthDay;

private TextView txtWareki;

@Override

public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.result);

    

    //Viewの初期化

    txtBirthDay = (TextView)findViewById(R.id.birthday);

    txtWareki = (TextView)findViewById(R.id.wareki);

    //Activityからの情報(bundle)を受け取る

    Bundle bundle = getIntent().getExtras();

    

    if(bundle != null){

        int year = bundle.getInt("extra_year");

        int month = bundle.getInt("extra_month");

        int day = bundle.getInt("extra_day");

        

        txtBirthDay.setText(year + " " + (month + 1) + " " +  day + " うまれ");

        String wareki = getWareki( year );

        txtWareki.setText( wareki );

    }   

}


String wareki = getWareki( year );getWarekiメソッドに変数year(西暦)を引数としてわたし、String型のwarekiに返り値(和暦)を入れています。


今回は、わかりやすさを第一とし、txtWareki.setText( wareki );とわけて記述しましたが、この2行はtxtWareki.setText( getWareki( year ));のように1行で記述することが一般的です。こちらの形式に直しておきましょう。


src/ResultActivity.java

String wareki = getWareki( year );

txtWareki.setText( wareki );

txtWareki.setText( getWareki( year ));


実行すると、2011年の場合には平成23年と表示されるのではないでしょうか。では、同じようにして昭和、大正、明治の条件も記述してみましょう。ちなみに、昭和は1926年から、大正は1912年から、明治は1868年からはじまっています。

和暦を判定する条件を作る

以下のようになります。


src/ResultActivity.java#getWareki()

        private static String getWareki(int year){

int toshi = 0;

String wareki= "";

if( year >= 1989 ){

toshi = year - 1988;

wareki = "平成";

}else if( year >= 1926 ){

toshi = year - 1925;

wareki = "昭和";

}else if( year >= 1912 ){

toshi = year - 1911;

wareki = "大正";

}else if( year >= 1868 ){

toshi = year - 1867;

wareki = "明治";

}

wareki = wareki + toshi + "";

return wareki;

     }


else-ifを使って記述できたでしょうか?しかし、この条件判定は正しいようで、正しくありません。例えば、平成は1989年1月8日からであり、1989年1月1日は昭和64年なのですが、現在の実装では平成元年と表示されてしまいます。


現在のgetWareki()メソッドは年の情報だけを引数として受け取っていましたが、正しく和暦判定を行うためには月や日の情報も必要なようですね。


正しく平成を判定するgetWareki()メソッドは以下のようになります。メソッドは、複数の引数を取ることも可能です。複数の引数を取るメソッドは、以下のように記述します。


src/ResultActivity.java#getWareki()

 private static String getWareki(int year,int month,int day){

int toshi = 0;

String wareki= "";

if( year >= 1989 && !(year == 1989 && month == 1 && day <= 7)){

toshi = year - 1988;

wareki = "平成";

}else if( year >= 1926 ){

toshi = year - 1925;

wareki = "昭和";


year >= 1989 && !(year == 1989 && month == 1 && day <= 7)という複雑な条件になりました。これは、もし1989年以降かつ、198917日以前ではない場合、平成である、という条件です。&&はかつ、を、!は条件の逆転を表しているのでしたね。


引数の数を変更したので、getWareki()メソッドを呼び出している部分も以下のように書き換えます。month+1としているのは、datePicker1月を選択した場合、monthに代入される値が0である、というAndroidSDKの仕様があるためです。


 txtWareki.setText( getWareki( year , month+1 , day ));

では、あとの年号も同じようにしてみましょう。

1989年1月8日より 平成

1926年12月25日より 昭和

1912年7月30日より 大正

1868年1月25日より 明治 

となります。

正しく和暦を判定する条件を作る



private static String getWareki(int year,int month,int day){

int toshi = 0;

String wareki= "";

if( year >= 1989 && !(year == 1989 && month == 1 && day <= 7)){

toshi = year - 1988;

wareki = "平成";

}else if(year >= 1926 && !(year == 1926 && ((month == 12 && day <= 24) || month <= 11))){

toshi = year - 1925;

wareki = "昭和";

}else if( year >= 1912 && !(year == 1912 && ((month == 7 && day <=30) || month <=6))){

toshi = year - 1911;

wareki = "大正";

}else if( year >= 1868 && !(year == 1868 && ((month == 9 && day <=7) || month <=8))){

toshi = year - 1867;

wareki = "明治";

}

wareki = wareki + toshi + "";

return wareki;

}


のようになりますね。このように、複雑な複数の条件を記述する際には、よく考えてから実装しないと重大なバグが潜みやすいです。注意しましょう。

年齢を計算する機能(メソッド)を追加

続いて、年齢 を計算するメソッドを追加します。年齢は、どのようにすれば計算できるでしょうか?


単純に考えれば、現在の西暦年から生年月日の西暦年を引けば計算できそうです。しかし、今が2012年1月8日だとして、2001年8月10日生まれの子供の場合、どうなるでしょうか?この子供の本当の年齢は、まだ8月の誕生日を迎えていないので10歳です。しかし、単純に2012-2001をすると、この子供の年齢は11歳と判定されてしまいます。この結果、誕生月が現在の月より大きい場合には2012-2001-1というように、単純な計算から-1する必要があることがわかりました。


また、1月8日だとして、1月20日が誕生日の人の場合、この計算で大丈夫でしょうか?考えてみてください。

この場合も、先ほどと同様に年齢が1年大きく計算されてしまいます。この結果から、誕生月と現在の月が同じ場合で、かつ誕生の日にちが現在の日にちより大きい場合にも、単純な計算から-1する必要があることがわかります。


以上を考慮すると、年齢を取得するメソッドgetAge()は以下のように記述されます。getWareki()メソッドの下に、getAge()メソッドを追記します。


src/ResultActivity.java

  wareki = wareki + toshi + "";

return wareki;

}

//年齢

private static String getAge(int year, int month, int day) {

int age;

String ageStr;

Calendar cal = Calendar.getInstance();

int yeartoday = cal.get(Calendar.YEAR);

int monthtoday = cal.get(Calendar.MONTH)+1;

int daytoday = cal.get(Calendar.DATE);

if( month > monthtoday ){

age = yeartoday - year - 1;

}else if( month == monthtoday && day > daytoday ){

age = yeartoday - year - 1;

}else{

age = yeartoday-year;

}

ageStr = age + "";

return ageStr;

}


Calendarクラスを利用しているので、インポート文を追加します。


ResultActivity.java

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.TextView;

import java.util.Calendar;


現在の年月日を取得するには、以下のようにします。


Calendar cal = Calendar.getInstance();

int yeartoday = cal.get(Calendar.YEAR);

int monthtoday = cal.get(Calendar.MONTH)+1;

int daytoday = cal.get(Calendar.DATE);


赤い部分で+1を行なっているのは、先ほどと同様に1月の場合0が代入される為です。

干支を取得するメソッドの記述

続いて、干支を取得するメソッドの記述を行いましょう。今回は、年号から十二支を取得してみます。干支は、どのように計算できるでしょうか?


十二支は12種類存在し、12年周期で1周しますね。



実は十二支は、年号から4を引いて12で割った数のあまりが、以下のように対応します。


0

1

2

3

4

5

6

7

8

9

10

11


12で割った数のあまり、というのはプログラムでどのように記述するのでしょうか?

今回の計算は、以下のように記述できます。


 int eto = (year - 4) % 12;

例えば、2012年は(2012 – 4)/12 = 167あまり4なので辰年、ということになります。今回は、変数etoに代入した値をもとにswitch文で分岐させ、判定を行いましょう。


src/ResultActivity.java

ageStr = age + "";

return ageStr;

}

//干支

private static String getEto(int year){

String etoStr = "";

int eto = (year - 4) % 12;

switch( eto ){

case 0:

etoStr = "";

break;

case 1:

etoStr = "";

break;

case 2:

etoStr = "";

break;

case 3:

etoStr = "";

break;

case 4:

etoStr = "";

break;

case 5:

etoStr = "";

break;

case 6:

etoStr = "";

break;

case 7:

etoStr = "";

break;

case 8:

etoStr = "";

break;

case 9:

etoStr = "";

break;

case 10:

etoStr = "";

break;

case 11:

etoStr = "";

break;

}

return etoStr + "";

}


本当は配列という仕組みを理解していると、短く(なんと2行ほどで)記述できるのですが、まだ説明していないので長くなってしまいました。

曜日を取得するメソッドの記述

最後に、年月日から曜日を逆算するメソッドを記述します。年月日から曜日を逆算するには、以下のようにします。


 Calendar cal = Calendar.getInstance();

cal.set(year, month, day);

int youbi = cal.get(Calendar.DAY_OF_WEEK);


このようにすることで、変数youbiに以下のように曜日に対応する整数が代入されます。


1

2

3

4

5

6

7


先ほどの十二支を取得するメソッドと同じように、switch文を用いて処理を記述しましょう。


src/ResultActivity.java

return etoStr + "";

}

//曜日

private static String getDayOfWeek(int year, int month, int day){

Calendar cal = Calendar.getInstance();

cal.set(year, month, day);

int youbi = cal.get(Calendar.DAY_OF_WEEK);

String youbiStr = "";

switch(youbi){

case 1:

youbiStr = "";

break;

case 2:

youbiStr = "";

break;

case 3:

youbiStr = "";

break;

case 4:

youbiStr = "";

break;

case 5:

youbiStr = "";

break;

case 6:

youbiStr = "";

break;

case 7:

youbiStr = "";

break;

}

return youbiStr + "曜日";

}


年齢・干支・曜日を表示する

では、最後にこれらの機能(メソッド)を使い、結果を表示する部分を追加しましょう。

まずはViewの宣言と初期化です。


src/ResultActivity.java

 //View

private TextView txtBirthDay;

private TextView txtWareki;

private TextView txtAge;

private TextView txtYoubi;

private TextView txtEto;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.result);


//Viewの初期化

txtBirthDay = (TextView)findViewById(R.id.birthday);

        txtWareki = (TextView)findViewById(R.id.wareki);

txtAge = (TextView)findViewById(R.id.age);

txtYoubi = (TextView)findViewById(R.id.youbi);

txtEto = (TextView)findViewById(R.id.eto);


//Activityからの情報(bundle)を受け取る

Bundle bundle = getIntent().getExtras();

       


次に機能(メソッド)を使い、結果を表示する部分を追加します。


src/ResultActivity.java#onCreate()

//Activityからの情報(bundle)を受け取る

Bundle bundle = getIntent().getExtras();


if(bundle != null){

       int year = bundle.getInt("extra_year");

        int month = bundle.getInt("extra_month");

        int day = bundle.getInt("extra_day");

            

        txtBirthDay.setText(year + " " + (month + 1) + " " +  day + " うまれ");

        txtWareki.setText(getWareki(year, month+1, day));

        txtAge.setText(getAge(year, month + 1, day));

        txtYoubi.setText(getDayOfWeek(year, month, day)); 

        txtEto.setText(getEto(year));

}


ここまで終わったら保存して実行してみましょう。

結果表示画面に、和暦、年齢、干支、曜日が表示されれば成功です。

外部アプリケーションとの連携

結果が表示されたらこの結果をメールで送信してみましょう。メールで送信するためにはメールを送るための機能を追加しなければならない、と考えますが、androidにおいてはその必要はありません。前章で出てきたIntent(やりたいこと)を用いれば、メールを送る機能を持ったほかのアプリを呼び出して、代わりにメールを送ってもらうことが出来ます。


では、ResultActivityにある「send mail」ボタンを押したら、メールを送れるように機能を追加します。

まずは、新たに利用するクラスのインポート文を追加します。


ResultActivity.java

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.TextView;

import java.util.Calendar;

import android.widget.Button;

import android.content.Intent;


ResultActivity.java
  private TextView txtYoubi;

private TextView txtWareki;

private TextView txtEto;

private Button mailButton;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.result);

//Viewの初期化

txtBirthDay = (TextView)findViewById(R.id.birthday);

txtAge = (TextView)findViewById(R.id.age);

txtYoubi = (TextView)findViewById(R.id.youbi);

txtWareki = (TextView)findViewById(R.id.wareki);

txtEto = (TextView)findViewById(R.id.eto);

mailButton = (Button)findViewById(R.id.btn_mail);

         mailButton.setOnClickListener(this);


//Activityからの情報(bundle)を受け取る

Bundle bundle = getIntent().getExtras();


これで、Viewの宣言と初期化は終わりです。Import ‘Button’を行うことを忘れないようにしましょう。次にボタンが押された時の処理を追加します。


ResultActivity.java

 //ボタンが押された時の処理

@Override

public void onClick(View v) {

switch(v.getId()){

case R.id.btn_mail:

Intent intent = new Intent(Intent.ACTION_SEND);  

intent.setType("text/plain");  

intent.putExtra(Intent.EXTRA_TEXTtxtBirthDay.getText() +"\n"txtAge.getText() +"\n"txtYoubi.getText() +"\n"txtWareki.getText() +"\n"txtEto.getText());  

startActivity(intent);

break;

}

}


追加する場所に注意して下さい。


ここまでできたら保存して実行してみましょう。

「send mail」ボタンをクリックした時に以下のようにメーラーを選択する画面が出てきたら成功です。(環境によっては選択する画面がなく、直接Gmail等のメーラが起動する場合もあります。)ここでGmailを選択すると、以下のようにメールの本文に結果がセットされて出てきます。




以上で機能の拡張は終わりました。今後の講義でもこういった外部アプリ(Youtube等)の連携が出てきますが、全てIntentを用いたものです。画面遷移にはIntentを用いることを前章で学びましたが、外部アプリとの連携にもIntentを用いることを覚えておいて下さい。


生まれた日を知るアプリの作成は以上で終わりとなります。このアプリを応用することで、生年月日から占いが出来るアプリや、小中高の入学年度を表示するアプリなどが作れるかと思います。各自で拡張してみてください。


Comments