IllegalStateException: ไม่สามารถทำการกระทำนี้หลังจาก onSaveInstanceState ด้วย ViewPager


496

ฉันได้รับรายงานผู้ใช้จากแอพของฉันในตลาดโดยให้ข้อยกเว้นต่อไปนี้:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)

เห็นได้ชัดว่ามีบางอย่างเกี่ยวข้องกับ FragmentManager ซึ่งฉันไม่ได้ใช้ สแต็คเทรซไม่แสดงคลาสใด ๆ ของฉันเองดังนั้นฉันจึงไม่รู้ว่าเกิดข้อยกเว้นนี้ขึ้นที่ใดและจะป้องกันอย่างไร

สำหรับบันทึก: ฉันมี tabhost และในแต่ละแท็บจะมีการสลับกลุ่มกิจกรรมระหว่างกิจกรรม


2
ฉันพบคำถามนี้เกี่ยวกับปัญหาเดียวกัน แต่ไม่มีวิธีแก้ปัญหา .. stackoverflow.com/questions/7469082/…
nhaarman

3
ในขณะที่คุณไม่ได้ใช้FragmentManagerHoneycomb จะเป็นเช่นนั้น สิ่งนี้เกิดขึ้นกับแท็บเล็ต Honeycomb จริงหรือไม่ หรืออาจเป็นไปได้ว่ามีใครบางคนกำลังเรียกใช้ Honeycomb ที่ถูกแฮกบนโทรศัพท์หรือบางสิ่งและมันเป็นรุ่นที่ถูกแฮ็กที่มีปัญหาหรือไม่?
CommonsWare

1
ฉันไม่รู้. นี่เป็นข้อมูลเดียวที่ฉันได้รับใน Market Developer Console ข้อความผู้ใช้ไม่มีข้อมูลที่เป็นประโยชน์อย่างใดอย่างหนึ่ง ..
nhaarman

ฉันใช้ Flurry ซึ่งแสดงให้ฉัน 11 ครั้งด้วย Android 3.0.1 และฉันมีรายงาน 11 ข้อยกเว้นนี้ อาจเป็นเรื่องบังเอิญแม้ว่า Android 3.1 และ 3.2 มี 56 และ 38 ครั้งตามลำดับ
nhaarman

รายงานข้อผิดพลาดของตลาดมีส่วน 'แพลตฟอร์ม' บางครั้งก็มีรุ่นของอุปกรณ์ Android อยู่ในนั้น
Nikolay Elenkov

คำตอบ:


720

โปรดตรวจสอบคำตอบของฉันที่นี่ โดยทั่วไปฉันต้อง:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

อย่าโทรไปsuper()ที่saveInstanceStateวิธีการ นี่เป็นสิ่งที่เลอะ ...

นี่เป็นข้อผิดพลาดที่รู้จักในแพ็คเกจสนับสนุน

หากคุณต้องการบันทึกอินสแตนซ์และเพิ่มบางสิ่งลงในของoutState Bundleคุณคุณสามารถใช้สิ่งต่อไปนี้:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

ในที่สุดการแก้ปัญหาที่เหมาะสมคือ (เท่าที่เห็นในความคิดเห็น) ที่จะใช้:

transaction.commitAllowingStateLoss();

เมื่อมีการเพิ่มหรือการปฏิบัติที่ก่อให้เกิดFragmentTransactionException


370
คุณควรใช้ commitAllowingStateLoss () แทนการกระทำ ()
Meh

18
ความคิดเห็นเกี่ยวกับ commitAllowingStateLoss () นี้เป็นคำตอบในสิทธิของตนเอง - คุณควรโพสต์ข้อความนั้น
Risadinha

20
เกี่ยวกับ 'commitAllowingStateLoss' - /> "นี่เป็นอันตรายเพราะการกระทำสามารถสูญหายได้หากกิจกรรมจำเป็นต้องกู้คืนจากสถานะในภายหลังดังนั้นควรใช้กรณีนี้ในกรณีที่โอเคสำหรับสถานะ UI ที่เปลี่ยนไปโดยไม่คาดคิด ผู้ใช้งาน."
Codeversed

10
ถ้าฉันดูที่แหล่ง v4 popBackStackImmediateมันจะล้มเหลวทันทีหากมีการบันทึกสถานะ ก่อนหน้านี้การเพิ่มส่วนด้วยcommitAllowingStateLossไม่เล่นส่วนใดส่วนหนึ่ง การทดสอบของฉันแสดงให้เห็นว่าสิ่งนี้เป็นจริง ไม่มีผลกับข้อยกเว้นเฉพาะนี้ สิ่งที่เราต้องการคือpopBackStackImmediateAllowingStateLossวิธีการ
Synesso

3
@DanieleB ใช่ฉันได้โพสต์คำตอบไว้ที่นี่ แต่ฉันได้พบวิธีแก้ปัญหาที่ดียิ่งขึ้นโดยใช้ Otto message bus: ลงทะเบียนแฟรกเมนต์เป็นสมาชิกและรับฟังผลลัพธ์ async จากบัส ยกเลิกการลงทะเบียนเมื่อหยุดชั่วคราวและลงทะเบียนใหม่ในประวัติย่อ async ยังต้องการวิธีการผลิตสำหรับเวลาที่มันเสร็จสมบูรณ์และชิ้นส่วนถูกหยุดชั่วคราว เมื่อฉันได้รับเวลาฉันจะอัปเดตคำตอบของฉันในรายละเอียดเพิ่มเติม
Synesso

130

มีปัญหามากมายที่เกี่ยวข้องกับข้อความแสดงข้อผิดพลาดที่คล้ายกัน ตรวจสอบบรรทัดที่สองของการติดตามสแต็กนี้โดยเฉพาะ ข้อยกเว้นนี้เกี่ยวข้องกับการเรียกไปยังFragmentManagerImpl.popBackStackImmediateโดยเฉพาะ

