অ্যান্ড্রয়েড ৪.২: নেস্টেড টুকরা সহ ব্যাক স্ট্যাকের আচরণ behavior


108

অ্যান্ড্রয়েড 2.২ সহ, সমর্থন লাইব্রেরি এখানে নীচে থাকা টুকরো জন্য সমর্থন পেয়েছে । আমি এটির সাথে চারপাশে খেলেছি এবং ব্যাক স্ট্যাক এবং getChildFraamentManager () সম্পর্কিত একটি আকর্ষণীয় আচরণ / বাগ খুঁজে পেয়েছি । GetChildFraamentManager () এবং addToBackStack (স্ট্রিং নাম) ব্যবহার করার সময়, পিছনের বোতামটি টিপে সিস্টেমটি পূর্ববর্তী খণ্ডটিতে ব্যাক স্ট্যাকটি চালায় না। অন্যদিকে, getFramentManager () এবং addToBackStack (স্ট্রিং নাম) ব্যবহার করার সময়, পিছনের বোতামটি টিপে সিস্টেমটি পূর্ববর্তী খণ্ডে ফিরে আসে।

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

এই আচরণ কি সঠিক? এই আচরণ কি বাগ? এই ইস্যুটির জন্য কি কোনও কাজ আছে?

getChildFraamentManager () সহ নমুনা কোড:

public class FragmentceptionActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);

    final FrameLayout wrapper1 = new FrameLayout(this);
    wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT));
    wrapper1.setId(1);

    final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT);
    params.topMargin = 0;

    final TextView text = new TextView(this);
    text.setLayoutParams(params);
    text.setText("fragment 1");
    wrapper1.addView(text);

    setContentView(wrapper1);

    getSupportFragmentManager().beginTransaction().addToBackStack(null)
            .add(1, new Fragment1()).commit();
}

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper2 = new FrameLayout(getActivity());
        wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper2.setId(2);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 100;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 2");
        wrapper2.addView(text);

        return wrapper2;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(2, new Fragment2()).commit();
    }
}

public class Fragment2 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper3 = new FrameLayout(getActivity());
        wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper3.setId(3);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 200;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 3");
        wrapper3.addView(text);

        return wrapper3;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getChildFragmentManager().beginTransaction().addToBackStack(null)
                .add(3, new Fragment3()).commit();
    }
}

public class Fragment3 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper4 = new FrameLayout(getActivity());
        wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper4.setId(4);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 300;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 4");
        wrapper4.addView(text);

        return wrapper4;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getChildFragmentManager().beginTransaction().addToBackStack(null)
                .add(4, new Fragment4()).commit();
    }
}

public class Fragment4 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper5 = new FrameLayout(getActivity());
        wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper5.setId(5);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 400;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 5");
        wrapper5.addView(text);

        return wrapper5;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

}

গেটফ্রেগমেন্টম্যানেজার () সহ নমুনা কোড:

public class FragmentceptionActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);

    final FrameLayout wrapper1 = new FrameLayout(this);
    wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT));
    wrapper1.setId(1);

    final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT);
    params.topMargin = 0;

    final TextView text = new TextView(this);
    text.setLayoutParams(params);
    text.setText("fragment 1");
    wrapper1.addView(text);

    setContentView(wrapper1);

    getSupportFragmentManager().beginTransaction().addToBackStack(null)
            .add(1, new Fragment1()).commit();
}

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper2 = new FrameLayout(getActivity());
        wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper2.setId(2);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 100;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 2");
        wrapper2.addView(text);

        return wrapper2;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(2, new Fragment2()).commit();
    }
}

public class Fragment2 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper3 = new FrameLayout(getActivity());
        wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper3.setId(3);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 200;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 3");
        wrapper3.addView(text);

        return wrapper3;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(3, new Fragment3()).commit();
    }
}

public class Fragment3 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper4 = new FrameLayout(getActivity());
        wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper4.setId(4);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 300;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 4");
        wrapper4.addView(text);

        return wrapper4;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(4, new Fragment4()).commit();
    }
}

public class Fragment4 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper5 = new FrameLayout(getActivity());
        wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper5.setId(5);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 400;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 5");
        wrapper5.addView(text);

        return wrapper5;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

}

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

