2011-08-28 5 views
14

का उपयोग करके एक्शनबार में कई बार बुलाया जा रहा है। यह मेरी समस्या है। मेरे पास एक ऐप है जहां मैं टैब के साथ एक्शनबार शेरलॉक का उपयोग कर रहा हूं, विकल्प मेनू के साथ टुकड़े। हर बार जब मैं एमुलेटर घुमाता हूं, तो मेन्यू को सभी टुकड़ों के लिए जोड़ा जाता है, जो कि छिपे/हटाए जाते हैं (मैंने दोनों की कोशिश की)। एक FragmentActivity,ऑनक्रेटऑप्शनमेनू को टैब

final ActionBar bar = getSupportActionBar(); 

    bar.addTab(bar.newTab() 
     .setText("1") 
     .setTabListener(new MyTabListener(new FragmentList1()))); 

    bar.addTab(bar.newTab() 
     .setText("2") 
     .setTabListener(new MyTabListener(new FragmentList2()))); 

    bar.addTab(bar.newTab() 
     .setText("3") 
     .setTabListener(new MyTabListener(new FragmentList3()))); 

    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
    bar.setDisplayShowHomeEnabled(true); 
    bar.setDisplayShowTitleEnabled(true); 

के साथ एक ActionBar टैब सभी एक ही श्रोता का उपयोग किया है कि:

यह सेटिंग है

private class MyTabListener implements ActionBar.TabListener { 
    private final FragmentListBase m_fragment; 


    public MyTabListener(FragmentListBase fragment) { 
    m_fragment = fragment; 
    } 


    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { 
    FragmentManager fragmentMgr = ActivityList.this.getSupportFragmentManager(); 
    FragmentTransaction transaction = fragmentMgr.beginTransaction(); 

     transaction.add(R.id.frmlyt_list, m_fragment, m_fragment.LIST_TAG); 

    transaction.commit(); 
    } 


    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { 
    FragmentManager fragmentMgr = ActivityList.this.getSupportFragmentManager(); 
    FragmentTransaction transaction = fragmentMgr.beginTransaction(); 

    transaction.remove(m_fragment); 
    transaction.commit(); 
    } 


    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { 
    } 
} 

FragmentListBase से प्रत्येक उपवर्ग अपने स्वयं के मेनू और इसलिए सभी है 3 उप-वर्गों में:

setHasOptionsMenu(true); 

और उपयुक्त

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    Log.d(TAG, "OnCreateOptionsMenu"); 

    inflater.inflate(R.menu.il_options_menu, menu); 
} 

जब मैं अनुप्रयोग मैं देख सकता हूँ कि onCreateOptionsMenu कई बार बुलाया जा रहा है, सभी अलग अलग टुकड़े के लिए चलाते हैं।

मैं पूरी तरह से स्टंप हूं।

मैंने भारी कोड के बिना जितना संभव हो उतना कोड पोस्ट करने का प्रयास किया, अगर आपको लगता है कि कुछ गुम है, तो कृपया सलाह दें।

[संपादित करें] मैंने और अधिक लॉगिंग जोड़ा, और यह पता चला कि रोटेशन पर टुकड़ा दो बार (या अधिक) लगाया जा रहा है। एक बात जो मैंने नोटिस की है कि ऑनक्रेट() विधि को छोड़कर सबकुछ कई बार कहा जा रहा है जिसे केवल एक बार कहा जा रहा है।

06.704:/WindowManager(72): Setting rotation to 0, animFlags=0 
06.926:/ActivityManager(72): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=1/1/2 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=35} 
07.374:/FragmentList1(6880): onAttach 
07.524:/FragmentList1(6880): onCreateView 
07.564:/FragmentList1(6880): onAttach 
07.564:/FragmentListBase(6880): onCreate 
07.564:/FragmentList1(6880): OnCreateOptionsMenu 
07.574:/FragmentList1(6880): OnCreateOptionsMenu 
07.604:/FragmentList1(6880): onCreateView 

[संपादित करें 2]

ठीक है, मैं Android कोड में वापस अनुरेखण शुरू कर दिया और यहाँ इस हिस्से में पाया गया (कि मैं इस पोस्ट को छोटा करने के संपादित)।

/com_actionbarsherlock/src/android/support/v4/app/FragmentManager.java

public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    if (mActive != null) { 
     for (int i=0; i<mAdded.size(); i++) { 
      Fragment f = mAdded.get(i); 
      if (f != null && !f.mHidden && f.mHasMenu) { 
       f.onCreateOptionsMenu(menu, inflater); 
      } 
     } 
    } 

समस्या यह है कि mAdded वास्तव में, उस में FragmentList1 के कई उदाहरण है इसलिए onCreateOptionsMenu() विधि "है सही ढंग से "3 बार कहा जा रहा है, लेकिन FragmentList1 वर्ग के विभिन्न उदाहरणों के लिए। जो मुझे समझ में नहीं आता है वह है कि उस वर्ग को कई बार क्यों जोड़ा जा रहा है ... लेकिन यह एक अच्छा नेतृत्व का नरक है।