การเรียกใช้เมธอดนี้popBackStackจะล้มเหลวเสมอIllegalStateExceptionหากสถานะเซสชันได้รับการบันทึกแล้ว ตรวจสอบแหล่งที่มา ไม่มีสิ่งใดที่คุณสามารถทำได้เพื่อหยุดข้อยกเว้นนี้

  • การลบการโทรไปยังsuper.onSaveInstanceStateจะไม่ช่วย
  • การสร้างแฟรกเมนต์ด้วยcommitAllowingStateLossจะไม่ช่วย

นี่คือวิธีที่ฉันสังเกตเห็นปัญหา:

  • มีแบบฟอร์มพร้อมปุ่มส่ง
  • เมื่อคลิกปุ่มไดอะล็อกจะถูกสร้างขึ้นและกระบวนการ async จะเริ่มขึ้น
  • ผู้ใช้คลิกที่ปุ่มโฮมก่อนที่กระบวนการจะเสร็จสิ้น - onSaveInstanceStateถูกเรียกใช้
  • กระบวนการเสร็จสมบูรณ์มีการติดต่อกลับและpopBackStackImmediateพยายาม
  • IllegalStateException ถูกโยนทิ้ง

นี่คือสิ่งที่ฉันทำเพื่อแก้ไข:

เนื่องจากเป็นไปไม่ได้ที่จะหลีกเลี่ยงIllegalStateExceptionในการติดต่อกลับ

try {
    activity.getSupportFragmentManager().popBackStackImmediate(name);
} catch (IllegalStateException ignored) {
    // There's no way to avoid getting this if saveInstanceState has already been called.
}

นี่เป็นการเพียงพอที่จะหยุดไม่ให้แอปหยุดทำงาน แต่ตอนนี้ผู้ใช้จะคืนค่าแอปและเห็นว่าปุ่มที่พวกเขาคิดว่าพวกเขากดไม่ได้ถูกกดเลย (พวกเขาคิดว่า) แฟรกเมนต์ฟอร์มยังคงแสดงอยู่!

เมื่อต้องการแก้ไขปัญหานี้เมื่อสร้างกล่องโต้ตอบให้สร้างสถานะเพื่อระบุว่ากระบวนการเริ่มทำงานแล้ว

progressDialog.show(fragmentManager, TAG);
submitPressed = true;

และบันทึกสถานะนี้ไว้ในชุดข้อมูล

@Override
public void onSaveInstanceState(Bundle outState) {
    ...
    outState.putBoolean(SUBMIT_PRESSED, submitPressed);
}

อย่าลืมโหลดมันอีกครั้ง onViewCreated

จากนั้นเมื่อกลับมาทำงานอีกครั้งให้ย้อนกลับชิ้นส่วนหากพยายามส่งไปก่อนหน้านี้ สิ่งนี้จะป้องกันผู้ใช้จากการกลับมาสู่สิ่งที่ดูเหมือนว่าฟอร์มที่ไม่ได้ส่ง

@Override
public void onResume() {
    super.onResume();
    if (submitPressed) {
        // no need to try-catch this, because we are not in a callback
        activity.getSupportFragmentManager().popBackStackImmediate(name);
        submitPressed = false;
    }
}

5
การอ่านที่น่าสนใจเกี่ยวกับที่นี่: androiddesignpatterns.com/2013/08/…
ปาสกาล

หากคุณใช้ DialogFragment ฉันได้สร้างทางเลือกให้กับมันที่นี่: github.com/AndroidDeveloperLB/DialogShard
นักพัฒนา Android

เกิดอะไรขึ้นถ้าpopBackStackImmediateAndroid ถูกเรียกตัวเอง?
Kimi Chiu

1
ยอดเยี่ยมอย่างแน่นอน อันนี้ควรเป็นคำตอบที่ได้รับการยอมรับ ขอบคุณมาก! บางทีฉันอาจเพิ่ม submitPressed = false; หลังจาก popBackStackInmediate
Neonigma

ฉันไม่ได้ใช้โมฆะสาธารณะ onSaveInstanceState (Bundle outState) วิธี ฉันต้องตั้งค่าวิธีว่างสำหรับโมฆะสาธารณะ onSaveInstanceState (Bundle outState) หรือไม่
Faxriddin Abdullayev

55

ตรวจสอบว่ากิจกรรมก่อนที่จะแสดงส่วนและใส่ใจกับisFinishing()commitAllowingStateLoss()

ตัวอย่าง:

if(!isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            DummyFragment dummyFragment = DummyFragment.newInstance();
            ft.add(R.id.dummy_fragment_layout, dummyFragment);
            ft.commitAllowingStateLoss();
}

1
! isFinishing () &&! isDestroyed () ไม่ทำงานสำหรับฉัน
Allen Vork

! isFinishing () &&! isDestroyed () ทำงานให้ฉัน แต่ต้องใช้ API 17. DialogFragmentแต่มันก็ไม่ได้แสดง ดูstackoverflow.com/questions/15729138/…สำหรับวิธีแก้ปัญหาที่ดีอื่น ๆstackoverflow.com/a/41813953/2914140ช่วยฉันด้วย
CoolMind

29

เป็นเดือนตุลาคม 2560 และ Google สร้างห้องสมุดสนับสนุน Android ด้วยสิ่งใหม่ ๆ ที่เรียกว่าคอมโพเนนต์ Lifecycle มันมีความคิดใหม่สำหรับปัญหานี้ 'ไม่สามารถทำการกระทำนี้หลังจากปัญหา onSaveInstanceState'