@ মার্কো, হুবহু, তবে এটি কার্যকর নয়। কেন এপিআই সঠিকভাবে কাজ করবে না?
ডিম

উত্তর:


67

এই সমাধানটি @ সিয়ান উত্তরের আরও ভাল সংস্করণ হতে পারে:

@Override
public void onBackPressed() {
    // if there is a fragment and the back stack of this fragment is not empty,
    // then emulate 'onBackPressed' behaviour, because in default, it is not working
    FragmentManager fm = getSupportFragmentManager();
    for (Fragment frag : fm.getFragments()) {
        if (frag.isVisible()) {
            FragmentManager childFm = frag.getChildFragmentManager();
            if (childFm.getBackStackEntryCount() > 0) {
                childFm.popBackStack();
                return;
            }
        }
    }
    super.onBackPressed();
}

আবার, আমি উপরের @ সিয়ান উত্তরের উপর ভিত্তি করে এই সমাধানটি প্রস্তুত করেছি।

@ এজেড 13 বলেছে যে, এই স্তরটি কেবলমাত্র এক স্তরের শিশু খণ্ডের পরিস্থিতিতে সম্ভব। একাধিক স্তরের টুকরো টুকরো ক্ষেত্রে, কাজগুলি কিছুটা জটিল হয়ে যায়, তাই আমি প্রস্তাব দিই যে কেবলমাত্র আমি বলি এমন সম্ভাব্য ক্ষেত্রেই এই সমাধানটি ব্যবহার করে দেখুন। =)

দ্রষ্টব্য: যেহেতু getFragmentsপদ্ধতিটি এখন একটি ব্যক্তিগত পদ্ধতি, তাই এই সমাধানটি কার্যকর হবে না। আপনি কোনও লিঙ্কের জন্য মন্তব্যগুলি পরীক্ষা করতে পারেন যা এই পরিস্থিতি সম্পর্কে সমাধানের পরামর্শ দেয়।


2
One 忠 উত্তরটির পরিবর্তে উত্তরটি ব্যবহার করা উচিত - এটি একাধিক নেস্টেড টুকরোগুলি সঠিকভাবে পরিচালনা করে
Hameno

এটি কি কার্যকরী কোড? এমনকি getFraਮੈਂਟগুলি কি পাবলিক পদ্ধতি নয়? stackoverflow.com/a/42572412/4729203
wonsuc

এটি একবারে কাজ করেছে তবে যদি এখনই কাজগুলি প্রকাশ্য না হয় তবে এখন কাজ করছে না working
ইসমাইলিলিক

1
getFragmentsএখন প্রকাশ্য
18:53

পেজারের ভিতরে ফ্রেগা -> ফ্রেগ বি -> ফ্রেগ সি থাকলে এটি সঠিকভাবে কাজ করে না ...
জহর

57

বাগের মতো মনে হচ্ছে। একবার দেখুন: http://code.google.com/p/android/issues/detail?id=40323

একটি কাজের জন্য আমি সফলভাবে ব্যবহার করেছি (মতামত হিসাবে প্রস্তাবিত):

    @Override
public void onBackPressed() {

    // If the fragment exists and has some back-stack entry
    if (mActivityDirectFragment != null && mActivityDirectFragment.getChildFragmentManager().getBackStackEntryCount() > 0){
        // Get the fragment fragment manager - and pop the backstack
        mActivityDirectFragment.getChildFragmentManager().popBackStack();
    }
    // Else, nothing in the direct fragment back stack
    else{
        // Let super handle the back press
        super.onBackPressed();          
    }
}

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

@ মুহাম্মাদবাবার না, আপনি পাবেন না। যদি এটি বাতিল হয় তবে বিবৃতিটির দ্বিতীয় অংশটি মূল্যায়ন করা হবে না কারণ এটি ইতিমধ্যে মিথ্যা নির্ধারণ করা হয়েছে। অপারেন্ডটি হয় এবং না | ।
শান

25

এই প্রশ্নের আসল উত্তর হ'ল সেট-প্রাইমারিনাভিগেশনফ্রেগমেন্ট নামে ফ্রেগমেন্ট ট্রানজেকশনের ফাংশনে।

