2013-02-07 33 views
5

मैं एंड्रॉइड को अभिविन्यास परिवर्तन को संभालने देना चाहता हूं। दुर्भाग्य से जब भी एक संवाद खुला होता है और अभिविन्यास परिवर्तन होता है तो यह क्रैश हो जाता है। मैं पहले से ही कारण संदेह है, लेकिन यह कैसे संभाल करने के लिए पता नहीं है:ओरिएंटेशन चेंज: IllegalStateException जब डायलॉगफ्रेगमेंट दिखाई देता है

आवेदन पहले backstack शुरू होता है इस तरह दिखता है:

02-07 15:26:03.316: I/System.out(14541): Added Fragments: 
02-07 15:26:03.316: I/System.out(14541): #0: PortraitModeFragment{41963330 #0 id=0x7f090001 ListViewFragment} 
02-07 15:26:03.326: I/System.out(14541): #1: MyDialogFragment{4199f6a0 #1 MyDialogFragment} 
:

02-07 15:25:36.517: I/System.out(14541): Added Fragments: 
02-07 15:25:36.517: I/System.out(14541): #0: PortraitModeFragment{41963330 #0 id=0x7f090001 ListViewFragment} 

महान, अब हम एक संवाद खोलने

02-07 15:26:37.502: E/AndroidRuntime(14541): FATAL EXCEPTION: main 
02-07 15:26:37.502: E/AndroidRuntime(14541): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.testapp/com.example.testapp.MainActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class fragment 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3692) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.access$700(ActivityThread.java:141) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.os.Handler.dispatchMessage(Handler.java:99) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.os.Looper.loop(Looper.java:137) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.main(ActivityThread.java:5039) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at java.lang.reflect.Method.invokeNative(Native Method) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at java.lang.reflect.Method.invoke(Method.java:511) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at dalvik.system.NativeStart.main(Native Method) 
02-07 15:26:37.502: E/AndroidRuntime(14541): Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class fragment 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:270) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.Activity.setContentView(Activity.java:1881) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at com.example.testapp.MainActivity.onCreate(MainActivity.java:17) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.Activity.performCreate(Activity.java:5104) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144) 
02-07 15:26:37.502: E/AndroidRuntime(14541): ... 12 more 
02-07 15:26:37.502: E/AndroidRuntime(14541): Caused by: java.lang.IllegalStateException: Fragment com.example.testapp.fragments.LandscapeModeFragment did not create a view. 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:303) 
02-07 15:26:37.502: E/AndroidRuntime(14541): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676) 

दिलचस्प मजेदार तथ्य:

और अब जब डिवाइस बारी बारी से यह ऐसा नहीं होता है, तो मैं पहली बार, डिवाइस बिलकुल पलट गया और बाद में संवाद खोलने और ओरिएंटेशन बदलने क्योंकि दोनों टुकड़े पहले से लोड कर रहे हैं और शांति से backstack में मौजूद है:

02-07 15:34:00.015: I/System.out(15412): #0: PortraitModeragment{419b99b0 #0 id=0x7f090001 ListViewFragment} 
02-07 15:34:00.015: I/System.out(15412): #1: LandscapeModeFragment{419b9b88 #1 id=0x7f090003 LandscapeModeFragment} 
02-07 15:34:00.025: I/System.out(15412): #2: MyDialogFragment{419d1da0 #2 MyDialogFragment} 

मैं नहीं कर सकते उपयोगकर्ता बनाने के उपयोग करने से पहले चारों ओर स्मार्टफोन घुमा मेरी ऐप, तो क्या करना है? ;)

पुन: पेश करने के लिए:

मैं संवाद कैसे जोड़ backstack रहे हैं:

1:

MyDialogFragment myTvShowDialog = new MyDialogFragment(); 
myTvShowDialog.show(getActivity().getSupportFragmentManager(),myTvShowDialog.TAG); 

क्या मैंने किया MainActivity के लिए दो XML फ़ाइलें बना था। रेस/लेआउट/main.xml (PortraitMode):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> 
    <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="layout-land/PORTRAIT" /> 
    <fragment class="com.example.testapp.fragments.PortraitModeFragment" 
         android:id="@+id/fragment" android:layout_weight="1" 
         android:layout_width="0px" android:layout_height="match_parent" android:tag="PortraitModeFragment"> 
    </fragment> 
</LinearLayout> 

2। रेस/लेआउट भूमि/main.xml (LandscapeMode)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> 
    <TextView android:id="@+id/textView1" android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="layout-land/LANDSCAPE" /> 
    <fragment class="com.example.testapp.fragments.LandscapeModeFragment" 
      android:id="@+id/LandscapeModeFragment" android:layout_weight="1" 
      android:layout_width="0px" android:layout_height="0dp" android:tag="LandscapeModeFragment"> 
    </fragment> 
</LinearLayout> 

MainActivity.java:

public class MainActivity extends FragmentActivity { 
    private static final String TAG = "MainActivity"; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.v(TAG, "onCreate()"); 
     setContentView(R.layout.activity_main); 
     getSupportFragmentManager().dump("", null, 
       new PrintWriter(System.out, true), null); 
    } 
} 

FragmentPortraitMode:

public class PortraitModeFragment extends Fragment { 
    @Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
    View fragment = inflater.inflate(R.layout.portraitmodefragment_layout, 
      null); 
    Button findViewById = (Button) fragment.findViewById(R.id.button1); 
    findViewById.setOnClickListener(new OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      MyDialogFragment myDialog = new MyDialogFragment(); 
      myDialog.show(getActivity().getSupportFragmentManager(), 
        MyDialogFragment.TAG); 
     } 
    }); 
    TextView textView = (TextView) fragment.findViewById(R.id.textView1); 
    textView.setText(TAG); 
    return fragment; 
} 

