LoginActivity
(ユーザーログイン)があります。基本的に、ダイアログのようにテーマが設定されているのは独自のActivity
です(ダイアログのように表示されます)。 SherlockFragmentActivity
の上に表示されます。私が欲しいのは:ログインに成功した場合、ビューを更新するために2つのFragmentTransaction
が必要です。コードは次のとおりです。
LoginActivity
で、ログインに成功した場合、
setResult(1, new Intent());
SherlockFragmentActivity
で:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 1) {
LoggedStatus = PrefActivity.getUserLoggedInStatus(this);
FragmentTransaction t = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
SherlockListFragment mFrag = new MasterFragment();
t.replace(R.id.menu_frame, mFrag);
t.commit();
// Set up Main Screen
FragmentTransaction t2 = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
SherlockListFragment mainFrag = new FeaturedFragment();
t2.replace(R.id.main_frag, mainFrag);
t2.commit();
}
}
このLogCatを使用すると、最初のコミットでクラッシュします。
E/AndroidRuntime(32072): Caused by: Java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
E/AndroidRuntime(32072): at Android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.Java:1299)
E/AndroidRuntime(32072): at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1310)
E/AndroidRuntime(32072): at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:541)
E/AndroidRuntime(32072): at Android.support.v4.app.BackStackRecord.commit(BackStackRecord.Java:525)
E/AndroidRuntime(32072): at com.kickinglettuce.rate_this.MainFragmentActivity.onActivityResult(MainFragmentActivity.Java:243)
E/AndroidRuntime(32072): at Android.app.Activity.dispatchActivityResult(Activity.Java:5293)
E/AndroidRuntime(32072): at Android.app.ActivityThread.deliverResults(ActivityThread.Java:3315)
まず、詳細については、私の blog post を読む必要があります(この例外が発生する理由とできることについて説明しています)それを防ぐために行う)。
commitAllowingStateLoss()
を呼び出すことは、修正というよりもハッキングです。州の損失はひどいものであり、どんな犠牲を払っても避けるべきです。 onActivityResult()
が呼び出された時点では、アクティビティ/フラグメントの状態はまだ復元されていない可能性があるため、この間に発生したトランザクションはすべて失われます。これは非常に重要なバグであり、対処する必要があります! (このバグは、システムによって殺された後にActivity
が戻ってきたときにのみ発生することに注意してください...デバイスのメモリ量によっては、まれに発生することがあります...バグはテスト中に見つけるのが非常に簡単なものではありません)。
代わりにトランザクションをonPostResume()
に移動してみてください(onPostResume()
の後にonResume()
が常に呼び出され、onResume()
の後にonActivityResult()
が常に呼び出されることに注意してください):
private boolean mReturningWithResult = false;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mReturningWithResult = true;
}
@Override
protected void onPostResume() {
super.onPostResume();
if (mReturningWithResult) {
// Commit your transactions here.
}
// Reset the boolean flag back to false for next time.
mReturningWithResult = false;
}
これは少し奇妙に思えるかもしれませんが、FragmentTransaction
sが常にコミットされるようにするには、この種のことを行う必要がありますafterActivity
の状態が元の状態に復元されました状態(onPostResume()
はActivity
の状態が復元された後に呼び出されることが保証されています)。
これは@Alex Lockwoodの回答に似ていますが、Runnable
を使用します。
private Runnable mOnActivityResultTask;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mOnActivityResultTask = new Runnable() {
@Override
public void run() {
// Your code here
}
}
}
@Override
protected void onPostResume() {
super.onPostResume();
if (mOnActivityResultTask != null) {
mOnActivityResultTask.run();
mOnActivityResultTask = null;
}
}
Android 3.以上でlambdasを指定して実行している場合、これを使用します:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mOnActivityResultTask = () -> {
// Your code here
}
}