2012-02-26 19 views
18

के साथ एंड्रॉइड घूर्णन वाला डबल टुकड़ा मैंने 2 टुकड़ों के बीच स्विच करने के लिए एक्शनबार के साथ एक साधारण एंड्रॉइड गतिविधि बनाई है। जब तक मैं डिवाइस को घुमाता हूं तब तक यह ठीक है। तथ्यों में, जब मैं घूमता हूं तो मुझे दूसरे पर एक टुकड़ा मिला है: पिछला सक्रिय एक और पहला वाला। क्यों? यदि घूर्णन मेरी गतिविधि को नष्ट कर देता है और फिर से बना देता है, तो मुझे 2 टुकड़े क्यों प्राप्त होते हैं?एक्शनबार

नमूना कोड:

गतिविधि

package rb.rfrag.namespace; 

import android.app.ActionBar; 
import android.app.ActionBar.Tab; 
import android.app.Activity; 
import android.os.Bundle; 

    public class RFragActivity extends Activity { 
    /** Called when the activity is first created. */ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // Notice that setContentView() is not used, because we use the root 
     // android.R.id.content as the container for each fragment 

    // setup action bar for tabs 
     final ActionBar actionBar = getActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
     //actionBar.setDisplayShowTitleEnabled(false); 

     Tab tab; 
     tab = actionBar.newTab() 
       .setText(R.string.VarsTab) 
       .setTabListener(new TabListener<VarValues>(
         this, "VarValues", VarValues.class)); 
     actionBar.addTab(tab); 

     tab = actionBar.newTab() 
       .setText(R.string.SecTab) 
       .setTabListener(new TabListener<SecFrag>(
         this, "SecFrag", SecFrag.class)); 
     actionBar.addTab(tab); 
    } 
} 

TabListener

package rb.rfrag.namespace; 

import android.app.ActionBar; 
import android.app.Activity; 
import android.app.Fragment; 
import android.app.FragmentManager; 
import android.app.FragmentTransaction; 
import android.app.ActionBar.Tab; 

public class TabListener<T extends Fragment> implements ActionBar.TabListener { 
    private Fragment mFragment; 
    private final Activity mActivity; 
    private final String mTag; 
    private final Class<T> mClass; 

    /** Constructor used each time a new tab is created. 
     * @param activity The host Activity, used to instantiate the fragment 
     * @param tag The identifier tag for the fragment 
     * @param clz The fragment's Class, used to instantiate the fragment 
     */ 
    public TabListener(Activity activity, String tag, Class<T> clz) { 
     mActivity = activity; 
     mTag = tag; 
     mClass = clz; 
    } 

    /* The following are each of the ActionBar.TabListener callbacks */ 

    public void onTabSelected(Tab tab, FragmentTransaction ft) {  
     // Check if the fragment is already initialized 
     if (mFragment == null) { 
      // If not, instantiate and add it to the activity 
      mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
      ft.add(android.R.id.content, mFragment, mTag); 
     } else { 
      // If it exists, simply attach it in order to show it 
      ft.attach(mFragment); 
     } 
    } 

    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     if (mFragment != null) { 
      // Detach the fragment, because another one is being attached 
      ft.detach(mFragment); 
     } 
    } 
} 

उत्तर

20

मैं गतिविधि में onSaveInstanceState और onRestoreInstanceState का उपयोग कर चयनित टैब बनाए रखने के लिए औरसंशोधित सुलझाया है 10 निम्नानुसार है।

आखिरी संशोधनों से बचा जाता है कि एंड्रॉइड ने फ्रैगमेंट का पुनर्निर्माण किया है, यह नष्ट नहीं होता है। हालांकि मुझे समझ में नहीं आता कि वर्तमान फ्रैगमेंट संख्या के दौरान गतिविधि घूर्णन घटना द्वारा क्यों नष्ट हो जाती है। जब से मैं एक android.support.v4.view.ViewPager अधिभावी onTabSelected मदद नहीं होगा का उपयोग करें (आप इस बारे में कुछ विचार है?)

