পিছনে স্ট্যাক থেকে খণ্ডগুলি পুনরায় শুরু করুন


96

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

আমি দেখেছি যে খণ্ড কাঠামোর মধ্যে কলব্যাকের মধ্যে কোনও বিল্ট নেই। এটি অর্জন করার জন্য কোনও ভাল অনুশীলন আছে?


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

4
আপনার ক্রিয়াকলাপ শিরোনাম সেট করতে পারে যে এটি যে কোন সময় কোন এক সময় টুকরা প্রদর্শিত হচ্ছে তা জানে এছাড়াও আমি মনে করি আপনি এমন কিছু করতে পারেন onCreateViewযাতে কোনও পপ পরে খণ্ডের জন্য ডাকা হবে।
পিজেএল

4
@ পিজেএল +1 রেফারেন্স অনুযায়ী এটি করা উচিত According তবে আমি শ্রোতার উপায় পছন্দ করি
মোমো

উত্তর:


116

আরও ভাল সমাধানের অভাবের জন্য, আমি এই কাজটি আমার জন্য পেয়েছি: ধরে নিন আমার 1 টি ক্রিয়াকলাপ (MyActivity) এবং কয়েকটি টুকরো যা একে অপরের প্রতিস্থাপন করে (কেবল একবারে একটি দৃশ্যমান)।

মাইঅ্যাক্টিভিটিতে, এই শ্রোতা যুক্ত করুন:

getSupportFragmentManager().addOnBackStackChangedListener(getListener());

(আপনি দেখতে পাচ্ছেন যে আমি সামঞ্জস্যতা প্যাকেজটি ব্যবহার করছি)।

getListener বাস্তবায়ন:

private OnBackStackChangedListener getListener()
    {
        OnBackStackChangedListener result = new OnBackStackChangedListener()
        {
            public void onBackStackChanged() 
            {                   
                FragmentManager manager = getSupportFragmentManager();

                if (manager != null)
                {
                    MyFragment currFrag = (MyFragment) manager.findFragmentById(R.id.fragmentItem);

                    currFrag.onFragmentResume();
                }                   
            }
        };

        return result;
    }

MyFragment.onFragmentResume()"পিছনে" চাপ দেওয়ার পরে ডাকা হবে। যদিও কয়েকটি গুপ্তচর:

  1. এটি ধরে নিয়েছে যে আপনি সমস্ত লেনদেন ব্যাকস্টকে যুক্ত করেছেন (ব্যবহার করে FragmentTransaction.addToBackStack())
  2. এটি প্রতিটি স্ট্যাক পরিবর্তনের পরে সক্রিয় করা হবে (আপনি অন্যান্য স্টাফ যেমন অ্যানিমেশন হিসাবে স্ট্যাক করতে পারেন) যাতে আপনি একই অংশে একই অংশে একাধিক কল পেতে পারেন।

4
আপনার নিজের উত্তরটি সঠিক হিসাবে গ্রহণ করা উচিত যদি এটি আপনার পক্ষে কাজ করে।
পাওয়ারj1984

7
আপনি যে খণ্ডন আইডিটি জিজ্ঞাসা করছেন তার ক্ষেত্রে এটি কীভাবে কাজ করে? প্রতিটি খণ্ডের জন্য এটি আলাদা কীভাবে এবং পিছনের স্ট্যাকের মধ্যে সঠিকটি পাওয়া যায়?
ম্যানফ্রেড মশার

4
@ ওয়ারপজিট যে পদ্ধতিটি বলা হয় না, এবং অ্যান্ড্রয়েড ডক্স চুপচাপ স্বীকার করে যে এটিকে কখনই ডাকা হবে না (কার্যকলাপটি পুনরায় শুরু করা হলে এটি কেবল তখনই বলা হয় - যা যদি সেই ক্রিয়াকলাপ ইতিমধ্যে সক্রিয় থাকে তবে)
অ্যাডাম

4
হাস্যকর যে আমাদের এটি করতে হবে! তবে খুশি যে অন্য কেউ এই "বৈশিষ্ট্যটি" সন্ধান করতে
পেরেছিল

4
onResume () বলা হয় না
মার্টি মিলার

33

আমি প্রস্তাবিত সমাধানটি কিছুটা পরিবর্তন করেছি। আমার জন্য আরও ভাল কাজ করে:

