কথোপকথন দেখানোর সময় আমি "onSaveInstanceState এর পরে এই ক্রিয়াটি সম্পাদন করতে পারি না" পেয়েছি


121

কিছু ব্যবহারকারী রিপোর্ট দিচ্ছেন, যদি তারা বিজ্ঞপ্তি বারে দ্রুত পদক্ষেপটি ব্যবহার করেন তবে তারা একটি বাহিনীকে কাছাকাছি পাচ্ছে।

আমি বিজ্ঞপ্তিতে একটি দ্রুত পদক্ষেপ প্রদর্শন করি যিনি "টেস্টডায়ালগ" শ্রেণি কল করেন । "স্নুজ" বোতাম টিপানোর পরে টেস্টডায়ালগ ক্লাসে আমি স্নুজডায়ালগটি দেখাব।

private View.OnClickListener btnSnoozeOnClick() {
    return new View.OnClickListener() {

        public void onClick(View v) {
            showSnoozeDialog();
        }
    };
}

private void showSnoozeDialog() {
    FragmentManager fm = getSupportFragmentManager();
    SnoozeDialog snoozeDialog = new SnoozeDialog();
    snoozeDialog.show(fm, "snooze_dialog");
}

ত্রুটিটি হ'ল *IllegalStateException: Can not perform this action after onSaveInstanceState*.

ইলেগারস্টেটএক্সপশনটি যে কোড লাইন থেকে বের হয়ে আসে তা হ'ল:

snoozeDialog.show(fm, "snooze_dialog");

ক্লাসটি "ফ্র্যাগমেন্টএটিভিটি" প্রসারিত করছে এবং "স্নুজডায়ালগ" শ্রেণিটি "ডায়ালগফ্রেগমেন্ট" প্রসারিত করছে।

এখানে ত্রুটির সম্পূর্ণ স্ট্যাক ট্রেস রয়েছে:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
at com.test.testing.TestDialog.f(TestDialog.java:538)
at com.test.testing.TestDialog.e(TestDialog.java:524)
at com.test.testing.TestDialog.d(TestDialog.java:519)
at com.test.testing.g.onClick(TestDialog.java:648)
at android.view.View.performClick(View.java:3620)
at android.view.View$PerformClick.run(View.java:14292)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)

আমি এই ত্রুটিটি পুনরুত্পাদন করতে পারি না, তবে আমি প্রচুর ত্রুটির প্রতিবেদন পাচ্ছি।

কেউ কীভাবে সহায়তা করতে পারে যে আমি কীভাবে এই ত্রুটিটি সংশোধন করতে পারি?


2
আপনি কি সমাধান খুঁজে পেয়েছেন? আপনার মতো আমারও সমস্যা আছে। আমি এখানে জিজ্ঞাসা করেছি: stackoverflow.com/questions/15730878/… দয়া করে আমার প্রশ্নটি পরীক্ষা করে দেখুন এবং সম্ভাব্য সমাধানটি দেখুন যা আমার ক্ষেত্রে কাজ করছে না। হয়তো এটা আপনার জন্য কাজ করবে।
রুটপাথের

