অবৈধ স্টেট এক্সেপশন: ভিউপ্যাজারের সাথে onSaveInstanceState এর পরে এই ক্রিয়াটি সম্পাদন করতে পারবেন না


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)

স্পষ্টতই এর একটি ফ্রেগমেন্টম্যানেজারের সাথে কিছু করার আছে যা আমি ব্যবহার করি না। স্ট্যাকট্রেস আমার নিজস্ব ক্লাসগুলির কোনও প্রদর্শন করে না, সুতরাং এই ব্যতিক্রমটি কোথায় ঘটে এবং কীভাবে এটি প্রতিরোধ করা যায় সে সম্পর্কে আমার কোনও ধারণা নেই।

রেকর্ডের জন্য: আমার একটি ট্যাবহস্ট রয়েছে এবং প্রতিটি ট্যাবে ক্রিয়াকলাপগুলির মধ্যে একটি ক্রিয়াকলাপ সুইচ রয়েছে।


2
আমি এই প্রশ্নের একই সমস্যা নিয়ে আলোচনা, কিন্তু কোন সমাধান হয় .. পাওয়া stackoverflow.com/questions/7469082/...
nhaarman

3
আপনি ব্যবহার না করার সময় FragmentManager, মধুচক্র অবশ্যই হয়। বাস্তব হানিকম্ব ট্যাবলেটগুলিতে কি এটি ঘটছে? বা এটি হতে পারে যে কোনও ব্যক্তি কোনও ফোন বা কোনও কিছুতে হ্যাকড হানিকম্ব চালাচ্ছেন এবং এটি হ্যাক সংস্করণে সমস্যা হচ্ছে?
কমন্সওয়্যার

1
আমার কোন ধারণা নাই. মার্কেট ডেভেলপার কনসোলে এটিই আমি পেয়েছি, ব্যবহারকারী বার্তায় কোনও দরকারী তথ্য নেই ..
nhaarman

আমি ফ্লুরি ব্যবহার করছি, যা আমাকে অ্যান্ড্রয়েড .1.০.১ এর সাথে ১১ টি সেশন দেখায় এবং আমার এই ব্যতিক্রমের ১১ টি প্রতিবেদন রয়েছে। যদিও কাকতালীয় হতে পারে। Android 3.1 এবং 3.2 এর যথাক্রমে 56 এবং 38 টি সেশন রয়েছে।
nhaarman

মার্কেট ত্রুটির প্রতিবেদনে একটি 'প্ল্যাটফর্ম' বিভাগ রয়েছে, কখনও কখনও এটিতে ডিভাইসের অ্যান্ড্রয়েড সংস্করণ থাকে।
নিকোলে এলেনকভ

উত্তর:


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();

যুক্ত বা সঞ্চালনের সময় FragmentTransactionযে কারণে ছিল Exception


370
আপনার প্রতিশ্রুতি () পরিবর্তে কমিটএলিংস্টেস্টলস () ব্যবহার করা উচিত
মে

18
কমিটএলিউস্টিংস্টেটলস () সম্পর্কে এই মন্তব্যটি তার নিজের পক্ষে একটি উত্তর - আপনার এটি পোস্ট করা উচিত।
রিসাদিনহা

20
'কমিটএলিংস্টিস্টস লস' সম্পর্কিত - /> "এটি বিপজ্জনক কারণ কারণ যদি ক্রিয়াকলাপটি পরে তার রাজ্য থেকে পুনরুদ্ধার করা প্রয়োজন তবে প্রতিশ্রুতিটি হারাতে পারে, সুতরাং ইউআই রাষ্ট্রের ক্ষেত্রে অপ্রত্যাশিতভাবে পরিবর্তিত হওয়া ঠিক এমন ক্ষেত্রেই এটি ব্যবহার করা উচিত this ব্যবহারকারী."
কোডভার্সড হয়েছে

10
যদি আমি এর জন্য ভি 4 উত্সটি popBackStackImmediateদেখি তবে রাষ্ট্রটি সংরক্ষণ করা থাকলে তা অবিলম্বে ব্যর্থ হয়। পূর্বে এর সাথে খণ্ড যুক্ত করা commitAllowingStateLossকোনও অংশ খেলবে না। আমার পরীক্ষাটি সত্য হতে দেখায়। এই নির্দিষ্ট ব্যতিক্রমটির কোনও প্রভাব নেই। আমাদের যা প্রয়োজন তা হল একটি popBackStackImmediateAllowingStateLossপদ্ধতি।
সিনেসো

