AsyncTaskLoaderでプログレスバーを出してみる


2014年5月30日現在、私が理解している内容です。
間違っている場合があります。


AsyncTaskLoaderを使ってみる。


AsyncTaskLoaderは、AsyncTaskよりも推奨されていて、APIレベル11以後(android3.0以後)で使うことができます。
それ以前のバージョンのandroidで使うには、サポートライブラリをインポートする必要があります。
また、サポートライブラリを使う場合は、「FragmentActivity」を継承する必要があります。

android2.3.3用とかの場合

import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { ....................... }




タイマーでカウントさせつつ、別途にAsynkTaskLoaderでカウントを開始させるテスト。
 

「AsynkTaskLoader」ボタンを押すとカウントを始めます。
ボタンを何度も押すと、「Progress」の値がおかしくなります。
AsynkTaskが複数同時起動され、カウントが並行処理されたためです。
「AsyncTaskRunCount1」が、現在実行中のAsynkTaskLoaderの数です。
そもそもAsynkTaskから外部の変数を参照するのは、あまりよろしくないコードだと思いますが、
とりあえず「注意しないとこういう不具合が出るよ」というテストということで。

複数同時起動させないためには、ToAsyncTaskLoader1()の、
「タスクの重複起動をさせない場合直前に起動したLoaderを止める」のコードを有効にします。




MainActivity.java

package com.example.test34; import java.util.Timer; import java.util.TimerTask; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.support.v4.app.FragmentActivity; import android.os.Bundle; import android.content.Context; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.graphics.Bitmap; public class MainActivity extends FragmentActivity { Timer timer1 = new Timer(); static int TimerCount1 = 0; TextView text1; TextView text2; TextView text3; TextView text4; static int AsyncTaskIdCount1=0; static int AsyncTaskRunCount1=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout1 = new LinearLayout(this); setContentView(layout1); layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ text1 = new TextView(this); layout1.addView(text1); text2 = new TextView(this); layout1.addView(text2); text3 = new TextView(this); layout1.addView(text3); text4 = new TextView(this); layout1.addView(text4); Button button1 = new Button(this); button1.setText("AsyncTaskLoader"); layout1.addView(button1); button1.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; } }); ToTimerTask1(); } //----------------------------------------------------------------------- private void ToTimerTask1(){ //タイマータスクで一定時間おきにカウントする timer1.scheduleAtFixedRate(new TimerTask() { @Override public void run() { TimerCount1 += 1; //Log.d("TAG_TIMER", String.valueOf(TimerCount1 )); runOnUiThread(new Runnable() { public void run() { text1.setText("TimerCount1 / AsyncTaskRunCount1 = " + String.valueOf(TimerCount1) + " / " + String.valueOf(AsyncTaskRunCount1)); } }); } }, 0, 1000); } public void ToAsyncTaskLoader1(int count_Id1){ LoaderManager.LoaderCallbacks<Bitmap> loaderCalBack = new LoaderManager.LoaderCallbacks<Bitmap>(){ //LoaderのIDを保存しておく int Loader_Id1; @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader " + String.valueOf(id)); Loader_Id1 =id; //AsyncTaskLoaderのインスタンスを作成 AsyncTaskLoader<Bitmap> ATLoader = new StartAsyncTaskLoader1(MainActivity.this,Loader_Id1); return ATLoader; } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished " + String.valueOf(Loader_Id1)); //ローダーのID取得 text4.setText( "AsyncTaskLoader 終了 ID = " + loader.getId()); } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onLoaderReset " + String.valueOf(Loader_Id1)); } }; /* //count_Id1を、LoaderのIDとする //タスクの重複起動をさせない場合直前に起動したLoaderを止める if(count_Id1>0){ //ここでは、キャンセルを指示するだけなので処理は止まらない //実際の処理の中断は、loaderの中で処理する //中断1//すぐにonStopLoadingが呼ばれる getSupportLoaderManager().getLoader(count_Id1-1).stopLoading(); //中断2//すぐにonResetが呼ばれる //getSupportLoaderManager().destroyLoader(count_Id1-1); //中断3//loadInBackgroundの処理が終わった後にonCanceledが呼ばれる //((AsyncTaskLoader<Object>) getSupportLoaderManager().getLoader(count_Id1-1)).cancelLoad(); } */ //LoaderにデータをBundleで渡す String ctl = Integer.toString(count_Id1); Bundle args = new Bundle(); args.putString("COUNT1", ctl); //--------------------------------------------------------------- //Loaderを起動する //起動1//IDごとに1回づつに実行//処理中に同じIDで起動しても前の処理が優先される //getSupportLoaderManager().initLoader(count_Id1, args, loaderCalBack); //起動2//同じIDが来たら、新規Loaderとして実行//前のLoaderも処理が続行され、処理後にonCanceledが呼ばれる getSupportLoaderManager().restartLoader(count_Id1, args, loaderCalBack); //--------------------------------------------------------------- } //---------------------------------------------------------------- //インナークラスをstaticにすること public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { int AsyncTaskLoadercount1=0; int AsyncTaskLoadercount2=0; MainActivity ma; boolean CancelFlg1 = false; //コンストラクタ StartAsyncTaskLoader1(Context context,int Id){ super(context); //LoaderのID AsyncTaskLoadercount1 = Id; Log.d("TAG_TASKLOADER2", "StartAsyncTaskLoader1 " + String.valueOf(AsyncTaskLoadercount1)); ma = (MainActivity)context; } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1)); for(int i=0;i<100;i++){ //キャンセルしようとして、CancelFlg1=trueになった場合は中断する if (CancelFlg1) { Log.d("TAG_TASKLOADER2", "CancelFlg1 = true"); ma.runOnUiThread(new Runnable() { @Override public void run(){ ma.text3.setText( "AsyncTaskLoader 中断された ID = " + String.valueOf(AsyncTaskLoadercount1) + " 中断 = " + String.valueOf(AsyncTaskLoadercount2)); } }); //タスクが終わった AsyncTaskRunCount1--; return null; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } AsyncTaskLoadercount2=i+1; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " - " + String.valueOf(AsyncTaskLoadercount2)); //UIを更新 ma.runOnUiThread(new Runnable() { @Override public void run() { ma.text2.setText( "AsyncTaskLoader 起動中 ID = " + String.valueOf(AsyncTaskLoadercount1) + " Progress = " + String.valueOf(AsyncTaskLoadercount2)); } }); } //タスクが終わった AsyncTaskRunCount1--; //Bitmapをロードしたつもり Bitmap bitmap =null; //読み出したBitmapを返す return bitmap; } @Override public void onCanceled(Bitmap data) { Log.d("TAG_TASKLOADER2", "onCanceled " + String.valueOf(AsyncTaskLoadercount1)); //cancelLoad()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる //処理中にrestartLoader()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる } @Override protected void onStartLoading() { // Loader開始時に呼ばれる Log.d("TAG_TASKLOADER2", "onStartLoading " + String.valueOf(AsyncTaskLoadercount1)); //タスクが始まった AsyncTaskRunCount1++; // Loaderを開始 forceLoad(); } @Override protected void onStopLoading() { super.onStopLoading(); //stopLoading()ですぐに呼ばれる Log.d("TAG_TASKLOADER2", "onStopLoading " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); } @Override protected void onReset() { super.onReset(); //destroyLoader()ですぐに呼ばれる //restartLoader()が実行された場合に、onLoadFinished()後に呼ばれる Log.d("TAG_TASKLOADER2", "onReset " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); onStopLoading(); } } }






AsyncTaskLoaderの使い方。


AsyncTaskLoaderを使うには、はじめに1つのパラメータを設定する必要があります。
AsyncTaskLoaderでロードされるデータの型で、任意に決められます。
Bitmapをロードしたい場合は、以下のように指定します。