private OnBackStackChangedListener getListener() {
    OnBackStackChangedListener result = new OnBackStackChangedListener() {
        public void onBackStackChanged() {
            FragmentManager manager = getSupportFragmentManager();
            if (manager != null) {
                int backStackEntryCount = manager.getBackStackEntryCount();
                if (backStackEntryCount == 0) {
                    finish();
                }
                Fragment fragment = manager.getFragments()
                                           .get(backStackEntryCount - 1);
                fragment.onResume();
            }
        }
    };
    return result;
}

4
দয়া করে পার্থক্যটি ব্যাখ্যা করুন এবং কেন এটি ব্যবহার করুন।
ম্যাথ চিলার

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

9
getFragments()সাপোর্টফ্রেগমেন্টম্যানেজার নামক কোনও পদ্ধতির কোনও রেকর্ড নেই ... -1: - /
প্রোটোস্টোম

4
অনারিউম () বলা হয় ut তবে আমি খালি স্ক্রিন পাচ্ছি..এই সমস্যাটি সমাধান করার জন্য অন্য কোনও উপায় নেই?
কাভি 11

আমি মনে করি ব্যাক স্ট্যাকএন্ট্রিকাউন্ট 0 হলে এটি আরেআউটআউটবাউন্ড ব্যতিক্রমের দিকে নিয়ে যায় আমি কি ভুল করছি? পোস্টটি সম্পাদনা করার চেষ্টা করা হলেও তা প্রত্যাখ্যান করা হয়েছিল।
মাইক টি

6

এর পরে popStackBack()আপনি নিম্নলিখিত কলব্যাকটি ব্যবহার করতে পারেন: onHiddenChanged(boolean hidden)আপনার খণ্ডের মধ্যে


4
এটি অ্যাপ কমপ্যাট টুকরাগুলির সাথে কাজ করে বলে মনে হচ্ছে না।
লো-টান

এটাই আমি ব্যবহার করেছি। ধন্যবাদ!
অ্যালবার্ট ভিলা কলভো

সবচেয়ে সহজ সমাধান! খণ্ডটি বর্তমানে দৃশ্যমান এবং ভয়েলাতে কেবল একটি চেক যুক্ত করুন, আপনি অ্যাপবারের শিরোনাম সেট করতে পারেন।
এরিক এইচ206 10

4

অ্যান্ড্রয়েড বিকাশকারীদের নিম্নলিখিত বিভাগটিতে একটি ক্রিয়াকলাপে ইভেন্ট কলব্যাক তৈরির একটি যোগাযোগ প্রক্রিয়া বর্ণনা করা হয়েছে । এটি থেকে একটি লাইন উদ্ধৃতি:

এটি করার একটি ভাল উপায় হ'ল খণ্ডের অভ্যন্তরে কলব্যাক ইন্টারফেসটি সংজ্ঞায়িত করা এবং হোস্ট ক্রিয়াকলাপটি এটি প্রয়োগ করা প্রয়োজন require ক্রিয়াকলাপটি যখন ইন্টারফেসের মাধ্যমে কলব্যাক পায়, এটি প্রয়োজনীয় হিসাবে লেআউটটিতে অন্যান্য টুকরাগুলির সাথে তথ্য ভাগ করতে পারে।

সম্পাদনা করুন: টুকরাটির একটি থাকে onStart(...)যা ভগ্নাংশটি ব্যবহারকারীর কাছে দৃশ্যমান থাকে। একইভাবে onResume(...)যখন দৃশ্যমান এবং সক্রিয়ভাবে চলমান। এগুলি তাদের ক্রিয়াকলাপের অংশগুলিতে আবদ্ধ। সংক্ষেপে: ব্যবহারonResume()


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