/**
 * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
 *
 * <p>The primary navigation fragment's
 * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
 * to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
 * if no ID or transaction name is provided to pop to. Navigation operations outside of the
 * fragment system may choose to delegate those actions to the primary navigation fragment
 * as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
 *
 * <p>The fragment provided must currently be added to the FragmentManager to be set as
 * a primary navigation fragment, or previously added as part of this transaction.</p>
 *
 * @param fragment the fragment to set as the primary navigation fragment
 * @return the same FragmentTransaction instance
 */
public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);

ক্রিয়াকলাপটি যুক্ত করার সময় আপনাকে এই প্রাথমিক ক্রিয়াকলাপটি সেট করতে হবে। আমার ক্রিয়াকলাপের ভিতরে আমার কাছে একটি প্রতিস্থাপনের ফাংশন রয়েছে যা দেখতে এরকম দেখাচ্ছে:

public void replaceFragment(int containerId, BaseFragment fragment, boolean addToBackstack) {
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.setPrimaryNavigationFragment(fragment);
    if (addToBackstack) {
        fragmentTransaction.addToBackStack(fragment.TAG);
    }

    fragmentTransaction.replace(containerId, fragment).commit();
}

এটি আপনাকে একই আচরণ দেয় যেন আপনি নিয়মিত খণ্ড বি থেকে ফিরে ফ্র্যাগমেন্ট এ-তে ফিরে যান, এখন এটি শিশু টুকরো টুকরো ছাড়াও!


3
দুর্দান্ত খুঁজে! এটি ওপি দ্বারা উল্লিখিত সমস্যাটিকে অনেক ক্লিনার এবং কম হ্যাকি উপায়ে সমাধান করে।
জোনা

হাভহোস্টফ্রেগমেন্ট হিসাবে নেভিগেশন লাইব্রেরির অংশ না থাকলে ক্রাশ হচ্ছে না
দিদি

22

এই সমাধানটি @ ইসমাইলিলিক উত্তরের আরও ভাল সংস্করণ হতে পারে:

নেস্টেড টুকরা সংস্করণ

