support libraryのバージョンの調べ方

app/build.gradleのdependenciesにさり気なく書いてあるサポートライブラリ。 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.1' } appcompat-v7:22.2.1のこの22.2.1の部分。自分で指定しようと思うと、バージョンいくつが存在しているのかが分からず、どうやって確認すればいいのかも分かりません。とりあえず最新のものが当たればいいやと、+を使ってごまかしたりしてきましたが、最新のものが当たるとそれはそれでうまくいかないことがあったりします(23が出てるんだけど、とりあえずはtargetSDKを22で作ってる今とか)。 要するに、1つ前のバージョンを指定したいのだけど、その1つ前のバージョンというのはいったいいくつなんだというのが困ります。結論から言うと22.2.1なんですけど、じゃあそれをどうやって調べたらいいのかという話です。 Support Library – Android Developersで確認できます。 また、パソコンにインストールしているAndroid SDKのディレクトリを潜って行くことでも調べることはできます。 (Android SDKのインストールディレクトリ)/extras/android/m2repository/com/android/support/appcompat-v7 このディレクトリに、バージョンごとのフォルダがあるのでそこでも確認可能です。 そもそも指定できるバージョンの候補を出してくれると楽なんですけどね。

EventBusを使ってAsyncTaskLoaderでProgressを通知する

greenrobot/EventBus – GitHubを使ってみました。 異なるスレッドからのイベントの通知でもうまくハンドリングしてくれるので、AsyncTaskLoaderでProgressを通知するのにも利用できます。 Broadcastを使って実装するのと比較するとコードがシンプルになって良いです。IntentFilterやIntentにデータを埋め込む際に使うキー文字列を定義したりしなくて済みます。 更に独自のオブジェクトをイベントとして渡すこともできるので、Broadcastでは難しいイベントの通知も簡単に出来ます。 準備 /app/build.gradleのdependenciesにcompile 'de.greenrobot:eventbus:2.4.0'と、1行追加するだけで使えます。 イベントの送信 イベントを送信したいところで、EventBus.getDefault().post("イベント発生");とするだけです。 これは単にStringオブジェクトを渡しているだけですが、独自オブジェクトを定義して渡すことも可能です。 イベントの受信 イベントの購読・解除 Activityでイベントを受信するなら、onResume()でEventBus.getDefault().register(this);とすることでイベントの購読を行います。 この際、onPause()でEventBus.getDefault().unregister(this);で購読解除を忘れないように。 イベントのハンドリング AsyncTaskLoaderからのイベントを受信してUIを更新するなら、onEventMainThread()をActivityに実装します。 public void onEventMainThread(String event){ mTextView.setText(event); } 送信するイベントのオブジェクトごとにこのメソッドを用意してやる必要があります。例えば他にMyEventという独自オブジェクトがある場合、別途public void onEventMainThread(MyEvent event){}を実装してやります。 メソッドをオーバーライドするわけではないので、コード補完は効きません。タイポするとこんな例外が起きてアプリが落ちます。 java.lang.RuntimeException: Unable to start activity ComponentInfo{jp.gcreate.sample.asynctaskloadersample/jp.gcreate.sample.asynctaskloadersample.MainActivity}: de.greenrobot.event.EventBusException: Illegal onEvent method, check for typos: public void jp.gcreate.sample.asynctaskloadersample.MainActivity.onEventBackgroundThrad(jp.gcreate.sample.asynctaskloadersample.MyEvent) まとめ AsyncTaskLoaderのProgressの通知で使ってみましたが、とても便利だなと思いました。 内部的にはHandlerを使ってイベントのハンドリングを行っているみたいでした。Handlerの具体的な使用例としていい勉強にもなって、個人的には一石二鳥な感じです。ありがたや〜。 便利な半面、無計画に使うとイベントが乱立してカオスな事になりそうなので、実際に使うときには気を付けないといけないなと思いました。

LocalBroadcastを使ってAsyncTaskLoaderでProgressの通知を実装する

