外部ライブラリーの - TechInstitute

第
15
章
外部ライブラリーの
利用と作成
著:八木俊広、片渕真太郎
15-1
外部ライブラリーを
使ってみよう
著:八木俊広、片渕真太郎
KEYWORD
LESSON
この章では、Androidアプリケーション開発における外部
ライブラリー
jar
ライブラリーの役割とその使い方、作り方を学びます。その
ライブラリーモジュール
中で、まずこの節では、まず外部ライブラリーとは何か、An
so
droidで利用できるライブラリーの種類、ライブラリーの利
用方法を学びましょう。
aar
クラスファイル
android-http-async
(https://github.com/loopj/android-async-http)
専門的な機能を持ったライブラリーを使って、
ラクにプログラムを作れるようになります。
Androidアプリケーションを作るにあたって、すべてをイチから製作するのではなく、先人たちがつ
くった「ライブラリー」を用いることで、高度な知識がなくても手軽に機能を利用できるようにしていきま
す。
ここでは、jarライブラリーを用いてHTTP通信を行い、
インターネットのデータを参照するという、
34
参照
クラスパス
静的リンク
この節を学ぶとできること
一見高度なアプリを作ってみます。
動的リンク
15 -1-1 ライブラリーとは何か
ライブラリーとは、特定の処理を行うプログラムをひとまとめにし、他のプログラムか
第
15
ら利用できる形式にしたモノのことです。ライブラリーは再利用のための仕組みだと
章
言い換えてもよいでしょう。例えば画像処理や数値計算などの汎用的な処理を行う
外
部
プログラムをライブラリーにすることで、他のプログラムからその機能を自由に利用で
ラ
イ
ブ
ラ
リ
ー
の
き、一度開発したプログラムを再度使いまわせるようになります
(図1)。
利
用
と
作
成
図1:アプリケーションとライブラリーの関係のイメージ
複数のライブラリーを組み合わせてより高機能なプログラムを作成し、それをまた
ライブラリーにするといったことも可能です。
Android自身も画像処理や音声処理や様々な部分でライブラリーを利用してい
ます。
また、Androidアプリケーションを開発する際に利用するAndroid SDKもライ
ブラリーです。Androidが提供するライブラリーによって私達はアプリケーションを開
発することができるのです。Androidに限らず、現代の様々なプラットフォームやプロ
ダクトは、過去に開発されたライブラリーの積み重ねによって成り立っていると言って
も過言ではありません。
15 -1-2 Android アプリケーションにおけるライブラリー
ライブラリーは、利用するOSやCPUやプログラミング言語などによって、様々な形
式に分かれています。Androidアプリケーションで利用できるライブラリーの形式は
「jar」
(Java Archive)、
「ライブラリーモジュール」、
「aar」
(Android Archi
ve)、
「so」
(Shared Object)
の4種類です。以下、順に見ていきましょう。
35
jar(Java Archive)
Androidアプリケーションは基本的にJavaでソースコードを記述します。そのた
め既存のJavaライブラリーの多くを利用できます。Javaライブラリーの形式は「jar」
(Java Archive)
と呼ばれ、クラスファイル群と署名やバージョン等のメタ情報が
書かれたファイルなどがアーカイブされています。
Java Archive( JAR)Featuresについて詳しくは、http://www.cse.yorku.
ca/tech/other/jdk1.2.1/docs/guide/jar/を参照してください。
コンパイル時に「jar」ファイルをクラスパスに通すことで利用できます。Android
Studioで作成したAndroidアプリケーションの場合「build.gradle」に「jar」ファ
イルの参照を記述するだけで依存関係が解決され利用が可能となります。
Eclipseの場合はプロジェクトの「libs」ディレクトリに「jar」ファイルを配置する必
要があります。
ライブラリーモジュール
「ライブラリーモジュール」は、Androidアプリケーション専用のライブラリー形式
です。通常のアプリケーションと同じようにプロジェクト形式で開発を行います。ライブ
ラリーモジュールにはソースコードの他にレイアウトXMLや画像等のリソースファイル
を含めることができます。これにより、画面を含んだUIやスタイル、画像リソースなどを
アプリケーションから参照して利用できるようになります。
aar( Android Archive)
「aar」はライブラリーモジュールをアーカイブした形式です。2013年のGoogle
I/Oで「Android Studio」
という新しいIDEが発表されました。Android Studio
は「Gradle」
というビルドツールと強く統合されており、Gradleを通してアプリケー
ションをビルドする形になっています。Gradleからライブラリーモジュールを参照する
時に利用するのがこの「aar」形式です。
so(Shared Object)
Androidのアプリケーション開発では、
「NDK」を用いることで、C/C++を使っ
てプログラムを記述できます。
Android NDK(Native Development Kit)
はAndroidアプリケーションで
利用するプログラムの一部、あるいは全体をC/C++で開発するための開発環境
です。
NDKを使ってビルドを行うと
「so」ファイルを出力し、
「apk」に同梱します。Andr
36
oidアプリケーションから
「so」ファイルへは「JNI」
(Java Native Interface)
を通
してアクセスすることになります。
第
15
章
外
部
15 -1-3 静的リンクと動的リンク
リーと結びつく必要があります。ライブラリーと結びつく方式は大きく分けると
「静的リ
ラ
イ
ブ
ラ
リ
ー
の
ンク」
と
「動的リンク」に分類できます。
と
ライブラリーは、ソースコード、オブジェクトコード、専用のフォーマットなど、さまざま
な形式で提供されており、利用するプログラムはそれらの形式に合わせてライブラ
利
用
作
成
静的リンク
静的リンクはアプリケーションとライブラリーをコンパイルのリンク時に結びつけ、実
行ファイルに含める方式です。静的リンクの場合、リンク時にライブラリーのAPIや
バージョン等の整合性をチェックすることになるので、コンパイルの時点で問題があ
れば検出できます。ただし、実行ファイルにライブラリーファイルを含めるので、実行
ファイルのサイズは大きくなってしまいます。また、ライブラリーをアップデートするには、
再度アプリケーションをコンパイルし直す必要があります。Androidにおいては「ライ
ブラリーモジュール」や「aar」、
「exportedなjar」が、静的リンクによって結びつく
ライブラリーです
(図2)。
図2:静的リンクのイメージ
37
check!
「exportedなjar」ファイルは静的リンク
通常
「jar」
ファイルは動的リンク形式のライブラリーです。しかしAndroidアプリケー
ションは「Dalvik VM」
というJavaとは異なる仮想マシン上で動作します。このため、
「class」ファイルを
「Dalvik VM」用の「dex」ファイルに変換する際に、参照している
「jar」
ファイルの中身も
「dex」
ファイルに変換し、アプリケーションに組み込みます。コ
ンパイルのタイミングでアプリケーション内にライブラリーを組み込んでいるので、An
droidアプリケーションでは「jar」
ファイルを静的リンクしているということになります。
「exportedなjar」
とは「dex」
ファイルに変換する対象に含める「jar」
ファイルのことを指
します。例えば「android.jar」
はexportedではないので、コンパイル時には処理されま
せん。アプリケーションを実行する時に動的にリンクします。
動的リンク
動的リンクはアプリケーションを実行する時にライブラリーとリンクする方式です。
Windowsを利用している方は「.dll(Dynamic Link Library)」
という拡張
子のファイルを見たことがあると思います。これが動的リンクができるライブラリーです。
実行ファイルとは独立したファイルなので、実行ファイルのサイズを圧迫することが
ありません。また複数のアプリケーションから同時に利用したり、ファイルを差し替えれ
ば、再コンパイルすることなくライブラリーをアップデートしたりできます
(図3)。しかしラ
イブラリーが互換性のないアップデートをしてしまった場合には、動作時にエラーと
なってしまいます。そのため、動的リンク形式のライブラリーを利用する場合は、バー
ジョン管理が重要になります。Androidでは、Android SDKや「so」ファイルが動
的リンク形式のライブラリーとなります。
図3:動的リンクのイメージ
例えば最新のAndroidのAPIを使ったアプリケーションを、古いAndroidが搭
載された端末で動作させるとエラーが発生します。これは動的リンクによってAndr
oid SDKとアプリケーションが結びついているからです。古いAndroidに存在しな
38
いAPIを利用していたりすると、当然APIが見つからないのでエラーとなるのです。
第
15
15 -1-4 Android SDK もライブラリー
章
外
部
前述の通りAndroid SDKもライブラリーです。しかしAndroidアプリケーション
ラ
イ
ブ
ラ
リ
ー
の
を開発する時に「Android SDKのライブラリーを使っている」
と意識したことはあま
りないかもしれません。ただ、実は新規モジュールを作成する時にAndroid SDKの
ライブラリーを選択しています
(図4)。
利
用
と
作
成
図4:新規プロジェクトのウィザード
Eclipseで新規プロジェクトを作成する際に選択していた「Compile With」は、
どのバージョンのAndroid SDKを使ってプロジェクトをコンパイルするかを設定する
ものでした。Android Studioでは、
「Compile With」の設定はなくなっているの
で、プロジェクト作成時にはSDKを直接選択することはできなくなっています。後で
見るように、開発環境にインストールされているSDKに含まれる
「android.jar」が実
際には参照されます。
「android.jar」ファイルがAndroid SDKの実体であり、そ
の中に含まれているActivityクラスやTextViewクラスなどを使ってアプリケーショ
ンを作ることになります。
Android Studioの「Project」
ビューでプロジェクトの中味を見てみると、参照
しているAndroid SDKのバージョンや中身を確認できます。図5は、Android 4.3
の「android.jar」を参照している例です。ライブラリーの中にどのようなクラスがある
か確認できます。
39
図5:Android 4.3の
「android.jar」
の中味
Androidプロジェクトで参照しているAndroid SDKには膨大な数のクラスが含まれている。そのクラスが持つメソッ
ドを見ることもできる
クラスを開くとソースコードを見ることもできます。図6は、Activityクラスのソース
コードを開いた例です。Activityクラスがどのように実装されているか読むことがで
きます。普段よく使う
「setContentView」メソッドや「findViewById」メソッドがど
のように実装されているか是非一度読んでみてください。
図6:Activityクラスのソースコードを覗く
40
クラスを開いてもソースコードが見られない場合は、Android SDKのソースコー
ドをインストールしているか確認してください。図7のように、
「Android SDK Mana
ger」を使って、該当するAndroidバージョンのソースコードがインストールされてい
第
15
るか確認できます。
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
図7:Android SDKのソースを
「Android SDK Manager」
で確認し、必要に応じてダウンロードする
15 -1-5 jar 形式のライブラリーを使ってみよう
ライブラリーの形態とAndroidアプリケーションにおけるライブラリーの種類がわ
かったところで、さっそくライブラリーを使ってみましょう。本項では「android-asynchttp」
(https://github.com/loopj/android-async-http)
という非同期通信
のためのオープンソースライブラリー使って、ネットワークプログラミングの章(HttpU
RLConnectionの利用)
で作る
「HttpURLConnection」の処理を置き換えます。
「android-async-http」は、さまざまな形式で配布していますが、ここでは「jar」
ファイルを直接利用することとします。
オープンソースとは、
プログラムのソースコードを第三者に公開していることを表しま
すが、実際にはもう少し立て込んでいます。ソースコードの複製、改変、再頒布など
の条件を定めたオープンソースライセンスを持つプログラムをオープンソースソフトウェ
アといいます。
「android-http-async」の場合は「Apache License, Version
2.0」
というライセンスを採用しています。オープンソースソフトウェアの利用者はオープ
ンソースライセンスに従う必要があります。
41
依存関係を解決する
「android-async-http」の「jar」ファイルは「http://loopj.com/androidasync-http/」でダウンロードできます。本書の執筆時点では「android-asynchttp-1.4.6.jar」が最新バージョンでした
(図8)。
図8:
「android-http-async」
のHP
「build.grade」に「android-http-async」の依存関係を追加します
(図9)。
図9:アプリケーションごとの
「build.gradle」
の
「dependencies」
に
「compile...」
の記述を1行追加する
42
通信処理を行うので「AndroidManifest.xml」への「android.permission.
INTERNET」パーミッションの追加も忘れずに行いましょう
(リスト1)。
リスト1:AndroidManifest.xml
(android.permission.INTERNET"パーミッションを追加する)
第
15
章
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
外
部
package="省略" >
ラ
イ
ブ
ラ
リ
ー
の
<uses-permission android:name="android.permission.INTERNET"/>
<application>
<!-- 省略 -->
</application>
利
用
</manifest>
と
//}
作
成
動作チェック
正しく導入ができたか確認してみましょう。新しく作ったプロジェクトの「MainAct
ivity.java」の冒頭にリスト2に示す「import」文を記述し、エラーが発生しなけ
れば準備完了です。
リスト2:MainActivity.java
(導入したライブラリーのクラスをインポートする)
import com.loopj.android.http.AsyncHttpClient;
もしエラーになる場合は、
「build.gradle」の場所(複数あります)
と記述内容をも
ういちど確認してください。
ライブラリーを用いない場合のコード
「android-async-http」を使う前に、
まずはライブラリーを使わない場合のコード
を見てみましょう。リスト3は、ネットワークプログラミングの章で実装する
「HttpUR
LConnection」を用いるコードから、一部のログ出力を取り除いたものです。接続
の準備やデータの取得、後処理などたくさんの処理を記述しています。また、この
コードはUIスレッドでは実行できないため、
「AsyncTask」等を用いて別のスレッド
で呼び出す仕組みを実装しています。
43
リスト3:MainActivity.java
(HttpURLConnectionを用いる場合)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadTask().execute();
}
private static class DownloadTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
try {
URL url = new URL("http://tomorrowkey.github.io");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Host", "tomorrowkey.github.io");
connection.connect();
int responseCode = connection.getResponseCode();
Log.d("TEST", "Response-Code=" + responseCode);
String contentLength = connection.getHeaderField("Content-Length");
Log.d("TEST", "Content-Length=" + contentLength);
String contentType = connection.getHeaderField("Content-Type");
Log.d("TEST", "Content-Type=" + contentType);
InputStream inputStream = connection.getInputStream();
String body = readToEnd(inputStream);
Log.d("TEST", "body=" + body);
inputStream.close();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return null;
}
private String readToEnd(InputStream inputStream) throws IOException {
StringBuilder sb = new StringBuilder();
int length;
byte[] buffer = new byte[1024];
while ((length = inputStream.read(buffer)) != -1) {
sb.append(new String(buffer, 0, length));
}
return sb.toString();
}
}
}
44
「Socket」を使った通信処理に比べれば、
「HttpURLConnection」でもかな
り楽に通信処理を記述できるようになっています。しかしまだまだ冗長です。Andro
odアプリケーションで「HttpURLConnection」を使って通信処理をする場合に
第
15
は、常に以下のことを考慮しなければなりません。
章
外
部
・ AsyncTaskなど非同期処理のコードを追加しなければならない
ラ
イ
ブ
ラ
リ
ー
の
・ 通信の成功や失敗を自分でチェックしなければならない
・ レスポンスをInputStreamで処理しなければならない
もちろんこれらの約束ごとは、一度覚えてしまえば、それほど難しいものではないで
boilerplateは正確には鋳型(鋳型
は強いて言えばtemplate)
ではあり
しょう。しかし、アプリケーションで通信処理をする場合、いつも実装しなければならな
ませんが、boilerplate
(ボイラーを作
いため、
「ボイラープレート
・コード」を沢山書くことになります。
コンピューター用語としてこのような
ボイラープレートとは鋳型のことです。ボイラープレート
・コードは決まりきっているけ
るための板、または機械の銘版)
が、
意味に使われるようになった経緯はよ
く分かりません
ど省略できないコードの断片のことを表します。
ボイラープレート
・コードが増えると、本来やりたいことに割くべき時間が削られてい
きます。通信処理の場合、やりたいことは通信処理そのものではなく、通信の結果
取得したデータを取り扱うことのはずです。ボイラープレート
・コードを回避するには、
それらを簡単かつ汎用的に再利用できる仕組みを用意すればよいわけですが、大
抵の場合時間がかかります。そういった場合にライブラリーの力を借りることになるわ
けです。
android-async-httpを用いたコード
では「android-async-http」を利用してみましょう。
「android-async-http」は
非同期的にネットワーク処理を行う
「AsyncHttpClient」クラスと、同期的にネット
ワーク処理を行う
「SyncHttpClient」クラスを提供しています。今回行いたいの
は非同期通信なので、
「AsyncHttpClient」クラスを利用します。
リスト4は、
「AsyncHttpClient」クラスを使って実際に非同期のリクエスト処
理する例です。実装の詳細はここでは深く立ち入りませんが、
「HttpURLConnec
tion」を使う例に比べて簡潔にリクエスト処理を記述できていることが分かると思いま
す。
45
利
用
と
作
成
リスト4:MainActivity.java
(android-http-asyncを用いる場合)
public class
extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadAsync();
}
private void loadAsync() {
AsyncHttpClient client = new AsyncHttpClient();
//自動的に別のスレッドで実行する
client.get("http://tomorrowkey.github.io",
new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int responseCode, Header[] headers, byte[] response) {
//通信処理が終了するとUIスレッドで呼び出される
String body = new String(response);
Log.d("TEST", "body=" + body);
}
@Override
public void onFailure(int responseCode, Header[] headers, byte[] response, Throwable e) {
//省略
}
});
}
}
「AsyncHttpClient」
クラスは自動的に非同期でネットワーク処理を行うので、UIス
レッドから呼び出しても問題ありません。また通信処理の結果を受け取るための「Asyn
cHttpResponseHandler」
クラスの「onSuccess」メソッドや、
「onFailure」メソッドは
自動的にUIスレッドで呼び出されるのでスレッドを意識しなくてもすみます。
ライブラリーの使い方を知るには
大抵のライブラリーには「説明書」があります。
「android-http-async」の場合
は以下のページを参照するとよいでしょう。
概要と使い方: http://loopj.com/android-async-http/
javadoc: http://loopj.com/android-async-http/doc/com/loopj/
android/http/package-summary.html
「android-http-async」はオープンソースのライブラリーですので、ソースコード
そのものを参照するという手もあります。
「android-http-async」のソースコードは
46
Githubにホスティングされています。
Github: https://github.com/loopj/android-async-http
第
15
章
今回利用した「AsyncHttpClient」クラスのソースコードは以下のURLで読め
外
部
ます。
async-http/blob/master/library/src/main/java/com/loopj/andro
ラ
イ
ブ
ラ
リ
ー
の
id/http/AsyncHttpClient.java#L831
と
AsyncHttpClientクラス: https://github.com/loopj/android-
利
用
作
成
15 -1-6 プログラムの再利用性を高める
リスト4に示したコードでは、
「loadAsync」メソッドに通信先のURLが埋め込
まれていました。また、通信結果はログに出力するだけです。これでは通信先を変更
したい場合毎回「loadAsync」メソッドを書き換えなければなりません。いろいろなと
ころで再利用ができるよう、以下の条件を満たすように書き換えてみましょう。
1:任意に通信先のURLを変更できる
2:通信結果をStringで受け取って自由に処理できる
任意に通信先のURLを変更できる
リスト4の「loadAsync」メソッドは、通信先URLがメソッド内に書かれているた
め「loadAsync」メソッドの外からURLの変更ができません。通信先のURLを引
数で受け取る形にすれば任意のURLを指定できるようになります
(リスト5)。
リスト5:MainActivity.java
(loadAsyncメソッドで任意のURLを引数に取る)
private void loadAsync(String url) {
AsyncHttpClient client = new AsyncHttpClient();
client.get(url,
new AsyncHttpResponseHandler() {
//省略
});
}
引数を追加することで任意のURLを受け取ることができるようになりました。しかし実
はリスト5の実装ではまだ不十分です。引数「url」が「null」の場合「NullPointer
Exception」が発生してしまいます。引数の妥当性をチェックする必要があります。
Androidには「TextUtils」クラスという文字列の操作やチェックができる便利
47
なクラスがあります。
「TextUtils」クラスの「isEmpty」メソッドを使えば引数が空
(長さが0)
あるいは「null」かどうかをチェックできます
(リスト6)。
リスト6:MainActivity.java
(引数の妥当性をチェックする)
private void loadAsync(String url) {
if (TextUtils.isEmpty(url)) {
return;
}
AsyncHttpClient client = new AsyncHttpClient();
client.get(url,
new AsyncHttpResponseHandler() {
//省略
});
}
空、
「null」だけでなく、URLとして正しい形式かチェックしたい場合もあるかもし
れません。ただ、
「AsyncHttpClient」の場合、誤ったURL形式を渡すと
「Asy
ncHttpResponseHandler」クラスの「onFailure」メソッドが呼び出されるので、
事前チェックが必須というわけではありません。
「String」クラスの「startsWith」メソッドを使えば、指定した文字列で始まってい
るかどうかをチェックできます
(リスト7)。
リスト7:MainActivity.java
(startsWithメソッドを使う)
// "http://"で始まっていなかったらreturn
if(!url.startsWith("http://")){
return;
}
もっと手っ取り早く確認するために、
「URL」クラスを用いるという手もあります。
「URL」クラスはコンストラクタに渡されたURLが正しいかをチェックし、問題があれ
ば「MalformedURLException」をthrowします。チェックはプロトコルとポート番
号に対して行われます
(リスト8)。
デフォルトでは、http、https、ftp、file、jarの各プロトコルに該当するかどうかと、
ポート番号が-1以上であることをチェックします。
( 参考:http://docs.oracle.com/
javase/jp/6/api/java/net/URL.html)
リスト8:MainActivity.java
(
「URL」
クラスを使う)
try{
URL url = new URL(urlString);
}catch(MalformedURLException e){
// URLクラスがMalformedURLExceptionをthrowしたらreturn
return;
}
48
通信結果をStringで受け取って自由に処理できるようにする
通信結果をメソッドの呼び出し元に渡すにはどのようにすればよいでしょうか。よく
第
15
ある誤りをリスト9に示します。何が間違っているかわかるでしょうか。
章
外
部
リスト9:MainActivity.java
(間違った例)
ラ
イ
ブ
ラ
リ
ー
の
private String loadAsync(String url) {
AsyncHttpClient client = new AsyncHttpClient();
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int responseCode, Header[] headers,
利
用
byte[] response) {
と
String body = new String(response);
作
成
return body;
}
//省略
});
}
ここでは、
「loadAsync」メソッドの戻り値を「String」にして、通信結果を「retu
rn body」で返しています。一見よさそうに思えるのですが実際は誤りです。まず、
そ
もそもこのコードはコンパイルが通りません。
「AsyncHttpClient」クラスの「get」メソッドは非同期で通信処理を行うので、
「get」メソッドそのものはすぐに終了します。
「get」メソッドが終了すると、次に処理す
るものはないので「loadAsync」メソッドが終了します。
「AsyncHttpResponseH
andler」クラスの「onSuccess」メソッドは通信が終わった時呼び出されるので、そ
れぞれの処理はリスト10に示した順番で実行されることになります。
リスト10:MainActivity.java
(処理が実行されるタイミング)
private String loadAsync(String url) {
AsyncHttpClient client = new AsyncHttpClient();
//1 getメソッドを実行する。非同期処理を開始するだけなのですぐ終わる。
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int responseCode, Header[] headers,
byte[] response) {
//3 通信処理が終わったら呼び出される
String body = new String(response);
return body;
}
//省略
});
//2 loadAsyncメソッドが終了する
}
49
「loadAsync」メソッドは、
「String」を戻り値としているので「2」の時点でなんら
かの値を返さなければなりません。しかし通信処理はまだ終わっていないため、通
信結果をこのタイミングで返すことはできません。コンパイルを通すためには「return
null」
といった記述をすることになります。これでは「String」を戻り値にしている意味
がありませんね。
次に「3」のタイミングで「return body」
と書いていますが、処理を書いている場
所は、
「AsyncHttpResponseHandler」クラスの「onSuccess」メソッドの中で
す。
「onSuccess」メソッドは戻り値が「void」なので「String」を返すことはできま
せん。また、返せたとしても
「loadAsync」メソッドの戻り値とはならないので、
これもま
た意味がありません。
ではどのようにすれば良いか。実はすでに答えがコード中に書かれています。コー
ルバックを利用すればよいのです。
「AsyncHttpClient」クラスの「get」メソッドは、
「AsyncHttpResponseHandler」クラスを渡してコールバックを受け取るスタイル
になっています。同様の仕組みを「loadAsync」メソッドに実装すればよいわけで
す。リスト11はコールバックを利用する実装の例です。
リスト11:MainActivity.java
(コールバックを利用する)
//コールバックを受け取るためのinterfaceを定義する
public interface OnLoadListener {
public void onLoad(String result);
}
//OnLoadListenerを引数に受け取る
private void loadAsync(String url, final OnLoadListener listener) {
AsyncHttpClient client = new AsyncHttpClient();
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int responseCode, Header[] headers,
byte[] response) {
String body = new String(response);
//コールバックする
listener.onLoad(body);
}
//省略
});
}
リスト12は、URLとコールバック用のinterfaceを引数に取るようになった「loa
dAsync」メソッドを利用する例です。これで色々なところから利用できるようになりま
した。また、
「android-http-async」を利用する部分を「loadAsync」メソッドの中
に隠蔽したことによって、利用する時のコードがシンプルになりました。
50
リスト12:MainActivity.java
(コールバックを渡して結果を受け取る)
@Override
protected void onCreate(Bundle savedInstanceState) {
第
super.onCreate(savedInstanceState);
15
setContentView(R.layout.activity_android_http_async);
章
外
部
loadAsync("http://tomorrowkey.github.io", new OnLoadListener() {
ラ
イ
ブ
ラ
リ
ー
の
@Override
public void onLoad(String result) {
//処理
}
});
利
用
}
と
作
成
check!
コードがシンプルになると新たな問題も
リスト11、12では、コードがシンプルになりましたが、同時に新たな問題を生んでい
る点についても意識する必要があります。
「loadAsync」
メソッドは通信エラー時の処理
ができません。またヘッダやステータスコードを見ることもできません。シンプルになっ
た代わりに制約も生んでいるのです。この制約をどのように取り扱うかはプログラムの
要件によって変わります。今回は細かなハンドリングは意識しないので、この形にして
います。
演習問題
1.RSSフィードを読み込んで結果をTextViewに表示してみよう
まず「http://headlines.yahoo.co.jp/rss/list」のページから好きなRSSフィー
ドを選んでください。
2.RSSフィードからitem要素を取り出してみよう
「jsoup」
(http://jsoup.org/)
という
「jar」形式のライブラリーを導入し、RSS
フィードのitem要素を取り出してみましょう。その後以下の処理を実装してみましょ
う。
・ RSSフィードのitem要素をListViewに表示
・ ListViewに表示したitem要素をタップして、ブラウザでURLを開く
(URLをブラウザで開く方法については、第4章「4-3-2:暗黙的Intent」の項が
参考になるでしょう)
51
まとめ
本節ではライブラリーとは何か、Androidで利用できるライブラリーの種類、
「jar」形式のライブラリーの使い方を学びました。ライブラリーを用いることで効率的
に開発が行えることを体験できたのではないかと思います。
本節では通信処理に関するライブラリーを利用しましたが、他にも様々な種類の
ライブラリーがあります。どのようなライブラリーがあり、どういった性質を持っているか
を知ることはアプリケーションの開発効率に大きな影響を与えます。不要な開発を減
らせるだけでなく、先人が通った道を見本にして、さらなる改善ができるからです。ラ
イブラリーをただ利用するだけでなく、ソースコードを読んだり、ドキュメントを読んだり
して「何故そのような実装になっているか」、
「何故そのような設計になっているか」を
日頃から考えるようにしてみましょう。
52
15-2
ライブラリーモジュールを
使ってみよう
LESSON
著:八木俊広、片渕真太郎
R.java
aapt
apkbuilder
ケーション内で利用するリソースファイル等を含めることが
zipalign
でき、jar形式のライブラリーよりもできることが増えます。
GNU General Public License
Apache license 2.0
MIT ライセンス
dex
いて学びます。ライブラリーモジュールは、Androidアプリ
章
外
部
KEYWORD
aidl
この節ではライブラリーモジュールの概要と利用方法につ
第
15
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
jarsigner
作
成
カスタム属性
オープンソースライセンス
Android-Bootstrap
(https://github.com/Bearded-Hen/
Android-Bootstrap)
この節を学ぶとできること
jar形式よりもさらに自由度の高い
ライブラリーを利用してみます
ライブラリーモジュールを使ったプログラミングについて学
んでいきます。前の節と異なるのは、プログラミングの自由度
がさらに高い点です。具体的には、かっこいいUIを作れる
「Android-Bootstrap」を使って、現代風の見た目のアプ
リを作っていきます。
53
15 -2 -1 ライブラリーモジュールとは何か
「ライブラリーモジュール」はAndroid専用のライブラリー形式です。
ソースコードと
リソースファイルを内部に持つことができ、レイアウトファイルやdrawableを利用する
ActivityやViewなどをライブラリーとして提供できます
(図10)。
ライブラリーモジュール形式
図10: JAR形式とライブラリーモジュール形式の違い
15 -2 -2 Android アプリケーションのビルドフロー
なぜ「ライブラリーモジュール」が誕生したのでしょうか。
「JAR」形式のライブラ
リーにリソースファイルを含めることはできないのでしょうか。これらの疑問に答えるに
は、Androidアプリケーションがどのようなプロセスでビルドされているかを知る必要
があります。
図11は、
「Android Developers」の「Building and Running」に記載さ
れているAndroidアプリケーションをビルドするフローです。
詳細はhttps://developer.android.com/tools/building/index.htmlで
確認できます。
Androidプロジェクトから
「apk」に変換されるまでの間に複数のツールで順番
に処理されていることがわかります。
これらのツールは$ANDROID_SDK/build-tools/(build tool version)/の
中にあります。
以下、
それぞれのツールで何が行われているか見ていきましょう。
54
aidl
第
15
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
図11: Androidアプリケーションをビルドするフロー
55
「AIDL」は「Android Interface Definition Language」の略で、
プロセス
間通信のためのインタフェースを定義する
「DSL」です。異なるプロセスで動作する
Serviceに対してActivityなどから接続する際に利用します。
「DSL」は「Domain-Specific Language」の略でドメイン固有言語と呼びま
す。
「 D S L 」は特 定のタスク向けに設 計された独自の言 語のことを差します。
「AIDL」はプロセス間通信のために設計された独自の言語ということになります。
典型的な例としてはアプリ内課金などを実装する際に「AIDL」を利用します。ア
プリ内課金は「Google Play」を通して行います。
「Google Play」に対して決済
の処理などを依頼するために「AIDL」を使って接続します。
「AIDL」は、Javaとは異なる独自の言語ですので、そのままではJavaコンパイラ
でコンパイルできません。アプリケーションのソースコードをコンパイルする前に、
「AIDL」をコンパイルしてJavaのソースコードを生成します。
aapt
「aapt」
(Android Asset Packaging Tool)
はアプリケーションのリソースファ
イルや「AndroidManifest.xml」を解析し
「R.java」を生成します。ここで生成す
る
「R.java」を使って画像やレイアウトファイルへプログラムからアクセスすることになり
ます。その他「values」ディレクトリをコンパイルしてアーカイブします。
Java Compiler
通常のJava言語のコンパイラ
(javac)
です。
「aidl」や「aapt」が生成したソー
スコードと、アプリケーションのソースコードをまとめてコンパイルして「class」ファイルを
出力します。
dex
「class」ファイルをコンパイルし、
「Dalvik VM」のバイトコードである
「dex」ファ
イルへ変換します。この時、Androidプロジェクトが「JAR」形式のライブラリーを利
用している場合は、それらのライブラリー内の「class」ファイルも同時に「dex」ファイ
ルへコンパイルします。
apkbuilder( sdklib.jar)
「dex」
ファイル、
コンパイルしたリソース、画像類などのリソースファイルをアーカイブ
して「apk」ファイルを作成します。
56
jarsigner
「jarsigner」はJavaの標準のツールです。
「jarsigner」を使って「apk」ファイ
第
15
ルにデジタル署名を行います。デバッグビルドの時はデバッグ用の共有の署名が使
章
われますが、アプリケーションをリリースする場合は自分で証明書を作成する必要が
外
部
あります。
ラ
イ
ブ
ラ
リ
ー
の
zipalign
利
用
「zipalign」は「apk」を最適化するツールです。
「apk」はアプリケーションのイン
と
作
成
ストール時や、
ホームアプリケーションに名前やアイコンを表示する時など様々な場面
で読み取られます。
「apkbuilder」でアーカイブした「apk」の内部を「zipalign」
を使って整列することで、
「apk」の読み取りを高速化できるようになります。
15 -2 -3 JAR 形式のライブラリーがリソースファイルを持てない理由
Androidアプリケーションのビルドフローを見ると、
「JAR」形式のライブラリーが
処理されるのは「dex」
ファイルに変換されるタイミングだということがわかります。
リソー
スファイルを取り扱うには「R.java」に定義されたリソースIDが必要です。
「R.java」
は「aapt」コマンドによって生成されるので、
「JAR」形式のライブラリーからは「R.j
ava」の中のリソースIDを事前に知ることができません。そのため「JAR」形式のライ
ブラリーではリソースファイルを持てない、持ったとしても内部から利用できない、
という
ことになるわけです。
ライブラリーモジュールの誕生
そこで誕生したのが「ライブラリーモジュール」です。
「ライブラリーモジュール」は
Androidプロジェクトと同じ構造なので、リソースファイルを持てます。ビルドの際は
Androidプロジェクトと一緒にビルドフローを辿るので、
「R.java」が問題になること
はありません。この仕組みによって、画面を持つActivityやViewなどをライブラリー
化できるようになりました。
57
15 -2 -4 ライブラリーモジュールを導入してみよう
「ライブラリーモジュール」を使ってアプリケーションを開発してみましょう。本節では
「Android-Bootstrap」
というスタイリッシュなUIの構築を助けるライブラリーを導
入します。
Font Awesomeは、アイコンを一種
のフォントとして、ベクトル形式のス
Android-Bootstrapとは
ケーラブルなデータから作成できるよ
うにするツールキット
(http://fortaw
esome.github.io/FontAwesome/)
。
「Android-Bootstrap」は、Web用のフロントエンドフレームワーク「Bootstr
ap」のコンセプトを元に構成したAndroid用のUIライブラリーです。角丸ボタンや
アイコン付きボタン、
「FontAwesome」の利用、円形サムネイルなど、様々なUI部
品を提供しています
(図12)。
図12:
「Android-Bootstrap」
のコンポーネントたち
ライブラリーモジュールの依存関係を解決する
Eclipseで開発する際はプロジェクトをローカルにダウンロードしてきて、ライブラ
リーモジュールとしてインポートするという手順が必要でしたが、Android Studioで
は「jar」
ライブラリと同じく
「build.gradle」に依存関係を記述することでプロジェク
トにライブラリを取り込むことができます
(図13)。
58
第
15
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
本書の執筆時点では1.2.1が
最新のバージョンでした
図14:
「build.gralde」
に依存関係を追加する
動作確認
正しく準備ができたか確認してみましょう。新しく作ったプロジェクトの「MainAct
ivity.java」の冒頭に、リスト13のような「import」文を記述し、エラーが発生し
なければ準備完了です。
リスト13:MainActivity.java
(導入したライブラリーのクラスをインポートする)
import com.beardedhen.androidbootstrap.BootstrapButton;
もしエラーになる場合はプロジェクトを一度「clean」
したり、再ビルドするなどして
みてください。
15 -2 -5 Android-Bootstrap の BootstrapButton を使う
「Android-Bootstrap」はいくつかのカスタムViewを提供しています。そのうち
の一つである
「BootstrapButton」を使ってみましょう。リスト14のようにレイアウト
ファイルに「BootstrapButton」を定義してください。
59
リスト14:activity_main.xml
(BootstrapButtonの定義)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:library="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<com.beardedhen.androidbootstrap.BootstrapButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Hello Bootstrap!"
library:bb_type="success" />
</RelativeLayout>
アプリケーションを起動すると図15のような表示になるはずです。
図 1 5:アプリ画 面 に
「BootstrapButton」
が表示された
15 -2 -6 カスタム属性
「BootstrapButton」のレイアウトの定義に見慣れない記述がありました。
レイアウ
トの要素には通常「android:」をプレフィクスとした属性値を定義しますが、
「Boot
strapButton」ではリスト15のように異なるプレフィクスを持った属性を定義して
います。
リスト15:activity_main.xml
(BootstrapButtonに指定したプレフィクスが異なる属性)
library:bb_type="success"
これは「カスタム属性」
というAndroidの機能です。Androidではレイアウトファイ
ルで利用する属性値を自分で定義できます。
「Android-Bootstrap」は「カスタム
属性」を各種コンポーネントに定義し、レイアウトファイル上で様々な設定ができるよう
60
になっています。
check!
プレフィクスは「library:」
第
15
章
この例では「library:」
というプレフィクスを使っていますが、特に決まりはありませ
ん。このプレフィクスは
「名前空間」
と呼び、属性の名前が衝突しないために用いられま
す。カスタム属性のための名前空間は、レイアウトファイルの冒頭の「xmlns」属性定義
で自由に決められます。ここでは「xmlns:library="http://schemas.android.com/
apk/res-auto"」のように定義し、
「library:」
というプレフィクスを用いることを宣言し
ています。
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
次に「BootstrapButton」の「bb_type」属性の値を変更してみましょう
(リス
と
作
成
ト16)。
リスト16:activity_main.xml
(bb_typeを変更する)
library:bb_type="danger"
アプリケーションを実 行 すると図 1 6 のような表 示になります。このように
「Android-Bootstrap」はカスタム属性によって様々な表示を簡単に設定できる
仕組みを提供しています。
図 1 6:カスタム 属 性
「bb_type」を「dang
er」
に変更した結果
ライブラリーが定義しているカスタム属性を知るには
UIコンポーネントを提供するライブラリーでは、カスタム属性を定義している場合
が多いです。ライブラリーが定義しているカスタム属性を知る方法として以下が挙げ
られます。
・ドキュメントを読む
・ ソースを読む
基本的にまずはドキュメントを探して読むことになるでしょう。例えば「AndroidBootstrap」の「BootstrapButton」の使い方は以下のページに解説がありま
す。
61
・ Bootstrap Button:https://github.com/Bearded-Hen/AndroidBootstrap/wiki/Bootstrap-Button
「Android-Bootstrap」には比較的ていねいなドキュメントが揃っていますが、
中にはドキュメントがなかったり、カスタム属性についての記述が不足しているライブ
ラリーもあります。参考になるドキュメントがない場合は、ライブラリーのソースを読ん
で調べることになります。
ソースを読んでカスタム属性を理解する
res/values/attrs.xml : https://
github.com/Bearded-Hen/
Android-Bootstrap/blob/mast
er/AndroidBootstrap/res/valu
es/attrs.xml
「Android-Bootstrap」の中を覗いて、
「BootstrapButton」クラスのカスタム
属性について調べてみましょう。
「Android-Bootstrap」の「res/values/attrs.
xml」を開いてください。
リスト1 7に「 a t t r s . x m l 」ファイルの冒頭 部 分を抜 粋します。
「declarestyleable」要素の「name」属性に「BootstrapButton」
という記述があります。
これは「 B o o t s t r a p B u t t o n 」のカスタム属 性の宣 言を表します。
「declarestyleable」要素の中に複数の「attr」要素を持っています。
「attr」要素には属
性名と、
それに対して指定できる値の種類を定義しています。
リスト17:AndroidBootstrap-attr.xml
(冒頭部分)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BootstrapButton">
<attr name="bb_type" format="string"/>
<attr name="bb_icon_left" format="string"/>
<attr name="bb_icon_right" format="string"/>
<attr name="bb_roundedCorners" format="boolean"/>
<attr name="bb_text_alignment" format="string"/>
<attr name="bb_size" format="string"/>
<attr name="bb_text_gravity" format="string"/>
<attr name="android:textSize"/>
<attr name="android:text"/>
<attr name="android:enabled"/>
<attr name="android:layout_width"/>
</declare-styleable>
<!-- 省略 -->
これで「BootstrapButton」の持つカスタム属性はわかりました。次はこれらの
属性がどのように使われているかを調べます。すべて調べるのは大変なので、代表と
して「bb_type」属性がどのように使われているかを「BootstrapButton」クラスの
ソースコードを読んで確認してみましょう。
「BootstrapButton」クラスは「src/
com/beardedhen/androidbootstrap/BootstrapButton.java」で定義され
ています
(図24)。
62
第
15
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
図24:
「BootstrapButton.java」
を開いて調べる
「BootstrapButton.java」を開き、
「bb_type」をキーにしてソースコード内を検
索をすると、140行目に「bb_type」属性を扱う処理が見つかります
(リスト18)。
将来変更される可能性があるので、ソースコードのハッシュ値を記載しておきま
す。
「9067416920a2a9a000a77280010fdc580aaf06b1」
リスト18:BootstrapButton.java
(140行目前後)
113:private void initialise( AttributeSet attrs ) {
-省略121:
TypedArray a = getContext().obtainStyledAttributes(attrs,
122:
R.styleable.BootstrapButton);
-省略126:
String bootstrapType = "default";
-省略140:
if (a.getString(R.styleable.BootstrapButton_bb_type) != null) {
141:
142:
bootstrapType = a.getString(R.styleable.BootstrapButton_bb_type);
}
カスタム属性を定義すると、Rクラスの「styleable」にIDが追加されます。ID名
は「 d e c l a r e - s t y l e a b l e 」要 素で定 義した「 n a m e 」属 性と「 a t t r 」要 素の
「name」属性を「_」
(アンダースコア)
でつないだものになります。このIDを使って
「TypedArray」クラスから指定された値を取り出すことができます。
「Bootstrap
Button」の「bb_type」属性の場合は、
「BootstrapButton_bb_type」
という
名前になります。
「TypedArray」クラスは「Context」クラスの「obtainStyledAttributes」メ
ソッドで取り出します。この時引数に「AttributeSet」クラスのオブジェクトと
「R.sty
leable.BootstrapButton」を渡します。
「AttributeSet」
オブジェクトは、Viewの
63
コンストラクタで受け取ったものを使います。
Viewのコンストラクタが3種類あったことを覚えているでしょうか。10章(UIのカス
タマイズ)
の第1節でカスタムViewを作成する際に、
「XMLより呼び出す際のコンス
トラクタ」
として解説したコンストラクタの引数に「AttributeSet」オブジェクトが渡っ
てきます。この「AttributeSet」オブジェクトには、レイアウトファイルで定義した属性
値が入っています。
「bb_type」の属性値は「String」なので、
「TypedArray」クラスの「getStri
ng」メソッドで取り出します。取り出した値は「bootstrapType」にセットしています。
次は「bootstrapType」がどこで使われているかを探します。
「bootstrapTy
pe」をキーにしてソースコード内を検索すると、240行目にリスト19のような実装が
見つかります。
リスト19:BootstrapButton.java
(240行目前後)
26:
private static Map<String, BootstrapTypes> bbuttonTypeMap;
-省略36:
private boolean roundedCorners = false;
-省略125:
BootstrapTypes type = null;
-省略240:
//get the correct background type
241:
if(roundedCorners == true)
242:
{
243:
244:
type = bbuttonTypeMapRounded.get(bootstrapType);
} else {
245:
246:
type = bbuttonTypeMap.get(bootstrapType);
}
247:
248:
//set up as default
249:
if (type == null)
250:
{
251:
252:
type = BootstrapTypes.DEFAULT;
}
253:
254:
//apply the background type
255:
layout.setBackgroundResource(type.backgroundDrawable);
256:
lblLeft.setTextColor(getResources().getColor(type.textColour));
257:
lblMiddle.setTextColor(getResources().getColor(type.textColour));
258:
lblRight.setTextColor(getResources().getColor(type.textColour));
241行目の「if」文は「roundedCorners」
という変数名から
「ボタンを角丸にす
るかどうか」を判定していることがわかります。今回は特に角丸の指定はしていなかっ
たので245行目の処理に進みましょう。245行目では「bbuttonTypeMap」
という
変数の「get」メソッドに「bootstrapType」を渡しています。
「bbuttonTypeMap」は「Map<String, BootstrapTypes>」クラスです。
「get」メソッドで「BootstrapTypes」クラスのインスタンスを取り出せます。そのイン
スタンスを「type」
という変数にセットし、
その後255行目で利用しています。
次は「bbuttonTypeMap」をどのように初期化しているか、
「BootstrapTyp
64
es」クラスがどのようなクラスなのかを見ていきます。
まずは「BootstrapTypes」クラ
スです。
「BootstrapTypes」クラスは84行目に定義されています
(リスト20)。
「BootstrapTypes」クラスは「class」ではなく
「enum」
と宣言されています。
第
15
「enum」は列挙型を表します。
章
リスト20:BootstrapButton.java
(84行目以降)
84:
private enum BootstrapTypes
85:
{
86:
DEFAULT(R.drawable.bbuton_default, R.color.black),
87:
PRIMARY(R.drawable.bbuton_primary, R.color.white),
88:
SUCCESS(R.drawable.bbuton_success, R.color.white),
89:
INFO(R.drawable.bbuton_info, R.color.white),
90:
WARNING(R.drawable.bbuton_warning, R.color.white),
91:
DANGER(R.drawable.bbuton_danger, R.color.white),
92:
INVERSE(R.drawable.bbuton_inverse, R.color.white),
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
-省略102:
private int backgroundDrawable;
103:
private int textColour;
104:
105:
BootstrapTypes(int backgroundDrawable, int textColour)
106:
{
107:
this.backgroundDrawable = backgroundDrawable;
108:
109:
this.textColour = textColour;
}
110: }
列挙型は通常のクラスと同じようにコンストラクタやフィールドやメソッドを持ちます。
ただしインスタンスは「enum」内に宣言した列挙子のみに限られるという特徴があり
ます。あらかじめ宣言したもの、数しかインスタンスが存在しないことが保証されている
ため、
「switch」文で比較したり定数として扱うことができます。
「BootstrapTypes」クラスは、フィールドとして「backgroundDrawable」
(背
景のdrawable)
と
「textColour」
(文字色)
を持った単純なクラスです。列挙子と
して「DEFAULT」や「PRIMARY」などが宣言されています。列挙子を宣言す
る際に、背景のdrawableと文字色のIDを渡しています。これによりボタンの色のバ
リエーションを定義しています。
次は「bbuttonTypeMap」の初期化です。41行目のstaticイニシャライザー
で、キーに対応する
「BootstrapTypes」クラスをセットしていることがわかります
(リ
スト21)。
staticイニシャライザーは、クラスが初めてクラスローダーに読み込まれる時に一
度だけ実行されるブロックのことです。クラスがインスタンス化される時ではない点に
注意してください。
65
リスト21:BootstrapButton.java
(41行目以降)
41:
static{
42:
43:
bbuttonTypeMap = new HashMap<String, BootstrapTypes>();
44:
45:
bbuttonTypeMap.put("default", BootstrapTypes.DEFAULT);
46:
bbuttonTypeMap.put("primary", BootstrapTypes.PRIMARY);
47:
bbuttonTypeMap.put("success", BootstrapTypes.SUCCESS);
48:
bbuttonTypeMap.put("info", BootstrapTypes.INFO);
49:
bbuttonTypeMap.put("warning", BootstrapTypes.WARNING);
50:
bbuttonTypeMap.put("danger", BootstrapTypes.DANGER);
51:
bbuttonTypeMap.put("inverse", BootstrapTypes.INVERSE);
-省略-
これですべての情報がそろいました。
「bb_type」属性で指定した値は「bbutto
nTypeMap」に登録された「BootstrapTypes」クラスを取り出すためのキーとし
て利用されていました。
「BootstrapTypes」は背景のdrawableと文字色を持つ
クラスで、
このクラスが持つ値を使ってViewの表示色などを変更していることがわか
りました。
少し大変だったかと思います。しかしソースを読むことによって「bb_type」属性
の役割がわかっただけでなく、
「表示を属性値によって簡単に切り替える仕組み」
がどのように実現されているかもわかりました。また「bb_type属性の値の種類が7
つあること」や「角丸表示の設定があること」や「enumクラスの使い方の参考」など
も得られました。ソースコードを読むことで非常に多くの学びが得られます。
15 -2 -7 ライブラリーとライセンス
Androidアプリケーションで利用するライブラリーのほとんどはオープンソースで
す。前項で「Android-Bootstrap」のカスタム属性を調べることができたのも
「Android-Bootstrap」がオープンソースだからです。オープンソースのソフトウェ
アには「オープンソースライセンス」が定義されています。
オープンソースのソフトウェア
を利用する場合、
「オープンソースライセンス」に記載されている条件に従う必要が
あります。
オープンソースライセンスには沢山の種類があります。本項では近年のオープン
ソースのライブラリーでよく利用されている
「Apache License 2.0」、
「MIT Lice
nse」に加え、コピーレフトという思想に則った「GPLライセンス」について簡単に解
説します。
66
GNU General Public License(GPLライセンス)
「GPLライセンス」は「オープンソース」
という概念が提唱される時代より前に作ら
第
15
れたライセンスのひとつです。ライセンス条項はコピーレフトの思想に則っています。コ
章
ピーレフトは著作権(コピーライト)
を保持したまま、すべての者がその著作物の利
外
部
用、再頒布、改変ができなければならないという考え方です。
用されます。つまりそのアプリケーションのソースコードも公開しなければならないという
ラ
イ
ブ
ラ
リ
ー
の
ことになります。
と
このため、
「GPLライセンス」を持ったオープンソースのライブラリーを利用する場
合、
ライブラリーを利用したアプリケーションのソースコードにも
「GPLライセンス」が適
利
用
作
成
Apache license 2.0
「Apache license 2.0」は、
「Apacheソフトウェア財団(ASF)」が策定した
オープンソースライセンスです。
「Apache license 2.0」ではソースコードの開示義
務はありません。
「Apache license 2.0」
ライセンスのライブラリーに「NOTICE」ファイルが含ま
れている場合、その内容についてアプリケーション上で表示する必要があります。多
くのアプリケーションでは「NOTICE」ファイルの有無に関係なくライブラリー名、著
作権者、
ライセンス条項を表示する場合が多いです。
MITライセンス
「MITライセンス」は、
「マサチューセッツ工科大学」が公開したオープンソースラ
イセンスです。非常にシンプルなライセンスで原文も20行程度しかありません。
利用にあたっては、著作権表示と許諾表示を行う必要があります。
「MITライセ
ンス」
もソースコードの開示義務はありません。
ライセンスを確認しよう
以上、代表的なオープンソースライセンスについてざっくり説明をしました。オープ
ンソースライセンスには様々な種類があり、それぞれで条件が異なります。オープン
ソースのライブラリーを利用する時は、必ずライセンスの確認をし、守るべき条件を確
認しましょう。図25は、
「Apache license 2.0」や「MITライセンス」の著作権表
示や許諾表示の例です。既存のアプリケーションがどのようにオープンソースライセ
ンスを取り扱っているか参考にするとよいでしょう。
67
図25:オープンソースの著作権表示、許諾表示の例
68
演習問題
1.Android-Bootstrapを使ってプロフィール画面を作ってみましょう。
第
15
Android-Bootstrapのコンポーネントを使ってプロフィール画面を作ってみましょ
章
う。以下の図26の例は「BootstrapButton」
「FontAwesomeText」
「Boots
外
部
trapCircleThumbnail」を使っています。この例を再現してもよいですし、独自に
ラ
イ
ブ
ラ
リ
ー
の
デザインしても構いません。
利
用
と
作
成
2.Android-Bootstrapのライセンスを調べてみましょう。
「Android-Bootstrap」のライセンスの種類は何か、利用にあたって何をしなけ
ればならないか調べてみましょう。
69
まとめ
本節では「ライブラリーモジュール」の生い立ち、その使い方、オープンソースライ
センスについて学びました。
「ライブラリーモジュール」はソースコードをインポートして
利用する形式なので、ライブラリー自身のソースコードを参照しやすいです。Andr
oidアプリケーションを作る時、Android自身のソースコードを参照することがよくあり
ます。ソースコードを読めば、ドキュメントに書かれていない詳細な処理や、Andro
idバージョン毎の違いを知ることができます。普段からソースコードを読む習慣を身
につけておきましょう。
check!
Androidはオープンソース
Androidのソースコードのダウンロード方法は以下のページで確認できます。
Downloading the Source:https://source.android.com/source/downloading.
html
Androidのソースコードは巨大で、すべてのソースコードをダウンロードすると、数十
GBの容量になります。気軽にダウンロードできるサイズではありません。Androidの
ソースコードを簡単に参照できるサービスがいくつかあります。まずはこれらのサービ
スを利用してソースコードを読むとよいでしょう。
Developer Collaboration Project:https://sites.google.com/site/devcollabora
tion/codesearch
GrepCode:http://grepcode.com/project/repository.grepcode.com/java/ext/
com.google.android/android/
70
15-3
ライブラリーモジュールを
作ってみよう
第
著:八木俊広、片渕真太郎
15
章
外
部
この節では「ライブラリーモジュール」の作り方を学びま
ラ
イ
ブ
ラ
リ
ー
の
す。 作成した
「ライブラリーモジュール」
を利用しながら、
「ラ
と
LESSON
KEYWORD
minSdkVersion
利
用
作
成
イブラリーモジュール」
へActivityを定義する方法や注意点
を学びます。
この節を学ぶとできること
ライブラリーモジュールそのものを作ってみます
前節で利用したライブラリーモジュールそのものの作り方について学んでい
きます。
「この処 理は後々使いまわせるな」
といった部 分をライブラリーモ
ジュールにしておくことで、今後の開発を省力化できるようになります。
71
15 -3 -1 新規ライブラリーモジュールを作成する
「ライブラリーモジュール」の開発は、ほとんど通常のAndroidアプリケーションプロ
ジェクトと同じです。新規の「ライブラリーモジュール」を作成し、簡単な計算を行う
「Calculator」クラスを追加してみましょう。
「File」→「New module」を選択し、新規モジュール作成画面を立ち上げ
「Android Library」を選択してください
(図27)。
図27:新規モジュールを作成し
「Android Library」
を選ぶ
ライブラリ名は「MyLibrary」
とします。
「Minimum SDK」は「API 18: Andr
oid 4.3 (Jelly Bean)」に設定しています
(図28)。
「Minimum SDK」
と
「ライブラリーモジュール」の関係については後ほど解説し
ます。
72
第
15
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
利
用
と
作
成
図28:ライブラリー名として
「MyLibrary」
を設定する
続いて表示される画面では「Add No Activity」を選択し、設定を完了してく
ださい
(図29)。
図29:
「Add No Activity」
を選択して
「Finish」
する
新規モジュールの作成が完了したら
「settings.grade」を開いて設定を確認し
ましょう
(図30)。アプリのモジュールに加えて先程作成したライブラリーのモジュー
ル名が追加されていれば成功です。
73
図30:
「settings.grade」
を開いて設定を確認する
Calculatorクラスを追加する
「Calculator」クラスは、足し算を行う
「plus」メソッドを持つ単純なクラスです。
このクラスをライブラリーモジュールに追加しましょう。
「mylibrary」モジュールの
「src」→「main」→「java」→「自分のパッケージ名」の上で右ボタンクリックして、
「New」→「JavaClass」を選んで「Calculator」クラスを作成します。リスト22
を参考に実装をしてください。
リスト22:Calculator.java
(Calculatorクラスの定義)
package jp.techinstitute.t051.mylibrary;
public class Calculator {
public int plus(int a, int b) {
return a + b;
}
}
Calculatorクラスを使う
「Calculator」クラスの「plus」メソッドを使って得た結果をTextViewに表示
してみましょう。まず、ライブラリーを使う方(app)
のモジュールのディペンデンシーを
設定する必要があります。まず「File」メニューから
「Project Structure...」を選
んで、
「app」モジュールの「Dependencies」タブを表示します
(図31)。
図31:
「File」
メニューから
「Project Structure...」
を選んで
「Dependencies」
タブを表示する
ここで、右上の「+」ボタンをクリックして表示するメニューから
「Module depen
dency」を選びます
(図32)。
74
第
15
章
外
部
ラ
イ
ブ
ラ
リ
ー
の
図32:
「+」ボタンをクリックして
「Module dependency」
を選ぶ
利
用
すると
「Choose Modules」
というダイアログが表示されるので、その中の1つしか
と
作
成
ない選択肢「:mylibrary」を選んで「OK」をクリックします
(図33)。
図33:
「Choose Mod
ules」
では「:mylibrary」
を選択する
この結果「Project Structure」のウィンドウにも、選択した「:mylibrary」が追
加されました
(図34)。
図34:
「Project Structure」
の
「Dependencies」
タブにも
「:mylibrary」
が追加された
75
この結果は、
「app」の「build.gradle」でも確認できます
(図35)。もちろん、こ
のファイルを最初からこのように編集しても同じことです。
図35:ディペンデンシーの設定結果を
「build.gradle」
で確認する
以上のように設定したら、アプリケーションの「activity_main.xml」をリスト23の
ように編集します。
アプリモジュールの「MainActivity」で使うレイアウトを次のリスト23のように
作成してください。
リスト23:activity_main.xml
(
「UseMyLibrary」
のレイアウト)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:textSize="40sp"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
次にリスト24のように「MainActivity」の実装を行います。
76
リスト24:MainActivity.java
(
「UseMyLibrary」
のアクティビティ)
package jp.techinstitute.t051.myapplication;
第
import android.support.v7.app.ActionBarActivity;
15
import android.os.Bundle;
章
import android.view.Menu;
外
部
import android.view.MenuItem;
ラ
イ
ブ
ラ
リ
ー
の
import android.widget.TextView;
import jp.techinstitute.t051.mylibrary.Calculator;
public class MainActivity extends ActionBarActivity {
利
用
@Override
protected void onCreate(Bundle savedInstanceState) {
と
super.onCreate(savedInstanceState);
作
成
setContentView(R.layout.activity_main);
Calculator calculator = new Calculator();
int result = calculator.plus(10, 15);
TextView textView = (TextView)findViewById(R.id.text);
textView.setText("result=" + result);
}
}
アプリケーションを実行し、図36のような結果が得られるか確認してください。
図36:
「Calculator」クラスの「plus」
メ
ソッドの結果を表示する
15 -3 -2 ライブラリーの minSdkVersion を確認する
今回作成した「ライブラリーモジュール」では、
「Minimum SDK」
(以後、min
SdkVersionとします)
を「API 18:Android 4.3 (Jelly Bean)」に設定しました。
この設定はライブラリーを利用する側にとって重要な意味を持ちます。
例えば、作成するAndroidアプリケーションのminSdkVersionを「10」
(Andr
oid 2.3.3)
に設定するとします。この時、アプリケーションが利用する
「ライブラリーモ
ジュール」はminSdkVersionが10以下でなければなりません(図37)。
77
図37:ライブラリーモジュールとminSdkVersionの関係
アプリケーションをコンパイルする時、minSdkVersionの大小関係の問題につ
いては警告してくれません。このため「ライブラリーモジュール」が指定しているminS
dkVersionよりも低いバージョンの端末にも、そのアプリケーションをインストールして
実行できてしまいます。もしそのアプリケーションが、その端末のAndroidバージョン
には存在しないAPIを利用してれば、
アプリケーションはクラッシュしてしまいます。
15 - 3 -3 Activity をライブラリーに含める
「ライブラリーモジュール」にActivityを追加してみましょう。追加そのものは通常
のAndroidアプリケーションと同じ手順でできますが、
「ライブラリーモジュール」内
のActivityを利用する際に注意しなければならないことがあります。
LibraryActivityをMyLibraryに追加する
「MyLibrary」に「LibraryActivity」
という名前のActivityを追加します。
通常のクラスの追加と同様、
「mylibrary」モジュールの「src」→「main」→
「java」→「自分のパッケージ名」の上で右ボタンクリックして、
「New」サブメ
ニューから
「Activity」→「Blank Activity」を選びましょう。
プロジェクトを新規に作成する場合と同様、アクティビティ名やレイアウトのXML
ファイルの名前を指定して追加します。ここではアクティビティ名は「LibraryActivi
ty」に設定します。それによりレイアウト名は自動的に「activity_library」になりま
す。追加したアクティビティはリスト25のように編集します。
78
リスト25:LibraryActivity.java
(クラスファイルごと追加)
public class LibraryActivity extends ActionBarActivity {
public static Intent createIntent(Context context) {
第
return new Intent(context, LibraryActivity.class);
15
}
章
外
部
@Override
ラ
イ
ブ
ラ
リ
ー
の
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_library);
}
}
利
用
と
作
成
LibraryActivityを起動する処理を実装する
メインのレイアウト
(activity_main.xml)
に「button」
というidのボタンを1つ追加
してから、
「MainActivity.java」をリスト26のように編集し、
ボタンをクリックすると
「LibrayActivity」を起動するようにします。
リスト26:MainActivity.java
(MainActivityからLibraryActivityを起動する)
package jp.techinstitute.t051.myapplication;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import jp.techinstitute.t051.mylibrary.LibraryActivity;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = LibraryActivity.createIntent(MainActivity.this);
startActivity(intent);
}
});
}
}
問題がなければコンパイルが通り、アプリケーションを実行できるはずです。ボタン
をクリックすると、アクティビティが切り替わり
「LibrayActivity」の画面が表示され
るはずです。この場合には、同じプロジェクト内のアクティビティの切り替えなので、こ
れで問題ありません。しかし、外部ライブラリーに組み込まれたアクティビティを起動し
79
ようとすると、
クラッシュしてしまうでしょう。
AndroidManifest.xmlにactivityを追加する
アプリケーションがクラッシュしてしまう理由は、呼び出し側の「AndroidManife
st.xml」に、呼び出される側のアクティビティが定義されていないからです。
通常のActivityと同ように、ライブラリーモジュールのActivityを利用する場合
も次のように「AndroidManifest.xml」を定義しておく必要があります
(リスト
27)。
リスト27:AndroidManifest.xml
(使用するアクティビティを追加)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.techinstitute.usemylibrary">
<application>
<!-- 省略 -->
<activity android:name="com.techinstitute.mylibrary.LibraryActivity"/>
</application>
</manifest>
Activityだけでなく、ServiceやBroadcastReceiverなど、
「AndroidManif
est.xml」に定義が必要なコンポーネントを利用する場合は、アプリケーション側の
「AndroidManifest.xml」に定義しなければなりません。こちらもアプリケーションを
コンパイルした時点ではエラーとならないので、minSdkVersionと同様に気をつけ
なければならない点です。
演習問題
今まで作ったプログラムをライブラリー化してみましょう。
例えば10章の第1節で作成したペイントViewなど、今まで作ったプログラムを再
利用できるようにしてみましょう。
まとめ
本節では「ライブラリーモジュール」の作り方と、minSdkVersionやActivityを
ライブラリーモジュールに含める場合の注意点について学びました。
「ライブラリーモ
ジュール」にアプリケーションで共通に利用できる機能を実装していくことで、効率的
に開発が行えるようになります。アプリケーションを開発する際、共通で利用できそう
なクラスができた場合は「ライブラリーモジュール」に含めることを検討しましょう。
80