private boolean onBackPressed(FragmentManager fm) {
    if (fm != null) {
        if (fm.getBackStackEntryCount() > 0) {
            fm.popBackStack();
            return true;
        }

        List<Fragment> fragList = fm.getFragments();
        if (fragList != null && fragList.size() > 0) {
            for (Fragment frag : fragList) {
                if (frag == null) {
                    continue;
                }
                if (frag.isVisible()) {
                    if (onBackPressed(frag.getChildFragmentManager())) {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

@Override
public void onBackPressed() {
    FragmentManager fm = getSupportFragmentManager();
    if (onBackPressed(fm)) {
        return;
    }
    super.onBackPressed();
}

নেস্টেড টুকরাগুলির একাধিক স্তর থাকলে এটি কাজ করে না বলে মনে হচ্ছে
স্প্লিন্টার

মেঘ আপনি আমাকে আপনার নেস্টেড টুকরাগুলির স্থাপত্য দেবেন? আমার অ্যাপে এটি কাজ করে। আমি কিছু মিস করছি
5 忠

9
ব্যাকস্ট্যাকটি পপিংয়ের ক্রমটি এই উদাহরণটিতে যেমনটি প্রত্যাশা করেছিলাম তেমন নয়। আমি বিশ্বাস করি আপনার প্রথমে গাছের মধ্যে সবচেয়ে গভীরভাবে নেস্টেড দৃশ্যমান খণ্ডটি পাওয়া উচিত এবং এর উপরের ব্যাকস্ট্যাকটি পপ করার চেষ্টা করা উচিত, তারপরে ক্রমবর্ধমানভাবে গাছটি সরিয়ে অন্য দৃশ্যমান খণ্ডগুলির সন্ধান করুন যেখানে আপনি ব্যাকস্ট্যাকটি পপ করতে না পারলে আপনি সেখানে পৌঁছাতে পারেন। একটি সহজ সমাধান যা সহজ ক্ষেত্রে পরিচালনা করে তা হ'ল অনব্যাকপ্রেসড (ফ্রেগমেন্টম্যানেজার এফএম) ফাংশন পরিবর্তন করা এবং টুকরোগুলি গণনা করে এমন একটিটির সাথে ব্যাকস্ট্যাকটি পপ করা ব্লকটি স্যুইচ করা। এই ভাবে আরও গভীরভাবে নেস্টেড শিশু টুকরা মধ্যে backstack পপিং প্রথম ঘটবে
থিও

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

এই সমাধানটি SupportFragmentManagerকেবলমাত্র স্ট্যান্ডার্ড ছাড়াই এবং ব্যবহার করা সম্ভব FragmentManager?
পিটার চ্যাপি

13

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

এটি আপনার ক্রিয়াকলাপে যুক্ত করুন যা অ্যাপকম্প্যাটঅ্যাক্টিভিটি প্রসারিত করে।

@Override
public void onBackPressed()
{
    if(!BaseFragment.handleBackPressed(getSupportFragmentManager())){
        super.onBackPressed();
    }
}

এটিকে আপনার বেসফ্রেগমেন্টে বা ক্লাসে যুক্ত করুন যাতে আপনার সমস্ত টুকরোগুলি উত্তরাধিকার সূত্রে প্রাপ্ত হতে পারে।

public static boolean handleBackPressed(FragmentManager fm)
{
    if(fm.getFragments() != null){
        for(Fragment frag : fm.getFragments()){
            if(frag != null && frag.isVisible() && frag instanceof BaseFragment){
                if(((BaseFragment)frag).onBackPressed()){
                    return true;
                }
            }
        }
    }
    return false;
}

protected boolean onBackPressed()
{
    FragmentManager fm = getChildFragmentManager();
    if(handleBackPressed(fm)){
        return true;
    }
    else if(getUserVisibleHint() && fm.getBackStackEntryCount() > 0){
        fm.popBackStack();
        return true;
    }
    return false;
}

এটি দুর্দান্ত উত্তর, ২৩/২৪ পৃষ্ঠার এপিআই স্তরে কাজ করছে এবং সমর্থন ২১.১.১-এর সাথে কাজ করছে
রিনাভ

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

কিছু ঠিক করা হয়েছে বা ২০২০ এ আমাদের এখনও সমস্যাটি রয়েছে এবং আপনার সমাধানটি বাস্তবায়ন করা উচিত ?? !!
জহর

3

এই কোডটি খণ্ড পরিচালকের গাছটিকে নেভিগেট করবে এবং সর্বশেষটি যুক্ত করা হবে যা এতে যোগ করা হয়েছিল যে কোনও খণ্ড রয়েছে এটি স্ট্যাকটি পপ করতে পারে:

private FragmentManager getLastFragmentManagerWithBack(FragmentManager fm)
{
  FragmentManager fmLast = fm;

  List<Fragment> fragments = fm.getFragments();

  for (Fragment f : fragments)
  {
    if ((f.getChildFragmentManager() != null) && (f.getChildFragmentManager().getBackStackEntryCount() > 0))
    {
      fmLast = f.getFragmentManager();
      FragmentManager fmChild = getLastFragmentManagerWithBack(f.getChildFragmentManager());

      if (fmChild != fmLast)
        fmLast = fmChild;
    }
  }

  return fmLast;
}

পদ্ধতিটি কল করুন:

@Override
public void onBackPressed()
{
  FragmentManager fm = getLastFragmentManagerWithBack(getSupportFragmentManager());

  if (fm.getBackStackEntryCount() > 0)
  {
    fm.popBackStack();
    return;
  }

  super.onBackPressed();
}

এটি সঠিকভাবে নিবন্ধিত হলে সমস্ত নেস্টেড টুকরা জন্য কাজ করে !! +100
প্রতীক সালুজা

2

কারণটি হ'ল আপনার ক্রিয়াকলাপটি ফ্র্যাগমেন্টএটিভিটি থেকে প্রাপ্ত, যা BACK কী টিপুন পরিচালনা করে ( ফ্র্যাগমেন্টএকটিভিটির 173 লাইনটি দেখুন ।

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

  • একটি একক পদ্ধতিতে OnBackKeyPressedListener একটি ইন্টারফেস সংজ্ঞায়িত void onBackKeyPressed()
  • ভিউপ্যাজার দেখায় এমন "শীর্ষ" টুকরাগুলিতে এই ইন্টারফেসটি প্রয়োগ করেছে
  • কেকেডাউনকে ওভাররাইড করে এবং ব্যাক প্রেসটি সনাক্ত করতে এবং ভিউ পেজারে সক্রিয়ভাবে বর্তমানে সক্রিয় অংশে কলবিপ্রেসকে কল করা।

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


2

আপনি যদি কোনও খণ্ডে টুকরো টুকরো ব্যবহার করছেন তবে ব্যবহার করুন getChildFragmentManager()

getChildFragmentManager().beginTransaction().replace(R.id.fragment_name, fragment).addToBackStack(null).commit();

যদি আপনি শিশু খণ্ড ব্যবহার করে থাকেন এবং এটি ব্যবহার করে প্রতিস্থাপন করেন getParentFragmentManager()

getParentFragmentManager().beginTransaction().replace(R.id.fragment_name, fragment).addToBackStack(null).commit();

যদি উভয়ই কাজ না করে তবে আপনি এটি চেষ্টা করুন getActivity().getSupportFragmentManager()

getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_name, fragment).addToBackStack(null).commit();

1

আমি অনক্রিট ভিউ () পদ্ধতিতে এই পদ্ধতিটি প্যারেন্ট টুকরোতে যুক্ত করে এবং টেক্সট ব্যাক স্ট্যাক পরিচালনা করতে সক্ষম হয়েছিল।

private void catchBackEvent(View v){
    v.setFocusableInTouchMode(true);
    v.requestFocus();
    v.setOnKeyListener( new OnKeyListener()
    {
        @Override
        public boolean onKey( View v, int keyCode, KeyEvent event )
        {
            if( keyCode == KeyEvent.KEYCODE_BACK )
            {
                if(isEnableFragmentBackStack()){
                    getChildFragmentManager().popBackStack();
                                    setEnableFragmentBackStack(false);
                    return true;
                }
                else
                    return false;   
            }
            return false;
        }
    } );
}

পদ্ধতিটি এনেবলফ্রেগমেন্টব্যাকস্ট্যাক () হ'ল একটি বুলিয়ান পতাকা যা আমি কখন প্রধান টুকরাটিতে বা তার পরে থাকি তা জানার জন্য।

নিশ্চিত হয়ে নিন যে আপনি যখন খণ্ডটি প্রতিশ্রুতিবদ্ধ যা স্ট্যাক থাকা দরকার, তখন আপনাকে অবশ্যই অ্যাডটোব্যাকস্ট্যাক পদ্ধতিটি যুক্ত করতে হবে।


1

এই সমাধানটি আরও ভাল হতে পারে, কারণ এটি নেস্টেড টুকরাগুলির সমস্ত স্তর পরীক্ষা করে:

 /**
 * This method will go check all the back stacks of the added fragments and their nested fragments
 * to the the {@code FragmentManager} passed as parameter.
 * If there is a fragment and the back stack of this fragment is not empty,
 * then emulate 'onBackPressed' behaviour, because in default, it is not working.
 *
 * @param fm the fragment manager to which we will try to dispatch the back pressed event.
 * @return {@code true} if the onBackPressed event was consumed by a child fragment, otherwise {@code false}.
 */
public static boolean dispatchOnBackPressedToFragments(FragmentManager fm) {

    List<Fragment> fragments = fm.getFragments();
    boolean result;
    if (fragments != null && !fragments.isEmpty()) {
        for (Fragment frag : fragments) {
            if (frag != null && frag.isAdded() && frag.getChildFragmentManager() != null) {
                // go to the next level of child fragments.
                result = dispatchOnBackPressedToFragments(frag.getChildFragmentManager());
                if (result) return true;
            }
        }
    }

    // if the back stack is not empty then we pop the last transaction.
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
        fm.executePendingTransactions();
        return true;
    }

    return false;
}

আপনার ক্রিয়াকলাপে onBackPressedআপনি কেবল এটিকে কল করতে পারেন:

FragmentManager fm = getSupportFragmentManager();
                // if there is a fragment and the back stack of this fragment is not empty,
                // then emulate 'onBackPressed' behaviour, because in default, it is not working
                if (!dispatchOnBackPressedToFragments(fm)) {
                    // if no child fragment consumed the onBackPressed event,
                    // we execute the default behaviour.
                    super.onBackPressed();
                }

1

তাদের সহায়তার জন্য প্রত্যেককে ধন্যবাদ, এটি (টুইট করা সংস্করণ) আমার পক্ষে কাজ করে:

@Override
public void onBackPressed() {
    if (!recursivePopBackStack(getSupportFragmentManager())) {
        super.onBackPressed();
    }
}

/**
 * Recursively look through nested fragments for a backstack entry to pop
 * @return: true if a pop was performed
 */
public static boolean recursivePopBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getFragments() != null) {
        for (Fragment fragment : fragmentManager.getFragments()) {
            if (fragment != null && fragment.isVisible()) {
                boolean popped = recursivePopBackStack(fragment.getChildFragmentManager());
                if (popped) {
                    return true;
                }
            }
        }
    }

    if (fragmentManager.getBackStackEntryCount() > 0) {
        fragmentManager.popBackStack();
        return true;
    }

    return false;
}

দ্রষ্টব্য: আপনি সম্ভবত এই নেস্টেড টুকরাগুলির ব্যাকগ্রাউন্ড রঙটি অ্যাপ থিমের উইন্ডো ব্যাকগ্রাউন্ড রঙে সেট করতে চাইবেন, ডিফল্ট হিসাবে এগুলি স্বচ্ছ। এই প্রশ্নের ক্ষেত্রের বাইরে কিছুটা হলেও এন্ড্রয়েড.আর.আট.আর.আর উইন্ডোব্যাকগ্রাউন্ডটি এবং এই সংস্থান আইডিতে ফ্রেগমেন্ট ভিউয়ের পটভূমি সেট করে এটি সম্পন্ন হয়েছে।


1

5 বছরেরও বেশি সময় এবং এটি এখনও প্রাসঙ্গিক। যদি আপনি এর সীমাবদ্ধতার কারণে টুকরো টুকরো টুকরো টুকরোটি ব্যবহার করতে না চান want নীচের ক্লাসগুলি প্রসারিত এবং ব্যবহার করুন:

NestedFragmentActivity.java

abstract public class NestedFragmentActivity extends AppCompatActivity {

    private final Stack<Integer> mActiveFragmentIdStack = new Stack<>();
    private final Stack<String> mActiveFragmentTagStack = new Stack<>();

    @Override
    public void onBackPressed() {
        if (mActiveFragmentIdStack.size() > 0 && mActiveFragmentTagStack.size() > 0) {

            // Find by id
            int lastFragmentId = mActiveFragmentIdStack.lastElement();
            NestedFragment nestedFragment = (NestedFragment) getSupportFragmentManager().findFragmentById(lastFragmentId);

            // If cannot find by id, find by tag
            if (nestedFragment == null) {
                String lastFragmentTag = mActiveFragmentTagStack.lastElement();
                nestedFragment = (NestedFragment) getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
            }

            if (nestedFragment != null) {
                nestedFragment.onBackPressed();
            }

            // If cannot find by tag, then simply pop
            mActiveFragmentTagStack.pop();
            mActiveFragmentIdStack.pop();

        } else {
            super.onBackPressed();
        }
    }

    public void addToBackStack(int fragmentId, String fragmentTag) {
        mActiveFragmentIdStack.add(fragmentId);
        mActiveFragmentTagStack.add(fragmentTag);
    }
}

NestedFragment.java

abstract public class NestedFragment extends Fragment {

    private final Stack<Integer> mActiveFragmentIdStack = new Stack<>();
    private final Stack<String> mActiveFragmentTagStack = new Stack<>();

    private NestedFragmentActivity mParentActivity;
    private NestedFragment mParentFragment;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        if (getParentFragment() == null) {
            try {
                mParentActivity = (NestedFragmentActivity) context;
            } catch (ClassCastException e) {
                throw new ClassCastException(context.toString()
                        + " must implement " + NestedFragmentActivity.class.getName());
            }
        } else {
            try {
                mParentFragment = (NestedFragment) getParentFragment();
            } catch (ClassCastException e) {
                throw new ClassCastException(getParentFragment().getClass().toString()
                        + " must implement " + NestedFragment.class.getName());
            }
        }
    }

    public void onBackPressed() {

        if (mActiveFragmentIdStack.size() > 0 && mActiveFragmentTagStack.size() > 0) {

            // Find by id
            int lastFragmentId = mActiveFragmentIdStack.lastElement();
            NestedFragment nestedFragment = (NestedFragment) getChildFragmentManager().findFragmentById(lastFragmentId);

            // If cannot find by id, find by tag
            if (nestedFragment == null) {
                String lastFragmentTag = mActiveFragmentTagStack.lastElement();
                nestedFragment = (NestedFragment) getChildFragmentManager().findFragmentByTag(lastFragmentTag);
            }

            if (nestedFragment != null) {
                nestedFragment.onBackPressed();
            }

            // If cannot find by tag, then simply pop
            mActiveFragmentIdStack.pop();
            mActiveFragmentTagStack.pop();

        } else {
            getChildFragmentManager().popBackStack();
        }
    }

    private void addToBackStack(int fragmentId, String fragmentTag) {
        mActiveFragmentIdStack.add(fragmentId);
        mActiveFragmentTagStack.add(fragmentTag);
    }

    public void addToParentBackStack() {
        if (mParentFragment != null) {
            mParentFragment.addToBackStack(getId(), getTag());
        } else if (mParentActivity != null) {
            mParentActivity.addToBackStack(getId(), getTag());
        }
    }
}

ব্যাখ্যা:

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

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

উদাহরণ:

    getChildFragmentManager().beginTransaction().replace(
            R.id.fragment,
            fragment,
            fragment.getTag()
    ).addToBackStack(null).commit();
    addToParentBackStack();

1

এখন পর্যন্ত কেউ উত্তর না পেলে আমি এটিকে সঠিকভাবে প্রয়োগ করেছি

আপনার সন্তানের নেস্টেড খণ্ডে এই পদ্ধতিটি যুক্ত করুন

   @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    // This callback will only be called when MyFragment is at least Started.
    OnBackPressedCallback callback = new OnBackPressedCallback(true ) {
        @Override
        public void handleOnBackPressed() {
            // Handle the back button event
            FragmentManager fm= getFragmentManager();
            if (fm != null) {
                if (fm.getBackStackEntryCount() > 0) {
                    fm.popBackStack();
                    Log.e( "Frag","back" );

                }

                List<Fragment> fragList = fm.getFragments();
                if (fragList != null && fragList.size() > 0) {
                    for (Fragment frag : fragList) {
                        if (frag == null) {
                            continue;
                        }
                        if (frag.isVisible()) {
                          Log.e( "Frag","Visible" );
                        }
                    }
                }
            }


        }
    };
    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
    super.onCreate( savedInstanceState );
}