AsyncTaskLoaderにはAsyncTaskのpublishProgress()のような途中経過を通知するメソッドが標準では用意されていません。 そこでブロードキャストを利用してこれを実装します。 Context#sendBroadcast()を使ってもいいのですが、これだと自分のアプリ外にもブロードキャストが送信されてしまうので、LocalBroadcastManagerを利用します。 AsyncTaskLoaderでの処理 AsyncTaskLoader側ではloadInBackground()内で、ブロードキャストの送信を行うだけです。 この際、途中経過のデータはIntentに埋め込んで送信する必要があります。 @Override public String loadInBackground(){ //非同期処理 Intent intent = new Intent(MainActivity.ACTION_PROGRESS) .putExtra("key", "hoge"); LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); } MainActivity.ACTION_PROGRESSはインテントフィルタを表す文字列です。 Activity側の実装 //インテントフィルタの定義 public static final String ACTION_PROGRESS = "jp.gcreate.sample.asynctaskloadersample.ACTION_PROGRESS"; //ブロードキャストレシーバーの作成 private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String progress = intent.getStringExtra("key"); mTextView.setText(progress); } }; @Override protected void onStart() {
super.onStart(); //ブロードキャストレシーバーの登録 LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); manager.registerReceiver(mReceiver, new IntentFilter(ACTION_PROGRESS)); } @Override protected void onStop() { super.onStop(); //ブロードキャストレシーバーの解除 LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); } ブロードキャストレシーバーを作成して、ここでAsyncTaskLoaderから送られてくるProgressを受け取りとUIの更新処理を実装します。 後はonStart()でブロードキャストレシーバーの登録、onStop()で解除を行ってやればOKです。 細かいサンプルはGitHubにおいてます。

Android StudioでJunit4によるテストを走らせる

基本的にはここに書いてあるとおりにやればいいだけの話です。 準備 /app/build.gradleのdependenciesにjunitを追加します。 testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.9.5' この際に注意が必要なのは、androidTestCompileとtestCompileは別物であるということです。 何が別物かというと、テストコードを配置するディレクトリがそれぞれ違います。 その名の通りandroidTestCompileはandroidTestディレクトリに配置したテストコードのコンパイル時にだけ使うライブラリです。同じくtestCompileはtestディレクトリに配置したテストコードのみに使われるライブラリになります。 なお、androidTestディレクトリは自動的に作成されていますが、testディレクトリは自分で作らなければなりません。(ディレクトリは/app/src/test/java/パッケージ名にしてやればOK) androidTestとtestの切り替え Build Variantsウィンドウを開くと、Test Artifactという欄があります。 Android Instrumentation Testsを選択していると、androidTestディレクトリ以下にあるテストコードが有効化されます。有効化されるというのが適切なのかは分かりませんが、Android Studioからコンパイル対象のソースコードであると認識されます。 Unit Testsに切り替えると、testディレクトリが有効化されます。試しに切り替えてみると、androidTestディレクトリの色が変わって、テストコードのアイコンに赤いJアイコンが出るようになると思います。 IDE上からテストを実行しようと思うと、このBuild Variantsをいちいち切り替えないといけないのが面倒くさいかもしれません。 しかし、ターミナルからGradleを使って実行する場合は、このTest Artifactsの切り替えはしなくてもいいみたいです。Gradleからテストを実行する場合、./gradlew connectedAndroidTestがAndroid Instrumentation Testsを、./gradlew testがUnit Testsを選択してテストを実行するのと同じになります。この場合のテスト結果は/app/build/reports/testsの中に出力されます。 テストコードはViewやActivityなどのUIに関するテストをandroidTestディレクトリに、純粋なJavaコードのテストはtestディレクトリに置くように工夫すべきでしょう。そうしてやれば、ユニットテストにかかる時間を削減できて幸せになれると思います。

Espressoを使ってUIテストを書いてみた

Android Studio 1.2でEspresso2.1を使ったUIテストをやってみました。 テストの実行に実機(エミュレータ)が必要なのが面倒くさいですが、実機無しでテストが実行できるようにする方が面倒くさい(というかやり方がわからない)ので、テストができるだけマシだと考えることにしました。 テストを実行する際に、開発者オプションでアニメーションの無効化をしておかないと、アニメーションのせいで同じテストが失敗することがあるのは注意が必要かもしれません。 しかしながら、Android Support Libraryに入っているおかげでテストを実行するまでのハードルが低いのはうれしいところです。 また、EspressoによるUIテストの書き方も非常にシンプルで分かりやすいと思います。 準備 詳しい手順はここに書いてあるとおりです。Get started – android-test-kit まずは/app/build.gradleにテストで利用するライブラリを追加します。 dependencies {
// Testing-only dependencies
androidTestCompile 'com.android.support.test:runner:0.2'
androidTestCompile 'com.android.support.test:rules:0.2'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
} /app/build.gradleにtestInstrumentationRunnerを追記します。場所はdefaultConfigの中です。 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 更に以下のおまじないも追加します。 packagingOptions { exclude 'LICENSE.txt' } 最終的な/app/build.gradle 適宜読み替えて使ってください。 apply plugin: 'com.android.application'
android {
compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "jp.gcreate.product.developersettingsshortcut"
minSdkVersion 15 targetSdkVersion 22
versionCode 1
versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions {
exclude 'LICENSE.txt' } } dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.jakewharton:butterknife:6.1.0'
// Testing-only dependencies androidTestCompile 'com.android.support.test:runner:0.2'
androidTestCompile 'com.android.support.test:rules:0.2'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1' } 一時的なバグ? Warning:Conflict with dependency 'com.
Read full post gblog_arrow_right