এখনও কোন সমাধান নেই :-( এবং আপনার পরামর্শটি আমার ক্লাসে ইতিমধ্যে যুক্ত হয়েছে
ক্রিসনলাইন

গৃহীত উত্তরটি এখান থেকে দেখুন। এটি আমার সমস্যার সমাধান করেছে: stackoverflow.com/questions/14177781/…
বোগদান

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

stackoverflow.com/questions/7575921/… আপনি নিশ্চিত এই চেষ্টা করেছেন।
ওরিওন

উত্তর:


66

এটি সাধারণ বিষয় । আমরা ডায়ালগফ্রেগমেন্টের বর্ধিত শ্রেণিতে ব্যতিক্রম হ্যান্ডরাইড করে (এবং) ওভারাইড করে এই সমস্যাটি সমাধান করেছি

public class CustomDialogFragment extends DialogFragment {

    @Override
    public void show(FragmentManager manager, String tag) {
        try {
            FragmentTransaction ft = manager.beginTransaction();
            ft.add(this, tag);
            ft.commit();
        } catch (IllegalStateException e) {
            Log.d("ABSDIALOGFRAG", "Exception", e);
        }
    }
}

নোট করুন যে এই পদ্ধতিটি প্রয়োগ করা ডায়ালগফ্রেগমেন্ট.ক্লাসের অভ্যন্তরীণ ক্ষেত্রগুলিকে পরিবর্তন করবে না:

boolean mDismissed;
boolean mShownByMe;

এটি কিছু ক্ষেত্রে অপ্রত্যাশিত ফলাফল হতে পারে। কমিট () এর পরিবর্তে কমিটএলয়েস্টিংস্টেটলস () ব্যবহার করুন


3
তবে কেন এই সমস্যাটি ঘটে? ত্রুটিটি উপেক্ষা করা কি ঠিক? কি করলে কি হয়? সর্বোপরি, ক্লিক করার পরে, এর অর্থ হ'ল ক্রিয়াকলাপটি লাইভ এবং ভাল ... যাইহোক, আমি এখানে এই সম্পর্কে রিপোর্ট করেছি কারণ আমি এটিকে একটি ত্রুটি হিসাবে বিবেচনা করছি: code.google.com/p/android/issues/detail?id= 207269
অ্যান্ড্রয়েড বিকাশকারী

1
আপনি কি দয়া করে তারা এবং / অথবা সেখানে মন্তব্য করতে পারেন?
অ্যান্ড্রয়েড বিকাশকারী

2
চেষ্টা করার ধরণের ভিতরে সুপার.শো (পরিচালক, ট্যাগ) কল করা ভাল better ডায়ালগফ্র্যাগমেন্টের মালিকানাধীন পতাকাগুলি এইভাবে নিরাপদ থাকতে পারে
শায়ান_আরয়ান

19
এই মুহুর্তে আপনি কমিটএলিংস্টেটলস () কমিট () এর পরিবর্তে কল করতে পারেন। ব্যতিক্রম উত্থাপিত হবে না।
এআরএল্যাবস

1
@আরল্যাবগুলি আমি এই ক্ষেত্রে কল্পনা করি যা উত্তরদাতাদের পক্ষেও ভাল হবে কারণ আপনি যদি এখানে বর্ণিত ব্যতিক্রমটি ধরেন তবে অবশ্যই ডায়ালগটি প্রদর্শিত হবে না। যদি আপনি পারেন তবে ডায়ালগটি দেখানো আরও ভাল এবং যদি রাষ্ট্রটি পুনরুদ্ধার করতে হয় তবে এটি চলে যেতে পারে। এছাড়াও আপনার অ্যাপ্লিকেশন মেমরিটি পটভূমিতে কম রাখুন যাতে এটি ধ্বংস হওয়ার সম্ভাবনা না থাকে।
androidguy

27

তার মানে আপনি commit()( show()ডায়ালগফ্র্যাগমেন্টের ক্ষেত্রে) এর পরে খণ্ড onSaveInstanceState()

অ্যান্ড্রয়েড এতে আপনার খণ্ডের অবস্থা সংরক্ষণ করবে onSaveInstanceState()। সুতরাং, আপনি যদি commit()খণ্ড খণ্ডের পরে onSaveInstanceState()খন্ড খণ্ডন হয়ে যায়।

ফলস্বরূপ, যদি কার্যকলাপটি মারা যায় এবং পরে পুনরায় তৈরি করা হয় তবে খণ্ডটি ক্রিয়াকলাপে যুক্ত হবে না যা ব্যবহারকারীর খারাপ অভিজ্ঞতা। এ কারণেই অ্যান্ড্রয়েড কোনও মূল্যে রাষ্ট্রীয় ক্ষতি হারাতে দেয় না।

ইতিমধ্যে রাষ্ট্রটি ইতিমধ্যে সংরক্ষিত আছে কিনা তা পরীক্ষা করে দেখার সহজ সমাধান।

boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;

@Override
public void onResumeFragments(){
    super.onResumeFragments();
    mIsStateAlreadySaved = false;
    if(mPendingShowDialog){
        mPendingShowDialog = false;
        showSnoozeDialog();
    }
}

@Override
public void onPause() {
    super.onPause();
    mIsStateAlreadySaved = true;
}

private void showSnoozeDialog() {
    if(mIsStateAlreadySaved){
        mPendingShowDialog = true;
    }else{
        FragmentManager fm = getSupportFragmentManager();
        SnoozeDialog snoozeDialog = new SnoozeDialog();
        snoozeDialog.show(fm, "snooze_dialog");
    }
}

দ্রষ্টব্য: টুকরোগুলি আবার শুরু হয়ে গেলে onResumeFraਮੈਂਟ () কল করবে।


1
যদি আমি অন্য খণ্ডের মধ্যে ডায়ালগফ্র্যাগমেন্টটি দেখাতে চাই তবে কী হবে?
অ্যান্ড্রয়েড বিকাশকারী

আমাদের সমাধান হ'ল ক্রিয়াকলাপ তৈরি এবং টুকরো টুকরো বেস শ্রেণি এবং অন-পুনরায় ফ্রেমগুলিকে খণ্ডগুলিতে প্রেরণ করা (আমরা ফ্রেগমেন্ট বেস শ্রেণিতে অন-পুনরায় ফ্রেম তৈরি করি)। এটি দুর্দান্ত সমাধান নয় তবে এটি কাজ করে। আপনার যদি এর থেকে আরও ভাল সমাধান থাকে তবে দয়া করে আমাকে জানান :)
পংপাট

ঠিক আছে, আমি ভেবেছিলাম যে "অন স্টার্ট" এ ডায়লগটি দেখানো ভাল কাজ করা উচিত, যেহেতু খণ্ডটি অবশ্যই দেখানো হচ্ছে, তবে আমি এখনও এটি সম্পর্কে কিছু ক্র্যাশ রিপোর্ট দেখতে পাচ্ছি। পরিবর্তে "অনারিউজুম" এ দেওয়ার চেষ্টা করার জন্য আমাকে নির্দেশ দেওয়া হয়েছিল। বিকল্প সম্পর্কে, আমি এটি দেখেছি: twigstechtips.blogspot.co.il/2014/01/… , তবে এটি বেশ অদ্ভুত।
অ্যান্ড্রয়েড বিকাশকারী 13

আমি মনে করি যে কারণগুলি twigstechtips.blogspot.co.il/2014/01/… কাজ করে কারণ এটি নতুন থ্রেড শুরু করে এবং তাই লাইফসাইकल কোড যেমন অনস্টার্ট, অন রেসুম, ইত্যাদি কোড রানঅনউইথ্রেড কখনও চালিত হওয়ার আগে ডাকা হয়। তার মানে, রানওনউইথ্রেড ডাকা হওয়ার আগেই ইতিমধ্যে রাজ্য পুনরুদ্ধার করুন।
পংপাট

2
আমি পোস্ট করতে একক কল ব্যবহার করি (চলমান)। GetFragmentManager সম্পর্কিত, এটি নির্ভর করে। আপনি যদি এই ক্রিয়াকলাপটিকে অন্য ক্রিয়াকলাপের সাথে ভাগ করতে চান তবে getFragmentManager ব্যবহার করা উচিত, তবে যদি সেই ডায়ালগটি কেবলমাত্র খণ্ড getChildFragmentManager এর সাথেই থাকে তবে এটি আরও ভাল পছন্দ বলে মনে হয়।
পংপাট

16
private void showSnoozeDialog() {
    FragmentManager fm = getSupportFragmentManager();
    SnoozeDialog snoozeDialog = new SnoozeDialog();
    // snoozeDialog.show(fm, "snooze_dialog");
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.add(snoozeDialog, "snooze_dialog");
    ft.commitAllowingStateLoss();
}

রেফ: লিঙ্ক


11

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

override fun show(manager: FragmentManager?, tag: String?) {
        try {
            val ft = manager?.beginTransaction()
            ft?.add(this, tag)
            ft?.commitAllowingStateLoss()
        } catch (ignored: IllegalStateException) {

        }

    }

1
তাই ডেভেলপারদের উত্তরাধিকারী হবে না যা থেকে DialogFragmentআপনি এই পরিবর্তন হতে পারে নিম্নলিখিত স্বাক্ষর সহ একটি Kotlin এক্সটেনশন ফাংশন হবে হবে: fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)। এছাড়াও, চেষ্টাটি প্রয়োজনীয় নয় যেহেতু আপনি commitAllowingStateLoss()পদ্ধতিটি নয় বরং commit()পদ্ধতিটি কল করছেন ।
আদিল হুসেন