public void onTabSelected(Tab tab, FragmentTransaction ft) { 
     // previous Fragment management 
     Fragment prevFragment; 
     FragmentManager fm = mActivity.getFragmentManager(); 
     prevFragment = fm.findFragmentByTag(mTag); 
     if (prevFragment != null) { 
      mFragment = prevFragment; 
     } // \previous Fragment management 

     // Check if the fragment is already initialized 
     if (mFragment == null) { 
      // If not, instantiate and add it to the activity 
      mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
      ft.add(android.R.id.content, mFragment, mTag); 
     } else { 
      // If it exists, simply attach it in order to show it 
      ft.attach(mFragment); 
     } 
    } 
+1

यह पूरी तरह से काम किया। किसी भी सुराग के रूप में अगर यह चीजों को करने का "उचित" तरीका है? –

+3

जब तक मुझे यह नहीं मिला, उसने मुझे पागल कर दिया ... इस जवाब के लिए बहुत बहुत धन्यवाद! (फिर भी यह विश्वास नहीं कर सकता कि Google उनके उदाहरण में इसे ठीक नहीं करेगा) – Patrick

+0

दिलचस्प। केवल मैं चित्र में 'android.support.v4.view.ViewPager' का उपयोग करता हूं और परिदृश्य के दौरान दोनों टुकड़े प्रदर्शित करता हूं। दो बार घुमाएं और मुझे परिदृश्य में दो टुकड़े मिलते हैं। एक * एंड्रॉइड की तरह कुछ कहा जाता है: स्विचर: 2131099773: 1 * - मुझे पागल बनाता है। मुझे ज़ोंबी से छुटकारा पाने के लिए एक झटका मिलना है। – Martin

11

। लेकिन फिर भी आप मुझे सही दिशा में इंगित संकेत दिया।

android.support.v4.app.FragmentManagerandroid.support.v4.app.FragmentActivity के onSaveInstanceState में सभी टुकड़े बचाता है। setRetainInstance अनदेखा - आपके डिज़ाइन के आधार पर यह डुप्लिकेट टुकड़ों का कारण बन सकता है।

सरल समाधान गतिविधि के orCreate में सहेजा टुकड़ा नष्ट करने के लिए है:

@Override 
    public void onCreate (final android.os.Bundle savedInstanceState) 
    { 
     if (savedInstanceState != null) 
     { 
     savedInstanceState.remove ("android:support:fragments"); 
     } // if 

     super.onCreate (savedInstanceState); 
… 
     return; 
    } // onCreate 
+0

+1000 इसे कभी नहीं मिला होगा। – Patrick

+1

यह अच्छी तरह से काम करता है सिवाय इसके कि जब Fragment2 लैंडस्केप में जाता है, खंड 1 प्रदर्शित होता है। यकीन नहीं है कि मैं अकेला हूं जिसकी यह समस्या है। कोई भी समाधान? – Art

+0

पोर्ट्रेट और परिदृश्य में भी आपके समाधान के साथ काम करता है। टैब के बीच स्विच करने के बाद और ओवरलैपिंग नहीं। –

3

समाधान वास्तव में काम का एक बहुत की आवश्यकता नहीं है, तो निम्न चरणों सुनिश्चित है कि जब स्क्रीन को घुमाने, टैब चयन बनाए रखा जाता है। मैं फ्रेगमेंट्स ओवरलैपिंग में भाग गया, क्योंकि स्क्रीन रोटेशन पर मेरा पहला टैब चुना गया था, स्क्रीन को घुमाने से पहले चुना गया दूसरा नहीं और इसलिए पहला टैब दूसरे टैब की सामग्री को ओवरलैप कर रहा था।

यह आपके गतिविधि कैसी दिखनी चाहिए, (मैं ActionBarSherlock उपयोग कर रहा हूँ, लेकिन यह एडजस्ट करने चाहिए बहुत आसान) है:

public class TabHostActivity extends SherlockFragmentActivity { 