0

ক্রিয়াকলাপের সম্পত্তিতে বর্তমানে খোলার খণ্ড রেখে এই সমস্যাটি সমাধান করেছি। তারপরে আমি পদ্ধতিটি ওভাররাইড করি

 // INSIDE ACTIVITY
 override fun onBackPressed() {
    val fragment = currentFragment

    if(fragment != null && fragment.childFragmentManager.fragments.any()){
        fragment.childFragmentManager.popBackStack()
    }
    else {
        super.onBackPressed()
    }
}

এইভাবে আমি নিজের মধ্যে থেকেই খোলার খণ্ডে শিশু খণ্ডকে যুক্ত করব।

 // INSIDE FRAGMENT
 menu_fragment_view.setBackgroundColor(-((Math.random() * 10000 ).toInt() % 30000)) // to see change
 add_fragment_button.setOnClickListener {
        val transaction = childFragmentManager.beginTransaction()

        transaction.add(R.id.menu_fragment_fragment_holder, MenuFragment())

        transaction.addToBackStack(null)

        transaction.commit()
    }

এটি প্যারেন্ট টুকরা এবং সংযুক্ত অংশের xML বিন্যাস

 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/menu_fragment_view">
     <Button
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:id="@+id/add_fragment_button"
         android:text="Just add fragment"/>
     <FrameLayout
         android:id="@+id/menu_fragment_fragment_holder"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"/> 