ในระยะสั้น:

  • ใช้ส่วนประกอบวงจรชีวิตเพื่อพิจารณาว่าถึงเวลาที่เหมาะสมในการเปิดส่วนย่อยของคุณหรือไม่

รุ่นที่ยาวขึ้นพร้อมคำอธิบาย:

  • ทำไมปัญหานี้ออกมา

    เป็นเพราะคุณกำลังพยายามที่จะใช้FragmentManagerจากกิจกรรมของคุณ (ซึ่งจะถือชิ้นส่วนของคุณฉันคิดว่า?) เพื่อทำธุรกรรมสำหรับคุณส่วน โดยปกติสิ่งนี้จะดูเหมือนว่าคุณกำลังพยายามทำธุรกรรมบางอย่างสำหรับส่วนที่กำลังจะมาถึงในขณะที่กิจกรรมโฮสต์เรียกsavedInstanceStateวิธีการแล้ว(ผู้ใช้อาจสัมผัสปุ่มโฮมเพื่อให้กิจกรรมเรียกonStop()ในกรณีของฉันมันเป็นเหตุผล)

    โดยปกติปัญหานี้ไม่ควรเกิดขึ้น - เราพยายามโหลดชิ้นส่วนเข้าสู่กิจกรรมในตอนเริ่มต้นเสมอเช่นonCreate()วิธีนี้เป็นสถานที่ที่สมบูรณ์แบบสำหรับสิ่งนี้ แต่บางครั้งสิ่งนี้เกิดขึ้นโดยเฉพาะอย่างยิ่งเมื่อคุณไม่สามารถตัดสินใจได้ว่าชิ้นส่วนใดที่คุณจะโหลดไปยังกิจกรรมนั้นหรือคุณกำลังพยายามโหลดชิ้นส่วนจากAsyncTaskบล็อก (หรืออะไรก็ตามจะใช้เวลาเล็กน้อย) เวลาก่อนที่การทำธุรกรรมแฟรกเมนต์จะเกิดขึ้นจริง แต่หลังจากonCreate()วิธีการของกิจกรรมผู้ใช้สามารถทำอะไรก็ได้ หากผู้ใช้กดปุ่มโฮมซึ่งเป็นต้นเหตุของonSavedInstanceState()วิธีการของกิจกรรมจะมีcan not perform this actionข้อผิดพลาด

    หากใครต้องการเห็นลึกลงไปในปัญหานี้ฉันขอแนะนำให้พวกเขาดูที่โพสต์บล็อกนี้ มันดูลึกลงไปในเลเยอร์ซอร์สโค้ดและอธิบายเกี่ยวกับมันมากมาย นอกจากนี้ยังให้เหตุผลที่คุณไม่ควรใช้commitAllowingStateLoss()วิธีการแก้ปัญหานี้ (เชื่อฉันว่ามันไม่มีอะไรดีสำหรับรหัสของคุณ)

  • จะแก้ไขได้อย่างไร?

    • ฉันควรใช้commitAllowingStateLoss()วิธีการโหลดชิ้นส่วนหรือไม่ ไม่คุณไม่ควร ;

    • ฉันควรจะแทนที่onSaveInstanceStateเมธอด, superเมธอดเมธอดด้านในหรือไม่? ไม่คุณไม่ควร ;

    • ฉันควรใช้isFinishingกิจกรรมภายในที่มีมนต์ขลังเพื่อตรวจสอบว่ากิจกรรมของโฮสต์อยู่ในช่วงเวลาที่เหมาะสมสำหรับธุรกรรมส่วน ใช่นี้ดูเหมือนว่าวิธีการที่เหมาะสมที่จะทำ

  • ดูที่ส่วนประกอบวงจรชีวิตสามารถทำอะไรได้บ้าง

    โดยทั่วไปของ Google ทำให้การดำเนินการบางอย่างภายในAppCompatActivityชั้น (และหลายชั้นฐานอื่น ๆ ที่คุณควรใช้ในโครงการของคุณ) ซึ่งจะทำให้มันง่ายต่อการตรวจสอบสถานะวงจรชีวิตปัจจุบัน กลับไปดูปัญหาของเรา: ทำไมปัญหานี้จะเกิดขึ้น เป็นเพราะเราทำอะไรผิดเวลา ดังนั้นเราจึงพยายามไม่ทำและปัญหานี้จะหมดไป

    ฉันรหัสเล็ก ๆ น้อย ๆ LifeCycleสำหรับโครงการของตัวเองนี่คือสิ่งที่ฉันจะใช้ ฉันรหัสใน Kotlin

val hostActivity: AppCompatActivity? = null // the activity to host fragments. It's value should be properly initialized.

fun dispatchFragment(frag: Fragment) {
    hostActivity?.let {
       if(it.lifecyclecurrentState.isAtLeast(Lifecycle.State.RESUMED)){
           showFragment(frag)
       }
    }
}