10

যদি কথোপকথনটি সত্যিই গুরুত্বপূর্ণ না হয় (অ্যাপটি বন্ধ হয়ে গেলে / আর দেখা না গেলে এটি প্রদর্শন না করা ভাল), ব্যবহার করুন:

boolean running = false;

@Override
public void onStart() {
    running = true;
    super.onStart();
}

@Override
public void onStop() {
    running = false;
    super.onStop();
}

এবং আপনার ডায়ালগটি (টুকরা) কেবল তখনই চালিত করুন যখন আমরা চালাচ্ছি:

if (running) {
    yourDialog.show(...);
}

সম্পাদনা করুন, সম্ভবত উন্নততর সমাধান:

যেখানে লাইফাইসাইকালে অনসাইভসানস্ট্যান্সস্টেট বলা হয় তা অনির্দেশ্য, আমি মনে করি এর চেয়ে ভাল সমাধান হ'ল এইভাবে সেভড ইনস্ট্যান্সস্টেটডোন () পরীক্ষা করা:

/**
 * True if SavedInstanceState was done, and activity was not restarted or resumed yet.
 */
private boolean savedInstanceStateDone;

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

    savedInstanceStateDone = false;
}

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

    savedInstanceStateDone = false;
}

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    savedInstanceStateDone = true;
}


/**
 * Returns true if SavedInstanceState was done, and activity was not restarted or resumed yet.
 */
public boolean isSavedInstanceStateDone() {
    return savedInstanceStateDone;
}

এটি কার্যকর হবে বলে মনে হচ্ছে না, কারণ আমি "অনস্টার্ট" পদ্ধতি কলটিতে এই ব্যতিক্রমটি পাই (সেখানে ডায়ালগফ্র্যাগমেন্টটি দেখানোর চেষ্টা করছি)।
অ্যান্ড্রয়েড বিকাশকারী

আপনি আমার দিন বাঁচিয়েছেন। ধন্যবাদ ফ্র্যাঙ্ক
Cüneyt

