Fragment onResume () और onPause () बैकस्टैक पर नहीं कहा जाता है


195

मेरे पास एक गतिविधि के अंदर कई टुकड़े हैं। एक बटन पर क्लिक करके मैं एक नया टुकड़ा शुरू कर रहा हूं, इसे बैकस्ट में जोड़ रहा हूं। मुझे स्वाभाविक रूप onPause()से वर्तमान फ्रेगमेंट की विधि की उम्मीद थी औरonResume() नए फ्रैगमेंट । खैर यह नहीं हो रहा है।

LoginFragment.java

public class LoginFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
      final FragmentManager mFragmentmanager =  getFragmentManager();

      Button btnHome  = (Button)view.findViewById(R.id.home_btn);
      btnHome.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view){
           HomeFragment fragment    = new HomeFragment();
           FragmentTransaction ft2   =  mFragmentmanager.beginTransaction();
           ft2.setCustomAnimations(R.anim.slide_right, R.anim.slide_out_left
                    , R.anim.slide_left, R.anim.slide_out_right);
           ft2.replace(R.id.middle_fragment, fragment);
           ft2.addToBackStack(""); 
           ft2.commit();    
         }
      });
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of LoginFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
    Log.e("DEBUG", "OnPause of loginFragment");
    super.onPause();
  }
}

HomeFragment.java

public class HomeFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of HomeFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
     Log.e("DEBUG", "OnPause of HomeFragment");
     super.onPause();
  }
}

मुझे क्या उम्मीद थी,

  1. जब बटन क्लिक किया, LoginFragment के साथ बदल जाता है HomeFragment , onPause()की LoginFragment , और onResume()की HomeFragment कहा जाता हो जाता है
  2. जब वापस दबाया जाता है, HomeFragment बाहर poped जाता है और LoginFragment , और देखा जाता है onPause()की HomeFragment और onResume()की LoginFragment कहा जाता हो जाता है।

मुझे जो मिल रहा है,

  1. जब बटन पर क्लिक किया जाता है, तो HomeFragment सही तरीके से LoginFragment की जगह ले रहा है , onResume () HomeFragment को कहते हैं, लेकिन LoginFragment के onPause () पर कभी नहीं कहा जाता है।
  2. जब वापस दबाया, HomeFragment सही ढंग से प्रकट करने के लिए पॉपिंग है LoginFragment , onPause () की HomeFragment बुलाया जाता है, लेकिन onResume (के) LoginFragment कभी नहीं कहा जाता हो जाता है।

क्या यह सामान्य व्यवहार है? क्यों है onResume()की LoginFragment बुलाया नहीं हो रही है जब मैं वापस बटन दबाएँ।


उस गतिविधि कोड को जोड़ें जो टुकड़े को संभालता है।
आशीर्वाद

मुझे नमूना समस्या हो रही है, ठहराव पर बुलाया नहीं जाता है, आपने इसे कैसे हल किया,
सैम

मुझे भी यही समस्या थी लेकिन एहसास हुआ कि मैं ft2.add () का उपयोग कर रहा था; ft2.replace () के बजाय। केवल अन्य कारण होगा यदि आपकी गतिविधि खंड का संदर्भ रख रही है (इसे संग्रह में जोड़ना, या इसे कक्षा चर में निर्दिष्ट करना)
Friggles