</androidx.constraintlayout.widget.ConstraintLayout>

0

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

একটি "প্যারেন্টফ্রেগমেন্ট" ইন্টারফেস সংজ্ঞায়িত:

interface ParentFragment {
/**
 * Fragments that host child fragments and want to control their BackStack behaviour when the back button is pressed should implement this
 *
 * @return true if back press was handled, false otherwise
 */
fun onBackPressed(): Boolean

}

প্যারেন্ট ক্রিয়াকলাপে (বা বেসঅ্যাক্টিভিটিতে) "অনব্যাকপ্রেসড" কে ওভাররাইড করা:

override fun onBackPressed() {
    val fm: FragmentManager = supportFragmentManager
    for (frag in fm.fragments) {
        if (frag.isVisible && frag is ParentFragment && frag.onBackPressed()) {
            return
        }
    }
    super.onBackPressed()
}

এবং তারপরে অভিভাবক টুকরোটি এটি যেমন ইচ্ছা পরিচালনা করতে দেয়, উদাহরণস্বরূপ:

override fun onBackPressed(): Boolean {
    val childFragment = childFragmentManager.findFragmentByTag(SomeChildFragment::class.java.simpleName)
    if (childFragment != null && childFragment.isVisible) {
        // Only for that case, pop the BackStack (perhaps when other child fragments are visible don't)
        childFragmentManager.popBackStack()
        return true
    }
    return false
}

