[解決済み] Android Fragmentsです。画面回転や構成変更時にAsyncTaskを保持する方法
質問
スマートフォン/タブレット用アプリで、APKを1つだけ使用し、画面サイズに応じて必要なリソースをロードする作業を行っていますが、ACL経由でフラグメントを使用するのが最適なデザインだと思われます。
このアプリは、これまでアクティビティベースのみで正常に動作していました。画面が回転したり、通信の途中で設定が変わったりしても動作するように、ActivityでAsyncTasksとProgressDialogsをどのように扱うかのモッククラスです。
アクティビティが再現されないようにマニフェストを変更するつもりはありません。そうしたくない理由はたくさんありますが、主に公式ドキュメントに推奨されないと書かれており、これまでそうせずに管理してきたので、そのルートを推奨しないでください。
public class Login extends Activity {
static ProgressDialog pd;
AsyncTask<String, Void, Boolean> asyncLoginThread;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.login);
//SETUP UI OBJECTS
restoreAsyncTask();
}
@Override
public Object onRetainNonConfigurationInstance() {
if (pd != null) pd.dismiss();
if (asyncLoginThread != null) return (asyncLoginThread);
return super.onRetainNonConfigurationInstance();
}
private void restoreAsyncTask();() {
pd = new ProgressDialog(Login.this);
if (getLastNonConfigurationInstance() != null) {
asyncLoginThread = (AsyncTask<String, Void, Boolean>) getLastNonConfigurationInstance();
if (asyncLoginThread != null) {
if (!(asyncLoginThread.getStatus()
.equals(AsyncTask.Status.FINISHED))) {
showProgressDialog();
}
}
}
}
public class LoginThread extends AsyncTask<String, Void, Boolean> {
@Override
protected Boolean doInBackground(String... args) {
try {
//Connect to WS, recieve a JSON/XML Response
//Place it somewhere I can use it.
} catch (Exception e) {
return true;
}
return true;
}
protected void onPostExecute(Boolean result) {
if (result) {
pd.dismiss();
//Handle the response. Either deny entry or launch new Login Succesful Activity
}
}
}
}
このコードは問題なく動作しており、約10,000人のユーザーを抱えていますが、不満はありません。したがって、このロジックを新しいフラグメントベース設計にコピーするのが論理的だと思われましたが、もちろん、それはうまくいきません。
これがLoginFragmentです。
public class LoginFragment extends Fragment {
FragmentActivity parentActivity;
static ProgressDialog pd;
AsyncTask<String, Void, Boolean> asyncLoginThread;
public interface OnLoginSuccessfulListener {
public void onLoginSuccessful(GlobalContainer globalContainer);
}
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
//Save some stuff for the UI State
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setRetainInstance(true);
//If I setRetainInstance(true), savedInstanceState is always null. Besides that, when loading UI State, a NPE is thrown when looking for UI Objects.
parentActivity = getActivity();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
loginSuccessfulListener = (OnLoginSuccessfulListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnLoginSuccessfulListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RelativeLayout loginLayout = (RelativeLayout) inflater.inflate(R.layout.login, container, false);
return loginLayout;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//SETUP UI OBJECTS
if(savedInstanceState != null){
//Reload UI state. Im doing this properly, keeping the content of the UI objects, not the object it self to avoid memory leaks.
}
}
public class LoginThread extends AsyncTask<String, Void, Boolean> {
@Override
protected Boolean doInBackground(String... args) {
try {
//Connect to WS, recieve a JSON/XML Response
//Place it somewhere I can use it.
} catch (Exception e) {
return true;
}
return true;
}
protected void onPostExecute(Boolean result) {
if (result) {
pd.dismiss();
//Handle the response. Either deny entry or launch new Login Succesful Activity
}
}
}
}
}
私は
onRetainNonConfigurationInstance()
はフラグメントではなくアクティビティから呼ばれなければならないので使えません。
getLastNonConfigurationInstance()
. 私はここでいくつかの同様の質問を読みましたが、答えはありません。
私は、このようなものをフラグメントで適切に整理するために、いくつかの作業が必要になるかもしれないことを理解しています。そうはいっても、私は同じ基本設計ロジックを維持したいと思います。
AsyncTaskはフラグメントの内部クラスであり、AsyncTask.execute()を呼び出すのはフラグメント自身であることを考慮して、設定変更中にAsyncTaskを保持し、まだ実行中であればprogressDialogを表示するには、どのような方法が適切でしょうか?
どのように解決するのですか?
フラグメントを使えば、実はもっと簡単にできます。 ただ、メソッド フラグメント.setRetainInstance(boolean) を使用するだけで、設定の変更に関わらずフラグメントのインスタンスを保持することができます。 なお、これは Activity.onRetainnonConfigurationInstance()の代わりに推奨されるものです。 に代わるものとして推奨されています。
何らかの理由でリテインされたフラグメントをどうしても使いたくない場合、他のアプローチもあります。 各フラグメントには フラグメント.getId() . また、あるフラグメントが設定変更のために破棄されているかどうかを調べるには、次のようにします。 Fragment.getActivity().isChangingConfigurations()を使って調べることができます。 . したがって、AsyncTask を停止する時点(おそらく onStop() または onDestroy() で)で、たとえば設定が変更されているかどうかを確認し、変更されている場合はフラグメントの識別子の下の静的 SparseArray にそれを格納し、次に onCreate() または onStart() で疎配列内の AsyncTask を使用できるかどうか確認することができます。
関連
-
[解決済み] Androidで画面の大きさをピクセル単位で取得する方法
-
[解決済み] Androidのローテーションでアクティビティを再開する
-
[解決済み] AsyncTaskのAndroidサンプル
-
[解決済み] FragmentのsetRetainInstance(boolean)を理解する。
-
[解決済み] ArrayAdapter<myClass> の使用方法
-
[解決済み] プログラムでソフトキーボードを開く
-
[解決済み] データベースでリサイクルビューを使用する
-
[解決済み] FragmentPagerAdapterのgetItemが呼び出されない
-
[解決済み] Android Lintが翻訳されていない文字列を訴えないようにする。
-
[解決済み] AsyncTaskLoaderとAsyncTaskの比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】プログレスダイアログとバックグラウンドスレッドがアクティブなときに、画面の向きが変わるのをどう処理するか?
-
[解決済み】バックグラウンドタスク、プログレスダイアログ、オリエンテーションの変更 - 100%動作する解決策はありますか?
-
[解決済み] Android Debug Bridgeでアプリケーションのインストール時にINSTALL_FAILED_VERSION_DOWNGRADEを無視する方法はありますか?
-
[解決済み] プログラムでソフトキーボードを開く
-
[解決済み] AndroidでラジオボタンにOnClickListenerを設定するには?
-
[解決済み] ViewPagerのアイテムを強制的に再インスタンス化する方法 [重複].
-
[解決済み] DialogFragmentを正しく終了させるには?
-
[解決済み] APKが署名済みかデバッグビルドかを確認するには?
-
[解決済み] BottomNavigationViewを新しいNavControllerで使用する際に、フラグメントを生かす方法はありますか?
-
[解決済み] スクリーンローテーション中にAsyncTaskを処理するには?