टुकड़ा LandscapeMode:

public class LandscapeModeFragment extends Fragment { 

    public static final String TAG = "LandscapeModeFragment"; 

    @Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
    View fragment = inflater.inflate(R.layout.landscapemode_fragment_layout, 
      container, false); 
    return fragment; 
} 
} 

landscapemode_fragment_layo ut.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
      <TextView 
      android:id="@+id/textView1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="LANDSCAPEFRAGMENT" /> 
</LinearLayout> 

portraitmode_fragment_layout_xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"  android:text="Button" /> 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

</LinearLayout> 
+0

'generic_dialog_layout.xml' क्या है/जहां लैंडस्केपमोडफ्रैगमेंट में फुलाया जा सकता है? – Kerry

+0

@ केरी ने संवाद के लिए लेआउट जोड़ा, नामकरण यहां कमजोर था, मैं स्वीकार करता हूं। यह सिर्फ एक सामान्य लेआउट है ... – AndacAydin

+0

मैंने इस्तेमाल किए गए लेआउट.एक्सएमएल का नाम बदलकर landscape_fragment_layout.xml में बदल दिया है, यह नामकरण के अनुसार स्पष्ट होना चाहिए। – AndacAydin

उत्तर

6

खैर मैं एक समाधान है जो बस के रूप में ठीक काम करता है पाया है।

पहला: समस्या क्या थी?

टुकड़े लेआउट-एक्सएमएल और FragmentManager प्रति जोड़ा टुकड़े में परिभाषित किया गया है, हालांकि यह FragmentManager अनपेक्षित व्यवहार (अपवादों) के साथ लेआउट-टुकड़े के साथ गड़बड़ करने के लिए संभव है दुर्घटना का कारण बनता है आवेदन विभिन्न lifecycles अब्द है। एक्सएमएल में

As Dianne Hackborn mentioned in the Google Groups Forum

परिभाषित टुकड़े ज्यादातर चीजें हैं जो जा रहे हैं चारों ओर रहने के लिए के लिए है। यदि आप जोड़ने और हटाने जा रहे हैं, तो आपको शायद इसे गतिशील रूप से लगातार करना चाहिए।

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

इसलिए हमें दुनिया को मिश्रण करने की अनुमति नहीं है (FragmentManager-Fragments और LayoutXML-Fragments)। दुर्भाग्य से यह रनटाइम में भी डायलॉगफ्रैगमेंट्स को शामिल किया गया है। क्या होता है: एंड्रॉइड-फ्रेमवर्क अभिविन्यास पर नए लेआउट-निर्मित फ्रैगमेंट को बैकस्टैक में बदल देता है। FragmentManager नए बनाए गए लेआउट-फ्रैगमेंट के समान सूचकांक पर बाद में डायलॉगफ्रैगमेंट जोड़ने की कोशिश करता है। चीजें जब गन्दा हो जाती हैं और IllegalStateException होती है।

तो, कामकाज क्या है?

विभिन्न अभिविन्यासों के लिए टुकड़ों का उपयोग करने वाले अधिकांश उदाहरणों में फ़्रेमलेआउट को कंटेनर के रूप में परिभाषित करना शामिल है, ताकि इसमें सही टुकड़ा हो सके। इसलिए हम FragmentManager साथ सभी तरह से जाने के लिए और हमारे डिजाइन से LayoutFragments Bann होगी:

ActivityMain अपने contentView के रूप में सिर्फ इस सरल एक्सएमएल का उपयोग करता है:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@+id/fragment_container_id" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent"> 
</FrameLayout> 

और जब शुरू कर दिया यह कंटेनर में सही टुकड़ा इंजेक्शन

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.mainactivity_framelayout); 
    createFragmentIfNotExits(); 
} 
private void createFragmentIfNotExits() { 
    int orientation = getResources().getConfiguration().orientation; 
    Fragment newFragment; 
    if (orientation == Configuration.ORIENTATION_PORTRAIT) { 
     newFragment = new TvShowListPortraitModeFragment(); 
    } else { 
     newFragment = new TvShowListLandscapeModeFragment(); 
    } 
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
    ft.replace(R.id.fragment_container_id, newFragment); 
    ft.commit(); 
} 

वापसी: दुर्भाग्य से टुकड़े की बचाया राज्य को बनाए रखना संभव नहीं है इस तरह से है। या कम से कम मुझे अभी भी यह समझने की जरूरत है कि यह कैसे करें।

मुझसे बहुत कुछ। मैं इस उत्तर को "उत्तर" के रूप में चिह्नित नहीं करूंगा क्योंकि मैंने वास्तव में इसे काम नहीं किया है, शायद कोई इसे समझ लेगा और एक सरल समाधान पोस्ट करेगा। मैं इस के बाद सही के रूप में चिह्नित करेंगे।

+4

क्योंकि एंड्रॉइड देव टीम के लड़के और लड़कियां फिक्सिंग बग के साथ परेशान नहीं हैं, बल्कि नए बग के साथ नए संस्करण पेश करती हैं, मुझे नहीं लगता कि आपके द्वारा वर्णित आधिकारिक बग का बेहतर समाधान कभी भी होगा http://code.google.com/पी/एंड्रॉइड/मुद्दों/विस्तार? आईडी = 18529 –

+2

पवित्र बकवास आदमी तुमने मुझे बहुत परेशानी बचाई! –

+0

मुझे बग में वर्णित वैकल्पिक वर्कअराउंड http://code.google.com/p/android/issues/detail?id=18529#c8 पर उपयोगी पाया गया – awy