उत्तर

7

मुझे समस्या (ओं) मिली है। मैं समस्या कहता हूं क्योंकि मेनू की भीड़ के शीर्ष पर, अब भी एक अपवाद है।

1)

bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

करने के लिए कॉल जो के बाद addTab के लिए कॉल() onTabSelected बुला का एक पक्ष प्रभाव (है) है। मेरा TabListener फिर FragmentManager

2 पर एक FragmentList1 जोड़ देगा) डिवाइस को घूर्णन करने से गतिविधि को नष्ट कर दिया जाएगा, लेकिन टुकड़ों को नष्ट नहीं करेगा। जब नई गतिविधि घूर्णन के बाद बनाई जाती है तो यह दो चीजें करेगी:

  1. टुकड़ों का एक और सेट बनाएं जो यह FragmentManager में जोड़ देगा। यह वही मेनू की भीड़
  2. कॉल onTabSelected पैदा कर रहा था है (setNavigationMode के माध्यम से()) जो निम्नलिखित कोड प्रदर्शन करेंगे:

    if (null != fragmentMgr.findFragmentByTag(m_fragment.LIST_TAG)) { 
        transaction.attach(m_fragment); 
        transaction.show(m_fragment); 
    } 
    else { 
        transaction.add(R.id.frmlyt_list, m_fragment, m_fragment.LIST_TAG); 
    } 
    

मूल रूप से अगर टुकड़ा FragmentManager में पहले से ही है वहाँ कोई है इसे जोड़ने की जरूरत है, बस इसे दिखाएं। लेकिन समस्या निहित है। यह एक ही टुकड़ा नहीं है! यह टुकड़ा है जो गतिविधि के पहले उदाहरण द्वारा बनाया गया था। तो यह इस नए बनाए गए टुकड़े को संलग्न करने और दिखाने का प्रयास करेगा जो एक अपवाद

समाधान का कारण बन जाएगा।

इस सब को ठीक करने के लिए कुछ चीजें करने के लिए कुछ चीजें थीं।

1) मैंने addTab() एस के ऊपर setNavigationMode() को स्थानांतरित कर दिया।

2) इस मैं कैसे अब मेरा टैब बनाने है:

FragmentListBase fragment = (FragmentListBase)fragmentMgr.findFragmentByTag(FragmentList1.LIST_TAG_STATIC); 
    if (null == fragment) { 
    fragment = new FragmentList1(); 
    } 
    bar.addTab(bar.newTab() 
     .setText("1") 
     .setTabListener(new MyTabListener(fragment))); 

तो गतिविधि निर्माण मैं अगर टुकड़े FragmentManager में पहले से ही कर रहे हैं देखने के लिए जाँच करने के लिए है पर। यदि वे हैं तो मैं उन उदाहरणों का उपयोग करता हूं, यदि नहीं तो मैं नया बना देता हूं। यह सभी तीन टैब के लिए किया जाता है।

आपने देखा होगा कि दो समान लेबल हैं: m_fragment.LIST_TAG और FragmentList1.LIST_TAG_STATIC। आह, यह सुंदर है ... -

ordrer मेरे TagListener उपयोग करने के लिए polymorphically मैं घोषणा की है (< व्यंग्य) आधार वर्ग में गैर स्थिर चर निम्नलिखित:

public class FragmentListBase extends Fragment { 
    public String LIST_TAG = null; 
} 

यह अंदर से असाइन किया गया है वंशज और मुझे FragmentListBase के विभिन्न वंशजों के लिए FragmentManager में देखने की अनुमति देता है।

लेकिन मुझे विशिष्ट वंशजों को उनके द्वारा बनाए जाने से पहले भी खोजना होगा (क्योंकि मुझे पता होना चाहिए कि मुझे उन्हें बनाना चाहिए या नहीं), इसलिए मुझे निम्नलिखित स्थिर चर घोषित करना होगा।

public class FragmentList1 extends FragmentListBase { 
    public final static String LIST_TAG_STATIC = "TAG_LIST_1"; 

    public FragmentList1() { 
     LIST_TAG = LIST_TAG_STATIC; 
    }; 
} 

पर्याप्त कहना है कि मैं disapointed हूँ कि कोई भी इस सरल और सुरुचिपूर्ण समाधान के साथ आया था (< - अधिक व्यंग्य)

धन्यवाद जेक व्हार्टन के लिए बहुत कुछ है जो समय मेरे लिए यह को देखने के लिए ले लिया :)

+1

यह उत्तर अत्यधिक जटिल है। * एक्शनबार * टैब में टैब जोड़ने से पहले बस मेरी समस्या को ठीक करने के लिए कॉल को 'bar.setNavigationMode (ActionBar.NAVIGATION_MODE_TABS)' पर ले जाया गया। – Phil