3
मुझे भी यही समस्या हो रही है। मैंने देखा कि .replace () आवश्यक जीवनचक्र विधियों को बुलाएगा, लेकिन यह अनिवार्य रूप से टुकड़े को नष्ट कर देता है। इसके अलावा, onSaveInstanceState को नहीं कहा जाता है। जैसे, मैं इसकी स्थिति नहीं रख सकता। इसलिए, मुझे ऐड का उपयोग करने की आवश्यकता है, लेकिन onResume / पॉज़ को नहीं बुलाया जाता है :(
ariets

FWIW, मेरा अनुभव है कि समर्थन पुस्तकालय के टुकड़े ऑनपॉज और onResume कॉल करते हैं, जब बैकस्टैक को पुश / पॉपिंग करते हैं, लेकिन एंड्रॉइड अंतर्निहित टुकड़े नहीं होते हैं। अभी तक इसके लिए एक उचित समाधान नहीं मिला है।
बेंक

जवाबों:


185

अंश onResume()या onPause()केवल तभी कहे जाएँगे जब क्रियाएँ onResume()या कहें onPause()। वे कसकर युग्मित हैं Activity

पढ़ें हैंडलिंग इस लेख का टुकड़ा जीवनचक्र अनुभाग


1
लेख में, यह कहा गया है कि "एक बार जब गतिविधि फिर से शुरू होने की स्थिति तक पहुंच जाती है, तो आप गतिविधि में टुकड़ों को स्वतंत्र रूप से जोड़ सकते हैं और हटा सकते हैं। इस प्रकार, केवल गतिविधि फिर से शुरू होने की स्थिति में एक टुकड़े का जीवनचक्र स्वतंत्र रूप से बदल सकता है।" इसका मतलब यह है कि onResume को कहा जा सकता है, भले ही गतिविधि onResume को क्यों न कहा जाए?
v4r

3
4.4 में मूल (समर्थन नहीं) अंशों के लिए (निश्चित रूप से पुराने संस्करणों के लिए सही नहीं होने पर) onPause () और onResume () को न केवल तब कहा जाता है जब ये घटनाएँ गतिविधि में होती हैं, लेकिन उदाहरण के लिए जब आप कॉल करते हैं (या जोड़ते हैं) () / निकालें () लेनदेन करते समय, इसलिए यह उत्तर कम से कम Android के हाल के संस्करणों के लिए भ्रामक है।
Dmide

19
उस दस्तावेज़ के अनुसार, बैकस्टैक में बदली जाने पर टुकड़े को वास्तव में बंद अवस्था में ले जाना चाहिए। लेकिन न केवल onPause और onResume कहे जा रहे हैं, न ही onStop और onStart हैं - या उस मामले के लिए, कोई अन्य जीवनचक्र के तरीके। तो गाइड निश्चित रूप से भ्रामक है।
बेंक

1
हालांकि संबंधित नहीं है, लेकिन मुझे यह सवाल मिला जबकि अपनी समस्या को खोजने के लिए पहले के बजाय onPause()बाद में बुलाया गया onSaveInstanceState()था। इसे फिर से प्रस्तुत किया जा सकता है यदि आप मेरे एक अलग बच्चे को FragmentStatePagerAdapterकहते हैं (कहते हैं कि आप बच्चे से बच्चे की ओर बढ़ते हैं 2, बच्चे के लिए ध्यान दें, यह इसलिए होता है क्योंकि बच्चा 2 के खुलने पर बच्चा 0 नष्ट हो जाता है )
सूफियान

पक्का नहीं आपका क्या मतलब है। कॉलिंग ft.replace को ऑनपॉज़ (बदले हुए टुकड़े के) और ऑनस्क्यूम (बदले हुए टुकड़े के) को ट्रिगर करना चाहिए। यह किसी भी गतिविधि की परवाह किए बिना किया जाता है ...
डेविड रेफेली

20
  • चूंकि आपने उपयोग किया है ft2.replace(), इसलिए FragmentTransaction.remove() विधि को कहा जाता है और Loginfragmentइसे हटा दिया जाएगा। का संदर्भ लें इस । इसलिए onStop()के LoginFragmentबजाय बुलाया जाएगा onPause()। (जैसा कि नया टुकड़ा पूरी तरह से पुराने को बदल देता है)।
  • लेकिन जब से तुम भी इस्तेमाल किया है ft2.addtobackstack(), की स्थिति Loginfragmentएक बंडल के रूप में सहेज लिया जाएगा और जब आप बटन से वापस क्लिक करें HomeFragment, onViewStateRestored()जिसके बाद बुलाया जाएगा onStart()की LoginFragment। तो अंततः onResume()कहा नहीं जाएगा

1
onViewStateRestoredकहा जाता है यदि आपके पासsetRetainInstance(true)
फरीद

14

यहाँ गोर के उत्तर का मेरा अधिक मजबूत संस्करण है (अंशों का उपयोग करके) आकार के कारण अप्रासंगिक होने के कारण अविश्वसनीय नहीं है (खंडित होने के बाद)

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager() != null) {

                Fragment topFrag = NavigationHelper.getCurrentTopFragment(getFragmentManager());

                if (topFrag != null) {
                    if (topFrag instanceof YourFragment) {
                        //This fragment is being shown. 
                    } else {
                        //Navigating away from this fragment. 
                    }
                }
            }
        }
    });

और 'getCurrentTopFragment' विधि:

public static Fragment getCurrentTopFragment(FragmentManager fm) {
    int stackCount = fm.getBackStackEntryCount();

    if (stackCount > 0) {
        FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(stackCount-1);
        return  fm.findFragmentByTag(backEntry.getName());
    } else {
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null && fragments.size()>0) {
            for (Fragment f: fragments) {
                if (f != null && !f.isHidden()) {
                    return f;
                }
            }
        }
    }
    return null;
}

9

यदि आप वास्तव में टुकड़े को अन्य टुकड़े के अंदर बदलना चाहते हैं तो आपको नेस्टेड फ्रेगमेंट का उपयोग करना चाहिए ।

अपने कोड में आपको प्रतिस्थापित करना चाहिए