3
@ ড্যানিলেব হ্যাঁ, আমি এখানে একটি উত্তর পোস্ট করেছি। তবে আমি অটো মেসেজ বাস ব্যবহার করে আরও একটি ভাল সমাধান পেয়েছি: খণ্ডটিকে গ্রাহক হিসাবে নিবন্ধন করুন এবং বাস থেকে অ্যাসিঙ্ক ফলাফলটি শুনুন। বিরতিতে নিবন্ধন করুন এবং পুনরায় শুরুতে পুনরায় নিবন্ধন করুন। অ্যাসিঙ্কটি যখন সম্পূর্ণ হয় এবং খণ্ডটি বন্ধ হয়ে যায় তখন তার জন্য একটি উত্পাদনের পদ্ধতিও প্রয়োজন। যখন আমি সময় পাই আমি আরও উত্তর দিয়ে আমার উত্তরটি আপডেট করব।
সেনেসো

130

অনুরূপ ত্রুটি বার্তার সাথে সম্পর্কিত অনেকগুলি সমস্যা রয়েছে। এই নির্দিষ্ট স্ট্যাক ট্রেসের দ্বিতীয় লাইনটি পরীক্ষা করুন। এই ব্যতিক্রমটি বিশেষভাবে কল করার সাথে সম্পর্কিতFragmentManagerImpl.popBackStackImmediate

এই পদ্ধতি কলটি, সেশনের স্থিতি ইতিমধ্যে সংরক্ষণ করা থাকলে সর্বদা ব্যর্থ popBackStackহবে । উত্স পরীক্ষা করুন। এই ব্যতিক্রম নিক্ষেপ করা বন্ধ করতে আপনার করার মতো কিছুই নেই।IllegalStateException

  • এতে কল সরিয়ে ফেললে কোনও লাভ super.onSaveInstanceStateহবে না।
  • এর সাথে খণ্ড তৈরি করা কোনও উপকারে commitAllowingStateLossআসবে না।

এখানে আমি কীভাবে সমস্যাটি পর্যবেক্ষণ করেছি:

  • জমা দেওয়ার বোতাম সহ একটি ফর্ম রয়েছে।
  • বোতামটি ক্লিক করা হলে একটি ডায়ালগ তৈরি হয় এবং একটি অ্যাসিঙ্ক প্রক্রিয়া শুরু হয়।
  • প্রক্রিয়াটি শেষ হওয়ার আগে ব্যবহারকারী হোম কীটি ক্লিক করে - 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
এখানে সে সম্পর্কে আকর্ষণীয় পড়া: অ্যান্ড্রয়েডসাইনপ্যাটার্নস.কম
পাসকাল

আপনি যদি ডায়ালগফ্র্যাগমেন্টটি ব্যবহার করেন তবে আমি এখানে এটির বিকল্প তৈরি করেছি: github.com/AndroidDeveloperLB/ ডায়ালগশার্ড
অ্যান্ড্রয়েড বিকাশকারী

যদি popBackStackImmediateএন্ড্রয়েড নিজেই ডাকত?
কিমি চিউ

1
একেবারে দুর্দান্ত। এই এক গ্রহণযোগ্য উত্তর হওয়া উচিত। আপনাকে অনেক ধন্যবাদ! হতে পারে আমি সাবপ্রেসড = যুক্ত করব; পপব্যাকস্ট্যাকআইডিমিয়েটের পরে।
নিওনিগমা

আমি SaveInstanceState (বান্ডিল আউটস্টেট) পদ্ধতিটি সর্বজনীন শূন্যতা ব্যবহার করি নি। SaveInstanceState (বান্ডেল আউটস্টেট) এর জন্য জনসাধারণের শূন্যতার জন্য কী আমাকে খালি পদ্ধতি নির্ধারণ করতে হবে?
ফ্যাক্সরদ্দিন আবদুললেভ

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
! ফিনিশিং () &&! isDestroyed () আমার পক্ষে কাজ করে না।
অ্যালেন ভর্ক

isFinishing () &&! isdestroyed () আমার জন্য কাজ করেছে, তবে এটির জন্য এপিআই 17 দরকার But তবে এটি কেবল একটি প্রদর্শন করে না DialogFragment। অন্যান্য ভাল সমাধানের জন্য স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 15729138/… দেখুন , স্ট্যাকওভারফ্লো . com / a / 41813953 / 2914140 আমাকে সহায়তা করেছে।
কুলমাইন্ড