private fun showFragment(frag: Fragment) {
    hostActivity?.let {
        Transaction.begin(it, R.id.frag_container)
                .show(frag)
                .commit()
    }

ตามที่ฉันแสดงด้านบน ฉันจะตรวจสอบสถานะวงจรชีวิตของกิจกรรมโฮสต์ ด้วยคอมโพเนนต์วงจรชีวิตภายในไลบรารีการสนับสนุนสิ่งนี้อาจเฉพาะเจาะจงมากขึ้น รหัสlifecyclecurrentState.isAtLeast(Lifecycle.State.RESUMED)หมายถึงหากสถานะปัจจุบันเป็นอย่างน้อยonResumeไม่ช้ากว่าหรือไม่ ซึ่งทำให้แน่ใจว่าวิธีการของฉันจะไม่ถูกดำเนินการในช่วงชีวิตอื่น (เช่นonStop)

  • มันทำทั้งหมดแล้วเหรอ?

    ไม่แน่นอน รหัสที่ฉันแสดงบอกวิธีใหม่ในการป้องกันไม่ให้แอปพลิเคชันหยุดทำงาน แต่ถ้ามันเข้าสู่สถานะของonStopบรรทัดของโค้ดนั้นจะไม่ทำอะไรเลยและไม่แสดงอะไรบนหน้าจอของคุณ เมื่อผู้ใช้กลับมาที่แอปพลิเคชันพวกเขาจะเห็นหน้าจอที่ว่างเปล่านั่นเป็นกิจกรรมของโฮสต์ที่ว่างเปล่าซึ่งไม่มีการแยกส่วนเลย มันเป็นประสบการณ์ที่ไม่ดี (ใช่ดีกว่าความผิดพลาดเล็กน้อย)

    ดังนั้นที่นี่ฉันหวังว่าอาจมีสิ่งที่ดีกว่า: แอปจะไม่ผิดพลาดถ้ามันมาถึงชีวิตในภายหลังonResumeวิธีการทำธุรกรรมคือการตระหนักถึงสถานะของชีวิต; นอกจากนี้กิจกรรมจะพยายามดำเนินการทำธุรกรรมส่วนย่อยให้เสร็จสิ้นหลังจากที่ผู้ใช้กลับมาที่แอพของเรา

    ฉันจะเพิ่มวิธีการนี้:

class FragmentDispatcher(_host: FragmentActivity) : LifecycleObserver {
    private val hostActivity: FragmentActivity? = _host
    private val lifeCycle: Lifecycle? = _host.lifecycle
    private val profilePendingList = mutableListOf<BaseFragment>()

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun resume() {
        if (profilePendingList.isNotEmpty()) {
            showFragment(profilePendingList.last())
        }
    }

    fun dispatcherFragment(frag: BaseFragment) {
        if (lifeCycle?.currentState?.isAtLeast(Lifecycle.State.RESUMED) == true) {
            showFragment(frag)
        } else {
            profilePendingList.clear()
            profilePendingList.add(frag)
        }
    }

    private fun showFragment(frag: BaseFragment) {
        hostActivity?.let {
            Transaction.begin(it, R.id.frag_container)
                    .show(frag)
                    .commit()
        }
    }
}

ฉันเก็บรายการไว้ในdispatcherคลาสนี้เพื่อเก็บชิ้นส่วนเหล่านั้นไม่มีโอกาสที่จะทำธุรกรรมให้เสร็จ และเมื่อผู้ใช้กลับมาจากหน้าจอหลักและพบว่ายังคงมีแฟรกเมนต์รอให้เปิดใช้งานผู้ใช้จะไปที่resume()วิธีการภายใต้@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)คำอธิบายประกอบ ตอนนี้ฉันคิดว่ามันควรจะทำงานอย่างที่ฉันคาดไว้


8
มันจะดีถ้าใช้ Java แทน Kotlin
Shchvova

1
เหตุใดการFragmentDispatcherใช้งานรายการเพื่อจัดเก็บชิ้นส่วนที่รอดำเนินการหากมีชิ้นส่วนที่เรียกคืนเพียงชิ้นเดียว
fraherm

21

นี่คือวิธีแก้ไขปัญหานี้ที่แตกต่างกัน

การใช้ตัวแปรสมาชิกส่วนตัวคุณสามารถตั้งค่าข้อมูลที่ส่งคืนเป็นเจตนาที่สามารถประมวลผลหลังจาก super.onResume ();

ชอบมาก

private Intent mOnActivityResultIntent = null; 

@Override
protected void onResume() {
    super.onResume();
    if(mOnActivityResultIntent != null){
        ... do things ...
        mOnActivityResultIntent = null;
    }
 }

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
    if(data != null){
        mOnActivityResultIntent = data;
    }
}

7
ขึ้นอยู่กับการกระทำที่คุณทำซึ่งไม่ได้รับอนุญาตนี่อาจจำเป็นต้องย้ายไปยังช่วงเวลาหลัง ๆ กว่า onResume () สำหรับ insatcne หาก FragmentTransaction.commit () เป็นปัญหาสิ่งนี้จะต้องเข้าไปที่ onResume () แทน
pjv

1
นี่คือคำตอบสำหรับคำถามนี้สำหรับฉัน เนื่องจากฉันต้องการส่งต่อแท็ก NFC ที่ได้รับไปยังกิจกรรมก่อนหน้านี่คือสิ่งที่ทำเพื่อฉัน
Janis Peisenieks

7
super.onActivityResult()สำหรับฉันมันเกิดขึ้นเพราะผมไม่ได้เรียกร้อง
Sufian

20

โซลูชันระยะสั้นและทำงาน:

ทำตามขั้นตอนง่าย ๆ

ขั้นตอน

ขั้นตอนที่ 1: แทนที่onSaveInstanceStateสถานะในส่วนที่เกี่ยวข้อง และลบ super method ออกจากมัน

 @Override
public void onSaveInstanceState( Bundle outState ) {

}  

ขั้นตอนที่ 2: ใช้ fragmentTransaction.commitAllowingStateLoss( );

แทน fragmentTransaction.commit( ); การดำเนินการในขณะที่ในส่วน


คำตอบไม่ได้ถูกคัดลอกหรืออ้างถึงแบบฟอร์มอื่นซึ่งเป็น. มันถูกโพสต์เพื่อช่วยให้ผู้คนด้วยวิธีการทำงานของฉันซึ่งได้รับจากการลองผิดลองถูกหลายครั้ง
Vinayak

12

ระวังการใช้transaction.commitAllowingStateLoss()อาจส่งผลให้เกิดประสบการณ์ที่ไม่ดีสำหรับผู้ใช้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่ทำให้เกิดข้อยกเว้นนี้ดูที่โพสต์นี้