    private static final String SELETED_TAB_INDEX = "tabIndex"; 


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

    // Setup the action bar 
    ActionBar actionBar = getSupportActionBar(); 
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

    // Create the Tabs you need and add them to the actionBar... 

    if (savedInstanceState != null) { 
     // Select the tab that was selected before orientation change 
     int index = savedInstanceState.getInt(SELETED_TAB_INDEX); 
     actionBar.setSelectedNavigationItem(index); 
    } 
    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    // Save the index of the currently selected tab 
    outState.putInt(SELETED_TAB_INDEX, getSupportActionBar().getSelectedTab().getPosition()); 
    } 
} 

और ये मेरे ActionBar.TabListener ऊपर में (अपने एक निजी वर्ग ऐसा दिखाई देता है गतिविधि):

private class MyTabsListener<T extends Fragment> implements ActionBar.TabListener { 
    private Fragment fragment; 
    private final SherlockFragmentActivity host; 
    private final Class<Fragment> type; 
    private String tag; 

    public MyTabsListener(SherlockFragmentActivity parent, String tag, Class type) { 
     this.host = parent; 
     this.tag = tag; 
     this.type = type; 
    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction transaction) { 
     /* 
     * The fragment which has been added to this listener may have been 
     * replaced (can be the case for lists when drilling down), but if the 
     * tag has been retained, we should find the actual fragment that was 
     * showing in this tab before the user switched to another. 
     */ 
     Fragment currentlyShowing = host.getSupportFragmentManager().findFragmentByTag(tag); 

     // Check if the fragment is already initialised 
     if (currentlyShowing == null) { 
      // If not, instantiate and add it to the activity 
      fragment = SherlockFragment.instantiate(host, type.getName()); 
      transaction.add(android.R.id.content, fragment, tag); 
     } else { 
      // If it exists, simply attach it in order to show it 
      transaction.attach(currentlyShowing); 
     } 
    } 

    public void onTabUnselected(Tab tab, FragmentTransaction fragmentTransaction) { 
     /* 
     * The fragment which has been added to this listener may have been 
     * replaced (can be the case for lists when drilling down), but if the 
     * tag has been retained, we should find the actual fragment that's 
     * currently active. 
     */ 
     Fragment currentlyShowing = host.getSupportFragmentManager().findFragmentByTag(tag); 
     if (currentlyShowing != null) { 
      // Detach the fragment, another tab has been selected 
      fragmentTransaction.detach(currentlyShowing); 
     } else if (this.fragment != null) { 
      fragmentTransaction.detach(fragment); 
     } 
    } 

    public void onTabReselected(Tab tab, FragmentTransaction fragmentTransaction) { 
     // This tab is already selected 
    } 

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

0

धन्यवाद उनके समाधान के लिए मार्टिन और एस्क्लपिक्स।मैं 3 टैब हैं और पहला टैब 2 टुकड़े, इस तरह शामिल हैं:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    tools:context=".MainActivity" > 

    <FrameLayout 
     android:id="@+id/frActiveTask" 
     android:layout_width="fill_parent" 
     android:layout_height="50dp" 
     android:layout_alignParentBottom="true" 
     /> 

    <FrameLayout 
     android:id="@+id/frTaskList" 
     android:layout_width="fill_parent" 
     android:layout_height="match_parent" 
     android:layout_alignParentTop="true" 
     android:layout_above="@id/frActiveTask" 
     /> 

</RelativeLayout> 

onRestoreInstanceState, onSaveInstanceState और savedInstanceState.remove("android:support:fragments"); तरीकों का उपयोग करना और बयान करता है, तो अपने सक्रिय टैब पहले एक नहीं है के अलावा लगभग ठीक काम कर रहा है और बारी बारी से और पहली पर क्लिक करें, एक स्पष्ट प्रदर्शन प्रकट होता है और केवल पहले टैब पर दूसरे क्लिक के लिए सही खंड प्रदर्शन आया था। कोड डिबगिंग के बाद मैं ने स्वीकार किया कि पहले addTab हमेशा टैब श्रोता में एक onTabSelected घटना कहता है, एक टुकड़ा add विधि के साथ और फिर जब setSelectedNavigationItemonRestoreInstanceState एक detach से कहा जाता है पहला टैब पर निष्पादित किया जाता है और अन्य एक के लिए एक add। यह अनावश्यक add कॉलिंग मेरे समाधान में तय की गई है।

मेरे गतिविधि

protected void onCreate(Bundle savedInstanceState) { 
    boolean firstTabIsNotAdded = false; 
    if (savedInstanceState != null) { 
     savedInstanceState.remove("android:support:fragments"); 
     firstTabIsNotAdded = savedInstanceState.getInt(SELETED_TAB_INDEX) != 0; 
    } 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.activity_main); 

// codes before adding tabs 