29

এটি অক্টোবর 2017, এবং গুগল নতুন জিনিসগুলি লাইফাইসাইকেল উপাদানটিকে কল করে অ্যান্ড্রয়েড সমর্থন লাইব্রেরি তৈরি করে। এটি 'SaveInstanceState এর পরে এই ক্রিয়াটি সম্পাদন করতে পারে না' সমস্যাটির জন্য কিছু নতুন ধারণা সরবরাহ করে।

সংক্ষেপে:

  • আপনার খণ্ডটি পপ করার জন্য এটি সঠিক সময় কিনা তা নির্ধারণের জন্য লাইফসাইকেল উপাদানটি ব্যবহার করুন।

ব্যাখ্যা সহ দীর্ঘতম সংস্করণ:

  • এই সমস্যাটি কেন সামনে আসবে?

    এটি কারণ আপনি FragmentManagerআপনার খণ্ড খণ্ডের জন্য লেনদেন করার জন্য আপনার ক্রিয়াকলাপটি (যা আমি মনে করি আপনার খণ্ডটি ধরে রাখছে?) থেকে ব্যবহার করার চেষ্টা করছেন । সাধারণত এটি দেখে মনে হবে আপনি আগত খণ্ডটির জন্য কিছু লেনদেন করার চেষ্টা করছেন, ইতিমধ্যে হোস্ট ক্রিয়াকলাপটি ইতিমধ্যে savedInstanceStateপদ্ধতি কল করে (ব্যবহারকারী বাড়ির বোতামটি স্পর্শ করতে পারে তাই ক্রিয়াকলাপটি কল করেonStop() , আমার ক্ষেত্রে এটির কারণ)

    সাধারণত এই সমস্যাটি হওয়া উচিত নয় - আমরা সর্বদা শুরুতে ক্রিয়াকলাপে খণ্ডটি লোড করার চেষ্টা করি, যেমন onCreate()পদ্ধতি এটির জন্য উপযুক্ত জায়গা। তবে কখনও কখনও এটি ঘটে , বিশেষত যখন আপনি সিদ্ধান্ত নিতে পারেন না যে আপনি কী ক্রিয়াকলাপটি সেই ক্রিয়াকলাপে লোড করবেন, বা আপনি কোনও AsyncTaskব্লক থেকে টুকরো লোড করার চেষ্টা করছেন (বা কোনও কিছুটা সময় নিতে হবে)। সময়টি, খণ্ডের লেনদেন সত্যিই ঘটে যাওয়ার আগে, তবে ক্রিয়াকলাপের onCreate()পদ্ধতির পরে , ব্যবহারকারী যে কোনও কিছু করতে পারে। ব্যবহারকারী যদি হোম বোতামটি টিপেন, যা ক্রিয়াকলাপের onSavedInstanceState()পদ্ধতিটি ট্রিগার করে , সেখানে can not perform this actionক্রাশ হবে।

    যদি কেউ এই ইস্যুতে আরও গভীরভাবে দেখতে চান তবে আমি তাদের এই ব্লগ পোস্টটি একবার দেখার পরামর্শ দিই । এটি উত্স কোড স্তরের ভিতরে গভীর দেখায় এবং এ সম্পর্কে অনেক কিছু ব্যাখ্যা করে। এছাড়াও, এটি এই কারণটি দেয় যে আপনি commitAllowingStateLoss()এই ক্র্যাশটিকে কার্যবিধ্বস্ত করার জন্য পদ্ধতিটি ব্যবহার করবেন না (বিশ্বাস করুন এটি আপনার কোডের জন্য ভাল কিছু দেয় না)

  • কিভাবে এটি ঠিক করবেন?

    • commitAllowingStateLoss()খণ্ড লোড করার জন্য আমার কী পদ্ধতি ব্যবহার করা উচিত ? না, আপনার উচিত হবে না ;

    • আমার কি onSaveInstanceStateপদ্ধতিটি ওভাররাইড করা উচিত , এর superভিতরে থাকা পদ্ধতিটি উপেক্ষা করা উচিত? না, আপনার উচিত হবে না ;

    • isFinishingহোস্ট ক্রিয়াকলাপটি খণ্ডিত লেনদেনের জন্য সঠিক মুহুর্তে আছে কিনা তা পরীক্ষা করার জন্য, আমার কী যাদুঘরের অভ্যন্তরীণ ক্রিয়াকলাপটি ব্যবহার করা উচিত ? হ্যাঁ এটি করার মতো সঠিক উপায়।

  • লাইফাইসাইকেলটি একবার দেখুন উপাদান কাজ করতে পারেন।

    মূলত, গুগল AppCompatActivityশ্রেণীর অভ্যন্তরে কিছু বাস্তবায়ন করে (এবং আপনার প্রকল্পে আপনাকে ব্যবহার করা উচিত এমন আরও কয়েকটি বেস ক্লাস), যা বর্তমান জীবনচক্রের অবস্থা নির্ধারণকে আরও সহজ করে তোলে । আমাদের সমস্যার দিকে একবার নজর দিন: কেন এই সমস্যাটি ঘটবে? এর কারণ আমরা ভুল সময়ে কিছু করি। সুতরাং আমরা এটি না করার চেষ্টা করি এবং এই সমস্যাটি চলে যাবে।

    আমি আমার নিজের প্রকল্পের জন্য একটু কোড করি, আমি এখানে যা ব্যবহার করছি তা এখানে LifeCycle। আমি কোডলিনে কোড করি।

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()
    }