6
นี้ไม่ได้ให้คำตอบสำหรับคำถามคุณต้องให้คำตอบที่ถูกต้องสำหรับคำถาม
Umar Ata

10

ฉันพบวิธีแก้ไขที่สกปรกสำหรับปัญหาประเภทนี้ หากคุณยังต้องการที่จะรักษาActivityGroupsเหตุผลของคุณไม่ว่าจะด้วยเหตุผลใดก็ตาม (ฉันมีเหตุผล จำกัด เวลา) คุณเพียงแค่นำ

public void onBackPressed() {}

ในของคุณActivityและทำbackรหัสในนั้น แม้ว่าจะไม่มีวิธีการดังกล่าวในอุปกรณ์รุ่นเก่า แต่วิธีนี้จะถูกเรียกใช้โดยอุปกรณ์รุ่นใหม่กว่า


6

ห้ามใช้ commitAllowingStateLoss () ควรใช้สำหรับกรณีที่ไม่เป็นไรสำหรับสถานะ UI ที่จะเปลี่ยนผู้ใช้โดยไม่คาดคิด

https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss ()

หากธุรกรรมเกิดขึ้นใน ChildFragmentManager ของ parentFragment ให้ใช้ parentFragment.isResume ()ข้างนอกเพื่อตรวจสอบแทน

if (parentFragment.isResume()) {
    DummyFragment dummyFragment = DummyFragment.newInstance();
    transaction = childFragmentManager.BeginTransaction();
    trans.Replace(Resource.Id.fragmentContainer, startFragment);
}

5

ฉันมีปัญหาที่คล้ายกันสถานการณ์เป็นดังนี้:

  • กิจกรรมของฉันคือการเพิ่ม / แทนที่รายการชิ้นส่วน
  • แต่ละส่วนของรายการมีการอ้างอิงถึงกิจกรรมเพื่อแจ้งกิจกรรมเมื่อมีการคลิกรายการ (รูปแบบผู้สังเกตการณ์)
  • แต่ละแฟรกเมนต์รายการเรียกใช้setRetainInstance (true); ในวิธีการonCreate

onCreateวิธีการกิจกรรมที่เป็นเช่นนี้

mMainFragment = (SelectionFragment) getSupportFragmentManager()
                .findFragmentByTag(MAIN_FRAGMENT_TAG);
        if (mMainFragment == null) {
            mMainFragment = new SelectionFragment();

            mMainFragment.setListAdapter(new ArrayAdapter<String>(this,
                    R.layout.item_main_menu, getResources().getStringArray(
                            R.array.main_menu)));
mMainFragment.setOnSelectionChangedListener(this);
            FragmentTransaction transaction = getSupportFragmentManager()
                    .beginTransaction();
            transaction.add(R.id.content, mMainFragment, MAIN_FRAGMENT_TAG);
            transaction.commit();
        }

เกิดข้อยกเว้นเนื่องจากเมื่อการเปลี่ยนแปลงการกำหนดค่า (หมุนอุปกรณ์) กิจกรรมจะถูกสร้างขึ้นชิ้นส่วนหลักจะถูกดึงออกมาจากประวัติของผู้จัดการส่วนและในเวลาเดียวกันส่วนที่มีการอ้างอิงOLDไปยังกิจกรรมที่ถูกทำลาย

การเปลี่ยนการดำเนินการเพื่อแก้ไขปัญหา:

mMainFragment = (SelectionFragment) getSupportFragmentManager()
                .findFragmentByTag(MAIN_FRAGMENT_TAG);
        if (mMainFragment == null) {
            mMainFragment = new SelectionFragment();

            mMainFragment.setListAdapter(new ArrayAdapter<String>(this,
                    R.layout.item_main_menu, getResources().getStringArray(
                            R.array.main_menu)));
            FragmentTransaction transaction = getSupportFragmentManager()
                    .beginTransaction();
            transaction.add(R.id.content, mMainFragment, MAIN_FRAGMENT_TAG);
            transaction.commit();
        }
        mMainFragment.setOnSelectionChangedListener(this);

คุณต้องตั้งค่าฟังของคุณทุกครั้งที่มีการสร้างกิจกรรมเพื่อหลีกเลี่ยงสถานการณ์ที่ชิ้นส่วนมีการอ้างอิงถึงอินสแตนซ์ที่ถูกทำลายของกิจกรรม


5

หากคุณรับช่วงต่อFragmentActivityคุณจะต้องเรียกใช้ superclass ในonActivityResult():

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    ...
}

ถ้าคุณไม่ทำเช่นนี้และพยายามที่จะแสดงกล่องโต้ตอบส่วนในวิธีการที่คุณอาจได้รับของ IllegalStateExceptionOP (พูดตามตรงฉันไม่ค่อยเข้าใจว่าทำไม super call จึงแก้ไขปัญหาonActivityResult()ถูกเรียกมาก่อนonResume()ดังนั้นจึงไม่ควรได้รับอนุญาตให้แสดงกล่องโต้ตอบแฟรกเมนต์)


1
ชอบที่จะรู้ว่าทำไมนี้แก้ไขปัญหา
Big McLargeHuge

3

ฉันได้รับข้อยกเว้นนี้เมื่อฉันกดปุ่มย้อนกลับเพื่อยกเลิกตัวเลือกเจตนาในกิจกรรมส่วนแผนที่ของฉัน ฉันแก้ไขได้โดยแทนที่รหัสของ onResume (โดยที่ฉันกำลังเริ่มต้นส่วน) กับ onstart () และแอปทำงานได้ดีหวังว่ามันจะช่วยได้


2