6
public FragmentListBase() { 
    setRetainInstance(true); 
    setHasOptionsMenu(true); 
} 

यह रोटेशन पर प्रत्येक टुकड़े के अलग-अलग राज्यों को सहेज/पुनर्स्थापित करेगा।


एक और सरल परिवर्तन अपने आप को टैब का चयन किया कॉलबैक में transaction.replace(R.id.frmlyt_list, m_fragment, m_fragment.LIST_TAG) बुला रहा है और इसे नहीं चुना जाता कॉलबैक में सामग्री से छुटकारा पाने के लिए चाहते हो सकता।

+0

जवाब जेक के लिए धन्यवाद, लेकिन: नाडा

यहाँ कोड का टुकड़ा है। मैंने कोड में कहा लेकिन कोई बदलाव नहीं आया। मैंने अपने प्रश्न में और जानकारी जोड़ दी हालांकि ... – MikeWallaceDev

-4

हनीकोम्ब संबंधित एसडीके है कम से कम पर समस्या अपने Andr में गतिविधि घोषणा करने के लिए

android:configChanges="orientation" 

जोड़कर हल किया जाता है oidManifest.xml फ़ाइल। आप अभी भी http://developer.android.com/guide/topics/ui/actionbar.html

0

जोड़ना टैब अनुभाग में दिखाए गए टुकड़ों को जोड़ और हटा सकते हैं, जो आपके पॉलीमोर्फिक टैग निराशाओं पर बस एक बहुत ही नोट है।

इसलिए की तरह अपने आधार वर्ग घोषित:

public abstract class ListFragmentBase { 
    protected abstract String getListTag(); 
} 

अब इस तरह अपने उप वर्गों कुछ की घोषणा:

public class FragmentList1 extends ListFragmentBase { 
    public static final String LIST_TAG = "TAG_LIST_1"; 

    @Override 
    protected String getListTag() { 
     return LIST_TAG; 
    } 
} 

अब उदाहरण टैग प्राप्त बहुरूपी तरह से इस तरह है:

ListFragmentBase frag = new FragmentList1(); 
frag.getListTag(); 

टैग को स्थिर रूप से प्राप्त करें:

FragmentList1.LIST_TAG; 
+1

आप किस संपत्ति का उपयोग करने के बारे में भ्रम से बचने के लिए स्थिर LIST_TAG स्ट्रिंग को निजी पर सेट भी कर सकते हैं। –

+0

@DominikvonWeber आप LIST_TAG को निजी पर सेट कर सकते हैं लेकिन फिर आप इसे स्थिर रूप से एक्सेस नहीं कर सके। यह मुझे लगता है कि आपकी जरूरतों पर निर्भर करेगा। समाधान में उपयोगकर्ता इसे स्थिर रूप से एक्सेस करता है – Dave

3

मेरे पास रोटेशन पर "स्टैकेबल" मेनू के साथ बहुत ही समान समस्याएं थीं। मैं टैब का उपयोग नहीं करता लेकिन मैं FragmentStatePagerAdapter के साथ ViewPager का उपयोग करता हूं, इसलिए मैं वास्तव में अपने टुकड़ों का पुन: उपयोग नहीं कर सकता। मेरे सिर को 2 दिनों तक टक्कर देने के बाद मुझे बहुत ही सरल समाधान मिला। दरअसल समस्या onCreateOptionsMenu के साथ कई बार कहा जाता है।

/** to prevent multiple calls to inflate menu */ 
private boolean menuIsInflated; 

@Override 
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { 
    if (!menuIsInflated) { 
     inflater.inflate(R.menu.job_details_fragment_menu, menu); 
     menuIsInflated = true; 
    } 
} 
+0

बेकार है कि हमें यह करना था .. मैं कसम खाता हूं कि यह उनकी तरफ एक बग है। – reidisaki

1

क्या के लिए मुझे गतिविधि जिसमें टुकड़ा घोषित किया गया था यानी बुला गतिविधि के setHasMenuOptions (सही) आगे बढ़ रहा था काम: इस छोटे से कोड स्निपेट देखभाल (? मास्क) सभी समस्याओं का समय लगता है। मैंने पहले इसे टुकड़े की ऑन क्रेट विधि में रखा था।

@Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     FragmentManager fragmentManager = getFragmentManager(); 
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 

     ForecastFragment forecastFragment = new ForecastFragment(); 
     forecastFragment.setHasOptionsMenu(true); 
     fragmentTransaction.add(R.id.fragment, forecastFragment); 
     fragmentTransaction.commit(); 
    } 
+0

उपर्युक्त उत्तरों में से कोई भी मेरे लिए काम नहीं करता है, लेकिन आपके उत्तर ने किया। धन्यवाद! –

संबंधित मुद्दे