7

আমি বছরের পর বছর ধরে এই সমস্যায় পড়েছি।
ইন্টার্নেটগুলি স্কোর (শত? হাজার?) নিয়ে এই বিষয়ে আলোচনার দ্বারা আবদ্ধ এবং তাদের মধ্যে বিভ্রান্তি এবং বিশৃঙ্খলা একেবারে আপত্তি বলে মনে হয়।
পরিস্থিতি আরও খারাপ করতে এবং xkcd "14 স্ট্যান্ডার্ড" কমিকের অনুপ্রেরণায় আমি আমার উত্তরটি রিংয়ের মধ্যে ফেলে দিচ্ছি।
xkcd 14 মান

cancelPendingInputEvents(), commitAllowingStateLoss(), catch (IllegalStateException e), এবং অনুরূপ সমাধান সব নৃশংস বলে মনে হচ্ছে।

আশা করি নীচে সহজেই কীভাবে সমস্যাটি পুনরুত্পাদন এবং সমাধান করা যায় তা দেখানো হয়েছে:

private static final Handler sHandler = new Handler();
private boolean mIsAfterOnSaveInstanceState = true;

@Override
protected void onSaveInstanceState(Bundle outState)
{
    super.onSaveInstanceState(outState);
    mIsAfterOnSaveInstanceState = true; // <- To repro, comment out this line
}

@Override
protected void onPostResume()
{
    super.onPostResume();
    mIsAfterOnSaveInstanceState = false;
}

@Override
protected void onResume()
{
    super.onResume();
    sHandler.removeCallbacks(test);
}

@Override
protected void onPause()
{
    super.onPause();
    sHandler.postDelayed(test, 5000);
}

Runnable test = new Runnable()
{
    @Override
    public void run()
    {
        if (mIsAfterOnSaveInstanceState)
        {
            // TODO: Consider saving state so that during or after onPostResume a dialog can be shown with the latest text
            return;
        }

        FragmentManager fm = getSupportFragmentManager();
        DialogFragment dialogFragment = (DialogFragment) fm.findFragmentByTag("foo");
        if (dialogFragment != null)
        {
            dialogFragment.dismiss();
        }

        dialogFragment = GenericPromptSingleButtonDialogFragment.newInstance("title", "message", "button");
        dialogFragment.show(fm, "foo");

        sHandler.postDelayed(test, 5000);
    }
};

2
আমি লোকেদের পছন্দ করি যে কোনও ব্যাখ্যা ছাড়াই ভোট দেয়। কেবলমাত্র ভোটগ্রহণের পরিবর্তে, তারা কীভাবে আমার সমাধানটি ত্রুটিযুক্ত তা ব্যাখ্যা করলে ভাল হয়? আমি কি ভোটারদের ডাউন ডাউন ভোট দিতে পারি?
21:40:40

1
হ্যাঁ, এটি এসও এর একটি সমস্যা, আমি প্রতিবারই পরামর্শগুলিতে এই সমস্যাটি লিখি, তবে তারা সমাধান করতে চায় না।
কুলমাইন্ড

2
আমি মনে করি ডাউনভোটগুলি এমবেডড এক্সকেসিডি-র ফলাফল হতে পারে, উত্তরগুলি সামাজিক মন্তব্যের জন্য সত্যই স্থান নয়, (যতই হাস্যকর এবং / অথবা সত্যই নয়)।
রেস্টিংরবোট

6

দয়া করে ফ্রেগমেন্টম্যানেজারের পরিবর্তে ফ্র্যাগমেন্ট ট্রান্সজিশন ব্যবহার করার চেষ্টা করুন। আমি মনে করি নীচের কোডটি আপনার সমস্যার সমাধান করবে। যদি না হয়, দয়া করে আমাকে জানান।

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(ft, "snooze_dialog");

সম্পাদনা করুন:

টুকরা লেনদেন

এই লিঙ্কটি চেক করুন। আমি মনে করি এটি আপনার প্রশ্নের সমাধান করবে।


4
ফ্রেগমেন্ট ট্রান্সজেকশন কেন ব্যবহার করে সমস্যাটি স্থির করে সে সম্পর্কে কোনও ব্যাখ্যা দুর্দান্ত।
হেমংশু

3
ডায়ালগ # শো (ফ্র্যাগমেন্টম্যানেজার, ট্যাগ) একই কাজ করে। এটি কোনও সমাধান নয়।
উইলিয়াম

3
এই উত্তরটি সমাধান নয়। ডায়ালগফ্রেগমেন্ট # শো (ফুট) এবং শো (এফএম) ঠিক একই কাজ করে।
ডানিজু

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

5

ক্রিয়াকলাপ-কেটিএক্স এর নতুন লাইফেসাইক্যাল স্কোপগুলি ব্যবহার করে এটি নিম্নলিখিত কোডের নমুনার মতোই সহজ:

lifecycleScope.launchWhenResumed {
   showErrorDialog(...)
}

অনসটপ () এর পরে এই পদ্ধতিটি সরাসরি কল করা যেতে পারে এবং অনারিউম () পুনরায় ফিরে আসার জন্য ডাকা হয়ে গেলে একবারে ডায়লগটি সফলভাবে দেখাবে।


3

অনেকগুলি দর্শন স্থগিত হওয়ার জন্য ইভেন্টের সারিটিতে ক্লিক হ্যান্ডলারের মতো উচ্চ-স্তরের ইভেন্টগুলি পোস্ট করে। সুতরাং সমস্যাটি হ'ল "onSaveInstanceState" ইতিমধ্যে ক্রিয়াকলাপের জন্য আহ্বান করা হয়েছে তবে ইভেন্টের সারিতে স্থগিত "ক্লিক ইভেন্ট" রয়েছে। অতএব যখন এই ইভেন্টটি আপনার হ্যান্ডলারের কাছে প্রেরণ করা হয়

at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)

এবং আপনার কোডটি showইলিজালস্টেট এক্সেপশন নিক্ষেপ করেছে।

সবচেয়ে সহজ সমাধান হল ইভেন্টের সারিটি পরিষ্কার করা in onSaveInstanceState

protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // ..... do some work
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            findViewById(android.R.id.content).cancelPendingInputEvents();
        }
}

আপনি কি সত্যই নিশ্চিত করেছেন যে এটি সমস্যার সমাধান করে?
মহ্মস্মিথ

গুগল এটি বর্তমানে বিটা ( activityএবং fragment) এ অ্যান্ড্রয়েডেক্স লাইব্রেরিগুলির পরবর্তী প্রকাশে যুক্ত করেছে in
মহ্মস্মিথ

1
@ এমএএমএসমিথ আমার মনে আছে যে এই সমাধানটি আমার কোডটিতে ইলিজালস্টেট এক্সেপশন সহ সমস্যার সমাধান করেছে
সিম

2

আপনার কথোপকথনের খণ্ডটি অবজেক্টকে বিশ্বব্যাপী করুন এবং অনপজ () পদ্ধতিতে বরখাস্ত অ্যালাউজিংস্টেটলস () কে কল করুন

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

    if (dialogFragment != null) {
        dialogFragment.dismissAllowingStateLoss();
    }
}

বোতাম ক্লিক করুন বা যেখানে ক্লিক করুন টুকরা এবং কল শো () তে মান নির্ধারণ করতে ভুলবেন না।


1

যদিও এটি আনুষ্ঠানিকভাবে কোথাও উল্লেখ করা হয়নি তবে আমি কয়েকবার এই সমস্যার মুখোমুখি হয়েছি। আমার অভিজ্ঞতার সাথে পুরানো প্ল্যাটফর্মগুলিতে টুকরা সমর্থন করে সামঞ্জস্য লাইব্রেরিতে কিছু ভুল আছে যা এই সমস্যার কারণ হয়ে দাঁড়ায়। আপনি সাধারণ খণ্ড পরিচালক ব্যবস্থাপক এপিআই ব্যবহার করে এটি পরীক্ষা করেন। যদি কিছুই কাজ না করে তবে আপনি ডায়ালগ খণ্ডের পরিবর্তে সাধারণ ডায়ালগটি ব্যবহার করতে পারেন।


1
  1. আপনার প্রকল্পে এই শ্রেণিটি যুক্ত করুন: (অবশ্যই android.support.v4.app প্যাকেজে থাকতে হবে )
প্যাকেজ android.support.v4.app;


/ **
 * 8/16/2017 এ গিল দ্বারা নির্মিত।
 * /