ฉันคิดว่าการใช้transaction.commitAllowingStateLoss();ไม่ใช่ทางออกที่ดีที่สุด ข้อยกเว้นนี้จะถูกโยนทิ้งเมื่อมีการเปลี่ยนแปลงการกำหนดค่าของกิจกรรมและonSavedInstanceState()มีการเรียกแฟรกเมนต์และหลังจากนั้นวิธีการโทรกลับ async ของคุณจะพยายามส่งแฟรกเมนต์

วิธีแก้ไขง่ายๆสามารถตรวจสอบได้ว่ากิจกรรมกำลังเปลี่ยนแปลงการกำหนดค่าหรือไม่

ตรวจสอบเช่น isChangingConfigurations()

กล่าวคือ

if(!isChangingConfigurations()) { //commit transaction. }

ชำระเงินลิงค์นี้เช่นกัน


ฉันได้รับข้อยกเว้นนี้เมื่อผู้ใช้คลิกที่บางสิ่ง (การคลิกคือตัวกระตุ้นให้ทำธุรกรรม) สิ่งนี้จะเป็นอย่างไร ทางออกของคุณจะอยู่ที่นี่ไหม
นักพัฒนา android

@androiddeveloper คุณทำอะไรกับผู้ใช้คลิก ส่วนใดกำลังบันทึกสถานะก่อนที่คุณจะยอมรับธุรกรรม
Amol Desai

มีการยกเว้นข้อผิดพลาดในบรรทัดการทำธุรกรรมที่แน่นอน นอกจากนี้ฉันมีตัวพิมพ์แปลก ๆ : แทนที่จะเป็น "มาที่นี่" ฉันหมายถึง "ทำงานที่นี่"
นักพัฒนาซอฟต์แวร์ Android

@androiddeveloper คุณพูดถูก! แต่ก่อนที่จะทำธุรกรรมคุณวางไข่เธรดพื้นหลังหรืออะไร?
Amol Desai

ฉันไม่คิดอย่างนั้น (ขอโทษที่ฉันออกจากสำนักงาน) แต่ทำไมมันถึงสำคัญ? นี่คือสิ่งต่าง ๆ ของ UI ที่นี่ ... ถ้าฉันทำบางสิ่งบางอย่างบนเธรดพื้นหลังฉันจะมีข้อยกเว้นที่นั่นและฉันไม่ได้ใส่สิ่งที่เกี่ยวข้องกับ UI ในเธรดพื้นหลังเนื่องจากมันเสี่ยงเกินไป
นักพัฒนา android

2

อาจเป็นวิธีที่ราบรื่นและวิธีที่ง่ายที่สุดที่ฉันพบในกรณีของฉันคือหลีกเลี่ยงการแตกส่วนที่ไม่เหมาะสมออกจากสแต็กเพื่อตอบสนองต่อผลกิจกรรม ดังนั้นการเปลี่ยนสายนี้ในonActivityResult():

popMyFragmentAndMoveOn();

สำหรับสิ่งนี้:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    public void run() {
        popMyFragmentAndMoveOn();
    }
}

ช่วยในกรณีของฉัน


2

หากคุณทำ FragmentTransaction บางส่วนใน onActivityResult สิ่งที่คุณสามารถทำได้คุณสามารถกำหนดค่าบูลีนบางส่วนใน onActivityResult จากนั้นใน onResume คุณสามารถทำ FragmentTransaction ของคุณบนพื้นฐานของค่าบูลีน โปรดอ้างอิงรหัสด้านล่าง

@Override
protected void onResume() {
    super.onResume;
    if(isSwitchFragment){
        isSwitchFragment=false;
        bottomNavigationView.getTabAt(POS_FEED).select();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == FilterActivity.FILTER_REQUEST_EVENT && data != null) {
        isSwitchFragment=true;
    }
}

โปรดอย่าโพสต์รหัสเป็นภาพใช้การจัดรูปแบบรหัสแทน
Micer

1
ใช่มันช่วยฉันได้ .. , นี่เป็นคำตอบที่ถูกต้องและเหมาะสมสำหรับอุปกรณ์ขนมหวานฉันได้รับข้อยกเว้นนี้และแก้ไขด้วยเคล็ดลับง่ายๆนี้ .. !! ดังนั้นการโหวต
sandhya sasane

2

มารยาท: โซลูชันสำหรับ IllegalStateException

ปัญหานี้ทำให้ฉันรำคาญเป็นเวลานาน แต่โชคดีที่ฉันมาพร้อมทางออกที่เป็นรูปธรรม คำอธิบายรายละเอียดของมันก็คือที่นี่

การใช้ commitAllowStateloss () อาจป้องกันข้อยกเว้นนี้ แต่จะนำไปสู่ความผิดปกติของ UI ดังนั้นเราจึงเข้าใจว่า IllegalStateException เกิดขึ้นเมื่อเราพยายามคอมมิตชิ้นส่วนหลังจากสถานะกิจกรรมหายไปดังนั้นเราควรชะลอการทำธุรกรรมจนกว่าสถานะจะถูกกู้คืน สามารถทำได้อย่างนี้

ประกาศตัวแปรบูลีนส่วนตัวสองตัว

 public class MainActivity extends AppCompatActivity {

    //Boolean variable to mark if the transaction is safe
    private boolean isTransactionSafe;

    //Boolean variable to mark if there is any transaction pending
    private boolean isTransactionPending;

ตอนนี้ใน onPostResume () และ onPause เราตั้งและยกเลิกการตั้งค่าตัวแปรบูลีน isTransactionSafe ความคิดคือการทำเครื่องหมาย trasnsaction ปลอดภัยเฉพาะเมื่อกิจกรรมอยู่เบื้องหน้าจึงไม่มีโอกาสของ stateloss

/*
onPostResume is called only when the activity's state is completely restored. In this we will
set our boolean variable to true. Indicating that transaction is safe now
 */
public void onPostResume(){
    super.onPostResume();
    isTransactionSafe=true;
}
/*
onPause is called just before the activity moves to background and also before onSaveInstanceState. In this
we will mark the transaction as unsafe
 */

public void onPause(){
    super.onPause();
    isTransactionSafe=false;

}

private void commitFragment(){
    if(isTransactionSafe) {
        MyFragment myFragment = new MyFragment();
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.frame, myFragment);
        fragmentTransaction.commit();
    }
}