AsyncTaskLoader<Bitmap>





AsyncTaskLoaderのクラスを作る。


はじめに、AsyncTaskLoaderを継承したクラスを作ります。
この中で、画像ロードなどの重い処理をさせます。

AsyncTaskLoaderのパラメータとして設定した型は、
それぞれのメソッドで受け渡しされます。
記述するときは、違う型を書くとエラーになるので注意しましょう。

インナークラスは、staticにしないとエラーになります。

「forceLoad();」を記述しないと実行されません。

「forceLoad();」で実行される

public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { public StartAsyncTaskLoader1(Context context) { super(context); // TODO 自動生成されたコンストラクター・スタブ } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER2", "loadInBackground " ); return null; } @Override protected void onStartLoading() { super.onStartLoading(); // Loaderを開始 forceLoad(); } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); } @Override protected void onStopLoading() { super.onStopLoading(); } @Override protected void onReset() { super.onReset(); } }






Loaderの呼び出し方。


Loaderを呼び出す場合は、以下のようにします。
LoaderCallbacksで、前処理や後処理をします。


//----------------------------------------------------------------------- //Loaderのコールバック LoaderManager.LoaderCallbacks<Bitmap> loaderCalBack = new LoaderManager.LoaderCallbacks<Bitmap>(){ @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ //Loaderを実行 Log.d("TAG_TASKLOADER1", "onCreateLoader "); //重い処理をさせるAsyncTaskLoaderを実行 AsyncTaskLoader<Bitmap> ATLoader = new StartAsyncTaskLoader1(MainActivity.this); return ATLoader; } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ } }; //----------------------------------------------------------------------- //Loaderを呼び出す getSupportLoaderManager().initLoader(id, bundle, loaderCalBack); //getSupportLoaderManager().restartLoader(id, bundle, loaderCalBack);

LoaderCallbacks
重い処理をさせるAsyncTaskLoaderを継承したクラスを実行させるための、前処理と実行、後処理を行います。
プログレスダイアログを出す場合は、ここで行います。

initLoader
このとき、initLoader()を使う場合、ID番号を同じ数値にすると、何度呼び出しても初めの1度しか実行されません。
処理が終わった後に何度も呼び出す場合、IDに、別のIDの値を渡すようにします。

restartLoader
restartLoader()を使う場合、同じID番号で、何度も起動できます。
処理中に、同じIDで次のLoaderを起動した場合、次のLoaderのIDが実行されます。
このとき、前のLoaderは処理を中断しません。
処理が終わった後に、onCanceledが呼ばれます。
目的に応じて使い分けたり、任意で処理を中断させたりします。






サンプルコード

画面では何も起きません。LOGを見ると、動作の流れがわかります。

onCreateLoader

loadInBackground

onLoadFinished(Loader


public class MainActivity extends FragmentActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ToAsyncTaskLoader1(0); } public void ToAsyncTaskLoader1(int id){ LoaderManager.LoaderCallbacks<Bitmap> loaderCalBack = new LoaderManager.LoaderCallbacks<Bitmap>(){ @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ //Loaderを呼び出す Log.d("TAG_TASKLOADER1", "onCreateLoader "); AsyncTaskLoader<Bitmap> ATLoader = new StartAsyncTaskLoader1(MainActivity.this); return ATLoader; } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished "); } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ } }; getSupportLoaderManager().initLoader(id, null, loaderCalBack); //getSupportLoaderManager().restartLoader(id, null, loaderCalBack); } //-------------------------------------------------------- public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { public StartAsyncTaskLoader1(Context context) { super(context); // TODO 自動生成されたコンストラクター・スタブ } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER2", "loadInBackground " ); return null; } @Override protected void onStartLoading() { super.onStartLoading(); // Loaderを開始 forceLoad(); } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); } @Override protected void onStopLoading() { super.onStopLoading(); } @Override protected void onReset() { super.onReset(); } } }




別の記述方法

public class MainActivity extends FragmentActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ToAsyncTaskLoader1(0); } public void ToAsyncTaskLoader1(int id){ //getSupportLoaderManager().initLoader(id, null, mLoaderCallbacks); getSupportLoaderManager().restartLoader(id, null, mLoaderCallbacks); } private final LoaderManager.LoaderCallbacks<Bitmap> mLoaderCallbacks = new LoaderManager.LoaderCallbacks<Bitmap>() { @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader "); return new StartAsyncTaskLoader1(MainActivity.this); } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished "); } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onLoaderReset "); } }; //-------------------------------------------------------- public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { public StartAsyncTaskLoader1(Context context) { super(context); // TODO 自動生成されたコンストラクター・スタブ } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER2", "loadInBackground " ); return null; } @Override protected void onStartLoading() { super.onStartLoading(); // Loaderを開始 forceLoad(); } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); } @Override protected void onStopLoading() { super.onStopLoading(); } @Override protected void onReset() { super.onReset(); } } }






LoaderCallbacksを、implementsする場合


LoaderCallbacksインターフェースをimplementsする場合は、次のようにします。


public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Bitmap>{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ToAsyncTaskLoader1(0); } //-------------------------------------------------------- public void ToAsyncTaskLoader1(int id){ //getSupportLoaderManager().initLoader(id, null, this); getSupportLoaderManager().restartLoader(id, null, this); } @Override public Loader<Bitmap> onCreateLoader(int arg0, Bundle arg1) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader "); return new StartAsyncTaskLoader1(MainActivity.this); } @Override public void onLoadFinished(Loader<Bitmap> arg0, Bitmap arg1) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished "); } @Override public void onLoaderReset(Loader<Bitmap> arg0) { // TODO 自動生成されたメソッド・スタブ } //-------------------------------------------------------- public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { public StartAsyncTaskLoader1(Context context) { super(context); // TODO 自動生成されたコンストラクター・スタブ } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER2", "loadInBackground " ); return null; } @Override protected void onStartLoading() { super.onStartLoading(); // Loaderを開始 forceLoad(); } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); } @Override protected void onStopLoading() { super.onStopLoading(); } @Override protected void onReset() { super.onReset(); } } }






プログレスダイアログフラグメントを出す。


AsyncTaskLoaderから、プログレスダイアログフラグメントを出すテスト。

FragmentActivityを継承しているので、このままダイアログフラグメントを出すことができます。

スピナーでくるくる、進捗不確定モード、プログレスバー。
   


以下を追加修正する。

import android.support.v4.app.DialogFragment; //こちらをインポートする //import android.app.DialogFragment; //これをインポートするとエラー import android.app.Dialog; import android.app.ProgressDialog; //------------------------------------------------------------------ public void ToAsyncTaskLoader1(int count_Id1){ @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { //プログレスダイアログ表示 ProgressDialogFragment dialog = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("TITLE", "おまちください"); args.putString("MESSAGE", "画像ロード中"); dialog.setArguments(args); dialog.show(getSupportFragmentManager(), "PROGRESS"); //Loader起動 return new StartAsyncTaskLoader1(MainActivity.this,Loader_Id1,dialog); } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { //Loaderの処理が終わった //プログレスダイアログを閉じる ProgressDialogFragment dialog = (ProgressDialogFragment)getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) dialog.onDismiss(dialog.getDialog()); } } //------------------------------------------------------------------ public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { ProgressDialogFragment dialog; //コンストラクタ StartAsyncTaskLoader1(Context context,int Id,ProgressDialogFragment dlg){ super(context); dialog = dlg; } @Override public Bitmap loadInBackground() { for(int i=0;i<100;i++){ ................................... //進捗情報更新 if (dialog != null) dialog.updateProgress(i+1); } } } //------------------------------------------------------------------ //プログレスダイアログフラグメント public static class ProgressDialogFragment extends DialogFragment { ProgressDialog dialog ; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { dialog = new ProgressDialog(getActivity()); dialog.setTitle(getArguments().getString("TITLE")); dialog.setMessage(getArguments().getString("MESSAGE")); //dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//くるくる //dialog.setIndeterminate(true);//進捗不確定モード dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//プログレスバー dialog.setMax(100); dialog.setProgress(0); return dialog; } public void updateProgress(int value){ if (dialog != null) dialog.setProgress(value); } }






loadInBackgroundから、UIを操作する。

AsyncTaskLoaderのloadInBackground() で、進捗情報をUIに知らせようとした場合の専用メソッドは無いのでしょうか?
進捗状況をUIに知らせようと、loadInBackground() にsetTextなんかを書くとエラーになります。

「LoaderからUI操作をするな」ということか、「面倒だろうけど、適当に実装してね」ということか、
どういう設計思想かよくわかりませんが、進捗状況は知らせたいところです。

というわけで、初めの例では、アクティビティからコンテキストを取得して、
runOnUiThread(new Runnable())〜を使って、setTextとかのUIの操作をしています。







「戻るキー」でキャンセルさせる。


ダイアログフラグメントは、「戻るキー」で勝手に閉じてしまうようです。
しかし、ダイアログを閉じてもLoaderの処理は続いているので、
「戻るキー」でキャンセルされたことをLoaderに通知するために、リスナーを登録する。

以下のように、ダイアログに、setOnCancelListenerを登録してキャンセルすると、DialogCanselFlg1がfalseになるので、
Loaderから、dialog.DialogCanselFlg1を判定するようにする。


import android.content.DialogInterface; ........................ public static class ProgressDialogFragment extends DialogFragment { Boolean DialogCanselFlg1=false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { //ダイアログをキャンセルできるようにする//ダイアログフラグメントは勝手に消える? dialog.setCancelable(true); dialog.setOnCancelListener(this); } @Override public void onCancel(DialogInterface dialog) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_PROGRESS", "onCancel"); //キャンセルするするフラグをたてる DialogCanselFlg1 = true; } } //------------------------------------------------------------------------ public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { @Override public Bitmap loadInBackground() { for(int i=0;i<100;i++){ //ダイアログからキャンセルされた? CancelFlg1 = dialog.DialogCanselFlg1; //キャンセルしようとして、CancelFlg1=trueになった場合は中断する if (CancelFlg1) { return null; } } }


これで、「戻るキー」でダイアログがキャンセルされたとき、Loaderの処理も停止する。





「 cancelLoad() 」ってなに?

実行中のタスクを中断させるために、最初のサンプル例では、
「タスクの重複起動をさせない場合直前に起動したLoaderを止める」コードの中で、
stopLoading()や、destroyLoader()を呼んでいる。

Loaderの処理中に、onStopLoading()や、onReset()が呼ばれることになるが、呼ばれただけでは処理が中断されない。
cancelLoad()というメソッドがあるが、それを書いただけでは停止しないし、onStopLoading() を呼び出しても停止しないようだ。

「タスクの重複起動をさせない場合直前に起動したLoaderを止める」のコードを復活させて、
destroyLoader()を実行させると、onStopLoading()、cancelLoad()が呼ばれる。
処理中にボタンを何度も押せば、前の処理は中断される。

が、中断されたのは、ここでも「CancelFlg1 = true; 」としているためで、
この行を削除すると、中断されなくなる。

「 cancelLoad() 」は、ただちにキャンセルされるものではなく
loadInBackgroundの処理中に「 cancelLoad() 」が呼ばれたことを、loadInBackgroundの処理が終わった後に、
onCanceled()に通知して、なにがしかの処理ができるようにするためのもののようだ。

ようするに、AsyncTaskLoaderを直接終了させるメソッドは用意されて無いということなのだ。
いや、わかりません。思い違いかもしれない。






端末を回転させたときの対応。


端末を回転させると、Activityが破棄されて再生成されるので、いろいろとエラーが起きます。

とりあえず、今回のダイアログは、フラグメントなので、回転させても消えたりはしないのですが、
ただ、進捗状態のプログレスバーが止まってしまったり、
処理が終わってもダイアログが消えないという不具合があるので修正が必要になります。

処理が終わった後に、ダイアログを消すには、deliverResult()を実装します。
loadInBackground()が終わった後に実行されるので、その中でダイアログを消すようにします。
super.deliverResult(data); を書かないと、onLoadFinished()が呼ばれないので注意。

プログレスバーが更新されないのは、
画面回転で、アクティビティが破棄されるので、もう一度取得すればいいということでしょう。
いろいろ方法はありそうですが、最初のonCreate()で、アクティビティを取得して、
Loaderが実行中に画面回転しても、いつでも最新のアクティビティを参照できるようにするのが簡単そうです。

最初のonCreate()で、MainAct1にアクティビティを保存して、LoaderのloadInBackground()から参照できるようにします。
AsyncTaskCount1をstaticにして、進捗状況を保存しておきます。

画面回転直後に「戻るキー」で処理が中断しなくなったので、
staticのCancelFlg2を用意してチェックするようにした。

あと、TextViewはstaticにしてみます。


しかし、まだ問題が発生しており、
処理中に画面回転させると、onLoadFinished()が呼ばれない、コールバックされてこないというわけです。
ということは、終了しても「AsyncTaskLoader 終了 ID = 〜」というテキストメッセージが表示されないということです。
これでは、画像をロードしたとしても、その後の処理を続行できません。

回転でアクティビティが破棄されているので、コールバック先を見失うのは当たり前なのですが。
こういう場合の簡易な対応策がわかりません。

最初、ダイアログがキャンセルされて閉じたらDialogCanselFlg1 がtrueになるからオッケーだと期待してましたが、
回転させると、ダイアログが新たに生成されるためか、DialogCanselFlg1をfalseに戻されるようでうまくいきません。

回転されたかをチェックしておいて、処理が終了した時点でなんらかの対応をすればいいということでしょう。
こうなってくると、AsyncTaskの不備?を補えるほど、AsyncTaskLoaderは便利なのかなんなのか……。

応急処置として、AsyncTaskFlg1を使って、onLoadFinishedが呼ばれずに、deliverResultが呼ばれたら、
処理が終わったと判定できるように、タイマータスクで監視することにしました。


技術資料には、getSupportLoaderManager()を、最初に一度起動しておくということが書かれてるみたいですが、
処理中に画面回転すると、onLoadFinished が呼ばれないのは変わらない気がする。




MainActivity.java

package com.example.test34; import java.util.Timer; import java.util.TimerTask; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.support.v4.app.FragmentActivity; import android.support.v4.app.DialogFragment; //こちらをインポートする //import android.app.DialogFragment; //これをインポートするとエラー import android.os.Bundle; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.graphics.Bitmap; public class MainActivity extends FragmentActivity { Timer timer1 = new Timer(); static int TimerCount1 = 0; static TextView text1; static TextView text2; static TextView text3; static TextView text4; static int AsyncTaskIdCount1=0; static int AsyncTaskRunCount1=0; static int AsyncTaskCount1=0; static MainActivity MainAct1; //画面回転対応 static boolean CancelFlg2 = false; //画面回転対応 static int AsyncTaskFlg1=0; //画面回転対応 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout1 = new LinearLayout(this); setContentView(layout1); layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ text1 = new TextView(this); layout1.addView(text1); text2 = new TextView(this); layout1.addView(text2); text3 = new TextView(this); layout1.addView(text3); text4 = new TextView(this); layout1.addView(text4); Button button1 = new Button(this); button1.setText("AsyncTaskLoader"); layout1.addView(button1); button1.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { CancelFlg2 = false; AsyncTaskCount1=0; ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; } }); ToTimerTask1(); MainAct1 = MainActivity.this; //画面回転対応//現在のアクティビティを取得 if(savedInstanceState==null){ //最初に一度起動しておく getSupportLoaderManager(); ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; } } //----------------------------------------------------------------------- private void ToTimerTask1(){ //タイマータスクで一定時間おきにカウントする timer1.scheduleAtFixedRate(new TimerTask() { @Override public void run() { TimerCount1 += 1; //Log.d("TAG_TIMER", String.valueOf(TimerCount1 )); runOnUiThread(new Runnable() { public void run() { text1.setText("TimerCount1 / AsyncTaskRunCount1 = " + String.valueOf(TimerCount1) + " / " + String.valueOf(AsyncTaskRunCount1)); if(AsyncTaskFlg1==4){ AsyncTaskFlg1=0; text4.setText( "AsyncTaskLoader 終了 onLoadFinished が呼ばれませんでした"); } } }); } }, 0, 1000); } public void ToAsyncTaskLoader1(int count_Id1){ LoaderManager.LoaderCallbacks<Bitmap> loaderCalBack = new LoaderManager.LoaderCallbacks<Bitmap>(){ //LoaderのIDを保存しておく int Loader_Id1; AsyncTaskLoader<Bitmap> ATLoader; @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader " + String.valueOf(id)); //プログレスダイアログ表示 ProgressDialogFragment dialog = new ProgressDialogFragment(); //dialog = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("TITLE", "おまちください"); args.putString("MESSAGE", "画像ロード中"); dialog.setArguments(args); dialog.show(getSupportFragmentManager(), "PROGRESS"); AsyncTaskFlg1 =1; Loader_Id1 =id; //return new StartAsyncTaskLoader1(MainActivity.this,Loader_Id1,dialog); ATLoader = new StartAsyncTaskLoader1(MainActivity.this,Loader_Id1,dialog); return ATLoader; } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished " + String.valueOf(Loader_Id1)); //ローダーのID取得 text4.setText( "AsyncTaskLoader 終了 ID = " + loader.getId()); //プログレスダイアログを閉じる ProgressDialogFragment dialog = (ProgressDialogFragment)getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) dialog.onDismiss(dialog.getDialog()); AsyncTaskFlg1 =3; } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onLoaderReset " + String.valueOf(Loader_Id1)); } }; //count_Id1を、LoaderのIDとする //タスクの重複起動をさせない場合直前に起動したLoaderを止める if(count_Id1>0){ //ここでは、キャンセルを指示するだけなので処理は止まらない //実際の処理の中断は、loaderの中で処理する //中断1//すぐにonStopLoadingが呼ばれる getSupportLoaderManager().getLoader(count_Id1-1).stopLoading(); //中断2//すぐにonResetが呼ばれる //getSupportLoaderManager().destroyLoader(count_Id1-1); //中断3//loadInBackgroundの処理が終わった後にonCanceledが呼ばれる //((AsyncTaskLoader<Object>) getSupportLoaderManager().getLoader(count_Id1-1)).cancelLoad(); } //LoaderにデータをBundleで渡す String ctl = Integer.toString(count_Id1); Bundle args = new Bundle(); args.putString("COUNT1", ctl); //--------------------------------------------------------------- //Loaderを起動する //起動1//IDごとに1回づつに実行//処理中に同じIDで起動しても前の処理が優先される getSupportLoaderManager().initLoader(count_Id1, args, loaderCalBack); //起動2//同じIDが来たら、新規Loaderとして実行//前のLoaderも処理が続行され、処理後にonCanceledが呼ばれる //getSupportLoaderManager().restartLoader(count_Id1, args, loaderCalBack); //--------------------------------------------------------------- } //---------------------------------------------------------------- //インナークラスをstaticにすること public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { int AsyncTaskLoadercount1=0; int AsyncTaskLoadercount2=0; MainActivity ma; boolean CancelFlg1 = false; ProgressDialogFragment dialog; //コンストラクタ StartAsyncTaskLoader1(Context context,int Id,ProgressDialogFragment dlg){ super(context); //LoaderのID AsyncTaskLoadercount1 = Id; Log.d("TAG_TASKLOADER2", "StartAsyncTaskLoader1 " + String.valueOf(AsyncTaskLoadercount1)); ma = (MainActivity)context; dialog = dlg; } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ AsyncTaskFlg1 = 2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " AsyncTaskCount1 "+ String.valueOf(AsyncTaskCount1)); for(int i=AsyncTaskCount1;i<100;i++){ //画面回転対応//アクティビティ情報を最新に更新 ma = MainAct1; //ダイアログからキャンセルされた? CancelFlg1 = dialog.DialogCanselFlg1; //キャンセルしようとして、CancelFlg1=trueになった場合は中断する //画面回転後にキャンセルしようとして、static の CancelFlg2=trueになった場合は中断する if (CancelFlg1==true || CancelFlg2==true) { Log.d("TAG_TASKLOADER2", "キャンセルされた " + String.valueOf(CancelFlg1) + " / " + String.valueOf(CancelFlg2)); ma.runOnUiThread(new Runnable() { @Override public void run(){ ma.text3.setText( "AsyncTaskLoader 中断された ID = " + String.valueOf(AsyncTaskLoadercount1) + " 中断 = " + String.valueOf(AsyncTaskLoadercount2)); } }); //タスクが終わった AsyncTaskRunCount1--; CancelFlg1 = false; CancelFlg2 = false; return null; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } AsyncTaskLoadercount2=i+1; AsyncTaskCount1 = AsyncTaskLoadercount2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " - " + String.valueOf(AsyncTaskLoadercount2)); //UIを更新 ma.runOnUiThread(new Runnable() { @Override public void run() { ma.text2.setText( "AsyncTaskLoader 起動中 ID = " + String.valueOf(AsyncTaskLoadercount1) + " Progress = " + String.valueOf(AsyncTaskLoadercount2)); } }); //画面回転対応 //現在のダイアログを取得 ProgressDialogFragment dialog = (ProgressDialogFragment)ma.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); //進捗情報更新 if (dialog != null) dialog.updateProgress(AsyncTaskCount1); } //タスクが終わった AsyncTaskRunCount1--; //Bitmapをロードしたつもり Bitmap bitmap =null; //読み出したBitmapを返す return bitmap; } @Override public void onCanceled(Bitmap data) { Log.d("TAG_TASKLOADER2", "onCanceled " + String.valueOf(AsyncTaskLoadercount1)); //cancelLoad()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる //処理中にrestartLoader()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる } @Override protected void onStartLoading() { // Loader開始時に呼ばれる Log.d("TAG_TASKLOADER2", "onStartLoading " + String.valueOf(AsyncTaskLoadercount1)); //タスクが始まった AsyncTaskRunCount1++; // Loaderを開始 forceLoad(); } @Override protected void onStopLoading() { super.onStopLoading(); //stopLoading()ですぐに呼ばれる Log.d("TAG_TASKLOADER2", "onStopLoading " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); } @Override protected void onReset() { super.onReset(); //destroyLoader()ですぐに呼ばれる //restartLoader()が実行された場合に、onLoadFinished()後に呼ばれる Log.d("TAG_TASKLOADER2", "onReset " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); onStopLoading(); } @Override public void deliverResult(Bitmap data) { super.deliverResult(data); //これが無いと処理終了後に、onLoadFinished()が呼ばれない //処理の終了時に呼ばれる Log.d("TAG_TASKLOADER2", "deliverResult" + String.valueOf(AsyncTaskLoadercount1)); ProgressDialogFragment dialog = (ProgressDialogFragment)MainAct1.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) { //ダイアログ消す dialog.onDismiss(dialog.getDialog()); } //onLoadFinishedを通過した if(AsyncTaskFlg1==3) AsyncTaskFlg1 = 0; else AsyncTaskFlg1 = 4; } } //------------------------------------------------------------------ //プログレスダイアログフラグメント public static class ProgressDialogFragment extends DialogFragment { ProgressDialog dialog ; Boolean DialogCanselFlg1=false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { dialog = new ProgressDialog(getActivity()); dialog.setTitle(getArguments().getString("TITLE")); dialog.setMessage(getArguments().getString("MESSAGE")); //dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//くるくる //dialog.setIndeterminate(true);//進捗不確定モード dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//プログレスバー dialog.setMax(100); dialog.setProgress(AsyncTaskCount1); //ダイアログをキャンセルできるようにする//ダイアログフラグメントは勝手に消える? dialog.setCancelable(true); dialog.setOnCancelListener(this); return dialog; } @Override public void onCancel(DialogInterface dialog) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_PROGRESS", "onCancel"); //キャンセルするするフラグをたてる DialogCanselFlg1 = true; CancelFlg2 = true; } public void updateProgress(int value){ if (dialog != null) dialog.setProgress(value); } } }




AsyncTaskLoaderから、フラグメントに通知する


もしかしたら、レイアウトをフラグメントにしたら改善するかな?
と、思って、フラグメントで表示するように改造してみました。

が、やっぱり、処理中に回転させると、
onLoadFinished()は、呼ばれてこないみたいです。

が、「AsyncTaskLoader 終了 onLoadFinished が呼ばれませんでした」通知は、
フラグメントのタグを呼び出すことで、
deliverResultからすぐにテキストに表示できるようになりました。

とりあえず。



MainActivity.java

package com.example.test34; import java.util.Timer; import java.util.TimerTask; import android.util.Log; import android.os.Bundle; import android.app.Dialog; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.support.v4.app.FragmentActivity; import android.support.v4.app.DialogFragment; //こちらをインポートする //import android.app.DialogFragment; //これをインポートするとエラー import android.support.v4.app.Fragment; //これをインポートすること //import android.app.Fragment; //これをインポートするとエラー import android.support.v4.app.FragmentTransaction; //これをインポートすること //import android.app.FragmentTransaction; //これをインポートするとエラー import android.support.v4.app.FragmentManager; //これをインポートすること //import android.app.FragmentManager; //これをインポートするとエラー import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.graphics.Bitmap; public class MainActivity extends FragmentActivity { Timer timer1 = new Timer(); static int TimerCount1 = 0; static int AsyncTaskIdCount1=0; static int AsyncTaskRunCount1=0; static int AsyncTaskCount1=0; static MainActivity MainAct1; //画面回転対応 static boolean CancelFlg2 = false; //画面回転対応 static int AsyncTaskFlg1=0; //画面回転対応 private static final int LAYOUT_ID1 = 777; //フラグメントのレイアウトID static int SetLoaderManager1 =0; //はじめに、一度だけLoaderManager()を呼び出す @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //親レイアウト LinearLayout L_layout1 = new LinearLayout(this); setContentView(L_layout1); L_layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ //---------------------------------------- //子レイアウト(フラグメント)を親レイアウト1に追加 LinearLayout L_layout2 = new LinearLayout(this); L_layout1.addView(L_layout2); //子レイアウト2に、フラグメントを設定するためのID L_layout2.setId(LAYOUT_ID1); //------------------------------------- MainAct1 = MainActivity.this; //画面回転対応//現在のアクティビティを取得 if(savedInstanceState==null){ //はじめにアクティビティが生成された時に1度だけフラグメントをつくる FragmentManager manager = getSupportFragmentManager(); FragmentTransaction ft = manager.beginTransaction(); FragmentF1 frag1 = new FragmentF1(); //フラグメントにタグ付きで追加する ft.add(LAYOUT_ID1, frag1,"TAG_FRAGMENT1"); ft.commit(); } ToTimerTask1(); } @Override protected void onStart() { super.onStart(); if(SetLoaderManager1==0){ SetLoaderManager1 = 1; //最初に一度起動しておく getSupportLoaderManager(); FragmentManager manager = getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); frag1.ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; } } //----------------------------------------------------------------------- private void ToTimerTask1(){ //タイマータスクで一定時間おきにカウントする timer1.scheduleAtFixedRate(new TimerTask() { @Override public void run() { TimerCount1 += 1; //Log.d("TAG_TIMER", String.valueOf(TimerCount1 )); runOnUiThread(new Runnable() { public void run() { FragmentManager manager = getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null){ frag1.updateText1("TimerCount1 / AsyncTaskRunCount1 = " + String.valueOf(TimerCount1) + " / " + String.valueOf(AsyncTaskRunCount1)); } } }); } }, 0, 1000); } //---------------------------------------------------------------- //インナークラスをstaticにすること public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { int AsyncTaskLoadercount1=0; int AsyncTaskLoadercount2=0; MainActivity ma; boolean CancelFlg1 = false; ProgressDialogFragment dialog; //コンストラクタ StartAsyncTaskLoader1(Context context,int Id,ProgressDialogFragment dlg){ super(context); //LoaderのID AsyncTaskLoadercount1 = Id; Log.d("TAG_TASKLOADER2", "StartAsyncTaskLoader1 " + String.valueOf(AsyncTaskLoadercount1)); ma = (MainActivity)context; dialog = dlg; } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ AsyncTaskFlg1 = 2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " AsyncTaskCount1 "+ String.valueOf(AsyncTaskCount1)); for(int i=AsyncTaskCount1;i<100;i++){ //画面回転対応//アクティビティ情報を最新に更新 ma = MainAct1; //ダイアログからキャンセルされた? CancelFlg1 = dialog.DialogCanselFlg1; //キャンセルしようとして、CancelFlg1=trueになった場合は中断する //画面回転後にキャンセルしようとして、static の CancelFlg2=trueになった場合は中断する if (CancelFlg1==true || CancelFlg2==true) { Log.d("TAG_TASKLOADER2", "キャンセルされた " + String.valueOf(CancelFlg1) + " / " + String.valueOf(CancelFlg2)); ma.runOnUiThread(new Runnable() { @Override public void run(){ FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText3( "AsyncTaskLoader 中断された ID = " + String.valueOf(AsyncTaskLoadercount1) + " 中断 = " + String.valueOf(AsyncTaskLoadercount2)); } }); //タスクが終わった AsyncTaskRunCount1--; CancelFlg1 = false; CancelFlg2 = false; return null; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } AsyncTaskLoadercount2=i+1; AsyncTaskCount1 = AsyncTaskLoadercount2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " - " + String.valueOf(AsyncTaskLoadercount2)); //UIを更新 ma.runOnUiThread(new Runnable() { @Override public void run() { FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText2( "AsyncTaskLoader 起動中 ID = " + String.valueOf(AsyncTaskLoadercount1) + " Progress = " + String.valueOf(AsyncTaskLoadercount2)); } }); //画面回転対応 //現在のダイアログを取得 ProgressDialogFragment dialog = (ProgressDialogFragment)ma.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); //進捗情報更新 if (dialog != null) dialog.updateProgress(AsyncTaskCount1); } //タスクが終わった AsyncTaskRunCount1--; //Bitmapをロードしたつもり Bitmap bitmap =null; //読み出したBitmapを返す return bitmap; } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); Log.d("TAG_TASKLOADER2", "onCanceled " + String.valueOf(AsyncTaskLoadercount1)); //cancelLoad()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる //処理中にrestartLoader()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる } @Override protected void onStartLoading() { // Loader開始時に呼ばれる Log.d("TAG_TASKLOADER2", "onStartLoading " + String.valueOf(AsyncTaskLoadercount1)); //タスクが始まった AsyncTaskRunCount1++; // Loaderを開始 forceLoad(); } @Override protected void onStopLoading() { super.onStopLoading(); //stopLoading()ですぐに呼ばれる Log.d("TAG_TASKLOADER2", "onStopLoading " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); } @Override protected void onReset() { super.onReset(); //destroyLoader()ですぐに呼ばれる //restartLoader()が実行された場合に、onLoadFinished()後に呼ばれる Log.d("TAG_TASKLOADER2", "onReset " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; cancelLoad(); onStopLoading(); } @Override public void deliverResult(Bitmap data) { super.deliverResult(data); //これが無いと処理終了後に、onLoadFinished()が呼ばれない //処理の終了時に呼ばれる Log.d("TAG_TASKLOADER2", "deliverResult" + String.valueOf(AsyncTaskLoadercount1)); ProgressDialogFragment dialog = (ProgressDialogFragment)MainAct1.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) { //ダイアログ消す dialog.onDismiss(dialog.getDialog()); } //onLoadFinishedを通過した if(AsyncTaskFlg1==3) AsyncTaskFlg1 = 0; else AsyncTaskFlg1 = 4; if(AsyncTaskFlg1==4){ FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); AsyncTaskFlg1=0; frag1.updateText4( "AsyncTaskLoader 終了 onLoadFinished が呼ばれませんでした"); } } } //------------------------------------------------------------------ //プログレスダイアログフラグメント public static class ProgressDialogFragment extends DialogFragment { ProgressDialog dialog ; Boolean DialogCanselFlg1=false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { dialog = new ProgressDialog(getActivity()); dialog.setTitle(getArguments().getString("TITLE")); dialog.setMessage(getArguments().getString("MESSAGE")); //dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//くるくる //dialog.setIndeterminate(true);//進捗不確定モード dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//プログレスバー dialog.setMax(100); dialog.setProgress(AsyncTaskCount1); //ダイアログをキャンセルできるようにする//ダイアログフラグメントは勝手に消える? dialog.setCancelable(true); dialog.setOnCancelListener(this); return dialog; } @Override public void onCancel(DialogInterface dialog) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_PROGRESS", "onCancel"); //キャンセルするするフラグをたてる DialogCanselFlg1 = true; CancelFlg2 = true; } public void updateProgress(int value){ if (dialog != null) dialog.setProgress(value); } } //----------------------------------------------------------------------------------- //フラグメント public static class FragmentF1 extends Fragment{ public FragmentF1() {} TextView text1; TextView text2; TextView text3; TextView text4; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //レイアウトを作る LinearLayout layout1 = new LinearLayout(getActivity()); layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ text1 = new TextView(getActivity()); layout1.addView(text1); text2 = new TextView(getActivity()); layout1.addView(text2); text3 = new TextView(getActivity()); layout1.addView(text3); text4 = new TextView(getActivity()); layout1.addView(text4); text1.setText("TEXT1"); text2.setText("TEXT2"); text3.setText("TEXT3"); text4.setText("TEXT4"); //----------------------------------------- Button button1 = new Button(getActivity()); button1.setText("AsyncTaskLoader"); layout1.addView(button1); button1.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { CancelFlg2 = false; AsyncTaskCount1=0; ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; //フラグメントマネージャーで、フラグメントを取得 FragmentManager manager = getActivity().getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); frag1.updateText1("ボタンがおされた"); } }); return layout1; } public void updateText1(String s1){ text1.setText(s1); } public void updateText2(String s1){ text2.setText(s1); } public void updateText3(String s1){ text3.setText(s1); } public void updateText4(String s1){ text4.setText(s1); } //--------------------------------------------------------------------------------------- public void ToAsyncTaskLoader1(int count_Id1){ //count_Id1を、LoaderのIDとする //タスクの重複起動をさせない場合直前に起動したLoaderを止める if(count_Id1>0){ //ここでは、キャンセルを指示するだけなので処理は止まらない //実際の処理の中断は、loaderの中で処理する //中断1//すぐにonStopLoadingが呼ばれる getActivity().getSupportLoaderManager().getLoader(count_Id1-1).stopLoading(); //中断2//すぐにonResetが呼ばれる //getActivity().getSupportLoaderManager().destroyLoader(count_Id1-1); //中断3//loadInBackgroundの処理が終わった後にonCanceledが呼ばれる //((AsyncTaskLoader<Object>) getActivity().getSupportLoaderManager().getLoader(count_Id1-1)).cancelLoad(); } //LoaderにデータをBundleで渡す String ctl = Integer.toString(count_Id1); Bundle args = new Bundle(); args.putString("COUNT1", ctl); //--------------------------------------------------------------- //Loaderを起動する //起動1//IDごとに1回づつに実行//処理中に同じIDで起動しても前の処理が優先される getActivity().getSupportLoaderManager().initLoader(count_Id1, args, loaderCalBack); //起動2//同じIDが来たら、新規Loaderとして実行//前のLoaderも処理が続行され、処理後にonCanceledが呼ばれる //getActivity().getSupportLoaderManager().restartLoader(count_Id1, args, loaderCalBack); //--------------------------------------------------------------- } //--------------------------------------------------------------------------------------- private final LoaderManager.LoaderCallbacks<Bitmap> loaderCalBack = new LoaderManager.LoaderCallbacks<Bitmap>(){ //LoaderのIDを保存しておく int Loader_Id1; @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader " + String.valueOf(id)); //プログレスダイアログ表示 ProgressDialogFragment dialog = new ProgressDialogFragment(); //dialog = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("TITLE", "おまちください"); args.putString("MESSAGE", "画像ロード中"); dialog.setArguments(args); dialog.show(getActivity().getSupportFragmentManager(), "PROGRESS"); AsyncTaskFlg1 =1; Loader_Id1 =id; return new StartAsyncTaskLoader1(getActivity(),Loader_Id1,dialog); } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished " + String.valueOf(Loader_Id1)); FragmentManager manager = getActivity().getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText4( "AsyncTaskLoader 終了 ID = " + loader.getId()); //ローダーのID取得 //プログレスダイアログを閉じる ProgressDialogFragment dialog = (ProgressDialogFragment)getActivity().getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) dialog.onDismiss(dialog.getDialog()); AsyncTaskFlg1 =3; } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onLoaderReset " + String.valueOf(Loader_Id1)); } }; } }






アクティビティ生成時に「initLoader()」を、実行しておく。


「処理中に回転させると、onLoadFinished()が、呼ばれない!」という不具合がやっと直ったかもしれません。

「LoaderManager」を、 onCreate()からonStart()あたりで実行させなければいけないらしい、という情報は得ていたのですが、
それを、どのように具体的に書けばいいのか、試行錯誤していたわけですが、
ようするに、回転させると、アクティビティが破棄されて、コールバックされる元が不明になるのが、よろしくないわけです。

で、あるならば、アクティビティが再生成されたときに、速やかにinitLoader()なり、restartLoader()なりを実行させて、
コールバックされるべきアクティビティはここだよと、LoaderManagerに再指定してやればいいというわけでしょう。

必ずしも、onCreate()で、LoaderManagerを呼ばなくてはならないわけではなく、
ローダーが実行中に、画面回転などで、アクティビティが再生成された場合に限り、速やかに、LoaderManagerを起動すればいい。
それは、実行される必要の無いダミーでかまわない。そのような設計のコードを書けばいい。
実行中のローダーを妨げてはいけないので、initLoader()のほうが、restartLoader()より都合がいいというわけです。

そうとわかれば、話は簡単です。

ライフサイクルを考慮し、onStart()の中で、以下のように書いてみる。


@Override protected void onStart() { super.onStart(); getSupportLoaderManager().initLoader(0, null, this); }


initLoaderのIDに、すでに使われてる番号を指定すれば、実行されずに、コールバックの設定だけがなされます。
これで、現在実行中のローダーのコールバック先が、現在のアクティビティに設定されたことになります。

処理中に画面回転しても、きちんと、onLoadFinished()が呼ばれるようになりました。

上の例は、LoaderManager.LoaderCallbacksをアクティビティにインプリメントした場合として、thisを代入しています。
必ずしもインプリメントの必要は無いようです。

「AsyncTaskLoaderから、フラグメントに通知する」の例の場合、onStart()を以下のように変更すればOKです。


@Override protected void onStart() { super.onStart(); //画面が回転するなどして再生成された場合、まだロード中か? if(AsyncTaskFlg1!=0){ //ダミーでローダー呼び出す //実行されなくてもいい FragmentManager manager = getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); //ID番号をひとつ戻して呼び出す frag1.ToAsyncTaskLoader1(AsyncTaskIdCount1-1); } }


ついでに、「implements LoaderManager.LoaderCallbacks」したコードを載せておきます。

MainActivity.java

package com.example.test34; import java.util.Timer; import java.util.TimerTask; import android.util.Log; import android.os.Bundle; import android.app.Dialog; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.support.v4.app.FragmentActivity; import android.support.v4.app.DialogFragment; //こちらをインポートする //import android.app.DialogFragment; //これをインポートするとエラー import android.support.v4.app.Fragment; //これをインポートすること //import android.app.Fragment; //これをインポートするとエラー import android.support.v4.app.FragmentTransaction; //これをインポートすること //import android.app.FragmentTransaction; //これをインポートするとエラー import android.support.v4.app.FragmentManager; //これをインポートすること //import android.app.FragmentManager; //これをインポートするとエラー import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.graphics.Bitmap; public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks <Bitmap> { Timer timer1 = new Timer(); static int TimerCount1 = 0; static int AsyncTaskIdCount1=0; static int AsyncTaskRunCount1=0; static int AsyncTaskCount1=0; static MainActivity MainAct1; //画面回転対応 static boolean CancelFlg2 = false; //画面回転対応 static int AsyncTaskFlg1=0; //画面回転対応 private static final int LAYOUT_ID1 = 777; //フラグメントのレイアウトID @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //親レイアウト LinearLayout L_layout1 = new LinearLayout(this); setContentView(L_layout1); L_layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ //---------------------------------------- //子レイアウト(フラグメント)を親レイアウト1に追加 LinearLayout L_layout2 = new LinearLayout(this); L_layout1.addView(L_layout2); //子レイアウト2に、フラグメントを設定するためのID L_layout2.setId(LAYOUT_ID1); //------------------------------------- MainAct1 = MainActivity.this; //画面回転対応//現在のアクティビティを取得 if(savedInstanceState==null){ //はじめにアクティビティが生成された時に1度だけフラグメントをつくる FragmentManager manager = getSupportFragmentManager(); FragmentTransaction ft = manager.beginTransaction(); FragmentF1 frag1 = new FragmentF1(); //フラグメントにタグ付きで追加する ft.add(LAYOUT_ID1, frag1,"TAG_FRAGMENT1"); ft.commit(); } ToTimerTask1(); } @Override protected void onStart() { super.onStart(); //画面が回転するなどして再生成された場合、まだロード中か? if(AsyncTaskFlg1!=0){ //ダミーでローダー呼び出す //実行されなくてもいい getSupportLoaderManager().initLoader(AsyncTaskIdCount1-1, null, this); } } //----------------------------------------------------------------------- private void ToTimerTask1(){ //タイマータスクで一定時間おきにカウントする timer1.scheduleAtFixedRate(new TimerTask() { @Override public void run() { TimerCount1 += 1; //Log.d("TAG_TIMER", String.valueOf(TimerCount1 )); runOnUiThread(new Runnable() { public void run() { FragmentManager manager = getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null){ frag1.updateText1("TimerCount1 / AsyncTaskRunCount1 = " + String.valueOf(TimerCount1) + " / " + String.valueOf(AsyncTaskRunCount1)); } } }); } }, 0, 1000); } public void ToAsyncTaskLoader1(int count_Id1){ //count_Id1を、LoaderのIDとする //タスクの重複起動をさせない場合直前に起動したLoaderを止める if(count_Id1>0){ //ここでは、キャンセルを指示するだけなので処理は止まらない //実際の処理の中断は、loaderの中で処理する //中断1//すぐにonStopLoadingが呼ばれる getSupportLoaderManager().getLoader(count_Id1-1).stopLoading(); //中断2//すぐにonResetが呼ばれる //getSupportLoaderManager().destroyLoader(count_Id1-1); //中断3//loadInBackgroundの処理が終わった後にonCanceledが呼ばれる //((AsyncTaskLoader<Object>)getSupportLoaderManager().getLoader(count_Id1-1)).cancelLoad(); } //LoaderにデータをBundleで渡す String ctl = Integer.toString(count_Id1); Bundle args = new Bundle(); args.putString("COUNT1", ctl); //--------------------------------------------------------------- //Loaderを起動する //起動1//IDごとに1回づつに実行//処理中に同じIDで起動しても前の処理が優先される getSupportLoaderManager().initLoader(count_Id1, args, this); //起動2//同じIDが来たら、新規Loaderとして実行//前のLoaderも処理が続行され、処理後にonCanceledが呼ばれる //getSupportLoaderManager().restartLoader(count_Id1, args, this); //--------------------------------------------------------------- } //---------------------------------------------------------------- //インナークラスをstaticにすること public static class StartAsyncTaskLoader1 extends AsyncTaskLoader<Bitmap> { int AsyncTaskLoadercount1=0; int AsyncTaskLoadercount2=0; MainActivity ma; boolean CancelFlg1 = false; ProgressDialogFragment dialog; //コンストラクタ StartAsyncTaskLoader1(Context context,int Id,ProgressDialogFragment dlg){ super(context); //LoaderのID AsyncTaskLoadercount1 = Id; Log.d("TAG_TASKLOADER2", "StartAsyncTaskLoader1 " + String.valueOf(AsyncTaskLoadercount1)); ma = (MainActivity)context; dialog = dlg; } @Override public Bitmap loadInBackground() { // TODO 自動生成されたメソッド・スタブ AsyncTaskFlg1 = 2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " AsyncTaskCount1 "+ String.valueOf(AsyncTaskCount1)); for(int i=AsyncTaskCount1;i<100;i++){ //画面回転対応//アクティビティ情報を最新に更新 ma = MainAct1; //ダイアログからキャンセルされた? CancelFlg1 = dialog.DialogCanselFlg1; //キャンセルしようとして、CancelFlg1=trueになった場合は中断する //画面回転後にキャンセルしようとして、static の CancelFlg2=trueになった場合は中断する if (CancelFlg1==true || CancelFlg2==true) { Log.d("TAG_TASKLOADER2", "キャンセルされた " + String.valueOf(CancelFlg1) + " / " + String.valueOf(CancelFlg2)); ma.runOnUiThread(new Runnable() { @Override public void run(){ FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText3( "AsyncTaskLoader 中断された ID = " + String.valueOf(AsyncTaskLoadercount1) + " 中断 = " + String.valueOf(AsyncTaskLoadercount2)); } }); //タスクが終わった AsyncTaskRunCount1--; CancelFlg1 = false; CancelFlg2 = false; return null; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } AsyncTaskLoadercount2=i+1; AsyncTaskCount1 = AsyncTaskLoadercount2; Log.d("TAG_TASKLOADER2", "loadInBackground " + String.valueOf(AsyncTaskLoadercount1) + " - " + String.valueOf(AsyncTaskLoadercount2)); //UIを更新 ma.runOnUiThread(new Runnable() { @Override public void run() { FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText2( "AsyncTaskLoader 起動中 ID = " + String.valueOf(AsyncTaskLoadercount1) + " Progress = " + String.valueOf(AsyncTaskLoadercount2)); } }); //画面回転対応 //現在のダイアログを取得 ProgressDialogFragment dialog = (ProgressDialogFragment)ma.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); //進捗情報更新 if (dialog != null) dialog.updateProgress(AsyncTaskCount1); } //タスクが終わった AsyncTaskRunCount1--; //Bitmapをロードしたつもり Bitmap bitmap =null; //読み出したBitmapを返す return bitmap; } @Override public void onCanceled(Bitmap data) { super.onCanceled(data); Log.d("TAG_TASKLOADER2", "onCanceled " + String.valueOf(AsyncTaskLoadercount1)); //cancelLoad()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる //処理中にrestartLoader()が実行された場合、loadInBackgroundの処理が終わった後に呼ばれる } @Override protected void onStartLoading() { // Loader開始時に呼ばれる Log.d("TAG_TASKLOADER2", "onStartLoading " + String.valueOf(AsyncTaskLoadercount1)); //タスクが始まった AsyncTaskRunCount1++; // Loaderを開始 forceLoad(); } @Override protected void onStopLoading() { super.onStopLoading(); //stopLoading()ですぐに呼ばれる Log.d("TAG_TASKLOADER2", "onStopLoading " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; //cancelLoad(); //不要? } @Override protected void onReset() { super.onReset(); //destroyLoader()ですぐに呼ばれる //restartLoader()が実行された場合に、onLoadFinished()後に呼ばれる Log.d("TAG_TASKLOADER2", "onReset " + String.valueOf(AsyncTaskLoadercount1)); //loadInBackground()の処理を中断するためにフラグをtrueにする CancelFlg1 = true; //cancelLoad(); //不要? //onStopLoading(); //不要? } @Override public void deliverResult(Bitmap data) { super.deliverResult(data); //これが無いと処理終了後に、onLoadFinished()が呼ばれない //処理の終了時に呼ばれる Log.d("TAG_TASKLOADER2", "deliverResult" + String.valueOf(AsyncTaskLoadercount1)); ProgressDialogFragment dialog = (ProgressDialogFragment)MainAct1.getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) { //ダイアログ消す dialog.onDismiss(dialog.getDialog()); } //onLoadFinishedを通過した if(AsyncTaskFlg1==3) AsyncTaskFlg1 = 0; else AsyncTaskFlg1 = 4; if(AsyncTaskFlg1==4){ FragmentManager manager = ma.getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); AsyncTaskFlg1=0; frag1.updateText4( "AsyncTaskLoader 終了 onLoadFinished が呼ばれませんでした"); } } } //------------------------------------------------------------------ //プログレスダイアログフラグメント public static class ProgressDialogFragment extends DialogFragment { ProgressDialog dialog ; Boolean DialogCanselFlg1=false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { dialog = new ProgressDialog(getActivity()); dialog.setTitle(getArguments().getString("TITLE")); dialog.setMessage(getArguments().getString("MESSAGE")); //dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//くるくる //dialog.setIndeterminate(true);//進捗不確定モード dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//プログレスバー dialog.setMax(100); dialog.setProgress(AsyncTaskCount1); //ダイアログをキャンセルできるようにする//ダイアログフラグメントは勝手に消える? dialog.setCancelable(true); dialog.setOnCancelListener(this); return dialog; } @Override public void onCancel(DialogInterface dialog) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_PROGRESS", "onCancel"); //キャンセルするするフラグをたてる DialogCanselFlg1 = true; CancelFlg2 = true; } public void updateProgress(int value){ if (dialog != null) dialog.setProgress(value); } } //----------------------------------------------------------------------------------- //フラグメント public static class FragmentF1 extends Fragment{ public FragmentF1() {} TextView text1; TextView text2; TextView text3; TextView text4; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //レイアウトを作る LinearLayout layout1 = new LinearLayout(getActivity()); layout1.setOrientation(LinearLayout.VERTICAL); //縦に並ぶ text1 = new TextView(getActivity()); layout1.addView(text1); text2 = new TextView(getActivity()); layout1.addView(text2); text3 = new TextView(getActivity()); layout1.addView(text3); text4 = new TextView(getActivity()); layout1.addView(text4); text1.setText("TEXT1"); text2.setText("TEXT2"); text3.setText("TEXT3"); text4.setText("TEXT4"); //----------------------------------------- Button button1 = new Button(getActivity()); button1.setText("AsyncTaskLoader"); layout1.addView(button1); button1.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { CancelFlg2 = false; AsyncTaskCount1=0; ((MainActivity) getActivity()).ToAsyncTaskLoader1(AsyncTaskIdCount1); AsyncTaskIdCount1++; //フラグメントマネージャーで、フラグメントを取得 FragmentManager manager = getActivity().getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); frag1.updateText1("ボタンがおされた"); } }); return layout1; } public void updateText1(String s1){ text1.setText(s1); } public void updateText2(String s1){ text2.setText(s1); } public void updateText3(String s1){ text3.setText(s1); } public void updateText4(String s1){ text4.setText(s1); } } //---------------------------------------------------------------------------- //「implements LoaderManager.LoaderCallbacks 」で実装 @Override public Loader<Bitmap> onCreateLoader(int id, Bundle bundle) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onCreateLoader " + String.valueOf(id)); //プログレスダイアログ表示 ProgressDialogFragment dialog = new ProgressDialogFragment(); //dialog = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("TITLE", "おまちください"); args.putString("MESSAGE", "画像ロード中"); dialog.setArguments(args); dialog.show(getSupportFragmentManager(), "PROGRESS"); AsyncTaskFlg1 =1; return new StartAsyncTaskLoader1(MainActivity.this,id,dialog); } @Override public void onLoadFinished(Loader<Bitmap> loader, Bitmap result) { // TODO 自動生成されたメソッド・スタブ //Loaderの処理が終わった Log.d("TAG_TASKLOADER1", "onLoadFinished " + loader.getId()); FragmentManager manager = getSupportFragmentManager(); FragmentF1 frag1 = (FragmentF1)manager.findFragmentByTag("TAG_FRAGMENT1"); if(frag1!=null) frag1.updateText4( "AsyncTaskLoader 終了 ID = " + loader.getId()); //ローダーのID取得 //プログレスダイアログを閉じる ProgressDialogFragment dialog = (ProgressDialogFragment)getSupportFragmentManager() .findFragmentByTag("PROGRESS"); if (dialog != null) dialog.onDismiss(dialog.getDialog()); AsyncTaskFlg1 =3; } @Override public void onLoaderReset(Loader<Bitmap> loader) { // TODO 自動生成されたメソッド・スタブ Log.d("TAG_TASKLOADER1", "onLoaderReset " + loader.getId()); } }




メモ


どうも、ダイアログを出したまま、「ホームキー」を押してホームに戻り、画面回転させて、またアプリに戻ったりすると、
これまたいろいろと問題が発生するようだ。
ダイアログが出たままだったり。

こんなときは、どこかのタイミングで、自分でダイアログを消してあげないといけない。
ProgressDialogFragmentのonStart()で、処理が終わっていたらダイアログを消してやればOKっぽい。

ホームからアプリに戻ると、勝手にloadInBackgroundが起動したりする場合がある気がする。
対応は結構面倒くさい。

また、LoaderをIDごとに止める場合でも、stopLoading()や、cancelLoad()で止めておくだけだと、エラーが出ることがある。
destroyLoader()してやったほうが、安全なようだ。




















戻る