final FragmentManager mFragmentmanager =  getFragmentManager();

साथ में

final FragmentManager mFragmentmanager =  getChildFragmentManager();

5
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> fragments = getFragmentManager().getFragments();
            if (fragments.size() > 0 && fragments.get(fragments.size() - 1) instanceof YoureFragment){
                //todo if fragment visible
            } else {
                //todo if fragment invisible
            }

        }
    });

लेकिन एक से अधिक टुकड़े दिखाई देने पर सावधान रहें


धन्यवाद, यह काम करता है, लेकिन अगर केवल एक टुकड़ा दिखाई दे रहा है (तो, ViewPagerटुकड़े के साथ इसके टुकड़े का संदर्भ होगा)।
CoolMind

3

मेरे पास एक कोड आपके जैसा ही है और अगर यह onPause () और onResume () पर काम करता है। टुकड़े को बदलते समय, ये कार्य क्रमशः सक्रिय होते हैं।

टुकड़े में कोड:

 @Override
public void onResume() {
    super.onResume();
    sensorManager.registerListener(this, proximidad, SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(this, brillo, SensorManager.SENSOR_DELAY_NORMAL);
    Log.e("Frontales","resume");
}

@Override
public void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
    Log.e("Frontales","Pause");

}

टुकड़ा बदलने पर लॉग इन करें:

05-19 22:28:54.284 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:28:57.002 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:28:58.697 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:00.840 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:29:02.248 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:03.718 2371-2371/madi.cajaherramientas E/Frontales: Pause

Fragment onCreateView:

View rootView;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.activity_proximidad, container, false);
    ButterKnife.bind(this,rootView);
    inflar();
    setTextos();
    return rootView;
}

कार्रवाई जब मैं वापस पल्स (गतिविधि में जहां मैं टुकड़ा लोड करता हूं):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();

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

 }

2

मैं बच्चे के टुकड़े में क्या करूँ:

@Override
public void onDetach() {
   super.onDetach();
   ParentFragment pf = (ParentFragment) this.getParentFragment();
   pf.onResume();
}

और फिर पेरेंटफ्रैगमेंट पर onResume पर ओवरराइड करें


1
आपको जीवन चक्र के तरीकों को कभी भी मैन्युअल रूप से नहीं कहना चाहिए, विशेष रूप से एक दूसरे के अंदर
ब्रेकलाइन

@ ट्रंकलाइन यह तकनीक काम करती है। क्या आपके पास कोई और रास्ता है?
विकाश पराजुली

हां, आपको अपने स्वयं के कार्यान्वयन को कॉल करने के लिए जोड़ना चाहिए क्योंकि जीवनचक्र विधियों को सिस्टम द्वारा भी कहा जाता है और यदि आप एक दूसरे के अंदर जीवनचक्र विधियों को कॉल करते हैं तो आप इस तरह (और सबसे अधिक संभावना है) बाद के मुद्दों का कारण बन सकते हैं।
ब्रेकलाइन

1

आप सरल एक टुकड़े में एक टुकड़ा नहीं जोड़ सकते हैं । यह FragmentActivity में होने की जरूरत है। मुझे लगता है कि आप एक FragmentActivity में LoginFragment बना रहे हैं, इसलिए इस कार्य को करने के लिए आपको लॉगिन बंद होने पर FragmentActivity के माध्यम से HomeFragment जोड़ने की आवश्यकता है।

सामान्य बिंदु यह है कि आपको एक FragmentActivity क्लास की आवश्यकता है जहाँ से आप प्रत्येक Fragment को FragmentManager में जोड़ते हैं। यह है संभव नहीं एक टुकड़ा वर्ग के अंदर यह करने के लिए।


हाँ, वे एक खंड गतिविधि के अंदर हैं।
कृष्णभद्र

अगर टुकड़े को गतिशील रूप से जोड़ा जाता है, तो आप एक टुकड़े के रूप में कई टुकड़े जोड़ सकते हैं, लेकिन xml में परिभाषित लोगों के लिए नहीं <खंड> टैग
अवैध तर्क

1

यदि आप XML में टुकड़ा जोड़ते हैं, तो आप उन्हें गतिशील रूप से स्वैप नहीं कर सकते। ऐसा होता है कि वे अत्यधिक हैं, इसलिए वे आग नहीं लगाते हैं क्योंकि एक की उम्मीद होगी। इस प्रश्न में समस्या का दस्तावेजीकरण किया गया है। FragmenManager प्रतिस्थापित ओवरले बनाता है

एक फ्रेम-आउट में मध्य_फ्रैगमेंट को चालू करें, और इसे नीचे की तरह लोड करें और आपकी घटनाओं में आग लग जाएगी।