- สิ่งที่เราทำจนถึงตอนนี้จะบันทึกจาก IllegalStateException แต่การทำธุรกรรมของเราจะหายไปหากพวกเขาทำหลังจากกิจกรรมย้ายไปที่พื้นหลังชนิดเช่น commitAllowStateloss () เพื่อช่วยในการที่เรามีตัวแปร isTransactionPending บูลีน

public void onPostResume(){
   super.onPostResume();
   isTransactionSafe=true;
/* Here after the activity is restored we check if there is any transaction pending from
the last restoration
*/
   if (isTransactionPending) {
      commitFragment();
   }
}


private void commitFragment(){

 if(isTransactionSafe) {
     MyFragment myFragment = new MyFragment();
     FragmentManager fragmentManager = getFragmentManager();
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
     fragmentTransaction.add(R.id.frame, myFragment);
     fragmentTransaction.commit();
     isTransactionPending=false;
 }else {
     /*
     If any transaction is not done because the activity is in background. We set the
     isTransactionPending variable to true so that we can pick this up when we come back to
foreground
     */
     isTransactionPending=true;
 }
}

2

การทำธุรกรรมชิ้นส่วนไม่ควรดำเนินการหลังจากActivity.onStop()! ตรวจสอบว่าคุณไม่มีการเรียกกลับที่สามารถดำเนินธุรกรรมonStop()ได้ มันจะดีกว่าที่จะแก้ไขเหตุผลแทนที่จะพยายามเดินไปรอบ ๆ ปัญหาด้วยวิธีการเช่น.commitAllowingStateLoss()


1

เริ่มต้นจากรุ่นห้องสมุดสนับสนุน 24.0.0 คุณสามารถโทรหาFragmentTransaction.commitNow()วิธีการที่กระทำธุรกรรมนี้พร้อมกันแทนการโทรตามมาด้วยcommit() executePendingTransactions()ดังที่เอกสารระบุว่าวิธีนี้ดียิ่งขึ้น:

การเรียกใช้ commitNow นั้นดีกว่าการเรียกใช้ commit () ตามด้วย executePendingTransactions () เนื่องจากหลังจะมีผลข้างเคียงของการพยายามที่จะส่งมอบธุรกรรมที่ค้างอยู่ในปัจจุบันทั้งหมดไม่ว่าจะเป็นพฤติกรรมที่ต้องการหรือไม่ก็ตาม


1

เมื่อใดก็ตามที่คุณกำลังพยายามโหลดชิ้นส่วนในกิจกรรมของคุณตรวจสอบให้แน่ใจว่ากิจกรรมนั้นอยู่ในประวัติย่อและจะไม่หยุดสถานะชั่วคราวในสถานะหยุดชั่วคราวคุณอาจสิ้นสุดการสูญเสียการดำเนินการที่ทำไว้

คุณสามารถใช้ transaction.commitAllowingStateLoss () แทน transaction.commit () เพื่อโหลดชิ้นส่วน

หรือ

สร้างบูลีนและตรวจสอบว่ากิจกรรมจะไม่หยุดหรือไม่

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

จากนั้นในขณะที่โหลดการตรวจสอบชิ้นส่วน

if(mIsResumed){
//load the your fragment
}

1

ในการหลีกเลี่ยงปัญหานี้เราสามารถใช้Navigation Architecture Componentซึ่งเปิดตัวใน Google I / O 2018 ส่วนประกอบ Navigation Architecture ช่วยให้การนำทางในแอป Android ง่ายขึ้น


มันไม่เพียงพอที่ดีและ bugy (การจัดการลิงก์ในรายละเอียดที่ยากจนไม่สามารถบันทึกรัฐแสดง / ซ่อนชิ้นส่วนและบางเรื่องที่สำคัญที่ยังคงเปิด)
do01

1

เกี่ยวกับ @Anthonyeef คำตอบที่ดีนี่คือตัวอย่างรหัสใน Java:

private boolean shouldShowFragmentInOnResume;

private void someMethodThatShowsTheFragment() {

    if (this.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
        showFragment();
    } else {
        shouldShowFragmentInOnResume = true;
    }
}

private void showFragment() {
    //Your code here
}

@Override
protected void onResume() {
    super.onResume();

    if (shouldShowFragmentInOnResume) {
        shouldShowFragmentInOnResume = false;
        showFragment();
    }
}

1

หากคุณมีปัญหากับวิธีการ popBackStack () หรือ popBackStackImmediate () โปรดลอง fixt ด้วย:

        if (!fragmentManager.isStateSaved()) {
            fragmentManager.popBackStackImmediate();
        }

มันก็ใช้ได้สำหรับฉันเช่นกัน


โปรดทราบว่าต้องใช้ API 26 ขึ้นไป
Itay Feldman

1

ในกรณีของฉันฉันได้รับข้อผิดพลาดนี้ในวิธีการแทนที่ที่เรียกว่า onActivityResult หลังจากขุดฉันแค่คิดออกบางทีฉันอาจต้องเรียกว่า ' super ' ก่อน
ฉันเพิ่มมันและใช้งานได้

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data); //<--- THIS IS THE SUPPER CALL
    if (resultCode == Activity.RESULT_OK && requestCode == 0) {
        mostrarFragment(FiltroFragment.newInstance())
    }

}