পাবলিক ক্লাস স্টেটলেসডায়ালগফ্র্যাগমেন্ট ডায়ালগফ্র্যাগমেন্ট প্রসারিত করে {
    / **
     * ডায়ালগটি প্রদর্শন করুন, বিদ্যমান লেনদেন ব্যবহার করে টুকরো যোগ করুন এবং তারপরে প্রতিশ্রুতিবদ্ধ
     * লেনদেনের ফলে রাষ্ট্রের ক্ষতির সুযোগ হয়।
* * আমি আপনাকে l @ লিঙ্ক # শো (ফ্রেগমেন্ট ট্রান্সজিশন, স্ট্রিং) ব্যবহার করার পরামর্শ দিচ্ছি} বেশিরভাগ সময় তবে * এটি এমন ডায়ালগগুলির জন্য যা আপনি সত্যিই যত্নশীল হন না। (ডিবাগ / ট্র্যাকিং / বিজ্ঞাপনগুলি ইত্যাদি) * * @ পরিমাপের লেনদেন * একটি বিদ্যমান লেনদেন যাতে খণ্ড যুক্ত করা যায়। * @ পরিমাপ ট্যাগ * এই খণ্ডটির জন্য ট্যাগ, * l @ লিঙ্ক ফ্র্যাগমেন্ট ট্রানজেকশন # অ্যাড (টুকরা, স্ট্রিং) ফ্র্যাগমেন্টট্রান্সঅ্যাকশন.এডডি} * @ পুনর্বার প্রতিশ্রুতিবদ্ধ লেনদেনের শনাক্তকারীকে ফিরিয়ে দেয় * l @ লিঙ্ক ফ্র্যাগমেন্ট ট্রান্সজেকশন # কমিট () ফ্রেগমেন্টট্রান্সজেকশন ডটমিট ()}} * @ স্টেটলেসডায়ালগফ্রেগমেন্ট # শোএলিউশনস্টেটলস (ফ্র্যাগমেন্টম্যানেজার, স্ট্রিং) * / পাবলিক ইন্ট শোএলিউস্টিং স্টেটলস (ফ্র্যাগমেন্ট ট্রানজেকশন লেনদেন, স্ট্রিং ট্যাগ) { mDismused = মিথ্যা; mShownByMe = সত্য; লেনদেন.এডডি (এটি, ট্যাগ); mViewDestroyed = মিথ্যা; এমব্যাকস্ট্যাকআইডি = লেনদেন.টমিটআলোইংস্টেটলস (); এমব্যাকস্ট্যাকআইডি রিটার্ন করুন; } / ** * প্রদত্ত ফ্রেগমেন্ট ম্যানেজারে টুকরো যোগ করে ডায়ালগটি প্রদর্শন করুন। এটি একটি সুবিধা * স্পষ্টভাবে একটি লেনদেন তৈরি করার জন্য, প্রদত্ত ট্যাগের সাথে এতে খণ্ড যুক্ত করা এবং and * রাষ্ট্রের বিষয়ে চিন্তা না করে এটি করা। এটি লেনদেনটি যুক্ত করে না * পিছনের স্ট্যাক খণ্ডটি বরখাস্ত করা হলে, এটি সরাতে একটি নতুন লেনদেন কার্যকর করা হবে * ক্রিয়াকলাপ থেকে।
* * আমি আপনাকে l @ লিঙ্ক # শো (ফ্রেগমেন্টম্যানেজার, স্ট্রিং) ব্যবহার করার পরামর্শ দিচ্ছি} বেশিরভাগ সময় তবে এটি * ডায়লগগুলির জন্য যা আপনার সত্যিই যত্নশীল নয়। (ডিবাগ / ট্র্যাকিং / বিজ্ঞাপনগুলি ইত্যাদি) * * * @ পরিমেল ম্যানেজার * ফ্রেগমেন্ট ম্যানেজার এই খণ্ডটি যুক্ত করা হবে। * @ পরিমাপ ট্যাগ * এই খণ্ডটির জন্য ট্যাগ, * l @ লিঙ্ক ফ্র্যাগমেন্ট ট্রানজেকশন # অ্যাড (টুকরা, স্ট্রিং) ফ্র্যাগমেন্টট্রান্সঅ্যাকশন.এডডি} * @ স্টেটলেসডায়ালগফ্রেগমেন্ট # শোএলয়িংস্টেটলস (ফ্র্যাগমেন্ট ট্রান্সজেকশন, স্ট্রিং) * / সর্বজনীন শূন্য অনুষ্ঠানএলিংস্টেস্টেটলস (ফ্র্যাগমেন্টম্যানেজার ম্যানেজার, স্ট্রিং ট্যাগ) { mDismused = মিথ্যা; mShownByMe = সত্য; ফ্র্যাগমেন্টট্রান্সএশন এফটি = ম্যানেজার.বেগিনট্রান্সঅ্যাকশন (); ft.add (এটি, ট্যাগ); ft.commitAllowingStateLoss (); } }
  1. প্রসারিত StatelessDialogFragment পরিবর্তে DialogFragment
  2. শোয়ের পরিবর্তে শোএলিউশনস্টেটলস পদ্ধতিটি ব্যবহার করুন

  3. উপভোগ করুন;)


এই সমস্ত বুলিয়ান ক্ষেত্রগুলি কীসের জন্য? কেন তাদের ক্লাস সদস্য হিসাবে ঘোষণা করা হয় না?
সংজ্ঞায়িত

1
বুলিয়ান ক্ষেত্রগুলি ডায়ালগফ্র্যাগমেন্টের সুরক্ষিত সদস্য, তাদের নামগুলি স্পষ্টতই বোঝায় যে তারা কীসের জন্য রয়েছে এবং ডায়ালগফ্র্যাগমেন্টের যুক্তিতে বাধা না দেওয়ার জন্য আমাদের সেগুলি আপডেট করতে হবে। মনে রাখবেন যে মূল ডায়ালগফ্রেগমেন্ট শ্রেণিতে এই ফাংশনগুলি উপস্থিত রয়েছে তবে জনসাধারণের অ্যাক্সেস ছাড়াই
গিল এসএইচ