উদাহরণস্বরূপ ভিউ পেজার ব্যবহার করার সময় (এবং পিছনে স্ট্যাক এন্ট্রি গণনা> 0) ব্যবহার করার সময় শিশুদের কিছু বৈধ টুকরা অপসারণ করা এই চিন্তা এড়াতে সহায়তা করে।


-1

আপনার যদি এমন কিছু থাকে DialogFragmentযা ঘুরেফিরে টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো করে থাকে তবে 'ওয়ার্কআরআন্ড' কিছুটা আলাদা। এটিতে একটি সেট onKeyListenerকরার পরিবর্তে rootViewআপনার সাথে এটি করা দরকার Dialog। এছাড়াও আপনি একটি স্থাপন করবেন এবং একটি DialogInterface.OnKeyListenerনয় View। অবশ্যই মনে আছে addToBackStack!

বিটিডব্লু, কলটিকে ক্রিয়াকলাপে ফেরত দেওয়ার জন্য ব্যাকস্টকে একটি করে টুকরো টুকরো থাকাই আমার ব্যক্তিগত ব্যবহারের কেস। সাধারণ পরিস্থিতি গণনা 0 হওয়ার জন্য হতে পারে।

অনক্রিটডায়ালগের মধ্যে আপনি যা করতে চান তা এখানে

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog =  super.onCreateDialog(savedInstanceState);
        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                if(keyCode == KeyEvent.KEYCODE_BACK){
                    FragmentManager cfm = getChildFragmentManager();
                    if(cfm.getBackStackEntryCount()>1){
                        cfm.popBackStack();
                        return true;
                    }   
                }   
                return false;
            }
        });
        return dialog;
    }

সত্যিই বোধগম্য নয় বা সম্পূর্ণ নয়। ডায়ালগফ্রেগমেন্ট বা এটির সুপারক্লাস টুকরাটিতে সেটঅনকিএলাইস্টেনার নেই।
আইএক্সএক্স

@ আইএক্সএক্স আপনাকে শ্রোতাদের সেট করতে হবে Dialog(না DialogFragment) এবং আপনি যে শ্রোতা ব্যবহার করেন তা হ'ল DialogInterface.OnKeyListener- কোডটি কাজ করছে এবং সম্পূর্ণ (এবং ব্যবহারে)। আপনি কেন আপনার পরিস্থিতি সরবরাহ করবেন না এবং সম্ভবত আমি সহায়তা করতে পারি।
শচীন অহুজা

-1

চাইল্ডফ্র্যাগমেন্টের জন্য এটি কাজ করে ..

@Override
    public void onBackPressed() {

 if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStack();
        } else {
            doExit(); //super.onBackPressed();
        }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.