บางทีคุณอาจต้องเพิ่ม 'super' ในการแทนที่ใด ๆ ที่คุณทำก่อนรหัสของคุณ


1

นามสกุล Kotlin

fun FragmentManager?.replaceAndAddToBackStack(
    @IdRes containerViewId: Int,
    fragment: () -> Fragment,
    tag: String
) {
    // Find and synchronously remove a fragment with the same tag.
    // The second transaction must start after the first has finished.
    this?.findFragmentByTag(tag)?.let {
        beginTransaction().remove(it).commitNow()
    }
    // Add a fragment.
    this?.beginTransaction()?.run {
        replace(containerViewId, fragment, tag)
        // The next line will add the fragment to a back stack.
        // Remove if not needed.
        // You can use null instead of tag, but tag is needed for popBackStack(), 
        // see https://stackoverflow.com/a/59158254/2914140
        addToBackStack(tag)
    }?.commitAllowingStateLoss()
}

การใช้งาน:

val fragment = { SomeFragment.newInstance(data) }
fragmentManager?.replaceAndAddToBackStack(R.id.container, fragment, SomeFragment.TAG)

คุณสามารถลบ () -> ก่อน Fragment
Claire

@ แคลร์ขอบคุณ! คุณหมายถึงเปลี่ยนไปfragment: Fragment? ใช่ฉันลองใช้ชุดตัวเลือกนี้ แต่ในกรณีนี้จะมีการสร้างแฟรกเมนต์ในทุกกรณี (แม้ว่าเมื่อ FragmentManager == null แต่ฉันไม่พบสถานการณ์นี้) ฉันปรับปรุงคำตอบและเปลี่ยน null addToBackStack()ไปยังแท็กใน
CoolMind

1

ความผิดพลาดนี้เกิดจาก FragmentTransaction กำลังกระทำหลังจากที่วัฏจักรของการเป็นเจ้าของกิจกรรมได้รันบนSaveInstanceStateแล้ว สิ่งนี้มักเกิดจากการกระทำ FragmentTransactions จากการโทรกลับแบบอะซิงโครนัส ตรวจสอบทรัพยากรที่เชื่อมโยงเพื่อดูรายละเอียดเพิ่มเติม

ธุรกรรมส่วนและการสูญเสียสถานะกิจกรรม

http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html


0

เพิ่มสิ่งนี้ในกิจกรรมของคุณ

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (outState.isEmpty()) {
        // Work-around for a pre-Android 4.2 bug
        outState.putBoolean("bug:fix", true);
    }
}

0

ฉันยังประสบปัญหานี้และปัญหาเกิดขึ้นทุกครั้งที่บริบทของคุณFragmentActivityได้รับการเปลี่ยนแปลง (เช่นการวางแนวหน้าจอมีการเปลี่ยนแปลง ฯลฯ ) FragmentActivityดังนั้นการแก้ไขที่ดีที่สุดสำหรับมันคือการปรับปรุงบริบทจากคุณ


0

ฉันลงเอยด้วยการสร้างชิ้นส่วนพื้นฐานและทำให้ชิ้นส่วนทั้งหมดในแอพของฉันขยายออก

public class BaseFragment extends Fragment {

    private boolean mStateSaved;

    @CallSuper
    @Override
    public void onSaveInstanceState(Bundle outState) {
        mStateSaved = true;
        super.onSaveInstanceState(outState);
    }

    /**
     * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException
     * would otherwise occur.
     */
    public void showAllowingStateLoss(FragmentManager manager, String tag) {
        // API 26 added this convenient method
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (manager.isStateSaved()) {
                return;
            }
        }

        if (mStateSaved) {
            return;
        }

        show(manager, tag);
    }
}

จากนั้นเมื่อฉันพยายามที่จะแสดงชิ้นส่วนที่ฉันใช้showAllowingStateLossแทนshow

แบบนี้:

MyFragment.newInstance()
.showAllowingStateLoss(getFragmentManager(), MY_FRAGMENT.TAG);

ฉันมาถึงโซลูชันนี้จาก PR นี้: https://github.com/googlesamples/easypermissions/pull/170/files


0

วิธีแก้ปัญหาอื่นที่เป็นไปได้ซึ่งฉันไม่แน่ใจว่าจะช่วยได้ในทุกกรณี ( ที่นี่ ):

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final View rootView = findViewById(android.R.id.content);
        if (rootView != null) {
            rootView.cancelPendingInputEvents();
        }
    }
}

0

ฉันรู้ว่ามีคำตอบที่ยอมรับโดย @Ovidiu Latcu แต่หลังจากผ่านไปสักพักข้อผิดพลาดยังคงมีอยู่

@Override
protected void onSaveInstanceState(Bundle outState) {
     //No call for super(). Bug on API Level > 11.
}

Crashlytics ยังส่งข้อความแสดงข้อผิดพลาดแปลก ๆ ถึงฉัน

อย่างไรก็ตามข้อผิดพลาดเกิดขึ้นเฉพาะในเวอร์ชัน 7+ (ตังเม) การแก้ไขของฉันคือการใช้commitAllowingStateLoss ()แทนที่จะคอมมิชชัน () ที่ FragmentTransaction

โพสต์นี้มีประโยชน์สำหรับ commitAllowingStateLoss () และไม่เคยมีปัญหาเกี่ยวกับส่วนอีกเลย

เพื่อสรุปผลคำตอบที่ยอมรับได้ที่นี่อาจใช้ได้กับ Android รุ่น Nougat รุ่นก่อน

การทำเช่นนี้อาจช่วยให้บุคคลอื่นสามารถค้นหาได้สองสามชั่วโมง แฮปปี้โค้ด <3 ไชโย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.