এই সদস্যগুলি সুরক্ষিত নয়, তারা অভ্যন্তরীণ। আমি StatelessDialogFragmentআমার এক প্যাকেজটির ভিতরে রাখার সাথে সাথে আমি সংকলন ত্রুটি পেয়ে যাচ্ছিলাম dড্যাব ধন্যবাদ I
সংজ্ঞায়িত


1

আমি প্রতিবিম্ব ব্যবহার করে এই সমস্যার জন্য একটি মার্জিত সমাধান খুঁজে পেয়েছি। উপরের সমস্ত সমাধানগুলির সমস্যা হ'ল এমডিসমিজড এবং এমশাউনবিএম তাদের ক্ষেত্রগুলি পরিবর্তন করে না।

নীচের নমুনার মতো আপনার নিজস্ব কাস্টম নীচের শীট ডায়ালগ খণ্ডে কেবল "পদ্ধতি" ওভাররাইড করুন

override fun show(manager: FragmentManager, tag: String?) {
        val mDismissedField = DialogFragment::class.java.getDeclaredField("mDismissed")
        mDismissedField.isAccessible = true
        mDismissedField.setBoolean(this, false)

        val mShownByMeField = DialogFragment::class.java.getDeclaredField("mShownByMe")
        mShownByMeField.isAccessible = true
        mShownByMeField.setBoolean(this, true)

        manager.beginTransaction()
                .add(this, tag)
                .commitAllowingStateLoss()
    }

4
"আমি প্রতিবিম্ব ব্যবহার করে এই সমস্যার জন্য একটি মার্জিত সমাধান খুঁজে পেয়েছি।" এটি মার্জিত কিভাবে?
মার্ক বুকেমা

মার্জিত, আড়ম্বরপূর্ণ, চটকদার, স্মার্ট, সুন্দর, করুণাময়
Богдан Богдан

1
এটি আমার পক্ষে কাজ করা একমাত্র সমাধান। আমি মনে করি এটি মার্জিত
এমবিএইচ

0

নিম্নলিখিত প্রয়োগটি Activityলাইফসাইকের সময় নিরাপদে রাষ্ট্র পরিবর্তনগুলি সম্পাদন করার সমস্যাটি সমাধান করতে ব্যবহার করা যেতে পারে , বিশেষত ডায়লগগুলি দেখানোর জন্য: উদাহরণস্বরূপ রাজ্যটি ইতিমধ্যে সংরক্ষণ করা হয়েছে (উদাহরণস্বরূপ কোনও কনফিগারেশনের পরিবর্তনের কারণে), পুনরায় শুরু হওয়া রাষ্ট্রটি না হওয়া পর্যন্ত এগুলি স্থগিত করে দেয় সম্পাদিত হয়েছে।

public abstract class XAppCompatActivity extends AppCompatActivity {

    private String TAG = this.getClass().getSimpleName();

    /** The retained fragment for this activity */
    private ActivityRetainFragment retainFragment;

    /** If true the instance state has been saved and we are going to die... */
    private boolean instanceStateSaved;

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        // get hold of retain Fragment we'll be using
        retainFragment = ActivityRetainFragment.get(this, "Fragment-" + this.getClass().getName());
    }

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

        // reset instance saved state
        instanceStateSaved = false;

        // execute all the posted tasks
        for (ActivityTask task : retainFragment.tasks) task.exec(this);
        retainFragment.tasks.clear();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        instanceStateSaved = true;
    }

    /**
     * Checks if the activity state has been already saved.
     * After that event we are no longer allowed to commit fragment transactions.
     * @return true if the instance state has been saved
     */
    public boolean isInstanceStateSaved() {
        return instanceStateSaved;
    }

    /**
     * Posts a task to be executed when the activity state has not yet been saved
     * @param task The task to be executed
     * @return true if the task executed immediately, false if it has been queued
     */
    public final boolean post(ActivityTask task)
    {
        // execute it immediately if we have not been saved
        if (!isInstanceStateSaved()) {
            task.exec(this);
            return true;
        }

        // save it for better times
        retainFragment.tasks.add(task);
        return false;
    }

    /** Fragment used to retain activity data among re-instantiations */
    public static class ActivityRetainFragment extends Fragment {

        /**
         * Returns the single instance of this fragment, creating it if necessary
         * @param activity The Activity performing the request
         * @param name The name to be given to the Fragment
         * @return The Fragment
         */
        public static ActivityRetainFragment get(XAppCompatActivity activity, String name) {

            // find the retained fragment on activity restarts
            FragmentManager fm = activity.getSupportFragmentManager();
            ActivityRetainFragment fragment = (ActivityRetainFragment) fm.findFragmentByTag(name);

            // create the fragment and data the first time
            if (fragment == null) {
                // add the fragment
                fragment = new ActivityRetainFragment();
                fm.beginTransaction().add(fragment, name).commit();
            }

            return fragment;
        }

        /** The queued tasks */
        private LinkedList<ActivityTask> tasks = new LinkedList<>();

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);

            // retain this fragment
            setRetainInstance(true);
        }

    }

    /** A task which needs to be performed by the activity when it is "fully operational" */
    public interface ActivityTask {

        /**
         * Executed this task on the specified activity
         * @param activity The activity
         */
        void exec(XAppCompatActivity activity);
    }
}