আমি উপরে দেখায় হিসাবে। আমি হোস্ট ক্রিয়াকলাপের জীবনকালীন অবস্থা পরীক্ষা করব check সমর্থন লাইব্রেরির মধ্যে লাইফাইসাইকেল উপাদান সহ, এটি আরও নির্দিষ্ট হতে পারে। কোড 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)। এখন আমি মনে করি এটি আমার প্রত্যাশার মতো কাজ করা উচিত।



1
যদি আপনার FragmentDispatcherকেবলমাত্র একটি টুকরো পুনরুদ্ধার করা হয় তবে কেন আপনার প্রয়োগের জন্য মুলতুবি টুকরোগুলি সংরক্ষণ করতে একটি তালিকা ব্যবহার করে?
ভীতু

21

এই সমস্যার আলাদা সমাধান এখানে দেওয়া হল।

একটি প্রাইভেট সদস্য ভেরিয়েবল ব্যবহার করে আপনি প্রত্যাশিত ডেটাটিকে একটি অভিপ্রায় হিসাবে সেট করতে সক্ষম হন যা সুপার.অনুসেট () এর পরে প্রক্রিয়া করা যায়;

তাই ভালো:

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
আপনি কী পদক্ষেপ নিচ্ছেন তা নির্ভর করে না তবে এটির রিসুম () এর চেয়ে আরও পরে কোনও মুহূর্তে যেতে হবে। ইনসটাকেনের জন্য, যদি ফ্রেগমেন্টট্রান্সকশন ডটমিট () সমস্যা হয় তবে এর পরিবর্তে এটি পোস্টপ্রেসিউম () এর মধ্যে চলে যাওয়া দরকার।
pjv

1
এটি আমার জন্য এই প্রশ্নের উত্তর। যেহেতু পূর্ববর্তী ক্রিয়াকলাপে আমার প্রাপ্ত এনএফসি ট্যাগটি ফরোয়ার্ড করা দরকার, তাই এটি আমার জন্য এটি হয়েছিল।
জ্যানিস পিসেনিক্স

7
আমার জন্য এটি ঘটছিল কারণ আমি ফোন করছিলাম না super.onActivityResult()
সুফিয়ান

20

সংক্ষিপ্ত এবং কাজের সমাধান:

সরল পদক্ষেপগুলি অনুসরণ করুন

ধাপ

পদক্ষেপ 1: onSaveInstanceStateসম্পর্কিত খণ্ডে ওভাররাইড রাষ্ট্র। এবং এটি থেকে সুপার পদ্ধতি সরান।

 @Override
public void onSaveInstanceState( Bundle outState ) {

}  

পদক্ষেপ 2: ব্যবহার করুন fragmentTransaction.commitAllowingStateLoss( );

পরিবর্তে fragmentTransaction.commit( ); টুকরা অপারেশন।


উত্তর অন্য অনুলিপি বা রেফার করা হয় না যেখানে আমার কাজ সমাধান দ্বারা লোকদের সাহায্য করার জন্য পোস্ট করা হয়েছিল যা বেশ কয়েকটি পরীক্ষার এবং ত্রুটির মধ্যে দিয়ে গেছে
বিনয়াক

12