アプリのパフォーマンスを向上させる GPUオーバードロー

LinearLayoutをネストしすぎたりするなど、Viewの階層を深くするとアプリのパフォーマンスに良くないという話はよく聞くと思います。 それと似たような話で、画面を何回描画しているかを確認して、アプリのパフォーマンスに役立てることができきます。今回はそれの紹介です。 確認の仕方 端末の開発者オプションで「GPUオーバードローをデバッグ」を有効にします。 これを有効にすると、目に悪そうな色で画面が表示されるようになります。 この各色が、GPUによって何回上書き描画されているのかを示しています。 青色:1回 緑色:2回 薄赤:3回 濃赤:4回以上 この状態で画面が真っ赤っ赤だと、描画方法を改善した方がいいぞということになります。 対策 例えばFrameLayoutでbackgroundDrawableを持ったViewを何個も重ねていくと、見えているのは一番上のものだけなのに、見えない下の要素まで描画するため上書き回数が増えて赤色になってしまいます。 そのため不要なbackgroundDrawableを描画しないようにすることが、この問題の対策になります。 例えばActivityでgetWindow().setBackgroundDrawable(null)とするだけでも画面の赤色が薄くなると思います。(ただし、これをやるとListViewやGridViewなど、スクロールをともなうViewの描画がおかしくなります) 重ねて描画せざるをえない場合は、canvas.clipRectを使って重なって見えない部分を描画しないようにすることで対応できるようです。 効果 ムダな描画回数を減らすことにつながるので、その分アプリの動きが軽快になるでしょう。 さらにバッテリーにも優しくなると思います。 ただし、アプリのもっさり感解消のための施策としては、優先度は低いのかなと思います。ちまたに出ているアプリでも、割と真っ赤なアプリが多いですし、赤くとも動作がもっさりしているものは少ない印象です。 やらないよりやった方がマシでしょうが、ここを気にするより、メモリの使用量を抑えるといったチューニングの方が、アプリのパフォーマンスにとって効果が高いような気がします。 Android Performance この話はUDACITYのAndroid Performanceという動画を見て知りました。 英語オンリーかつ字幕すらありませんが、大体雰囲気で分かるんじゃないかなと思います。 Android Performance – UDACITY

その画面がどんなViewを使って作られているか調べる方法

「このアプリのデザインを参考にしたいんだけど、どうやって作ってるのか知りたい」というときに便利かもしれないコマンドです。 調べたい画面を表示させた状態で、ターミナルからadb shell dumpsys activity topと入力すると、現在表示中のView階層などが表示されます。 View階層だけを調べたいなら、hierarchyviewerを使った方がグラフィカルに見えて便利なのですが、hierarchyviewerはroot権限がないと起動しないので、実機で調べたい画面を表示して解析することができません。 その点、このadb shell dumpsys activity topはroot権限を必要としないので、実機でちょっと調べたいという時に便利だと思います。 どこからどこまでがActionBarの領域で、どこがコンテンツの領域なのかが非常に分かりづらいのですが、Viewに割り振られているIDも一緒に表示されるのである程度把握できると思います。 このIDが表示されるのを利用して、View階層の中でIDの衝突が起こっていないかなんてことを調べるのにも便利かもしれません。 ちなみにadb shell dumpsys activityと最後のtopを省略すると、Activity Managerの情報がズラズラと表示されます。 Broad castがどうなってるかとか、Content Providerがどんなのが動いているかとか、どんなServiceが動いているかとか、スタックがどうなってるかとかが出力されます。 実機でコマンドを打つだけで調べられるので、手軽で便利だと思います。