    actionBar = getSupportActionBar(); 
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 


    tabStartAndStop = actionBar.newTab().setText(getString(R.string.tab_title_start_and_stop)) 
      .setTabListener(
        new FragmentTabListener<StartStopFragment>(this, 
          getString(R.string.tab_title_start_and_stop_id), 
          StartStopFragment.class, 
          firstTabIsNotAdded)); 
    tabHistory = actionBar.newTab().setText(getString(R.string.tab_title_history)) 
      .setTabListener(
        new FragmentTabListener<HistoryFragment>(this, 
          getString(R.string.tab_title_history_id), 
          HistoryFragment.class, 
          false)); 
    tabRiporting = actionBar.newTab().setText(getString(R.string.tab_title_reporting)) 
      .setTabListener(
        new FragmentTabListener<ReportingFragment>(this, 
          getString(R.string.tab_title_reporting_id), 
          ReportingFragment.class, 
          false)); 

    actionBar.addTab(tabStartAndStop); 

     actionBar.addTab(tabHistory); 
     actionBar.addTab(tabRiporting); 

    } 

    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) { 
     if (savedInstanceState != null) { 
      int index = savedInstanceState.getInt(SELETED_TAB_INDEX); 
      actionBar.setSelectedNavigationItem(index); 
     } 
     super.onRestoreInstanceState(savedInstanceState); 
    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     // Save the index of the currently selected tab 
     outState.putInt(SELETED_TAB_INDEX, getSupportActionBar().getSelectedTab().getPosition()); 
    } 

और संशोधित टैब श्रोता

public class FragmentTabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener { 
    private Fragment mFragment; 
    private final Activity mFragmentActivity; 
    private final String mTag; 
    private final Class<T> mClass; 
    private boolean doNotAdd; 

    /** Constructor used each time a new tab is created. 
     * @param activity The host Activity, used to instantiate the fragment 
     * @param tag The identifier tag for the fragment 
     * @param clz The fragment's Class, used to instantiate the fragment 
     */ 
    public FragmentTabListener(Activity activity, String tag, Class<T> clz, boolean doNotAdd) { 
     mFragmentActivity = activity; 
     mTag = tag; 
     mClass = clz; 
     this.doNotAdd = doNotAdd; 
    } 

    /* The following are each of the ActionBar.TabListener callbacks */ 
    public void onTabSelected(Tab tab, FragmentTransaction ft) { 

     // Check if the fragment is already initialized 
     if (mFragment == null) { 
      // If not, instantiate and add it to the activity 
      if(doNotAdd){ 
       doNotAdd = false; 
      }else{ 
       mFragment = Fragment.instantiate(mFragmentActivity, mClass.getName()); 
       ft.add(android.R.id.content, mFragment, mTag); 
      } 
     } else { 
      // If it exists, simply attach it in order to show it 
      ft.attach(mFragment); 
     } 
    } 

    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     if (mFragment != null) { 
      // Detach the fragment, because another one is being attached 
      ft.detach(mFragment); 
     } 
    } 

    public void onTabReselected(Tab tab, FragmentTransaction ft) { 
     // User selected the already selected tab. Usually do nothing. 
    } 
} 
संबंधित मुद्दे