সাবধান , ব্যবহারের transaction.commitAllowingStateLoss()ফলে ব্যবহারকারীর জন্য খারাপ অভিজ্ঞতা হতে পারে। কেন এই ব্যতিক্রম নিক্ষেপ করা হয় তার আরও তথ্যের জন্য, এই পোস্টটি দেখুন


6
এটি প্রশ্নের উত্তর সরবরাহ করে না, আপনাকে অবশ্যই প্রশ্নের একটি বৈধ উত্তর দিতে হবে
উমর আতা

10

আমি এই ধরণের সমস্যার একটি নোংরা সমাধান পেয়েছি। যদি আপনি এখনও ActivityGroupsযেকোন কারণে আপনার কাছে রাখতে চান (আমার সময়সীমাবদ্ধতার কারণ ছিল) তবে আপনি কেবল প্রয়োগ করেন

public void onBackPressed() {}

আপনার Activityএবং backসেখানে কিছু কোড করুন। এমনকি পুরানো ডিভাইসগুলিতে এ জাতীয় কোনও পদ্ধতি না থাকলেও, এই পদ্ধতিটি নতুন দ্বারা কল করা হয়।


6

কমিটএলিউস্টিংস্টেটলস () ব্যবহার করবেন না, এটি কেবল সেই ক্ষেত্রে ব্যবহার করা উচিত যেখানে ইউআই রাষ্ট্রের পক্ষে ব্যবহারকারীর উপর অপ্রত্যাশিতভাবে পরিবর্তন ঘটে।

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

যদি প্যারেন্টফ্র্যাগমেন্টের চাইল্ডফ্রেগমেন্ট ম্যানেজারে লেনদেন ঘটে থাকে তবে পরিবর্তে চেক করতে প্যারেন্টফ্রেগমেন্ট.আইআরএসিউম () ব্যবহার করুন।

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

5

আমারও একই সমস্যা ছিল, দৃশ্যটি ছিল এরকম:

  • আমার ক্রিয়াকলাপ তালিকার টুকরো যোগ / প্রতিস্থাপন করছে।
  • তালিকার আইটেম ক্লিক করা হয় (পর্যবেক্ষক প্যাটার্ন) ক্লিক করার পরে ক্রিয়াকলাপকে অবহিত করতে প্রতিটি তালিকার খণ্ডটির ক্রিয়াকলাপের একটি রেফারেন্স থাকে।
  • প্রতিটি তালিকার খণ্ড সেটকে রিটেনইনস্ট্যান্স (সত্য) বলে; এটির অনক্রিট পদ্ধতিতে।

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();
        }

ব্যতিক্রমটি ছুঁড়ে দেওয়া হয়েছিল কারণ যখন কনফিগারেশন পরিবর্তন হয় (ডিভাইস ঘোরানো), ক্রিয়াকলাপটি তৈরি হয়, মূল খণ্ডটি খণ্ড পরিচালকের ইতিহাস থেকে পুনরুদ্ধার করা হয় এবং একই সময়ে খণ্ডটি ইতিমধ্যে ধ্বংস হওয়া ক্রিয়াকলাপের একটি পুরানো রেফারেন্স রয়েছে

সমস্যা সমাধানের জন্য বাস্তবায়ন পরিবর্তন:

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আপনার অবশ্যই সুপারক্লাসে কল করতে হবে onActivityResult():

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

আপনি যদি এটি না করেন এবং সেই পদ্ধতিতে কোনও খণ্ড ডায়ালগ বাক্সটি দেখানোর চেষ্টা করেন, আপনি ওপি'র পেতে পারেন IllegalStateException। (সত্যি কথা বলতে কি , সুপার কল কেন সমস্যার সমাধান করে তা আমি খুব একটা বুঝতে পারি না onActivityResult()called আগে কল করা হয়েছিল onResume(), সুতরাং এটি এখনও একটি খণ্ড সংলাপ বাক্সটি দেখানোর অনুমতি দেওয়া উচিত নয়))


1
এটি কেন সমস্যার সমাধান করে তা জানতে আগ্রহী love
বড় ম্যাকলার্জহিউজ

3

আমি যখন আমার মানচিত্রের খণ্ডগুলির ক্রিয়াকলাপে অভিপ্রায় চয়নকারীটিকে বাতিল করতে পিছনে বোতাম টিপছিলাম তখন আমি এই ব্যতিক্রম পাচ্ছিলাম। অনার্ট () যেখানে আমি টুকরাটি শুরু করছিলাম) কোডটি অনস্টার্ট () এ প্রতিস্থাপন করে আমি এটিকে সমাধান করেছি এবং অ্যাপটি ঠিকঠাকভাবে কাজ করছে ope আশা করি এটি সহায়তা করে।


