2013-02-07 41 views
5

Tôi muốn cho phép Android xử lý thay đổi định hướng. Rất tiếc, sự cố xảy ra mỗi khi hộp thoại mở và thay đổi hướng xảy ra. Tôi đã nghi ngờ nguyên nhân nhưng không biết làm thế nào để xử lý nó:Thay đổi định hướng: IllegalStateException khi DialogFragment hiển thị

Khi ứng dụng đầu tiên bắt đầu backstack trông như thế này:

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} 

lớn, bây giờ chúng tôi mở một hộp thoại:

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} 

Và bây giờ khi xoay thiết bị:

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) 

Thú vị thực tế: Điều này không xảy ra nếu tôi lần đầu tiên quay lại điện thoại và sau đó mở hộp thoại và thay đổi định hướng, bởi vì cả hai mảnh được cài đặt sẵn và tồn tại một cách hòa bình trong 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} 

tôi không thể làm cho người dùng xoay điện thoại thông minh trên toàn trước khi sử dụng của tôi ứng dụng, vậy phải làm gì? ;)

Để tái sản xuất:

Làm thế nào tôi thêm các Dialog để backstack:

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

Những gì tôi đã làm là tạo ra hai tập tin xml cho MainActivity:

1. res/layout/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. res/layout-đất/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; 
} 

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' ở đâu/đâu không bị thổi phồng trong LandscapeModeFragment? – Kerry

+0

@Kerry đã thêm bố cục cho hộp thoại, đặt tên là yếu ở đây tôi thừa nhận. nó chỉ là một bố trí chung ... – AndacAydin

+0

Tôi đã thay đổi cách đặt tên của tệp layout.xml đã sử dụng thành landscape_fragment_layout.xml bây giờ đặt tên-khôn ngoan nó phải rõ ràng hơn. – AndacAydin

Trả lời

6

Vâng, tôi đã tìm ra một cách giải quyết khác mà hoạt động giống như tốt.

Đầu tiên: Sự cố là gì?

Phân đoạn được xác định trong bố cục-xml và phân đoạn được thêm vào mỗi FragmentManager có vòng đời khác nhau mặc dù có thể lộn xộn với các đoạn bố cục với hành vi không mong muốn FragmentManager (Ngoại lệ) khiến ứng dụng gặp sự cố.

As Dianne Hackborn mentioned in the Google Groups Forum

mảnh Định nghĩa trong XML là chủ yếu dành cho những điều mà sẽ ở lại xung quanh. Nếu bạn định thêm và xóa, bạn nên có thể thực hiện liên tục động.

tôi có thể nhìn vào việc này cho một thông cáo trong tương lai, nhưng xin lưu ý rằng bất cứ điều gì tôi làm, bạn có thể dễ dàng có được cho mình vào tình huống xấu sử dụng này - ví dụ nếu bạn không có một độc đáo chứa giao diện nhóm cho mảnh vỡ, điều xảy ra khi bạn xóa/thêm các đoạn tại điểm trong cấu trúc phân cấp sẽ hoạt động không nhất quán.

Vì vậy, chúng tôi không được phép kết hợp các thế giới (FragmentManager-Fragments và LayoutXML-Fragments). Điều này không may liên quan đến DialogFragments được thêm vào lúc chạy quá. Điều gì xảy ra: Android-Framework thêm vào định hướng thay đổi Fragment vừa được tạo bố cục vào hậu trường. FragmentManager trys để thêm DialogFragment sau đó trên cùng một chỉ mục như Layout-Fragment mới được tạo ra. Thats khi mọi thứ trở nên lộn xộn và IllegalStateException xảy ra.

Vì vậy, giải pháp thay thế là gì?

Hầu hết các ví dụ sử dụng Phân đoạn cho các định hướng khác nhau liên quan đến việc xác định FrameLayout làm vùng chứa, để đưa Phân đoạn chính xác vào đó. Vì vậy, chúng ta sẽ đi tất cả các cách với FragmentManager và Bann các LayoutFragments từ thiết kế của chúng tôi:

ActivityMain chỉ sử dụng xml này đơn giản như contentView của nó:

<?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> 

và khi bắt đầu nó tiêm Fragment đúng vào container

/** 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(); 
} 

các Nhược điểm: Thật không may duy trì trạng thái đã lưu của mảnh vỡ là không thể theo cách này. Hoặc ít nhất tôi vẫn cần phải tìm cách làm điều này.

Rất nhiều từ tôi. Tôi sẽ không đánh dấu câu trả lời này là "trả lời" vì tôi đã không thực sự làm cho nó hoạt động, có thể ai đó sẽ tìm ra và đăng một giải pháp đơn giản hơn. Tôi sẽ đánh dấu điều này sau đó ofcourse là chính xác.

+4

bởi vì các chàng trai và cô gái từ đội dev android không bận tâm với sửa lỗi, thay vì giới thiệu phiên bản mới với lỗi mới, tôi không nghĩ rằng sẽ có một giải pháp tốt hơn về lỗi chính thức mà bạn mô tả http://code.google.com/p/android/issues/detail? id = 18529 –

+2

Người đàn ông crap Thánh bạn đã cứu tôi rất nhiều rắc rối! –

+0

Tôi thấy hữu ích giải pháp thay thế được mô tả trong lỗi tại http://code.google.com/p/android/issues/detail?id=18529#c8 – awy

Các vấn đề liên quan