Android Studio 1.0.1版 ver1.1

実践Androidアプリ開発
「ペイントアプリケーション」
Android Studio 1.0.1 対応
第1.1版
2015年 1月
1日
2
目次
1. はじめに・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・3
2. Androidの概要・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ 4
3. 開発環境・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・5
4. 動作仕様・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・11
5. アプリケーション開発・・・・・・・・・・・・・・・・・・・・・・・・・13
6. アプリケーション開発(描画処理)・・・・・・・・・・・・・・・・・・・19
7. アプリケーション開発(オプション機能)・・・・・・・・・・・・・・・・24
8. アプリケーション開発(機能追加)・・・・・・・・・・・・・・・・・・・37
9. アプリケーション開発(付録)・・・・・・・・・・・・・・・・・・・・・38
使用ソフトウェア
・Android Studio 1.0.1(android-studio-bundle-135.1641136.exe)
2
3
はじめに
プログラマやインフラエンジニアなどのIT系職種を経験後、2012年より、IT系のフリ
ーランス講師を経験。専門学校生にプログラミングやサーバ構築を教える傍ら、自治体
が実施している公共職業訓練(http://www.mhlw.go.jp/bunya/nouryoku/kousyoku/)でもIT
技術に関する授業を行っていました。
最近では、この公共職業訓練(国、東京都)を実施しているコースでは、時代の流れ
から、Android開発を行うコースが多いです。私もこのコースを担当しています。
コースでは受講生の方向けに勉強会を開催し、JavaプログラミングやAndroid開発を独
自に教えたりしています。そこで作成した教材などを、もっと多くの方に知っていただ
こうと本書の執筆に至りました。
2014年4月より、日本工学院八王子専門学校の専任講師となり、IT教育に携わってい
ます。ちなみに、Androidと自分の出会いは2010年になります。当時、Androidが流行り
出して、仕事ではAndroidアプリ開発を扱うようになっていました。そこで、auのIS03
を購入し自分でも使ってみました(当時、レディガガがCMをしていて話題になったや
つです)
Android開発をやってみた感想ですが、iPhoneアプリケーションの開発もしていました
が、それよりもお手軽な感覚でした。そして、Java言語を使ったことのある人なら慣れ
るのに時間がかからない印象です。本書は、Java言語やEclipseを使ったことのある方向
けに執筆しています。
2014年11月にAndroid Studio 1.0が正式リリースされ、Eclipseが時代遅れのIDEになりそ
うです。今までEclipseを使っていた私にとっては衝撃的な出来事ですが、時代に乗り遅
れないために本書をAndroid Studioに対応させることにしました。
2015年1月1日
木崎悟
3
4
Android の概要
Android の特徴
Androidの特徴としてあげられる点ですが、まず、オープンソースという点が挙げられ
ます。オープンソースのソフトウェアとは、ソースコードが公開されていて、誰でも自
由に無料で使うことができます。そして、多様な開発環境で開発できることが特徴です。
WindowsでもMacでもLinuxでもさまざまなOSの元で開発をすることができます。さらに
機能に制約がなく、docomoやauみたいなキャリアに限定して作る必要もありません。も
っとも大きな特徴は、Google Playというマーケットで誰でも自由に配布することができ
ることです。つまり、アプリケーションの流通に制約がありません。
Android のマーケット(市場)
Androdiアプリの市場にはGoogle Playがあります。Google PlayとはGoogle社により提供
される、主にAndroid端末向けデジタルコンテンツ(アプリケーション・映画・音楽・書
籍など)の配信サービスです。利用者は世界中の個人・企業の開発したアプリを入手す
ることができます。
2013年7月31日の調査だと、世界中で9億台の端末が利用されていて、アプリ数は1
00万、累計ダウンロード数は500億、売上の67%が米国外(日本はトップ5に入
る)とされています。1人当たりの売り上げも昨年度比2.5倍に増えたとGoogleが発
表しています。
Android の思想
All applications are created equal
上記の言葉はAndroidの開発思想です。日本語にする
と『すべてのアプリケーションは等しく作られる』とな
ります。つまり、誰でもが平等に企画したアプリケーシ
ョンを開発しAndroidのマーケットで公開することがで
きます。
4
5
開発環境
JDK(Java Development Kit)
Javaでソフトウェア開発をするために必要な開発キットです。AndroidはJava言語で開
発するため必要になります。
Eclipse
統合開発環境(IDE)です。自動ビルドやコード補完機能などの多くの機能がありま
す。プラグイン機能でさまざまな言語で開発をすることもできます。Android開発を行う
ときもAndroidアプリ開発用のプラグインであるADT(Android Development Tool)をイン
ストールします。※ 現在は推奨されていません。
Android SDK
開発に必要なツールやドキュメント類です。最新バージョンは2014年12月11日に公開
されたAndroid 5.0.1 (Lollipop) になります。
Android Studio
Android5.xより、Eclipseに代わりIDEにはAndroid Studioを使うことが推奨されました。
Android Studioとは「IntelliJ IDEA」というオープンソースのIDEを基にAndroid向けに最
適化された統合開発環境です。日本ではそれほど話題になってはいませんが、世界的に
はEclipseの次に人気のあるIDEです。2014年11月より、Eclipseに代わって、Android Studio
を使うことが推奨されています。
インストール方法
下記のサイトにアクセスして開発環境一式をダウンロードしましょう。
Android SDK (http://developer.android.com/sdk/index.html)
クリック
5
6
開発環境
Android SDKのダウンロードサイトには次のように書かれています。
http://developer.android.com/sdk/installing/index.html?pkg=studio より
Android Studioのインストールについて
Android Studioは、 Android Studio IDEとAndroid SDK toolsを含んでおり、Androidア
プリケーション開発を始めるための必要なすべての機能を提供しています。もし、あ
なたがAndroid Studioをダウンロードしなかったなら、今すぐにAndroid Studioをダウン
ロードに行きましょう。あなたがAndroid Studioをセットアップする前に、JDKバージ
ョン6以上をインストールされているか確認してください。(ただし、JREだとダメ)
JDKバージョン7は Androidのバージョン5.0以上の開発をするときに必要です。JDKの
バージョンはコマンドプロンプトから javac -version で確認することができます。も
し、JDKバージョン6よりも古い場合は最新のJDKをダウンロードしてください。
Windowsの場合のセットアップ方法
1.実行ファイル(.exeファイル)をダウンロードしてください。
2.Android Studioのセットアップウィーザードに従ってインストール作業をしてくだ
さい。Javaがインストールされている場所がわからないというような問題が発生した
場合は、環境変数を設定する必要があります。
[スタートメニュー] > [コンピューター] (右クリック)> [プロパティ] > [システム
の詳細設定] > [環境変数] を選択します。
システム環境変数「JAVA_HOME」を追加します。
設定値に関しては、例えば、C:¥Program Files¥Java¥jdk1.7.0_21 のようにします。
開発ツールおよびその他のSDKパッケージはAndroid Studioフォルダの外に保存され
ます。あなたが直接ツールにアクセスする必要がある場合は、それらがインストール
されている場所に移動して、端末を使用します。
Android Studioは、Android開発ツールが準備されています。しかし、Android SDKを
使用するのに必要なパッケージが残っている場合は追加する必要があります。
※ 詳しい設定方法については次章以降に記述します。
6
7
開発環境
JDKのインストール方法
Android Studio 1.0.1を使うにはJDKをインストールする必要があります。次に、Java SE
Development Kit (JDK)のインストール手順を説明します。Oracleのダウンロードサイトか
らJDKをダウンロードします。
(URL: http://www.oracle.com/technetwork/java/javase/downloads/index.html)
Java SE Development Kit 8u25 から JDK の Download をします。
Accept License Agreement にチェックを入れてください。自分の環境にあった JDK をダ
ウンロードしてください。Windows の場合、OS が 32bit であれば Windows x86、64bit
であれば Windows x64 にしてください。
ダウンロードが完了したら jdk-8u25-windows-i586.exe(64bit: jdk-8u25-windows-x64.exe)
を実行します。セットアップが開始されるので画面の指示に従ってインストールしてく
ださい。
Installer がダウンロードされるので,画面の表示に従ってインストールを行います.
Windows の場合,C:¥Program Files (x86)¥Java¥jdk1.8.0_25 にインストールされます.
参考:JDK のダウンロード
(URL: http://www.oracle.com/technetwork/java/javase/downloads/index.html)
7
8
環境変数の設定
Java のコマンドを実行するために、環境変数を設定します。環境変数はコンピュータ
ー → 右クリックでプロパティを表示→システムの詳細設定→環境変数と進みます。
ユーザー環境変数に次のように追加します。
新規ボタン押下 → OK ボタン押下
パスが通っているか確認します。コマンドプロンプトを起動して次のコマンドを打ち込
んでください。バージョン情報が表示されれば環境設定が完了しています。
C:\>java –version
C:\>javac –version
8
9
MS-DOS からのコマンド実行
Android Studio 1.0.1 のインストール方法
ダウンロードしたexeファイル(android-studio-bundle-135.1641136.exe)を実行して
ください。インストーラが起動しますので指示に従って進めていきます。
インストールが完了すると、C:¥Program Files¥Android¥Android Studioというフォルダが
できています。実行ファイルは、binフォルダの下のstudio64.exeがAndroid Studioの実行
ファイルになります。
9
10
Android Studio 1.0.1 の実行
すべての開発環境がインストールされたフォルダに含まれています。統合開発環境の
Android Studio1.0.1 を 起 動 し ま す 。 展 開 さ れ た フ ォ ル ダ の Android フ ォ ル ダ に あ る
studio64.exeを実行しましょう。起動のやり方は、Windowsの場合、スタートメニューに
追加されるのでそこから[Android Studio]を選択しても実行することができます。デスク
トップにショートカットアイコンを作るなどして起動しやすくしておきましょう。
次章から実際にペイントアプリケーションを作成してみましょう。
10
11
動作仕様
次に今回作成するペイントアプリケーションの動作仕様を示します。基本的な描画機
能をまず作成し、その後にメニューを追加して、1操作戻るボタン、クリアボタン、保
存ボタンをそれぞれ追加してみましょう。
描画機能
・タッチ開始から終了までの間、移動している範囲に線を描画する
※タッチ開始から終了までを一つの履歴として記録(線の再描画・ヒストリーバックを
考慮)
・画面を縦横変更した場合の挙動は、そのままの状態で回転する(縦横の幅の考慮はし
ない)
.
[メニュー]1 操作戻るボタン処理
1 操作前の線の描画状態に戻す
[メニュー]クリアボタン処理
ビューに描画されている線を削除する
[メニュー]保存ボタン処理
ビューに描画されている線を外部 SD へ PNG ファイルとして出力する
※ファイル名の形式は「yyyymmdd-hhmiss.png」
11
12
動作仕様
プロジェクト概要
プロジェクト情報
項目
Application name
Minimum SDK
Company Domain
Project location
Activity Name
SDK Version
設定
PaintApplication
Android 4.0.3
paint
C:¥PaintApplication
MainActivity
15
アプリケーションの構成について
ファイル名
詳細
PaintApplicationActivity.java
メインアクティビティ
PaintView.java
カスタムビュー(描画用の View を独自に作成)
menu.xml
メニューのレイアウト XML
strings.xml
画面内に表示する文字情報を扱う
【詳細】
上記「アプリケーションの構成について」がアプリケーションの主要なファイル群に
なります。
メインアクティビティ「PaintApplicationActivity.java」ファイルと描画用の「PaintView.java」
ファイルで処理を分けて作成します。
描画用の「PaintView.java」は View を継承してカスタムするためのファイルとして扱い
ます。
今回のアプリケーションではメニューを使用して描画のクリアやファイルの保存を行
うため、メニュー用のレイアウトファイル「menu.xml」を準備します。
プロジェクト作成時にデフォルトで同時に作成される strings.xml についてはアプリケ
ーションで使用する文字列情報を保持します。
12
13
アプリケーション開発
アプリケーションの作成
① プロジェクト新規作成
まずは「プロジェクト情報」通りにプロジェクトを作成してください。ツールバー
の[File]から[New Project]を選択してください。 次のように入力してください。
[Application name]は作成するアプリケーションの名前です。[Company name]は、パッ
ケージ名に使われます。paint と入力すると paint.paintapplication というパッケージ名が
付きます。
パッケージ名というのはアプリケーションを識別する ID のようなものです。
通常は、会社のドメイン名+アプリケーション名となります。[Project location]は、アプ
リケーションの保存場所になります。
項目
Application name
Company Domain
Project location
入力値
PaintApplication
paint
C:¥PaintApplication
意味
アプリケーション名
ドメイン名(パッケージ名)
アプリケーションの保存場所
[Next]ボタンを押してください。
13
14
次の画面で、[Phone and Tablet]というチェックボックスにチェックを入れます。スマー
トフォン・タブレット向けのアプリケーションを作成します。最近は、スマートフォン
だけでなく、家電製品やカーナビなど、様々な分野で Android OS が使われているので
複数の選択肢があります。
ここで、[Minimum SDK]というセレクトボックスがありますが、Minimum SDK とは
最低限動作させる SDK のバージョンになります。
ここでは[API 15:Android 4.0.3 (IceCreamSandwich)]を選択します。自動的に対応するバ
ーションが決められます。Android の最新バージョンは Android 5.0 (Lolipop)です。この
設定で Android4.0.3~Android5.0 まで対応したアプリケーションを作成できます。
[Next]ボタンを押してください。
14
15
続いて、デフォルトの Activity を選択します。Activity とは画面のことです。ここでは、
画面の種類を選択します。[Blank Activity]を選択してください。
次の画面では初期設定で作成するファイルですが、デフォルトのまま[Next]ボタンを押
してください。しばらくすると、スケルトンプロジェクト(デフォルトのプロジェクト)
ができます。
15
16
② カスタムビューファイルの作成
描画用の View を新たに作成するため、View 用ファイルをメインアクティビティと
同じパッケージ「paint.paintapplication」へ作成します。View とはアプリケーションの画
面に表示する部品のことです。[app] > [java] > [paint.paintapplication]と選択していって、
[paint.paintapplication]を右クリックしてください。そのあと、ポップアップされたメニ
ューから[New] > [Java Class]と選択してください。
次の Java クラスを作成します。クラスとは Java のプログラムの単位になります。通常、
1 クラス、1 つの Java ファイルになります。
PaintView.java
カスタムビュー(描画用の View を独自に作成)
ポップアップされたウィンドウの[Name]に PaintView と入力して OK ボタンを押してく
ださい。
16
17
作成された PaintView クラスを次のように修正します。対象のファイルをダブルクリッ
クするとエディタビューにプログラムが表示されます。スケルトンコードの修正を行い
ます。
PaintView.java
package paint.paintapplication;
import android.content.Context;
import android.view.View;
/**
* Created by kizaki on 2014/12/31.
*/
public class PaintView extends View {
public PaintView(Context context) {
super(context);
}
}
View クラスを継承し、コンストラクタ内では親クラスのコンストラクタを呼び出し
ます。View の処理として SDK が提供している処理になるため、決め打ちで呼び出しま
す。呼び出さないと、もともとの View でもっている処理を受け継げなくなります。
③ メインアクティビティからカスタムビューのインスタンス生成
続いて、先ほど作成した画面の部品を Activity と呼ばれる画面に配置するプログラム
を作成しましょう。今回はレイアウトを使用せずに、アクティビティにカスタムビュー
を配置するのみとします。クラスの作成手順は先ほどと同様にしてください。
PaintApplicationActivity.java
package paint.paintapplication;
import android.app.Activity;
import android.os.Bundle;
/**
* Created by kizaki on 2014/12/31.
*/
public class PaintApplicationActivity extends Activity {
PaintView paintView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
paintView = new PaintView(this); // カスタムビューのインスタンス生成
setContentView(paintView); // カスタムビューをアクティビティにセット
}
}
17
18
PaintView クラスのインスタンスを生成し、そのまま setContentView メソッドでレイアウ
トとして決定しています。PaintView クラスの変数は、今後のカスタマイズを考え、ク
ラスのフィールドとして宣言しておきます。
ここで、継承とメソッドのオーバーライドについて記述します。Java はオブジェクト
指向言語です。オブジェクト指向を簡単にいうと、すでにあるプログラム(機能)を再
利用して効率的に開発を行う考え方です。
「継承」とは、オブジェクト指向の考え方で、
Java では「extends」というキーワードを使います。Java の「継承」は、すでにあるクラ
スの機能を引き継いで機能を拡張する時に利用します。
「extends」というキーワードは、
class 定義に書かれているので探してみてください。
上記の例では、PaintView クラスは、View というクラスを継承しています。また、
PaintApplicationActivity クラスは、Activity クラスを継承しています。続いて、メソッド
のオーバーライドですが、オーバーライドとは、継承元のクラスで定義してある機能(メ
ソッド)を再定義して、機能を拡張することを指します。Android Studio でオーバーラ
イドをする時は、画面上で「Ctrl + o」というショートカットキーを使うと便利です。次
のようなウィンドウがポップアップされ選択すると自動で書いてくれる機能が付いて
います。
18
19
アプリケーション開発(描画処理)
④ カスタムビューで描画処理
カスタムビューを修正して、描画処理を作成します。
PaintView.java
package paint.paintapplication;
import
import
import
import
import
import
import
android.content.Context;
android.view.View;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.graphics.Path;
android.view.MotionEvent;
public class PaintView extends View {
// フィールド
private float oldX = 0f; // ひとつ前の X 座標保持
private float oldY = 0f; // ひとつ前の Y 座標保持
private Path path = null; // パス情報を保持
// コンストラクタ
public PaintView(Context context) {
super(context);
}
// 描画時に呼び出し
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
// 線の色
paint.setColor(Color.WHITE);
// アンチエイリアスの有無
paint.setAntiAlias(true);
// 線のスタイル(STROKE:図形の輪郭線のみ表示)
paint.setStyle(Paint.Style.STROKE);
// 線の太さ
paint.setStrokeWidth(2);
// 線の先端スタイル(ROUND:丸くする)
paint.setStrokeCap(Paint.Cap.ROUND);
// 線と線の接続点のスタイル(ROUND:丸くする)
paint.setStrokeJoin(Paint.Join.ROUND);
if (path != null) {
canvas.drawPath(path, paint);
}
}
19
20
// 画面のタッチ時に呼び出し
public boolean onTouchEvent(MotionEvent e) {
// タッチイベント判定処理
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: // タッチして画面を押した時
path = new Path();
oldX = e.getX();
oldY = e.getY();
path.moveTo(oldX, oldY);
break;
case MotionEvent.ACTION_MOVE: // タッチしてから離すまでの間
oldX = e.getX();
oldY = e.getY();
path.lineTo(oldX, oldY);
invalidate();
break;
case MotionEvent.ACTION_UP: // タッチして離した時
oldX = e.getX();
oldY = e.getY();
path.lineTo(oldX, oldY);
invalidate();
break;
default:
break;
}
return true;
}
}
ペイントアプリケーションのアルゴリズムについての理解が必要になります。画面に
タッチしてから離すまでの間のイベントを取得して、各イベントで線の描画処理を行う
ことが必要となります。画面を押したとき(MotionEvent.ACTION_DOWN)、画面を押し
て か ら 離 す ま で (MotionEvent.ACTION_MOVE) 、 画 面 を 離 し た と き
(MotionEvent.ACTION_UP)の3つのイベントを onTouchEvent メソッドで判別していきま
す。
onTouchEvent は Activity クラスのメソッドのため、リスナーの登録などは不要です。
線のパス情報を保持する Path クラスを使用して、線の描画に必要な情報を保持していく
ことにします。
まずは、画面をタッチしたときの ACTION_DOWN ではタッチした箇所の XY 座標を取
得します。座標の取得は MotionEvent の変数が所持していますので、ここから取得しま
す。
取得した座標を moveTo メソッドを使用して座標の始点として設定し、次に、画面を
タッチしてから離すまでの間に発生するイベントでは、実際に線を書き込む処理を実行
します。ここも同様に移動時の XY 座標の値を取得し、lineTo メソッドに設定します。
そして、線を実際に画面に描画しないといけないので、invalidate メソッドで再描画をし
20
21
ます。
座標については、左上を起点として、横軸を X、縦軸を Y として表す。数学と違い、
プログラムでは、X 座標は右に行くとプラスになり、Y 座標は下に行くとプラスになる
仕組みとなっています。
関連メソッド
メソッド
moveTo メソッド
lineTo メソッド
invalidate メソッド
説明
線を描画するときの始点となる座標を設定する
moveTo の始点から線をつなぐ任意の座標を設定する
描画処理(onDraw メソッドの呼び出し)実行
invalidate メソッドが実行されると、再描画となり、画面は初期状態(なにも描画され
ていない)に戻ります。onDraw メソッドでは画面に実際に取得したパス情報をもとに
線を描画する処理を記述します。線自体のスタイルの設定は Paint クラスを使用して、
線の太さ、色などを細かく設定していきます。通常のペイントでは先端、接続点は丸く
なることがお絵かきアプリでは主流なため、setStrokeCap メソッド、setStrokeJoin メソッ
ドの引数は ROUND とします。
Paint paint = new Paint();
// 線の色
paint.setColor(Color.WHITE);
// アンチエイリアスの有無
paint.setAntiAlias(true);
// 線のスタイル(STROKE:図形の輪郭線のみ表示)
paint.setStyle(Paint.Style.STROKE);
// 線の太さ
paint.setStrokeWidth(2);
// 線の先端スタイル(ROUND:丸くする)
paint.setStrokeCap(Paint.Cap.ROUND);
// 線と線の接続点のスタイル(ROUND:丸くする)
paint.setStrokeJoin(Paint.Join.ROUND);
21
22
関連メソッド一覧
メソッド
setColor メソッド
setAntiAlias メソッド
setStyle メソッド
説明
線の色を設定
アンチエイリアスの有無の設定
線のスタイルの設定
(STROKE:線を引く
FILL:塗る FILL_AND_STROKE:線を引き塗る)
setStrokeWidth メソッド
線の太さの設定
setStrokeCap メソッド
線の先端のスタイルの設定
(ROUND:丸くする BUTT:なし SQUARE:四角くする)
setStrokeJoin メソッド
線と線の接続点のスタイルの設定
(ROUND:丸くする BEVEL:なし MITER:三角形にする)
取得したパス情報、設定した線のスタイル情報をもとに実際に画面に線を描画すること
を行います。そのために、drawPath メソッドを使用することで描画することが可能にな
ります。
この繰り返しで画面を移動している間は ACTION_MOVE メソッドが呼び出され、描画
が常に行われています。そして、画面を離したときは ACTION_UP が呼び出される。今
の段階は処理は ACTION_MOVE と同様とします。※次項で変更
関連メソッド一覧
メソッド
drawPath メソッド
説明
画面にパス情報、ペイントスタイル情報を元に実際に
線を描画する
ペンの動きと画面をタッチして動かしている指とで、ペンと指の位置が合っていない
ため、少し調整をすることにします。
フィールドと ACTION_MOVE を次のように改修して下さい。
PaintView.java
case MotionEvent.ACTION_MOVE: // タッチしてから離すまでの間
oldX += (e.getX() - oldX);
oldY += (e.getY() - oldY);
path.lineTo(oldX, oldY);
invalidate();
break;
こうすることで、指の位置とペンの位置が近くになり、より違和感なく描画することが
できることになります。
仕組みは、前の線の位置と指の位置の間により近くになるように調整し、なめらかな動
きとなるようにしています。
22
23
しかし、今のままでは、次の線を描いた時に、前の線が消えてしまいます。これを改
善するために、前回までの情報を保持することが必要になります。保持する方法として
は、コレクション(リスト、配列など)を使用することが考えられます。
この方法をとることで、線情報をすべて保持することになるので、拡張として、たとえ
ば線の描画の履歴として、前の状態に戻すことも簡単にできるようになります。さらに、
線情報をそのまま保存すれば、再度読み込んだ場合に前回と同様の状態から始めること
もできるようになります。
PaintView.java
import エリア
import java.util.ArrayList;
フィールド
// フィールド
ArrayList<Path> drawList = new ArrayList<Path>(); // 全てのパス情報を保持
OnDraw メソッドの Paint 情報設定の後
for (Path pt : drawList) {
canvas.drawPath(pt, paint);
}
onTouchEvent メソッド
case MotionEvent.ACTION_UP: // タッチして離した時
oldX = e.getX();
oldY = e.getY();
path.lineTo(oldX, oldY);
drawList.add(path);
invalidate();
break;
パスを保持する方法として ArrayList を今回は使用して値を保持することにします。
ジェネリックスを使用し中に保持できるオブジェクトは、Path クラスのみとしています。
ArrayList に値を追加する場合には add メソッドを使用します。
そして、格納する場所ですが、描画している処理になるので、ACTION_UP 内となりま
す。ここでパスの lineTo を決定したら、そのあとに ArrayList に格納します。
そして描画処理 onDraw では線のスタイル情報を設定した後に、今までのすべての線情
報をすべて格納されている分だけループして描画していく処理を行います。
この方法の場合には、線情報が増えれば増えるほど、ループされる回数があがるため、
パフォーマンス的には徐々に落ちることになりますが、基本的にそこまでのパフォーマ
ンスロスにはならないので十分問題なく続けてペイントすることが可能です。
23
24
アプリケーション開発(オプション機能)
アプリケーションの作成(機能追加)
⑤ オプションの追加
ここまでの処理で描画する基本的な機能は付きましたが、まだペイントアプリとしては
不十分です。機能を拡張してもう少しユーザインターフェイスを豊かにしていきます。
今回は、描画された線のクリア、1手順戻す、描画データの保存の3点の機能を Android
標準のメニューを使用して作成していきます。
⑥メニューのレイアウトファイル作成
まずはメニューのレイアウトファイルを作成しますが、使用する文字列は今後を考え、
全て strings.xml ファイルで定義していきます。
[プロジェクト直下] > [res] > [values] > strings.xml を開いてください。
strings.xml を次のように修正してください。Android Studio では基本的にハードコードで
xml ファイルを使います。
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PaintApplication</string>
<string name="menu_back">1 操作戻る</string>
<string name="menu_clear">クリア</string>
<string name="menu_save">保存</string>
</resources>
24
25
では次にメニューのレイアウトファイルを作成していきます。
[res] > [layout] > [menu]を選択して、右クリックします。そして、[New] > [Menu resource
file] を開いて下さい。
Android のメニューボタンを押すと、いろいろなメニューが表示されます。自分でオリ
ジナルのメニューを作成することができます。⑥でメニューに表示する文字列を作成し
ました。今度はレイアウトの作成をします。レイアウトも文字列同様に XML ファイル
に記述します。
25
26
[File name]に menu と入力してください。OK ボタンを押すと menu.xml のレイアウトフ
ァイルが作成されています。このレイアウトファイルを使用してメニューのレイアウト
を作成していきます。menu.xml を次のように修正してください。
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/backId" android:title="@string/menu_back"></item>
<item android:id="@+id/clearId" android:title="@string/menu_clear"></item>
<item android:id="@+id/saveId" android:title="@string/menu_save"></item>
</menu>
menu タグの中には、表示したいメニューの item タグを定義します。id 属性は、表示す
るメニューの識別番号です。title 属性は、メニューの表示タイトルを設定します。
26
27
⑦メインアクティビティにメニュー処理追加
メニューを処理するために、処理を追加します。PaitApplicationActivity.java のソース
コードにオーバーライドで処理を追加します。エディタービューの空白箇所で[ctrl+o]
と入力します。一覧から onCreateOptionsMenu()と onOptionsItemSelected()を選択し
てください。
27
28
onOptionsItemSelected メソッドを次のように修正してください。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.backId: // 1 操作戻るボタン押下時
break;
case R.id.clearId: // クリアボタン押下時
break;
case R.id.saveId: // 保存ボタン押下時
break;
}
return super.onOptionsItemSelected(item);
}
メニューを処理する場合には、次の二つの Activity クラスの持つメソッドをオーバー
ライドして使用することになります。
一つ目は onCreateOptionsMenu メソッドで、Android のメニューボタンを押下した場合に
呼び出されます。ここで、メニューの画面を生成することが Android では定石となって
います。メニュー生成では親クラスの処理を行うために、親クラスのコンストラクタを
呼ぶようにしています。
二つ目は onOptionsItemSelected メソッドでこちらも同様に Android クラスの持つメソッ
ドをオーバーライドして使用します。
こちらは、メニューの選択時に呼び出されます。二つとも Android クラスが持つメソッ
ドのため、リスナーの登録などは不要となり、そのまま直ぐに使うことができます。
MenuItem クラスの getItemId メソッドで選択したメニューの ID を取得することが可能
なため、メニューレイアウトで指定した ID と比較して処理を分岐するようにしていま
す。
「R.Id.」ではすべての ID 情報を保持しているため、これで、メニューレイアウトで指
定した ID を取得することが可能です。
case R.id.backId: // 1 操作戻るボタン押下時
case R.id.clearId: // クリアボタン押下時
case R.id.saveId: // 保存ボタン押下時
28
29
次にメニューレイアウトの読み込みを行います。
onCreateOptionMenu メソッドでメニューボタンを押したときのイベントリスナーとなる
ため、ここでメニューレイアウトを読み込むこととします。
PaintApplicationActivity.java
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
レイアウトを読み込むには MenuInflater クラスを使用します。
inflate メソッドで読み込みたいレイアウトファイルを指定して読み込みを行います。メ
ニューを指定するには「R.menu.」で全てのメニュー情報が取得できます。
関連メソッド一覧
メソッド
inflate メソッド
説明
メニューレイアウトを読み込む
⑧ 1 操作戻るボタンの処理
1 操作戻るボタンの処理を実装します。これは ArrayList へすべてのパス情報を保持して
いるために、実現できる機能となります。線を新たに描画するたびに ArrayList のパス
情報を使用しているため、1 操作戻る場合には 1 つ前の ArrayList の情報を削除すること
で実現します。
PaintView.java
// 1 操作戻る
public void historyBack() {
Path previous = (Path) drawList.get(drawList.size() - 1);
drawList.remove(previous);
previous.reset();
invalidate();
}
全パス情報の一つ前の情報を削除するため、ArrayList のサイズから 1 を引いた数の要素
のパス情報を取得しています。
Path previous = (Path) drawList.get(drawList.size() - 1);
そして remove メソッドで削除対象の Path 変数を渡して、パスを削除しています。
drawList.remove(previous)
29
30
そして reset メソッドでパス情報をなくしています。
最後に、invalidate メソッドで再描画を行い、画面上反映させています。
関連メソッド一覧
メソッド
get メソッド
remove メソッド
reset メソッド
説明
ArrayList の保持する情報を指定された要素番号で取得する
ArrayList から指定した要素を削除する
パス情報のリセット
作成したメソッドをメインアクティビティで呼び出します。
PaintApplicationActivity.java
switch (item.getItemId()) {
case R.id.backId: // 1 操作戻るボタン押下時
paintView.historyBack();
break;
⑨クリアボタンの処理
クリアボタンの処理を実装します。これは ArrayList の値をすべてクリアにして、その
他パス情報を保持する変数も初期化することで実現する機能となります。
PaintView.java
// クリア
public void clearPathList() {
drawList.clear();
oldX = 0f;
oldY = 0f;
path = null;
invalidate();
}
ArrayList の値をクリアするには、clear メソッドを呼ぶことで行い、その他 XY 座標、パ
ス情報を保持するデータも初期化します。
最後に、invalidate メソッドで再描画を行い、画面上反映されています。
作成したメソッドをメインアクティビティで呼び出します。
PaintApplicationActivity.java
case R.id.clearId: // クリアボタン押下時
paintView.clearPathList();
break;
30
31
⑩画像データの取得
今回は描画されたデータを画像ファイル png として保存することとします。まだ描画
したデータは画像形式にはなっていないため、画像データとして取得ことが必要になり
ます。
Android にはキャッシュという概念があり、キャッシュ機能をONにすると、今の画
面のキャプチャを取得することが可能となっています。取得のタイミングですが、パス
情報が最終的に確定して、保存を実行する時点になります、そのため保存用の
isSaveToFile メソッドを作成し、その一番初めの処理としていれることが良いとされま
す。
PaintView.java
import エリア
import android.graphics.Bitmap;
フィールド
private Bitmap bitmap = null;
onTouchEvent メソッド
// 画像ファイルを保存
public boolean isSaveToFile(PaintApplicationActivity paint) {
// キャッシュからキャプチャを作成、そのためキャッシュを ON
setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(getDrawingCache());
// キャッシュはもうとらないのでキャッシュを OFF
setDrawingCacheEnabled(false);
// 仮
return true;
}
キャッシュをキャプチャをとるときのみの一時的な間のみ ON にして、Bitmap を生成し
て、即時キャッシュを OFF にします。
キャッシュはメモリを多く食うため、基本的には OFF にすることが必要です。デフォル
トは OFF になっています。
bitmap 変数にキャッシュから取得した Bitmap が格納されます。
bitmap = Bitmap.createBitmap(getDrawingCache());
関連メソッド一覧
メソッド
setDrawingCacheenabled メソッド
createBitmap メソッド
getDrawingCache メソッド
説明
キャッシュのオン、オフを設定する
取得した画像をもとに画像を生成、再編成する
View をキャプチャする
31
32
⑪ 保存ボタンの処理
描画されたデータを保存する処理を実装します。キャッシュから取得したビットマップ
を保存対象とします。
PaintView.java
isSaveToFile メソッド
// 画像ファイルを保存
public boolean isSaveToFile(PaintApplicationActivity paint) {
// キャッシュからキャプチャを作成、そのためキャッシュを ON
setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(getDrawingCache());
// キャッシュはもうとらないのでキャッシュを OFF
setDrawingCacheEnabled(false);
// 保存先の決定(存在しない場合は作成)
File file;
String path = Environment.getExternalStorageDirectory()
+ "/PaintApplication/";
if(!Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
file = Environment.getDataDirectory();
} else {
file = new File(path);
file.mkdirs();
}
// 一意となるファイル名を取得(タイムスタンプ)
Date d = new Date();
String fileName = String.format("%4d%02d%02d-%02d%02d%02d.png",
(1900 + d.getYear()), d.getMonth() + 1, d.getDate(),
d.getHours(), d.getMinutes(), d.getSeconds());
file = new File(path + fileName + ".png");
// 画像をファイルに書き込む
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, out);
out.flush();
out.close();
return true;
} catch (Exception e) {
return false;
}
}
32
33
今回の保存処理は3つの処理に分けています。まず、[1]保存先を決定すること、[2]
保存するファイル名を生成すること、[3]画像を実際に書き込むことです。
保存先の決定について、getExternalStorageState()メソッドを使用して、外部ストレージが
マウントされているか確認します。マウントされている場合は、
Environment.MEDIA_MOUNTED を 返 し ま す 。 マ ウ ン ト さ れ て い な い 場 合 は 、
Environment.REMOVED が返されます。
getDataDirectory()メソッドは「/date」を返し、Environment.getExternalStorageDirectory()
メソッドは「/sdcard」を返します。問題なく外部ストレージがマウントされていれば、
mkdirs メソッドでフォルダを作成し「/sdcard/PaintApplication/」へ保存されることになり
ます。保存するファイル名を生成について、ここでは Date クラスを使用して一意とな
るようなファイル名を作成しています。フォーマット形式は「yyyymmdd-hhmiss.png」
となる画像を実際に書き込むについて、ここでは生成したファイル名でキャッシュされ
ているビットマップを png で保存しています。
関連メソッド一覧
メソッド
getExternalStorageState メソッド
getDataDirectory メソッド
compress メソッド
説明
外部 SD のマウント状態を返す
マウントしている:
Environment.MEDIA_MOUNTED
マウントしていない:Environment.REMOVED
内部ストレージのパス情報を持つ File クラス
を返す
指定された出力ストリームにビットマップの
圧縮バージョンを作成する
メインアクティビティで使用する文言を strings.xml で追加して下さい。手順については
「⑥メニューのレイアウトファイル作成」を参照下さい。
strings.xml
<string name="save_success">保存成功</string>
<string name="save_fail">保存失敗</string>
<string name="save">save</string>
<string name="ok">OK</string>
作成したメソッドをメインアクティビティで呼び出します。
saveToFile メソッドは戻り値として正常に保存できた場合には true を、保存に失敗した
場合には false を返すため、そのまま条件分岐式の条件に指定します。
33
34
PaintApplicationActivity.java
onOptionsItemSelected メソッド
case R.id.saveId: // 保存ボタン押下時
new AlertDialog.Builder(this)
.setTitle(R.string.save)
.setMessage(paintView.isSaveToFile(this) ? R.string.save_success
: R.string.save_fail)
.setPositiveButton(R.string.ok, null).show();
break;
AlertDialogBuilder クラスを使用して成功、失敗を知らせるダイアログを表示しています。
setTitle メソッドでダイアログのタイトル表示文字列を指定、setMessage メソッドでダイ
アログのメッセージ表示分を指定、setPositiveButton メソッドボタンの文言を指定してい
ます。Show メソッドでダイアログ本体を画面へ表示することになります。
「R.String.」
で strings.xml に定義した値を取得することが可能になります。コードの書き方として、
クラスの変数を使用せずにまとめてコンパクトにコードを書けているが、それは、全て
の使用しているメソッドの戻り値が Builder となっていることで、そのまま、Builder ク
ラスの持つメソッドを使用して可能となっています。
関連メソッド一覧
メソッド
setTitle メソッド
setMessage メソッド
setPositiveButton メソッド
show メソッド
説明
ダイアログのタイトルを設定する
ダイアログのメッセージを設定する
ダイアログのボタンのメッセージを設定する。ボタン
を押した場合になんらかの処理を行う場合には第 2 引
数へリスナーを設定することで可能。
ダイアログを表示する
このままではまだ保存機能が動作しません。
外部メディアへ書き込むためのパーミッションがないためです。最後にマニフェストフ
ァイルへパーミッションを設定します。AndroidManifest.xml を開いてください。
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
これで保存はできますが、まだ Android のギャラリーにこの段階では反映されません。
メディアスキャンというものが実行されて初めてギャラリーへ反映されます。通常は、
メディアのマウント時つまり、Android の再起動時に実行されます。しかしそれでは困
るので、メディアスキャンを明示的に実行する必要があります。
メディアスキャンをファイル保存後に実行することで、リアルタイムでギャラリーへフ
ァイルが反映されることになります。
34
35
PaintView.java
フィールド
MediaScannerConnection mc;
クラス内
void mediaScanExecute(PaintApplicationActivity paint,final String file) {
mc = new MediaScannerConnection(paint,
new MediaScannerConnection.MediaScannerConnectionClient() {
public void onScanCompleted(String path, Uri uri) {
mc.disconnect();
}
public void onMediaScannerConnected() {
mc.scanFile(file, "image/png");
}
});
mc.connect();
}
メディアスキャンを行う場合、MediaScannerConnection クラスを使用して行います。
MediaScannerConnectionClient インターフェースを実装したクラスを匿名クラスとして
実装しています。※MediaScannerConnection のインスタンス生成時に、
MediaScannerConnectionClient のインターフェースの参照が必要です。実態は、
onScanCompleted メソッド、onMediaScannerConnected メソッドの二つを抽象メソッドと
して宣言しているため、処理をオーバーライドしてあげる必要があります。
OnMediaScannerConnected メソッドは、
connect メソッドが実行されると呼び出されます。
処理としては実際にスキャン処理をおこなうため、scanFile メソッドを呼びます。
OnScanCompleted メソッドは、スキャン完了時に呼び出され、処理は
MediaScannerConnection の接続を切断します。
※ 匿名クラスについて
無名クラスとも言う。クラスの宣言をすることなく(クラス名を指定しない)、クラス
の処理を直に記述する方法のことです。
メリットとしては、その場で処理が記述できるため、コードの可読性が良くなることが
あります。ただし、匿名クラスとなるクラスの内容が他でも使用する場合には、クラス
の宣言を行うほうが良い。一か所でしか使用しないような処理の場合には、匿名クラス
を使う場合が多い。
35
36
関連メソッド一覧
メソッド
connect メソッド
disconnect メソッド
scanFile メソッド
説明
メディアスキャン処理を呼び出す
メディアスキャン処理を切断する
メディアスキャンを実行する。対象のファイルを指定し、
contenttype を指定することで対象のファイルがスキャンさ
れる。
メディアスキャン時には指定するファイル、コンテンツタイプを指定することが必要で
す。
mc.scanFile(file, "image/png");
主な Content Type 一覧
Content Type
image/jpeg
image/png
application/pdf
video/mpg
video/quicktime
video/avi
audio/mp3
拡張子
jpeg
png
pdf
mpg
mov
avi
mp3
用途
jpeg 画像
png 画像
pdf ファイル
mpeg ビデオファイル
mov ビデオファイル
avi ビデオファイル
mpeg3 音声ファイル
ファイルを保存した後に、メディアスキャンの処理を呼び出して実行します。
これで保存してメディアスキャンが同時に実行されるため、ギャラリーへ反映されるこ
とになります。
PaintView.java
isSaveToFile メソッド
// 画像をファイルに書き込む
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, out);
out.flush();
out.close();
this.mediaScanExecute(paint, file.getPath());
return true;
} catch (Exception e) {
return false;
}
36
37
アプリケーション開発(機能追加)
ペイントアプリケーションは機能が多々存在しますので、ここまで基盤にさらに拡張さ
せてください。
☆ 機能拡張のリストアップ
例)
・線のスタイル(太さなど)指定
・線の色指定
・消しゴム機能
・線情報の保存
・図形の描画(○△□など)
・塗りつぶし機能
・モジュール分け(ファイル操作に関してクラスファイルを作成するなど)
☆ リストアップ項目のクラス設計
クラス構成を考えて設計を行う
☆ 開発担当者の決定
各モジュール毎に担当者を決定する
☆ 開発
担当となったモジュールの開発作業
37
38
アプリケーション開発(付録)
最後に、Android Studio を使う時に便利なショートカットキーをまとめておきます。
キー操作
Ctrl+Space
Ctrl+Alt+L
Shift+F6
Alt+Insert
Ctrl+O
Ctrl+S
Ctrl+C
Ctrl+V
説明
コード補完
インポート編成、自動インデント
変数名の変更
コード生成 (getter,setter,equals など)
オーバーライド/インプリメント
保存
コピー
貼り付け
38
39
実践Androidアプリ開発
「ペイントアプリケーション」
Android1.0.1対応
2015年1月版
日本工学院八王子専門学校 木崎 悟
ホームページ:http://collam.dip.jp/
E メール:kizakistr@hac.neec.ac.jp
39