2

আমি মনে করি ব্যবহার transaction.commitAllowingStateLoss();করা সবচেয়ে ভাল সমাধান নয়। যখন ক্রিয়াকলাপের কনফিগারেশন পরিবর্তন হয় এবং খণ্ডকে কল onSavedInstanceState()করা হয় এবং এর পরে আপনার অ্যাসিঙ্ক কলব্যাক পদ্ধতিটি খণ্ডন প্রতিপন্ন করার চেষ্টা করে তখন এই ব্যতিক্রমটি ছুঁড়ে দেওয়া হবে ।

ক্রিয়াকলাপটি কনফিগারেশন পরিবর্তন করছে কিনা তা সহজ সমাধানে পরীক্ষা করা যেতে পারে

যেমন চেক isChangingConfigurations()

অর্থাত

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

পাশাপাশি এই লিঙ্কটি চেকআউট করুন


ব্যবহারকারী কোনও কিছুর উপরে ক্লিক করলে কোনওভাবেই আমি এই ব্যতিক্রম পেয়েছি (ক্লিকটি লেনদেন-প্রতিশ্রুতি সম্পাদনের জন্য ট্রিগার)। এটা কী ভাবে সম্ভব? এখানে কি আপনার সমাধান হবে?
অ্যান্ড্রয়েড বিকাশকারী

ব্যবহারকারী এবং ক্লিক ক্লিক করুন লেনদেন করার আগে কোনওভাবে খণ্ড খণ্ডের রাজ্যটি সংরক্ষণ করছে
অমল দেশাই

লেনদেনের প্রতিশ্রুতি দেওয়ার সঠিক লাইনে ব্যতিক্রমটি ছুঁড়ে দেওয়া হয়েছিল। এছাড়াও, আমার একটি অদ্ভুত টাইপও ছিল: "এখানে এখানে" পরিবর্তে আমি বোঝাতে চাইছি "এখানে কাজ"।
অ্যান্ড্রয়েড বিকাশকারী

@ অ্যান্ড্রয়েড ডেভেলপার আপনি ঠিক আছেন! তবে লেনদেন করার আগে আপনি কোনও পটভূমি থ্রেড বা অন্য কিছু তৈরি করছেন?
আমোল দেশাই

আমি তাই মনে করি না (দুঃখিত আমি অফিস থেকে বাইরে আছি), তবে কেন ব্যাপার হবে? এটি এখানে সমস্ত ইউআই স্টাফ ... আমি যদি কখনও কোনও পটভূমির থ্রেডে কিছু করি তবে আমার সেখানে ব্যতিক্রম হবে, এবং আমি ইউআই সম্পর্কিত জিনিসগুলি ব্যাকগ্রাউন্ড থ্রেডগুলিতে রাখি না, কারণ এটি খুব ঝুঁকিপূর্ণ।
অ্যান্ড্রয়েড বিকাশকারী

2

আমার ক্ষেত্রে সম্ভবত সবচেয়ে স্মুথ এবং সহজ সমাধানটি খুঁজে পেয়েছি হ'ল ক্রিয়াকলাপের ফলাফলের প্রতিক্রিয়া হিসাবে আক্রমণাত্মক খণ্ডটিকে স্ট্যাকের বাইরে পপিং এড়ানো। আমার এই কলটি পরিবর্তন করে onActivityResult():

popMyFragmentAndMoveOn();

এটি:

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

আমার ক্ষেত্রে সাহায্য করেছে।


2

আপনি যদি অ্যাক্টিভিটিস রেজাল্টে কিছু ফ্রেগমেন্ট ট্রান্সজিশন করে থাকেন তবে আপনি যা করতে পারেন তা আপনিঅ্যাক্টিভিটিস রেজাল্টের ভিতরে কিছু বুলিয়ান মান সেট করতে পারেন তবে অনারুমে আপনি বুলিয়ান মানটির ভিত্তিতে আপনার ফ্র্যাগমেন্ট ট্রান্সজেকশনটি করতে পারেন। নীচের কোড উল্লেখ করুন।

@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;
    }
}