getFragmentManager().beginTransation().
    add(R.id.middle_fragment, new MiddleFragment()).commit();

1

आप यह कोशिश कर सकते हैं,

Step1: अपनी गतिविधि में टैबलेक्टेड विधि को ओवरराइड करें

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    try {
    if(MyEventsFragment!=null && tab.getPosition()==3)
    {
        MyEvents.fragmentChanged();
    }
    }
    catch (Exception e)
    {

    }
    mViewPager.setCurrentItem(tab.getPosition());
}

चरण 2: स्थैतिक विधि का उपयोग करना जो आप अपने टुकड़े में चाहते हैं,

public static void fragmentChanged()
{
    Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}

1

मैं अपनी गतिविधि में उपयोग करता हूं - कोटलिन

supportFragmentManager.addOnBackStackChangedListener {
                val f = supportFragmentManager.findFragmentById(R.id.fragment_container)

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }

0

एक टुकड़ा हमेशा एक गतिविधि में एम्बेडेड होना चाहिए और टुकड़ा का जीवन चक्र सीधे मेजबान गतिविधि के जीवन चक्र से प्रभावित होता है। उदाहरण के लिए, जब गतिविधि को रोक दिया जाता है, तो इसमें सभी टुकड़े होते हैं, और जब गतिविधि नष्ट हो जाती है, तो सभी टुकड़े होते हैं


0

onPause() गतिविधि वर्ग में विधि काम करती है जिसका आप उपयोग कर सकते हैं:

public void onDestroyView(){
super.onDestroyView    
}

उसी उद्देश्य के लिए ।।


0

नीचे दिए गए चरणों का पालन करें, और आपको आवश्यक उत्तर मिलेगा

1- दोनों टुकड़ों के लिए, एक नया अमूर्त जनक बनाएं।
2- एक कस्टम अमूर्त विधि जोड़ें जो उन दोनों द्वारा लागू की जानी चाहिए।
3- दूसरे के साथ बदलने से पहले इसे वर्तमान उदाहरण से कॉल करें।


यह उस स्थिति में कैसे मदद करता है जब कोई उपयोगकर्ता खंड 2 से खंड 1 पर लौटता है?
CoolMind

0

@Gor के उत्तर के आधार पर मैंने Kotlin में समान लिखा। इस कोड को रखेंonCreate() को एक गतिविधि । यह दिखाई देने वाले एक टुकड़े के लिए काम करता है। यदि आपके पास ViewPagerटुकड़े हैं, तो यह ViewPagerपिछले एक नहीं, बल्कि टुकड़ा कहलाएगा।

supportFragmentManager.addOnBackStackChangedListener {
    supportFragmentManager.fragments.lastOrNull()?.onResume()
}

Https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 पढ़ने के बाद मैं समझ गया कि नए टुकड़ों को संलग्न करने के लिए कई स्थितियों में बेहतर होगा replace, नहीं add। तो onResumeकुछ मामलों में एक आवश्यकता गायब हो जाएगी।


0

कॉलिंग ft.replace को ऑनपॉज (बदले हुए टुकड़े का) और ऑनस्क्यूम (बदले हुए टुकड़े का) को ट्रिगर करना चाहिए।

मैं नोटिस करता हूं कि आपका कोड login_fragmentघर के टुकड़े पर बहता है , और onCreateView में भी विचार वापस नहीं करता है। यदि ये टाइपो हैं, तो क्या आप दिखा सकते हैं कि इन टुकड़ों को आपकी गतिविधि के भीतर से कैसे बुलाया जा रहा है?


यह जवाब नहीं है, क्या होगा अगर "जोड़ने" किसी के डिजाइन के लिए है?
फरीद

0

हालांकि विभिन्न कोड के साथ, मुझे ओपी के रूप में एक ही समस्या का अनुभव हुआ, क्योंकि मैं मूल रूप से उपयोग करता था

fm.beginTransaction()
            .add(R.id.fragment_container_main, fragment)
            .addToBackStack(null)
            .commit();

के बजाय

fm.beginTransaction()
                .replace(R.id.fragment_container_main, fragment)
                .addToBackStack(null)
                .commit();

जब आप दूसरी खंड से लौटते हैं तो "रिप्लेसमेंट" के साथ पहला टुकड़ा फिर से बनाया जाता है और इसलिए onResume () भी कहा जाता है।


यह जवाब नहीं है, क्या होगा अगर "जोड़ने" किसी के डिजाइन के लिए है?
फरीद

-2

एक टुकड़ा लेनदेन बनाते समय, निम्नलिखित कोड जोड़ना सुनिश्चित करें।

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

बैकस्टैक से जोड़ने के बाद लेनदेन सुनिश्चित करने के लिए भी सुनिश्चित करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.