তারপরে এই জাতীয় ক্লাস ব্যবহার করা:

/** AppCompatDialogFragment implementing additional compatibility checks */
public abstract class XAppCompatDialogFragment extends AppCompatDialogFragment {

    /**
     * Shows this dialog as soon as possible
     * @param activity The activity to which this dialog belongs to
     * @param tag The dialog fragment tag
     * @return true if the dialog has been shown immediately, false if the activity state has been saved
     *         and it is not possible to show it immediately
     */
    public boolean showRequest(XAppCompatActivity activity, final String tag) {
        return showRequest(activity, tag, null);
    }

    /**
     * Shows this dialog as soon as possible
     * @param activity The activity to which this dialog belongs to
     * @param tag The dialog fragment tag
     * @param args The dialog arguments
     * @return true if the dialog has been shown immediately, false if the activity state has been saved
     *         and it is not possible to show it immediately
     */
    public boolean showRequest(XAppCompatActivity activity, final String tag, final Bundle args)
    {
        return activity.post(new XAppCompatActivity.ActivityTask() {
            @Override
            public void exec(XAppCompatActivity activity) {
                if (args!= null) setArguments(args);
                show(activity.getSupportFragmentManager(), tag);
            }
        });
    }

    /**
     * Dismiss this dialog as soon as possible
     * @return true if the dialog has been dismissed immediately, false if the activity state has been saved
     *         and it is not possible to dismissed it immediately
     */
    public boolean dismissRequest()
    {
        return dismissRequest(null);
    }

    /**
     * Dismiss this dialog as soon as possible
     * @param runnable Actions to be performed before dialog dismissal
     * @return true if the dialog has been dismissed immediately, false if the activity state has been saved
     *         and it is not possible to dismissed it immediately
     */
    public boolean dismissRequest(final Runnable runnable)
    {
        // workaround as in rare cases the activity could be null
        XAppCompatActivity activity = (XAppCompatActivity)getActivity();
        if (activity == null) return false;

        // post the dialog dismissal
        return activity.post(new XAppCompatActivity.ActivityTask() {
            @Override
            public void exec(XAppCompatActivity activity) {
                if (runnable != null) runnable.run();
                dismiss();
            }
        });
    }
}

আপনি অ্যাপ্লিকেশন স্থিতি নিয়ে চিন্তা না করে নিরাপদে ডায়লগগুলি প্রদর্শন করতে পারেন:

public class TestDialog extends XAppCompatDialogFragment {

    private final static String TEST_DIALOG = "TEST_DIALOG";

    public static void show(XAppCompatActivity activity) {
        new TestDialog().showRequest(activity, TEST_DIALOG);
    }

    public TestDialog() {}

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        return new AlertDialog.Builder(getActivity(), R.style.DialogFragmentTheme /* or null as you prefer */)
                .setTitle(R.string.title)
                // set all the other parameters you need, e.g. Message, Icon, etc.
                ).create();
    }
}

এবং তারপরে আপনার TestDialog.show(this)কাছ থেকে কল করুন XAppCompatActivity

আপনি পরামিতি সঙ্গে আরো একটি জেনেরিক ডায়ালগ বর্গ তৈরি করতে চান, তাহলে আপনি একটি তাদের রক্ষা করতে পারে Bundleমধ্যে আর্গুমেন্ট সহ show()পদ্ধতি এবং তাদের সঙ্গে উদ্ধার getArguments()মধ্যে onCreateDialog()

পুরো পদ্ধতিকে কিছুটা জটিল মনে হতে পারে তবে আপনি একবার ক্রিয়াকলাপ এবং কথোপকথনের জন্য দুটি বেস ক্লাস তৈরি করে ফেললে এটি ব্যবহার করা বেশ সহজ এবং পুরোপুরি কার্যকর is এটি অন্যের জন্য ব্যবহার করা যেতে পারেFragment ভিত্তিক ক্রিয়াকলাপগুলির যেতে পারে যা একই সমস্যা দ্বারা প্রভাবিত হতে পারে।


0

এই ত্রুটিটি ঘটছে বলে মনে হচ্ছে কারণ ইনপুট ইভেন্টগুলি (যেমন কী ডাউন বা অনক্লিক ইভেন্টগুলি) পরে সরবরাহ করা হচ্ছে onSaveInstanceState ডাকা হচ্ছে।

সমাধানটি হ'ল onSaveInstanceStateআপনার ক্রিয়াকলাপে ওভাররাইড করা এবং কোনও মুলতুবি থাকা ইভেন্ট বাতিল করা।

@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();
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.