@রিহরেল আপডেট হওয়া উত্তর দেখুন। ক্রিয়াকলাপটি লোড হয়ে গেলে আপনি অনাটাচ, অনক্রিট, অনঅ্যাক্টিভিটি তৈরি, অন স্টার্ট, অন রিসুমে বিভিন্ন কল পাবেন। আপনি যদি `setRetainInstance (সত্য) 'বলে ডাকেন তবে যদি টুকরাটি আবার ক্লিক করে পুনরায় দেখানো হচ্ছে তখন আপনি একটি অনক্রিট পাবেন না।
পিজেএল

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

hmm with compat lib v4 আমি আমার খণ্ডের জন্য একটি পুনঃসূচনা দেখতে পাচ্ছি। আমি @ অরিহরেলের উত্তরটি পছন্দ করি যদিও এটি কেবল অগ্রভাগে আনার চেয়ে পপব্যাকস্ট্যাকের মাধ্যমে দৃশ্যমান হওয়ার মধ্যে পার্থক্য করে।
পিজেএল

3

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

boolean fragmentAlreadyLoaded = false;
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onViewCreated(view, savedInstanceState);

        if (savedInstanceState == null && !fragmentAlreadyLoaded) {
            fragmentAlreadyLoaded = true;

            // Code placed here will be executed once
        }

        //Code placed here will be executed even when the fragment comes from backstack
    }

3

আমার ক্রিয়াকলাপে ক্রিয়াকলাপে ()

getSupportFragmentManager().addOnBackStackChangedListener(getListener());

নির্দিষ্ট টুকরোটি ধরার জন্য এই পদ্ধতিটি ব্যবহার করুন এবং পুনরায় চালু করুন ()

private FragmentManager.OnBackStackChangedListener getListener()
    {
        FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
                if (currentFragment instanceof YOURFRAGMENT) {
                    currentFragment.onResume();
                }
            }
        };

        return result;
    }

আমার জন্য কাজ করছেন না
আমির ডোরা।

2

কিছুটা উন্নত এবং একটি ম্যানেজার সমাধানে মোড়ানো।

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

এই সমস্যাটি মোকাবেলায় নিখরচায় ক্লাসগুলি ব্যবহার করুন (ডাগার 2 ইনজেকশন ব্যবহার করুন)। ক্রিয়াকলাপে কল করুন:

//inject FragmentBackstackStateManager instance to myFragmentBackstackStateManager
FragmentManager fragmentManager = getSupportFragmentManager(); 
myFragmentBackstackStateManager.apply(fragmentManager);

ফ্রেগমেন্টব্যাকস্ট্যাক স্টেট ম্যানেজ.আরভা:

@Singleton
public class FragmentBackstackStateManager {

    private FragmentManager fragmentManager;

    @Inject
    public FragmentBackstackStateManager() {
    }

    private BackstackCallback backstackCallbackImpl = new BackstackCallback() {
        @Override
        public void onFragmentPushed(Fragment parentFragment) {
            parentFragment.onPause();
        }

        @Override
        public void onFragmentPopped(Fragment parentFragment) {
            parentFragment.onResume();
        }
    };

    public FragmentBackstackChangeListenerImpl getListener() {
        return new FragmentBackstackChangeListenerImpl(fragmentManager, backstackCallbackImpl);
    }

    public void apply(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
        fragmentManager.addOnBackStackChangedListener(getListener());
    }
}

ফ্র্যাগমেন্টব্যাকস্ট্যাক চেঞ্জলিস্টার আইপল.জভা:

public class FragmentBackstackChangeListenerImpl implements FragmentManager.OnBackStackChangedListener {

    private int lastBackStackEntryCount = 0;
    private final FragmentManager fragmentManager;
    private final BackstackCallback backstackChangeListener;

    public FragmentBackstackChangeListenerImpl(FragmentManager fragmentManager, BackstackCallback backstackChangeListener) {
        this.fragmentManager = fragmentManager;
        this.backstackChangeListener = backstackChangeListener;
        lastBackStackEntryCount = fragmentManager.getBackStackEntryCount();
    }

    private boolean wasPushed(int backStackEntryCount) {
        return lastBackStackEntryCount < backStackEntryCount;
    }

    private boolean wasPopped(int backStackEntryCount) {
        return lastBackStackEntryCount > backStackEntryCount;
    }

    private boolean haveFragments() {
        List<Fragment> fragmentList = fragmentManager.getFragments();
        return fragmentList != null && !fragmentList.isEmpty();
    }


    /**
     * If we push a fragment to backstack then parent would be the one before => size - 2
     * If we pop a fragment from backstack logically it should be the last fragment in the list, but in Android popping a fragment just makes list entry null keeping list size intact, thus it's also size - 2
     *
     * @return fragment that is parent to the one that is pushed to or popped from back stack
     */
    private Fragment getParentFragment() {
        List<Fragment> fragmentList = fragmentManager.getFragments();
        return fragmentList.get(Math.max(0, fragmentList.size() - 2));
    }

    @Override
    public void onBackStackChanged() {
        int currentBackStackEntryCount = fragmentManager.getBackStackEntryCount();
        if (haveFragments()) {
            Fragment parentFragment = getParentFragment();

            //will be null if was just popped and was last in the stack
            if (parentFragment != null) {
                if (wasPushed(currentBackStackEntryCount)) {
                    backstackChangeListener.onFragmentPushed(parentFragment);
                } else if (wasPopped(currentBackStackEntryCount)) {
                    backstackChangeListener.onFragmentPopped(parentFragment);
                }
            }
        }

        lastBackStackEntryCount = currentBackStackEntryCount;
    }
}

ব্যাকস্ট্যাকক্যালব্যাক.জভা:

public interface BackstackCallback {
    void onFragmentPushed(Fragment parentFragment);

    void onFragmentPopped(Fragment parentFragment);
}

0

এটি সঠিক উত্তর যা আপনি অনারুমে () কল করতে পারেন তা সরবরাহ করে খণ্ডটি ক্রিয়াকলাপের সাথে যুক্ত। বিকল্পভাবে আপনি অনাচ এবং অনডেটাচ ব্যবহার করতে পারেন


4
আপনি উদাহরণ পোস্ট করতে পারেন দয়া করে?
কাভি

0

খন্ডের জন্য onResume () ভাল কাজ করে ...

public class listBook extends Fragment {

    private String listbook_last_subtitle;
...

    @Override
       public void onCreate(Bundle savedInstanceState) {

        String thisFragSubtitle = (String) getActivity().getActionBar().getSubtitle();
        listbook_last_subtitle = thisFragSubtitle;
       }
...

    @Override
        public void onResume(){
            super.onResume();
            getActivity().getActionBar().setSubtitle(listbook_last_subtitle);
        }
...

0
public abstract class RootFragment extends Fragment implements OnBackPressListener {

 @Override
 public boolean onBackPressed() {
  return new BackPressImpl(this).onBackPressed();
 }

 public abstract void OnRefreshUI();

}


public class BackPressImpl implements OnBackPressListener {

 private Fragment parentFragment;

 public BackPressImpl(Fragment parentFragment) {
  this.parentFragment = parentFragment;
 }

 @Override
 public boolean onBackPressed() {
  ((RootFragment) parentFragment).OnRefreshUI();
 }
}

এবং চূড়ান্ত সীমাটি আপনার ফ্রেমটিকে রুটফ্র্যাগমেন্ট থেকে প্রভাব দেখতে হবে


0

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

@Override
public void onResume() {
    super.onResume();
    // Get/Backup current title
    mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
            .getTitle();
    // Set new title
    ((ActionBarActivity) getActivity()).getSupportActionBar()
        .setTitle(R.string.this_fragment_title);
}

@Override
public void onDestroy() {
    // Set title back
    ((ActionBarActivity) getActivity()).getSupportActionBar()
        .setTitle(mTitle);

    super.onDestroy();
}

0

আমি FragmentTagsআমার সমস্ত খণ্ড ক্লাস সংজ্ঞায়িত করতে এনাম ব্যবহার করেছি।

TAG_FOR_FRAGMENT_A(A.class),
TAG_FOR_FRAGMENT_B(B.class),
TAG_FOR_FRAGMENT_C(C.class)

FragmentTags.TAG_FOR_FRAGMENT_A.name()টুকরা ট্যাগ হিসাবে পাস

এবং এখন

@Override
public void onBackPressed(){
   FragmentManager fragmentManager = getFragmentManager();
   Fragment current
   = fragmentManager.findFragmentById(R.id.fragment_container);
    FragmentTags fragmentTag = FragmentTags.valueOf(current.getTag());

  switch(fragmentTag){
    case TAG_FOR_FRAGMENT_A:
        finish();
        break;
   case TAG_FOR_FRAGMENT_B:
        fragmentManager.popBackStack();
        break;
   case default: 
   break;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.