BaseSaveStateにを拡張してカスタムViewの状態を復元する際の注意点

カスタムViewを作った場合、BaseSaveStateを拡張してViewの状態をカスタムView自身で復元できるようにできます。 この際に注意すべきことが3点あります。 Activityを保持しないを有効にしてチェックする カスタムViewの復元機能を実装したら、必ず開発者オプションのActivityを保持しないを有効にしてちゃんどう動くかどうか確認しましょう。 自分ではちゃんと実装したつもりでも、これを有効にした状態で画面回転させるとアプリが落ちる場合があります。 フィールド名のタイポに注意 BaseSaveStateを拡張したクラスには、必ずpublic static final Parcelable.Creator<BaseSaveStateを拡張したクラス名> CREATORというフィールドが必要です。 このフィールドの名前はCREATORでなければなりません。 CREATERとタイポすると動きません。動かない上にエラーメッセージはjava.lang.RuntimeException: Unable to start activity ComponentInfo{jp.gcreate.sample.savestatecustomview/jp.gcreate.sample.savestatecustomview.MainActivity2Activity}: java.lang.RuntimeException: Parcel android.os.Parcel@18c09797: Unmarshalling unknown type code 2131296303 at offset 264のように、「フィールド名が違います」と教えてくれません。 writeToParcelで書き出す順番 writeToParcelで書き出す順番とコンストラクタで読み出す順番は同じ順番にしなければなりません。 書き出す順番と読み出す順番が異なるとうまく復元することができません。 順番を同じにすることと一緒に忘れていけないのは、最初にsuperを呼び出すことです。 public ImageState(Parcel source) {
super(source);
savedUri = source.readParcelable(Uri.class.getClassLoader());
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(savedUri, flags);
}
``` コンストラクタで`super(source)`を最初に呼び出す、`writeToParcel`の最初で`super.writeToParcel(dest, flags)`を呼び出すことも忘れてはいけません。 単純なことですが、エラーメッセージからどこが悪いのか把握しづらいので、知らないとドはまりするので注意しましょう。 ## サンプル public class UriImageView extends ImageView{
private Uri mUri;
public UriImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setImage();
}
private void setImage() {
if(mUri == null){
setImageDrawable(getContext().getResources().getDrawable(android.R.drawable.btn_star, getContext().getTheme()));
}else{
setImageURI(mUri);
}
}
public void setUri(Uri uri) {
mUri = uri;
setImage();
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.
Read full post gblog_arrow_right

AsyncTaskLoaderの動きを確認中 その2

前回の続きでAsyncTaskLoaderを使ったサンプルを作って、Loaderの動きを確認していたのですが、1つの問題点にぶち当たりました。 initLoaderでLoaderを動かす分にはとてもスッキリしたのですが、restartLoaderを使うと非同期処理がイメージ通りに動きませんでした。 それは以前の非同期処理が終わらないと、restartLoaderで新しく動かす非同期処理が始まらないということです。 私が作ったサンプルでは、指定した数字までカウントアップを行う非同期処理をしています。しかし非同期処理中にrestartLoaderを呼び出すと、今動いている非同期処理が終わらないと新しい非同期処理が動いてくれないのです。 restartLoaderを呼んだら今動いている非同期処理には停止してもらい、すぐに新しい非同期処理が始まって欲しいです。使いもしない非同期処理の終了を待つのは時間の無駄ですし、使いもしない処理にリソースを割くのももったいないです。 ## ソースコードを読んで分かったこと
現在進行形で格闘しているので、まとまっていないですがこんな感じ。 onStopLoadingはActivityがonStopになったときに呼ばれる(画面回転時は除く) キャンセルの処理(restartLoader実行時)は、まずonCancelLoadが呼ばれる AsyncTaskLoader.onCancelLoadでLoaderの状態に合わせてキャンセル処理を行う 実際のキャンセル処理はcancelLoadInBackgroundメソッドで行われる しかしAsyncTaskLoader.cancelLoadInBackgroundでは何もしていない すなわち実際にloadInBackgroundの処理を止めるのは自分で実装しなければならない AsyncTaskLoader.onCancelLoadを経ていれば、loadInBackgroundの処理結果は最終的にonCanceledに通知される LoaderManagerがうまいこと管理してくれているので、restartLoader呼んだ数だけ非同期処理が乱立するわけではない(それでもいくつか並行して走るけれども) そもそもLoaderManagerは何している? LoaderManagerはrestartLoaderが呼ばれた時に何をしているのかも、同時進行で読み解いています。 LoaderManagerはLoaderをmLoadersとmInactiveLoadersという2つのリストで管理しています。 mLoadersでは現在実行中のLoaderを、mInactiveLoadersでは以前実行されていたLoaderを管理しています。mInactiveLoadersはLoaderを破棄するためのもののようです。おそらく。 restartLoaderをすると、LoaderManagerはLoaderの状態によってあれやこれやしながら新しいLoaderを作成します。現在実行中のLoaderがあればキャンセル処理を行いますが、新しいタスクはmPendingLoaderに登録します。 mPendingLoaderが何者かというと、その名が表すように次に実行される非同期処理のタスク(Loader)です。このmPendingLoaderがいつ実行されるのかというと、今実行されているタスクのloadInBackgroundが終了した時です。 そのため実行中のタスクが終わらないと、restartLoaderで作られた新しいタスクが始まらないのです。 AsyncTaskLoader上のキャンセル処理 Loaderの非同期処理が実行されているときにキャンセルがかかると、以下の場合にonCanceledが呼ばれます。 Loaderが非同期処理実行中の間に、Activity等でinitLoader().forceLoad()をしたとき Activity等でrestartLoaderを呼んだ時(非同期処理が実行中かは問わない) AsyncTaskLoader.onCancelLoad()でキャンセル関連の処理が行われているためsuper.onCancelLoad()を呼ぶ必要があります。 ただしやってるのはLoaderの管理情報の更新だけで、実行中のloadInBackgroundを止めるような処理は何もしていません。 具体的には、、現在実行中の非同期処理があるか確認(mTask != null)し、タスクがなければキャンセル対象がないので何もしません。 ある場合には、キャンセル処理中の非同期処理があるかを確認します(mCancellingTask != null)。 mCancellingTaskがある場合、onCancelLoadが呼び出されたLoaderがPendingTaskなら破棄します(mTask.waiting == true)。これは実行待ち状態のLoaderをキャンセルすることを意味しています。実行待ちのタスクはまだ開始されてないから破棄するだけでいいわけです。 mCancellingTaskがない場合は、onCancelLoadが呼び出されたLoaderがPendingTaskか確認します。上と同じことをやっていますが、mCancellingTaskがない場合、このLoaderをキャンセルされたタスクとして退避させる必要があるので条件分岐されてます。 で、PendingTaskであればLoaderをそのまま破棄します。まだ非同期処理が始まっていないのでそのまま破棄するだけでいいからです。 PendingTaskでないのであれば、このLoaderは現在稼働中の非同期処理ということになります。そこでこれをキャンセルし、mCancellingTaskへと退避します。その上でcancelLoadInBackgroundを呼び出します。 そのため、Loaderをキャンセルするための処理は、cancelLoadInBackgroundで実装すればいいことになります。 cancelLoadInBackgroundで何をすればいいか Loaderをキャンセルするための処理を実装するといっても、具体的にどう実装すればいいかというとよく分かりません。 このメソッドの中からloadInBackgroundの処理を停止させることはできないでしょう。むしろこのメソッドは、メインスレッド(Activityとか)からLoaderを停止させるためのメソッドのような気がします。 しかし直接ActivityからこのcancelLoadInBackgroundを呼ぶと、LoaderManagerの管理下から外れた動きをすることになって、変なことになりそうな気がします。 結局のところ、loadInBackgroundの中でisLoadInBackgroundCancelled(Loaderがキャンセルされたらtrueになる)をチェックして非同期処理を途中で止めるように実装するしかなさそうです。 新たな謎 今気づいたんですが、ActivityからLoaderのforceLoadを呼んだ後でrestartLoaderすると、前の非同期処理完了を待つことなくrestartLoaderした処理が走っていることに気づきました。前の処理は走ったままなので、2つの非同期処理が並列で走ってますけども。 この違いはいったいどこからやってくるのか・・・。 ちなみにサンプルはGitHubで公開中です。

重い腰をあげてLoaderを使ってみた(とりあえずinitLoaderだけ)

重い腰をあげてLoader触ってみました。 これまでもAsyncTaskはやめろ、Loader(AsyncTaskLoader)使えっていう話は知ってはいたんですが、Loader使い方よく分からんって敬遠してたんですよね。 とりあえずAsyncTaskLoaderを使ってみてわかったこと、感じたことを書いてみたいと思います。 参考にしたところ AsyncTaskLoader – Android Developers 非同期処理 – mixi-inc/AndroidTraning サンプルはGitHubに上げてます。 未だによく分かってないところもあるんですが(キャンセル処理についてはまだ手を付けていない)、とりあえず現状で分かったことを書いてまとめます。 ちなみにソースコード読んで動きを把握したいなら、サポートパッケージではなくandroid.app.LoaderManager、android.content.Loaderを使った方がいいと思います。 LoaderManagerの動きを知る getLoaderManager.initLoaderを呼ぶより前に、LoaderManager.enableDebugLogging(true);を実行すると、LoaderManagerがログを出力してくれるようになるので便利。 LoaderManagerがLoaderの状態を管理しているので、ActivityやAsyncTaskLoaderは非同期処理がどんな状態にあるのか気にしなくて済むのがいいですね。 ただしちゃんと動くようにするためには、Loder側でどういう状態の時にどのメソッドが呼び出されるのかを理解しておく必要があります。そのためにはLoaderManagerの動きを知っておかないとわけが分からないというわけです。 ついでに言うと、メソッド名から想定したイメージと実際の動きの間が、私の感覚と違っていて余計に混乱したというのもあります。 getLoaderManager().initLoader getLoaderManager(もしくはgetSupportLoaderManager).initLoaderは指定したIDのLoaderがなければLoaderを作成、既に存在していればActivityへのCallbackを設定します。 Loaderを初期化するメソッドというより、コールバックを更新するものと思った方が理解しやすい気がします。私はずっとこのメソッドでLoader作って非同期処理を開始するものだとばかり思っていて、ずっと混乱していました。 指定されたIDのLoaderがまだ存在しない場合は、ActivityのonCreateLoaderにコールバックを行い、ここでLoaderを作ります。 Loaderを作るのはActivityのお仕事です。initLoaderだけなら、onCreateLoaderが呼ばれるのはActivityがonCreateされたとき(画面回転時は除く)だけです。 Loader.onReset 名前からして再稼働させた時に呼ばれるのかと思って混乱しました。いまだによく分かっていません。 onResetが呼ばれたLoaderは再利用されることはない・・・であってると思うんですけど、自信がありません。 LoaderManagerは、LoaderのIDごとに現在動いているLoader、以前に使ってたLoaderを管理しているだけなのようです。だから以前使ったLoaderのインスタンスを再活用したりはしてないと思います。 Loaderで使ってたリソースを解放してねってタイミングのようです。 バックグラウンド処理を引き継げる とりあえずやってみて感じたのは、AsyncTaskと違ってバックグラウンドの処理を引き継げることがいいなと感じました。 AsyncTaskだと画面回転したらまた最初からやり直しになってたものが、そのままバックグラウンド処理は続いてくれるし、結果もそのまま受け取れるのが素敵。 Loader側でキャッシュ機構を持たせることで、ムダな非同期処理を防ぐことができるのもいいなと思います。 Loader側が非同期処理だけに専念できる AsyncTaskと違って呼び出し元のActivity(Fragment)が生きてるかどうかを確認しなくていいのが想像以上にやりやすいです。 AsyncTaskだとonPostExecuteで処理結果をUIに反映します。バックグラウンド処理をしている最中に画面回転が生じるとUI更新しようとするものの、対象のActivityは既にお亡くなりになっているせいでアプリが落ちてました。 LoaderではUIの更新について何1つ考える必要がないので、とてもスッキリします。 でも途中経過を伝えられない AsyncTaskLoaderには途中経過を通知するメソッドが標準で用意されていません。そのためバックグラウンド処理の途中経過を表示することができません。同じAsyncTaskがつくのに別物と 対策としてはAsyncTaskLoaderにActivityへの参照を持たせて通知するみたいなやり方がありましたけど、そんなことするとLoader使う意味が無い気がします。せっかくの非同期処理とUI処理を分離するための機構が台無しです。 LocalBroadcastで対応するっていう策も見つけましたが、こっちの方がまだましかなと思います。 しかし、いっそのことプログレス表示しないという選択肢もありなのかもしれません。データが全部で10件あって、そのうち◯件処理済みとか表示するのではなく、データ読み込み中ですよって表示するだけ。そういう方向での切り替えをした方が通知のための仕組みを実装するより安全な気がします。