TL;DR: 本書では、日々の Android 開発に役立つ 15 のライブラリを簡単に見ていきます。これらを使って、より良いパフォーマンスとより良いユーザー エクスペリエンスを提供するアプリケーションを作成することができます。
“大人気の Android ライブラリはより良いパフォーマンスとユーザーエクスペリエンスを提供するアプリケーションの作成に役立ちます。”
これをツイートする
大人気の Android ライブラリ
ライブラリはプラットフォームやスタックに関連付けられたソフトウェア開発に大変革をもたらします。ライブラリを使って、他の開発者の作業を利用して、より重要度の低い定型句コードでより早く、より効果的にアクション/機能を実行します。本書では、Android 開発におけるさまざまなカテゴリやそれらに使用される共通ライブラリについて学んでいきます。
Android ライブラリ — 画像読み込み
画像読み込みライブラリは複数の画像を同時に読み込んで大量のメモリが消費されないようにするときにとても便利です。画像は Android 開発で起きるメモリ不足エラーの最大の源です。よって、これらライブラリはシームレスなユーザーエクスペリエンスを提供するためにメモリ使用量を最小限にして、画像を読み込んだりキャッシュしたりする面倒を減らします。おなじみの 2 つの画像読み込みライブラリ、Glide と Picasso を見てみましょう。
Glide
Glide はスムーズなスクロールにフォーカスした画像読み込みライブラリです。Glide は、ストレージ オーバーヘッドとデコード時間を最小限にするために自動式スマート ダウンサンプリングとキャッシュを画像読み込みを適用して、できるだけ速くかつスムーズに行います。また、バイト配列のようなリソースを再利用し、必要なときにアプリケーションリソースを自動的にリリースします。Glide の最新バージョンは書き込みのときに SDK の API レベル 14 (Android 4.0)以上、SDK の API 26 (Android 8.0)以降のコンパイルが必要です。
GLIDE を使用する
まず、プロジェクト
build.gradle
ファイルに Maven および Google レポジトリを次のように追加します。repositories { mavenCentral() google() }
それから、アプリモジュール
build.gradle
ファイルにライブラリ依存関係を追加して、それを同期して次のようにライブラリを使用可能にします。implementation 'com.github.bumptech.glide:glide:4.4.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'
すると、次のように 1 行のコードでリモート URL から画像をロードできます。
GlideApp .with(this) .load("https://res.cloudinary.com/demo/video/upload/dog.png") .into(imageView);
with
メソッドは Context
、 Activity
、Fragment
または View
オブジェクトを取ることができます。 load
メソッドはリモート URL またはドローアブルファイル(例 R.drawable.image
)を取ります。引数として into
メソッドにパスされた imageView
インスタンスはタイプ ImageView であるべきです。gradle
バージョンが 3.0 以下の場合は、依存関係を追加するために implementation
の代わりに compile
キーワードを使用するように 注意してください 。Picasso
Picasso はもうひとつの素晴らしい Android 用画像ライブラリです。オープンソースの世界に強く依存し、貢献する会社の Square が作成・管理しており、画像読み込み・処理を提供しています。Picasso を使用すると、画像を外部の場所から表示するプロセスが簡素化されます。Picasso は複雑な画像変換、ディスクへの自動キャッシュ、
ImageView
リサイクル、アダプタのダウンロード取り消しをサポートします。このライブラリはプロセスの全ステップを処理します。HTTP 要求を処理することから始まり、画像のキャッシュも処理します。丁度 Glide と同様です。
PICASSO を使用する
まず、Picasso 依存関係を次のようにアプリモジュール
build.gradle
ファイルに追加します。implementation 'com.squareup.picasso:picasso:2.5.2'
その後、
gradle
ファイルを同期し、次のように 1 行のコードで画像リソースをロードします。Picasso .with(this) .load("https://res.cloudinary.com/demo/video/upload/dog.png") .into(imageView);
ご覧のように、Picasso が提供した API は Glide が提供したものと非常によく似ています。
長い間、どっちのライブラリのパフォーマンスが良いかということについて議論され、論争されてきました。以下の表には両者の長所と短所が記載されています。
Android ライブラリ — ビデオ
ビデオの表示は開発の間に難しい作業が課せられます。処理するプロセスと詳細があまりにも多すぎるからです。この種では、利用可能なオプションがいくつかあります。しかし、最も普及していて強力なものは
ExoPlayer
で、この章ではこれについてフォーカスしていきます。ExoPlayer
ExoPlayer は Google が開発した Android Media Player ライブラリです。オーディオとビデオを再生するときに(ローカルとインターネット上の両方で)Android の MediaPlayer API に代替オプションが与えられ、他の利点もあります。
ExoPlayer
は Android の MediaPlayer API が現在サポートしていない DASH や SmoothStreaming 適応型再生 のような機能を提供します。ExoPlayer
の最大の利点のひとつはカスタマイズが簡単なことです。EXOPLAYER を使用する
まず最初に、JCenter および Google レポジトリを次のようにプロジェクト
build.gradle
構成ファイルに追加します。repositories { jcenter() google() }
次に、Gradle コンパイル依存関係を次のように同じファイルに追加します。
implementation 'com.google.android.exoplayer:exoplayer:2.6.0'
それから、レイアウトリソースファイルに
SimpleExoPlayerView
コンポーネントを次のように追加します。<com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/simple_exoplayer_view" android:layout_width="match_parent" android:layout_height="wrap_content"/>
その後、対応するアクティビティ クラスで、次のように
ExoPlayer
のクラスのインスタンスを作成します。SimpleExoPlayerView simpleExoPlayerView; SimpleExoPlayer player;
それから、次のようにアクティビティの onCreate メソッドで
simpleExoPlayerView
を初期化します。simpleExoPlayerView = findViewById(R.id.simple_exoplayer_view);
そして
onStart
メソッドで、 次のように setupPlayer
メソッドを呼び出します。@Override protected void onStart() { super.onStart(); setupPlayer(); }
次のように
setupPlayer
メソッドも呼び出します。void setupPlayer(){ BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); //既定の構成でプレーヤーを初期化します player = ExoPlayerFactory.newSimpleInstance(this, trackSelector); // simpleExoPlayerView を割り当てます simpleExoPlayerView.setPlayer(player); // メディアデータが読み込む DataSource インスタンスを作ります。 DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "CloudinaryExoplayer")); // メディアデータを解析する抽出インスタンスを作ります。 ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory(); // これはメディアが再生される MediaSource を表します MediaSource videoSource = new ExtractorMediaSource(videoUri, dataSourceFactory, extractorsFactory, null, null); // ソースでプレーヤーを用意します。 player.prepare(videoSource); }
ここで、既定の構成で
player
を初期化し、それを SimpleExoPlayerView
インスタンスに割り当てます。videoUri
は Uri
のタイプです。格納された全てのファイルには Uri
があり、そのファイルを一意のアドレスにします。ビデオをリモート URL から表示するのであれば、次のように解析する必要があります。Uri videoUri = Uri.parse("any_remote_url");
これが
ExoPlayer
の基本的な実装になります。Google では このライブラリで始める方法についての素晴らしいチュートリアル を提供しています。Android ライブラリ — ネットワーク
最近のほとんど全てのモバイルアプリは、機能を実行するために何らかのネットワークコミュニケーションを必要とします。これまで、ネットワーク要求をしたければ、
Async
タスククラスを実行して HttpsUrlConnection
を使ってデータをフェッチする必要がありました。しかし、これは、特に大量のデータを返す API を使うときは、あまり有効ではありません。幸運なことに、スレッドやデバイスのリソースを適切に管理しながら、このプロセスを最適化する素晴らしいネットワーク ライブラリがあります。代替オプションの中で、Retrofit と Volley が際立ちます。この 2 つでは Retrofit の方が人気が高いので、これを見ていきましょう。
Retrofit
Retrofit は Square(Picasso をサポートする同じ会社)が開発・管理する Android / Java 用の タイプセーフ HTTP クライアントです。Retrofit は Android 開発では最もよく使われているネットワークライブラリです。Retrofit は注釈だけで要求本文の追加、エンドポイントの操作、ヘッダーの操作、クエリ パラメータの追加、要求メソッドの選択が簡単にできます。Retrofit はコンバータを使って、POJO の解析を処理します。
RETROFIT を使用する
Retrofit を使用するには、まず、次のように依存関係をアプリ build.gradleファイルに追加します。
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
また、使用する予定のコンバーターの依存関係も挿入します。コンバーターは応答本文に対する Java オブジェクトのマッピングを処理します。コンバーターについての詳細は こちら をご覧ください。
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
上記の最初のコンバーター(
converter-gson
)はその名前のとおり、JSON フォーマットから/までマップします。ふたつめは String
のようにプリミティブ データ型で処理したいときに使用します。ご希望のコンバーターをインポートした後、次のようにアクセスするエンドポイントを構成するインターフェイスを作成します。public interface ApiService { @GET("/data") Call<ResponseClass> fetchData(@Body JsonObject jsonObject); }
そのスニペットから、要求に対して
JsonObject
@Body
を必要とするエンドポイント /data
があります。また、要求の予想応答本文にマップされる ResponseClass
もあります。ただし、クラスは簡潔にするため、ここでは省略されます。POJO に対して JSON オブジェクトをマップするには、JsonSchema2Pojo ライブラリを使用します。利用可能なエンドポイントを定義した後、次のように Retrofit クライアントを作成します。
public class RetrofitClient { static ApiService getService(){ OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); Retrofit.Builder builder = new Retrofit.Builder() .baseUrl("http://127.0.0.1:5000/") .addConverterFactory(GsonConverterFactory.create()); Retrofit retrofit = builder .client(httpClient.build()) .build(); return retrofit.create(ApiService.class); } }
Retrofit オブジェクトを構築するとき、必要な数のコンバーターを追加できます。これによってデータを解析するオプションが広がります。その後、次のように呼び出しでネットワーク要求をします。
RetrofitClient.getService().fetchData(jsonObject).enqueue(new Callback<ResponseClass>() { @Override public void onResponse(Call<ResponseClass> call, Response<ResponseClass> response) { } @Override public void onFailure(Call<ResponseClass> call, Throwable t) { } });
jsonObject
が要求パラメータを含む場合です。この要求は上記のコードスニペットで定義されたように http://127.0.0.1:5000/data
エンドポイントに対して行われます。この最後のスニペットでご覧のように、Retrofit もコールバック メソッドを提供して要求の状況を提供します。Android ライブラリ — 依存関係挿入
依存関係挿入 はオブジェクトがその依存関係を構成する必要がない場合の概念です。代わりに、依存関係は別のオブジェクトによってパスされます。この原理はクラスを実装から切り離すのに役立ちます。コードがゆったりと結合され、管理やテストが簡単になるので、エンジニアプラクティスの良い、注目に値するソフトウェアです。依存関係挿入のライブラリはたくさんありますが、Dagger2 が主力のようです。
Dagger2
Dagger2 は Java および Android 用の完全静的、コンパイル時間 依存関係挿入 のフレームワークです。これは Square が作成した以前の バージョン(Dagger1) のアップグレードで、現在は Google が管理しています。最新の Dagger バージョンには Android 用の Android 固有ヘルパーが含まれています。具体的には、新しいコードジェネレータを使用する自動生成のサブコンポーネントが含まれています。Dagger2 は非常に深く、適切に理解するには簡単な使用例以上のものが必要とされますが、とにかく見てみましょう。
DAGGER2 を使用する
いつものように、次のようにアプリモジュール
build.gradle
ファイルに依存関係を追加します。implementation 'com.google.dagger:dagger:2.14.1' annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1' // これを追加したので Android サポートライブラリを使用できます implementation 'com.google.dagger:dagger-android-support:2.14.1' annotationProcessor 'com.google.dagger:dagger-android-processor:2.14.1'
その後、アクティビティ ビルダー モジュールクラスを作成して Dagger が依存関係を必要とするそのアクティビティのサブコンポーネントを作成できるようにします。
@Module public abstract class ActivityBindingModule { @ContributesAndroidInjector() abstract MainActivity mainActivity(); }
任意ですが、アクティビティへの特定の依存関係でモジュールクラスを作成できます。それから、例えば次のように、そのモジュールを
@ContributesAndroidInjector
注釈のコンストラクターに追加します。@ContributesAndroidInjector(modules = {MainActivityModule.class} ) abstract MainActivity mainActivity();
また、1 つのアクティビティクラス以上に使用する依存関係を提供するためにモジュールクラスをもうひとつ作成できます。
Module
クラスを @Module
で注釈して、オブジェクトを提供する担当にします。オブジェクトは提供されているものと同じ戻り値の型があるメソッド(通常 @Provides
または @Binds
の注釈付き)を作成して提供されます。以下のサンプルのモジュールクラスはアプリに String
を提供します。@Module public abstract class AppModule { @Provides static String providesString(){ return "I love Auth0"; } }
@Module
を配置したら、抽象クラスまたはインターフェイスを作成します。この場合 AppComponent
と名付けます。AppComponent
には @Component
の注釈付けをします。注釈はサポートライブラリからの AndroidSupportInjection
クラスを含む、上記で作成したモジュールクラスに入れます。Dagger はクラスを生成してから、このインターフェイスを実装します。このクラスはパスしたモジュールから挿入されたインスタンスを提供します。この Component
インターフェイスは次のように表示されます。@Singleton @Component(modules = {AndroidSupportInjectionModule.class, AppModule.class, ActivityBindingModule.class}) public interface AppComponent extends AndroidInjector<AppController> { @Override void inject(App instance); @Component.Builder interface Builder { @BindsInstance Builder application(Application application); AppComponent build(); } }
AppController
はアプリのアプリケーションクラスで、オブジェクトはアプリのライフサイクルで初期化されます。AppController
は次のように表示されます。public class App extends Application implements HasActivityInjector { @Inject DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector; @Override public void onCreate() { super.onCreate(); DaggerAppComponent.builder().application(this) .build().inject(this); } @Override public DispatchingAndroidInjector<Activity> activityInjector() { return activityDispatchingAndroidInjector; } }
DispatchingAndroidInjector<Activity>
のインスタンスを作成し、実装されたメソッドに返します。これは、アクティビティにメンバー挿入するためです。それから Component
を構築し、Application
クラスにそれを挿入します。最後に、依存関係を使用するつもりのアクティビティで、
HasSupportFragmentInjector
を実装し、次のように @Inject
注釈を使って依存関係にアクセスします。public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector { @Inject DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector; @Inject String string; @Override protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); Log.d("TAG",string); } @Override public AndroidInjector<Fragment> supportFragmentInjector() { return fragmentDispatchingAndroidInjector; } }
App
クラスで同じようなことをしましたが、唯一の違いはここでは HasSupportFragmentInjector
を実装しているので DispatchingAndroidInjector<T>
には Fragment
があります。この論理は、Application
には Activities
が含まれ、これらは Fragments
を囲むということです。この後、AndroidInjection.inject(this)
を onCreate
メソッドに呼び出します。この簡単な例を使ってこのアプリを実行している方には、
I love Auth0
がログに書き出されます。依存関係をクラスで初期化する代わりに、挿入できました。これが Dagger2 が提供する機能の一部です。詳細については、次の 2 つの記事を参照してください。Android ライブラリ — ビューバインディング
ビューバインディング ライブラリはビューを変数に割り当て、アクティビティクラスのそれらにアクセスする場合、定型句コードを減らす必要があるときに出現します。このエリアのライブラリは限られています。基本的に、重要な点はButterKnife と Android データ バインディングの 2 つです。
Butterknife
ButterKnife は Jake Wharton が開発したビューバインディング ライブラリです。Butterknife は
ids
をビューに割り当てるときに役立つライブラリで、過剰 findViewById
を避けます。ドキュメントの「シャープさが無限に少ないだけで Butterknife は Dagger のよう」によると、ビューバインディングは依存関係挿入の形態として見ることができる、ということです。ButterKnife では、注釈は代わりに定型句コードを生成するために使用されます。Butterknife を使用する
Butterknife を使用するには、依存関係をアプリモジュール
build.gradle
ファイルに次のように追加する必要があります。implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
それから、アクティビティで、
@BindView
注釈を使って次のように id
をそのビューに割り当てます。class MainActivity extends AppCompatActivity { @BindView(R.id.firstname) EditText firstName; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); ButterKnife.bind(this); // TODO ... } }
上記のコード スニペットでは、
bind
メソッドを使って onCreate
メソッドの ButterKnife を初期化したことに注意してください。代わりに、ButterKnife
を Fragment
に使用したければ、次のように onCreateView メソッドでそれを初期化します。View view = inflater.inflate(R.layout.sample_fragment, container, false); ButterKnife.bind(this,view);
ButterKnife を使って
OnClickListeners
の作成を避けます。例えば、@OnClick
注釈とビューを一緒に使って、次のようにクリックリスナーをビューに追加します。@OnClick(R.id.button) void buttonClicked() { // TODO ... }
ButterKnife についてのドキュメントは こちらから アクセスしてそのライブラリの機能について学ぶことができます。
Android データバインディング ライブラリ
Android データバインディング ライブラリ は Android Support Library に内蔵されています。Android Studio のバージョン
1.3
以降が必要です。ButterKnife とは異なりこのライブラリは注釈を使用しません。データバインディング ライブラリを使用する
アプリモジュール
build.gradle
ファイルで次のようにデータバインディングと同期化が可能になります。android { .... dataBinding { enabled = true } }
その後、レイアウトファイルのルートタグを次のように
layout
に設定します。<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </android.support.constraint.ConstraintLayout> </layout>
それから、アクティビティ バインディング クラスがレイアウトの名前
activity.main.xml
を基に生成されます(ActivityMainBinding
)。このクラスのインスタンスを使ってビューにアクセスします。他のユーティリティを処理するために生成された別のクラス DataBindingUtil
もあります。それから、アクティビティクラスでは次のようになります。
public class MainActivity extends AppCompatActivity { ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.textview.setText("Hello world!"); } }
Android データバインディング ライブラリはその他たくさんの機能と共に、
onClick
リスナーの置換を提供します。これら機能については公式 ドキュメント をご覧ください。ButterKnife と Android Databinding Library の 2 つのライブラリはビューにアクセスするために書くコードの量を大きく減らします。しかし、Android DataBinding ライブラリは ButterKnife と比較したとき、より簡単な設定、少ないコードで結果達成、より多くの機能などを提供するため、勝ち目があるようです。
Android ライブラリ — リアクティブプログラミング
リアクティブプログラミングは、データがコンポーネント(ソース)から別のコンポーネント(サブスクライバー)に生成されるパラダイムです。これによって非同期のタスクを効果的に処理できます。よって、リアクティブプログラミング ライブラリはデータをソースからサブスクライバーにパスするのに役立つライブラリです。Android 開発者にとって最も人気の高い代替オプションは RxJava2 と RxAndroid です。よって、これらを見ていきましょう。
RxJava2 & RxAndroid
RxJava はリアクティブプログラミング を実装させるライブラリですから、リアクティブアプリケーションを作ります。RxJava2 は RxJava の旧バージョンのアップデートです。RxJava2 には Observables、Observers、Schedulers があります。
Observables
はデータソースで、Observer
、Single
、Flowable
、Maybe
、Completable
のさまざまなタイプがあります。これら各タイプには固有の使用ケースがあり、その詳細については こちら をご覧ください。特に
Flowable
には バックプレッシャ サポートが付いています。バックプレッシャは Observer
が Observable
にシグナルを送るとき、後者が値を早く発行し過ぎることです。Observers
はデータレシーバー(またはコンシューマ)で、Schedulers
はスレッドの管理に役立ちます。一方、RxAndroid は RxJava2 の拡張子です。メインスレッドでスケジュールする
Scheduler
のプロビジョニングまたは指定された Looper
のような Android プラットフォームに特有の機能を提供します。RXANDROID を使用する
RxAndroid を使用するには、次のようにアプリモジューラ
build.gradle
ファイルに依存関係を追加する必要があります。compile 'io.reactivex.rxjava2:rxandroid:2.0.1' // RxAndroid リリースはとてもまれなので、バグ修正と最新機能には // RxJava の最新バージョンに明示的に依存することを推奨します。 compile 'io.reactivex.rxjava2:rxjava:2.1.7'
それから、
CompositeDisposable
のインスタンスをクラスに作成します。CompositeDisposable
は次のように複数の破棄可能を保留できるコンテナーです。disposables.add( Observable.just("Hello world!") // バックグラウンドスレッドで実行します .subscribeOn(Schedulers.io()) // メインスレッドで通知を受けます .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableObserver<String>() { @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(String value) { } }) );
上記のコードスニペットでは、
disposables
変数に追加したものは 1 つの文字列を発行するデータソース、プロセスが行われるスレッド、オブザーバーが結果の通知を受けるスレッド、サブスクライバー/オブザーバーで成ります。DisposableObserver<String>
はオブザーバーで、実装する 3 つのメソッドを提供します。ひとつめはデータが発行されたときに呼び出される onNext
、ふたつめはエラーが発生したことを示す onError、みっつめは Observable
がデータ発行を終了し、これ以上 onNext
を呼び出さないことを示す onCompleted
です。それから、アクティビティがバックグラウンドにあるときに、次のようにリソースを消去してメモリリークを避けます。
@Override protected void onPause() { super.onPause(); disposables.clear(); }
基本的ですが、興味深い Mindorks によるチュートリアルがありますので、RxJava2 についての詳細は こちら をご覧ください。
Android ライブラリ — テストする
ソフトウェアのテストは単に、バグを見つける目的で行われます。テストは長い間にわたって進化し、ソフトウェア開発プロセスの最終段階のひとつをとっても、はるかに超えるものです。実際、テストは最初に書き込みが行われる場合はコーディング段階の初期で採用され、それからソフトウェアの論理が実装されてテストが予期することのみをパスします。これは通常、テスト駆動開発 として参照されます。アプリケーションのテストを書き込むことはバグを素早く見つけたりアプリケーションの強化に役立つので良いプラクティスです。さまざまな長所のテストライブラリがたくさんあり、Android 開発で使用できます。そのうちの 4 つ、JUnit、Mockito、Robolectric、Espresso を見てみましょう。
JUnit
JUnit は単体テストに使用するフレームワークです。単体テストはテストのタイプで、ソースコードの個々の単体がテストされます。このフレームワークには
assert
メソッドのセットが含まれ、実際の結果に対して期待される結果をチェックします。JUnit は注釈を多用します。その例を少し挙げると、@Test
(テストメソッドを識別する)、 @Before
(テストが呼び出される前に呼び出されるべきメソッドを宣言する)、@After
(テストの後に呼び出されるべきメソッドを宣言する)があります。JUNIT を使用する
まず、次のようにアプリモジュール
build.gradle
ファイルに依存関係を追加します。testImplementation 'junit:junit:4.12'
それから、サンプルのテストクラスは次のように表示されます。
public class ExampleUnitTest { @Test public void additionIsCorrect() throws Exception { assertEquals(4, 2 + 2); } }
ここでは、2 と 2 を足すと 4 になることを確認します。JUnit テストは通常、JVM で実行し、デバイスやエミュレーターを必要としないので、 早くできます。JUnit テストの詳細については こちら をご覧ください。
Mockito
ほとんどの場合、テストを書き込むクラスは他のクラスに依存します。この目的だけのためにこれらクラスを構成するのは荒ただしい作業になります。このような場合に Mockito を使用します。これはモッキングフレームワークで、モック(フェイク)オブジェクトを作成・構成するのに役立ちます。通常、JUnit と一緒に使用します。
Mockito を使用する
まず、JCenter レポジトリ、
jcenter()
がプロジェクト build.gradle
ファイルにあるかを確認します。次に、その依存関係をアプリモジュール build.gradle
ファイルに追加して次のように同期します。testCompile 'junit:junit:4.12' // 単体テストの ために Mockito を使用したい ならば 必須です testCompile 'org.mockito:mockito-core:2.13.0' // Android テストの ために Mockito を使用したい ならば 必須です androidTestCompile 'org.mockito:mockito-android:2.13.0'
それから、次のように Mockito を使用します。
@Test public void mockitoTest throws Exception { List mockedList = mock(List.class); // モックオブジェクトを使用すること mockedList.add("one"); mockedList.clear(); // 検証 verify(mockedList).add("one"); verify(mockedList).clear(); }
ここで、リストをモックし、それにデータを追加し、それを消去します。それから、これらアクションが実施されたことを検証します。Mockito を使ったテストについての詳細は、公式 ドキュメント をご覧ください。
Robolectric
Robolectric はもうひとつの単体テストライブラリです。JUnit との違いは、この Robolectric は Android 開発者に役立つように作られたことです。Robolectric はビューのインフレ、リソース読み込みなどその他多数を処理します。これにより、テストは Espresso などでデバイスを起動せずに、Android フレームワーク依存関係がある実際のデバイスでできるほとんどのことができます。ある意味、Robolectric はテストのために Android SDK をシュミレートします。Robolectric では、Mockito のような追加のモッキングフレームワークが必要ありません。
ROBOLECTRIC を使用する
Robolectric を使用するには、次のようにアプリ
build.gradle
ファイルに依存関係を追加します。testCompile "org.robolectric:robolectric:3.6.1"
それから、次のようにサンプルのテストクラスを作成します。
@RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class) public class MyActivityTest { @Test public void checkActivityNotNull() throws Exception { Activity activity = Robolectric.setupActivity(MyActivity.class); assertNotNull( activity ); } }
これは非常に基本的なテストで、アクティビティをセットアップし、Null でないことをチェックします。Robolectric を使ったテストについての詳細は こちら からご覧ください。
Espresso
Espresso はテストフレームワークで、Android Testing Support Library の一部です。このテストフレームワークで、Android アプリ用のユーザーインターフェイス テストを作成できます。つまり、Espresso で
TextView
のテキストが別のテキストに一致するかをチェックできるテストを書くことができます。Espresso テストは実際のデバイスとエミュレーターの両方で実行でき、まるで実際のユーザーがアプリを使っているかのように動作します。ESPRESSO を使用する
まず、次のようにアプリモジュール
build.gradle
ファイルにこれら依存関係を追加します。androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.1' androidTestCompile 'com.android.support.test:runner:1.0.1'
それから、同じ
gradle
ファイルに、インストルメンテーションランナーを設定します。その後に、次のような Gradle ファイルの同期化を忘れないようにしましょう。defaultConfig { applicationId "com.my.awesome.app" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" }
それから、次のようなテストファイルを(例:
EspressoSampleTest
)を作成できます。@RunWith(AndroidJUnit4.class) public class EspressoSampleTest { @Rule public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class); @Test public void isHelloWorldDisplayed() { onView(withText("Hello world!")) .check(matches(isDisplayed())); } }
このテストクラスは
MainActivity
が開いたときに「世界の皆さん、こんにちは」のメッセージが表示されるかを確認します。さまざまなテストライブラリの調査から、JUnit はその他のライブラリと共に作動するので、何とも競合しないと推測されます。Espresso はユーザーインターフェイス テストに良いプラットフォームを提供します。Mockito と Robolectric の両方には同じような機能がありますが、Robolectric は少ないコードでテストを達成します。Robolectric はビューをテストするなど、多くの機能も提供します。Robolectric には Google エンジニアのサポートがあるという有利な点もあります。
Android ライブラリ — データベースヘルパー
オフラインデータの永続性はユーザーエクスペリエンスを高めるのに非常に重要です。通常、アプリを次回起動するのに必要な重要情報を保存するアプリケーション、またはインターネット接続が使えないときにデータを使えるようにするアプリケーションが必要です。データを保存することはキーと値を組み合わせるよりももっと複雑ですから、このタスクを Android に簡単に保存するために多数のライブラリが作成されました。本章では、Room のような素晴らしい永続化ライブラリを見て行きます。
Room
Room は永続化ライブラリで、Android Architecture Components の一部です。Room は最小の定型句コードに一貫するローカルデータを提供します。SQLite 上に抽象化レイヤーを提供するので、アプリのデータベースと取り組むのが簡単になります。このライブラリにはコンパイル時間で SQL クエリの検証、メインスレッド上のデータベースクエリの拒否(データベースの初期化中に明示しているときは除く)、実装ベストプラクティスの提示などたくさんの長所があります。
Room はデータベース、DAO (Data Access Object)、エンティティの 3 つのメインコンポーネントでできています。それぞれはライブラリを機能させるために相関性があります。
Entity
クラスはデータベーステーブルを表し、@Entity
の注釈が必要です。クラスの変数はテーブルにある列を表します。DAO はデータベースにアクセスするために使用するメソッドを含むインターフェイスです。Room はインターフェイスを使用し、次のようにユーザーのための実装クラスを生成します。基本的な DAO 操作に固有の注釈には@Insert、
@Update
、@Delete
、@Query
の 4 つがあります。それから、データベースクラスがあります。これは @Database
の注釈が付いた抽象クラスで、RoomDatabase
を拡張します。このクラスは使用するエンティティと DAO のリストを定義します。ROOM を使用する
Room を使用するには、まず Google Maven レポジトリをプロジェクト
build.gradle
ファイルに追加します。前回の Android プロジェクトは次で事前に構成されています。allprojects { repositories { // ... その他リポジトリ google() } }
それから、Room 依存関係を次のようにアプリモジュール
build.gradle
ファイルに追加します。implementation "android.arch.persistence.room:runtime:1.0.0" annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
次に、
Entity
クラスを作成します。いつものように、かなりシンプルなものを使います。そして、id
と name
の 2 つの列があります。id
列は主キーで、追加した全ての行が固有になるように自動生成されます。@Entity(tableName = Person.TABLE_NAME) public class Person { public static final String TABLE_NAME = "person"; String name; @PrimaryKey(autoGenerate = true) public int id; }
テーブルはずっと小文字で名付けることがベストプラクティスです。Java クラスに名付けるときとは同じ慣習ではないので、テーブルにはカスタム名を使用できます。通常、Room はテーブル名としてクラス名を使用します。その後、DAO を作成します。DAO はデータベース自体にインターフェイスを提供し、データのクエリと保存を処理します。次に、次のようにデータベース操作に使用するメソッドを含む DAO を作成します。
@Dao public interface PersonDao { // データベースに個人を追加します @Insert void insert(Person person); // データベースから個人を削除します @Delete void delete(Person person); // データベースの個人全てを取得します @Query("SELECT * FROM "+Person.TABLE_NAME) List<Person> getAllPeople(); }
インターフェイスはさまざまなメソッドに配置された注釈で一目瞭然です。その後、データベースクラスを作成します。これは、次のようにデータベースを管理し、インスタンスを DAO に提供することが担当の抽象クラスです。
@Database(entities = {Person.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract PersonDao getPersonDao(); }
これらクラスを配置したら、データベースのインスタンスを取得し、クエリを作り始めます。アプリのライフサイクルでデータベースのインスタンスを 1 つだけ作ることが推奨されています。これを次のように
Application
クラスでできます。public class App extends Application { private static AppDatabase appDatabase; @Override public void onCreate() { super.onCreate(); // アプリのライフサイクルで db を一度初期化します appDatabase = Room.databaseBuilder( getApplicationContext(), AppDatabase.class, "person.db" ).build(); } public static AppDatabase provideDb(){ return appDatabase; } }
それから、データベースインスタンスにアクセスして、データをデータベースに挿入します。これは次のように DAO クラスの
insert
メソッドを呼び出して実行します。Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { // データベースに挿入します Person person = new Person(); person.name= "Idorenyin Obong" App.provideDb().getPersonDao().insert(person); } });
ここで、
Person
のインスタンスを作成し、データベースに挿入しました。前述したように、id
は自動的に作成されるので、名前だけを割り当てました。バックグラウンドでクエリを実行する新しいスレッドを作成したことにもご注意ください。データベースでその他の演算操作を実施する上記のパターンを同様に採用します。Google は、ユーザーがこのライブラリで始めることができるように ナイスチュートリアル を提供しています。
Android ライブラリ - カスタムフォント
ほとんど全ての Android 開発者はアプリの外観に一生懸命です。ときには、アプリが全デバイスに同じ感覚を与えることができるように、固有のフォントを選ぶために一層の努力を要することがあります。このような状況で、アプリの全てのテキストにカスタムフォントを使うことができるライブラリがあります。
Calligraphy
Calligraphy は最も人気が高いカスタムフォント ライブラリのひとつで、使い方はとても簡単です。このライブラリで、アプリケーション全体で同じフォントを使ったり個々のテキストにフォントを定めたり簡単にできます。
Calligraphy を使用する
いつものように、次のようにアプリモジュール
build.gradle
ファイルに依存関係を追加し、それを同期化します。implementation 'uk.co.chrisjenx:calligraphy:2.3.0'
それから、
assets
フォルダを作成し、そこにカスタムフォントを挿入します。Android Studio のプロジェクトディレクトリにあるアプリケーションのルート フォルダを右クリックし、[New]、[Folder] を選択し、それから [Assets Folder] を選択します。これで、アセットフォルダが生成されます。その後、そのライブラリを初期化し、次のように Application
クラスに既定のフォントを設定します。public class App extends Application { @Override public void onCreate() { super.onCreate(); CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() .setDefaultFontPath("red-velvet.ttf") .setFontAttrId(R.attr.fontPath) .build() ); } }
最後に、次のように各アクティビティの
attachBaseContext
メソッドを上書きします。@Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); }
これで完成です!これで、Red Velvet フォントがこのアプリの既定のフォントになりました。次のように単一のテキストに特定のフォントを適用することもできます。
<TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" fontPath="fonts/red-velvet.ttf"/>
カスタムフォントとサポートライブラリ
Android Support Library のお陰で、バージョン
26
以上からアプリの依存関係を増やさずにカスタムフォントを使用できます。これはどっちみち build.gradle
ファイルで appcompat
依存関係を見つけるのでこのようになります。これは新しい Android プロジェクトを作成するときに自動的に追加されます。implementation 'com.android.support:appcompat-v7:26.1.0'
SUPPORT LIBRARY でカスタムフォントを使用する
まず、
fonts
リソースフォルダを作成します。これは res
フォルダを右クリックしてから、[New → Android リソース] ディレクトリを選択します。その後、リソースタイプとしてのフォントを選択し、[OK] を選択します。それから font
リソースディレクトリ(例 redvelvet
)に希望するフォントファイルを追加します。カスタムフォントを次のように直接 XML レイアウトに適用します。
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/redvelvet"/>
さらに、新しいフォントファミリを作成できます。フォントファミリはスタイルや太さの詳細を合わせたフォントファイルのセットです。そのフォントソースフォルダを右クリックし、[New] をクリックし、それから [New Font Resource File] をクリックして名前を挿入し、[OK] を選択します。サンプルのフォントファミリは次のようなものがあります。
<?xml version="1.0" encoding="utf-8"?> <font-family xmlns:app="http://schemas.android.com/apk/res-auto"> <font app:font="@font/redvelvet" app:fontStyle="normal" app:fontWeight="400" /> </font-family>
フォントを
XML
レイアウトに適用すると、使用されたテキストスタイルを基にシステムが正しいフォントをピックします。フォントを XML
レイアウトに適用することはさておき、それらをプログラムや複数のフォームで適用することも可能ですので、公式 ドキュメント でご覧ください。Support Library でカスタムフォントを使用することについての素晴らしいリソースは こちら をご覧ください。ジョブのスケジューリング
往々にして Android アプリケーションはユーザーのインタラクションから操作する必要があることがあります。このために、アプリのパフォーマンスとデバイスを全般に最適化するためにタスクを非同期、かつインテリジェントに処理する必要があります。これで、バックグラウンドで処理するタスクが均等に呼び出されます。
Android にはバックグラウンドタスクをスケジューリングする独自の API、JobScheduler があり、API 21 (Android 5.0) 以降をサポートするときのみ使用できるという短所があります。
このカテゴリの 2 つの共通オプションは Evernote による Android ジョブライブラリ と Firebase による Firebase Jobdispatcher があります。
Firebase Jobdispatcher には Google Play 開発者サービスが必要というもうひとつの代償がありますが、ずっと前の API 9 (Android 2.3) まで互換性があります。Android ジョブは Android の JobScheduler と Firebase Jobdispatcher の取り組みを結合して安定したジョブスケジューリングライブラリを提供します。広く普及されているのも不思議ではありません。
Android ジョブ
Android ジョブ はバックグラウンドでジョブを処理するために使用する Android ライブラリです。Android のバージョンによって
JobScheduler
、GcmNetworkManager
、または larmManager
のどれかが使用されます。これが、このライブラリが人々の心を引き付ける理由です。ひとつのコードベース内で別の API を使って、使用するスケジューリング API を知るために API バージョンを確認する代わりに、Android ジョブはコードサイズの他にストレスも減らして実行してくれます。このライブラリは API 14 (Android 4.0) 以降が必要です。Android ジョブを使用する
Android ジョブを使用するには、次のようにアプリモジュール
build.gradle
ファイルに依存関係を追加し、それを同期化します。compile 'com.evernote:android-job:1.2.1'
それから、次のように
Application
クラスの JobManager
を初期化します。public class App extends Application { @Override public void onCreate() { super.onCreate(); JobManager.create(this).addJobCreator(new SampleJobCreator()); } }
この
Application
クラスはアプリケーションサイクルでオブジェクトを一度だけ初期化するために使用されます。SampleJobCreator
はジョブの一意タグを基にした Job
のインスタンスを返すクラスです。SampleJobCreator
は次のように表示されます。public class SampleJobCreator implements JobCreator { @Override @Nullable public Job create(@NonNull String tag) { switch (tag) { case FirstJob.TAG: return new FirstJob(); default: return null; } } }
最後に、
FirstJob
と名付けられた Job
クラスは次のように表示されます。public class FirstJob extends Job { public static final String TAG = "first_job_tag"; @Override @NonNull protected Result onRunJob(@NonNull Params params) { // ここでジョブを実行します return Result.SUCCESS; } public static void scheduleJob(long timeJobShouldStart) { new JobRequest.Builder(ReviewStayJob.TAG) .setExact(timeJobShouldStart) .build() .schedule(); } }
上記のコードスニペットでは、
onRunJob
メソッドで何をするかを Job
に伝えました。それから、FirstJob.scheduleJob(timeinMills)
(timeInMillis
がデータ型 long
の場合)を呼び出してジョブをスケジュールします。GitHub repo はデバイスが充電しているときにジョブを実行するように伝えるなど、もっと複雑なスケジューリングのオプションを提供します。“Android ライブラリに関する素晴らしい記事を読みました。”
これをツイートする
補足:Android アプリを Auth0 でセキュアにする
アプリケーションを Auth0 でセキュアにすることは非常に簡単で、たくさんの素晴らしい機能を提供します。Auth0 を使うと、数行のコード行を書くだけで、強固なID 管理ソリューション、シングル サインオン、ソーシャル ID プロバイダー(Facebook、GitHub、Twitter など)のサポート、およびエンタープライズ ID プロバイダー(Active Directory、LDAP、SAML、カスタムなど)のサポートを得ることができます。
以下のセクションでは、Android アプリをセキュアにする Auth0 を使用する方法を学んでいきます。ご覧のように、そのプロセスはシンプルで素早くできます。
依存関係
Android アプリを Auth0 でセキュアにするには、Auth0.Android ライブラリをインポートするだけです。このライブラリはツールキットで、基本的な多数の Auth0 API 機能と素晴らしい方法で通信することができます。
このライブラリをインポートするには、
build.gradle
ファイルに次の依存関係を含みます。dependencies { compile 'com.auth0.android:auth0:1.12.0' }
その後、アプリの
AndroidManifest.xml
ファイルを開き、次のアクセス許可を追加します。<uses-permission android:name="android.permission.INTERNET" />
クライアントを作成する
ライブラリをインポートしてアクセス許可を追加した後、新しいクライアントアプリケーションを Auth0 ダッシュボードに作成します。ところで、Auth0 アカウントをお持ちでない方は、無料アカウントを作成する でアカウントを作成されることをお勧めします。
Auth0 ダッシュボードで、クライアント に移動し、クライアントを作成する ボタンをクリックします。表示のフォームで、クライアントの名前を定義し、その ネイティブ タイプを選択します。その後、作成 ボタンを押します。これで、次のようなスクリーンが表示されます。
このスクリーンで、コールバック URL を構成します。これは、Auth0 がユーザーを認証した後にリダイレクトするアプリケーションの URL です。
クライアント 設定 ページの 許可されたコールバック URL フィールドにあるアプリのコールバック URL をホワイトリストします。コールバック URL を設定しなければ、ユーザーがログインしたときに不一致のエラーが表示されます。
demo://bkrebs.auth0.com/android/OUR_APP_PACKAGE_NAME/callback
OURAPPPACKAGE_NAME とアプリケーションのパッケージ名を置換することを忘れないようにしましょう。この名前は
app/build.gradle
ファイルの applicationId
属性にあります。資格情報を設定する
アプリケーションは Auth0 と通信するために、クライアントの詳細情報が必要です。この詳細情報は Auth0 ダッシュボード にあるクライアントの 設定 セクションにあります。
次の情報が必要です。
- クライアント ID
- ドメイン
これらの値は将来、変更する必要があるかもしれないので、ハードコードしないことをお勧めします。代わりに、値を定義するときは
@string/com_auth0_domain
のような文字列リソースを使いましょう。res/values/strings.xml
ファイルを次のように編集しましょう。<resources> <string name="com_auth0_client_id">2qu4Cxt4h2x9In7Cj0s7Zg5FxhKpjooK</string> <string name="com_auth0_domain">bkrebs.auth0.com</string> </resources>
これらの値はクライアントの 設定 セクションにある値と置換します。
Android ログイン
ログイン機能をアプリに実装するには、SDK が必要とするマニフェスト プレースホルダーを追加します。これらプレースホルダーは前に構成された認証コールバック URL をキャプチャする
intent-filter
を定義するために内部で使用します。マニフェスト プレースホルダーを追加するには、次の行を追加しましょう。
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.3" defaultConfig { applicationId "com.auth0.samples" minSdkVersion 15 targetSdkVersion 25 //... //---> Add the next line manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "demo"] //<--- } }
その後、Android Studio 内で Gradle ファイルでプロジェクトを同期する を実行するか、コマンドラインから ./gradlew clean assembleDebug を実行します。
認証プロセスを開始する
Auth0 ログインページ は認証をアプリケーションに設定する最も簡単な方法です。最高のエクスペリエンス、最高のセキュリティ、完全な機能配列を得るには Auth0 ログインページをご使用されることをお勧めします。
では、認証プロセスを始めるためにメッソドを実装します。このメソッド
login
を呼び出し、それを MainActivity
クラスに追加しましょう。private void login() { Auth0 auth0 = new Auth0(this); auth0.setOIDCConformant(true); WebAuthProvider.init(auth0) .withScheme("demo") .withAudience(String.format("https://%s/userinfo", getString(R.string.com_auth0_domain))) .start(MainActivity.this, new AuthCallback() { @Override public void onFailure(@NonNull Dialog dialog) { // エラー ダイアログをユーザーに表示します } @Override public void onFailure(AuthenticationException exception) { // エラーをユーザーに表示します } @Override public void onSuccess(@NonNull Credentials credentials) { // 資格情報を保存します // メインアクティビティに移動します } }); }
ご覧のように、ユーザーの資格情報を保留するために Auth0 クラスの新しいインスタンスを作成しました。次の文字列リソースを追加したら、Android Context を受信するコンストラクターを使用できます。
string.com_auth0_client_id
string.com_auth0_domain
リソースのハードコードを希望する場合は、両方の文字列を受信するコンストラクターを使用できます。それから、Auth0 ダッシュボード のクライアントで有効にした接続で認証する
WebAuthProvider
クラスを使用します。WebAuthProvider#start
機能を呼び出したら、ブラウザーを起動して Auth0 ログインページを表示します。ユーザー認証が終了したら、コールバック URL が呼び出されます。コールバック URL には認証プロセスの最終結果が含まれています。結果をキャプチャする
認証の後、ブラウザーは認証結果と共にユーザーをアプリケーションにリダイレクトします。SDK はその結果をキャプチャして、分析します。
Auth0 ドメインとスキーム値でマニフェスト プレースホルダーを定義しましたので、アクティビティに固有の
intent-filter
を宣言する必要はありません。AndroidManifest.xml
ファイルは次のように表示されます。<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.auth0.samples"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name="com.auth0.samples.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
これだけです。これで、Auth0 で Android アプリケーションをセキュアにしました。これら詳細については、公式ドキュメント を参照してください。ここで セッションの処理方法 や ユーザープロファイルのフェッチ などのトピックを学ぶことができます。
まとめ
Android を開発しながら、ライブラリが、さまざまな機能を実行するために書かれた定型句コードの量をどのようにして大きく減らすかを学んできました。また、これらライブラリをほとんどのケースで使用する方法についても学びました。利用可能なライブラリの中で最高のライブラリについて知ることは、アプリの品質改善に役立ち、少ない時間で多くを作成できます。ですから、これらライブラリについて知り、使用することは有利な状況につながることは間違いありません。
About the author
Idorenyin Obong
Software Engineer at Busha