দয়া করে কোডটি কোনও চিত্র হিসাবে পোস্ট করবেন না, পরিবর্তে কোড বিন্যাস ব্যবহার করুন।
মাইক্রো

1
হ্যাঁ এটি আমাকে সাহায্য করেছিল .., মার্শমেলো ডিভাইসের জন্য এটি সঠিক এবং সঠিক সমাধান আমি এই ব্যতিক্রম পেয়েছি এবং এই সাধারণ কৌশলটি দিয়ে সমাধান করেছি .. !! সুতরাং আপ ভোট দিয়েছেন।
সন্ধ্যা সাসনে

2

সৌজন্যে: অবৈধ স্টেট এক্সেপশন এর সমাধান

এই ইস্যুটি আমাকে অনেক সময় বিরক্ত করেছিল তবে ভাগ্যক্রমে আমি এর একটি দৃ concrete় সমাধান নিয়ে এসেছি। এটি একটি বিস্তারিত ব্যাখ্যা এখানে

কমিটএলস্টেস্ট্লোস () ব্যবহার করা এই ব্যতিক্রমটি রোধ করতে পারে তবে ইউআই অনিয়ম হতে পারে far সুতরাং আমরা বুঝতে পেরেছি যে ক্রিয়াকলাপের অবস্থাটি নষ্ট হওয়ার পরে যখন আমরা কোনও খণ্ডন করার চেষ্টা করি তখন অবৈধ স্টেপ এক্সেপশন হয় so সুতরাং রাষ্ট্রটি পুনরুদ্ধার না হওয়া পর্যন্ত আমাদের কেবল লেনদেনকে বিলম্ব করা উচিত .এটা সহজভাবে করা যেতে পারে

দুটি বেসরকারী বুলিয়ান ভেরিয়েবল ঘোষণা করুন

 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 এ আমরা আমাদের বুলিয়ান ভেরিয়েবল ট্রান্সঅ্যাকশনসেফ সেট এবং আনসেট করি। আইডিয়াটি হ'ল ট্রান্সস্যাকশনটিকে নিরাপদ হিসাবে চিহ্নিত করা হবে যখন ক্রিয়াকলাপটি অগ্রভাগে থাকে তাই স্টেটলাসের কোনও সম্ভাবনা নেই।

/*
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();
    }
}

- আমরা এখন পর্যন্ত যা করেছি তা অবৈধ স্টেটএক্সপশন থেকে রক্ষা পাবে তবে ক্রিয়াকলাপ ব্যাকগ্রাউন্ডে চলে যাওয়ার পরে যদি তা করা হয় তবে আমাদের লেনদেনগুলি নষ্ট হয়ে যাবে, যেমন কমিটএলস্টেস্ট্লোস () এর মতো। এটির সাহায্যে আমাদের কাছে ট্রান্সঅ্যাকশনপেন্ডিং বুলিয়ান ভেরিয়েবল রয়েছে

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()ডকুমেন্টেশন যেমন এই পদ্ধতির আরও ভাল বলে:

কমিটিকে কল করা এখন কমিটিকে কল করা () এর পরে এক্সিকিউটেডপেন্ডিং ট্রান্সঅ্যাকশনস () এরপরে কল্যাণকর as


1

যখনই আপনি আপনার ক্রিয়াকলাপে কোনও খণ্ড লোড করার চেষ্টা করছেন তা নিশ্চিত করুন যে ক্রিয়াকলাপটি আবার শুরু হয়েছে এবং স্থিতি থামাতে যাচ্ছেন না I বিরতি অবস্থায় আপনি সমাপ্ত অঙ্গীকারের কাজটি হারাতে পারেন।

আপনি টুকরো লোড করতে লেনদেন.কমের পরিবর্তে লেনদেন.কমএলয়েস্টিংস্টেটলস () ব্যবহার করতে পারেন

অথবা

একটি বুলিয়ান তৈরি করুন এবং পরীক্ষা করুন যে ক্রিয়াকলাপটি বন্ধ হচ্ছে না কিনা

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

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

তারপরে খণ্ড চেক লোড করার সময়

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

1

এই সমস্যাটিকে বাইপাস করার জন্য, আমরা ন্যাভিগেশন আর্কিটেকচার উপাদানটি ব্যবহার করতে পারি , যা গুগল আই / ও 2018 সালে চালু হয়েছিল। নেভিগেশন আর্কিটেকচার উপাদানটি অ্যান্ড্রয়েড অ্যাপে নেভিগেশন কার্যকরকরণকে সহজতর করে if


এটা ভালো যথেষ্ট, এবং bugy নয় (দরিদ্র deeplink হ্যান্ডলিং, করতে পারেন সংরক্ষণ করা রাষ্ট্র প্রদর্শন করুন / আড়াল টুকরা এবং কিছু গুরুত্বপূর্ণ বিষয় এখনও খোলা) যে
do01

1

@ অ্যান্টনিয়েফ দুর্দান্ত উত্তরের সাথে সম্পর্কিত, এখানে জাভাতে একটি নমুনা কোড দেওয়া হয়েছে:

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

আপনার যদি পপব্যাকস্ট্যাক () বা পপব্যাকস্ট্যাকমিডিয়েট () পদ্ধতিতে ক্রাশ হয় তবে দয়া করে এর সাথে ফিক্সটি ব্যবহার করে দেখুন:

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

এটি আমার জন্যও কাজ করা হয়েছে।


নোট করুন যে এটির জন্য 26 এবং তার
বেশিের

1

আমার ক্ষেত্রে আমি ক্রিয়াকলাপের ফলাফল হিসাবে পরিচিত ওভাররাইড পদ্ধতিতে এই ত্রুটিটি পেয়েছি। খোঁড়াখুঁড়ি করার পরে আমি ঠিক বুঝতে পারি আগে আমাকে ' সুপার ' কল করার দরকার ছিল ।
আমি এটি যুক্ত করেছি এবং এটি সবেমাত্র কাজ করেছে

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())
    }

}

আপনার কোডের আগে আপনি যে কোনও ওভাররাইড করছেন তার জন্য আপনাকে কেবল একটি 'সুপার' যুক্ত করতে হবে।


1

কোটলিন এক্সটেনশন

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: Fragment? হ্যাঁ, আমি এই বৈকল্পিকটি চেষ্টা করেছি, তবে এই ক্ষেত্রে সমস্ত ক্ষেত্রে একটি টুকরো তৈরি করা হবে (এমনকি ফ্রেগমেন্টম্যানেজার == নালার পরেও, তবে আমি এই পরিস্থিতির মুখোমুখি হইনি)। আমি উত্তরটি আপডেট করেছি এবং ট্যাগে নাল পরিবর্তন করেছি addToBackStack()
কুলমাইন্ড

1

এই ক্র্যাশটির ক্রিয়াকলাপের নিজের ক্রিয়াকলাপটি ইতিমধ্যে সেভিআইনস্ট্যান্সস্টেটে চালুর পরে ফ্রেগমেন্ট ট্রান্সজেকশনের প্রতিশ্রুতিবদ্ধ। এটি প্রায়শই একটি অ্যাসিনক্রোনাস কলব্যাক থেকে ফ্রেগমেন্ট ট্রানজ্যাক্ট প্রতিশ্রুতিবদ্ধ হওয়ার কারণে ঘটে। আরও তথ্যের জন্য লিঙ্কযুক্ত সংস্থানটি দেখুন।

খণ্ডিত লেনদেন এবং ক্রিয়াকলাপের রাজ্যের ক্ষতি

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);

আমি এই জনসংযোগ থেকে এই সমাধানটিতে পৌঁছেছি: https://github.com/googlesferences/easypermission/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

আমি জানি @ ওভিদিউ লাটকু দ্বারা গৃহীত উত্তর আছে তবে কিছুক্ষণ পরেও ত্রুটিটি এখনও থেকেই যায়।

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

ক্র্যাশলাইটিক্স এখনও আমাকে এই অদ্ভুত ত্রুটি বার্তা প্রেরণ করছে।

তবে ত্রুটি এখন কেবলমাত্র 7+ সংস্করণে ঘটছে (নুগাত) আমার ফিক্সটি ছিল কমিটএলিং স্টেটলস () ব্যবহার করা পরিবর্তে ব্যবহার করা।

এই পোস্ট কমিটলয়েস্টিংস্টেটলস () এর জন্য সহায়ক এবং এর আগে কখনও খণ্ড খণ্ডনের সমস্যা নেই।

এটির সংক্ষেপে, এখানে গৃহীত উত্তরটি প্রাক নওগট অ্যান্ড্রয়েড সংস্করণগুলিতে কাজ করতে পারে।

এটি কাউকে অনুসন্ধানের কয়েক ঘন্টা বাঁচাতে পারে। শুভ কোডিং <3 চিয়ার্স

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.