9

Tôi có một Hoạt động Phân đoạn gốc có một ViewPager có chứa một ViewPager con. ViewPager con chứa Fragments cho mỗi trang. Tôi liên lạc giữa các đoạn trang con này và Hoạt động phân đoạn gốc hàng đầu bằng cách sử dụng giao diện gọi lại, ví dụ:'IllegalStateException: Hoạt động đã bị hủy' khi 'getSupportFragmentManager()' được gọi sau khi Hoạt động khởi động lại

public interface Callbacks { 
    public void onItemSelected(Link link); 
} 

Trong bố mẹ Hoạt động phân đoạn tôi lắng nghe sự kiện onItemSelected ví dụ:

@Override 
public void onItemSelected(Link link) { 
    Bundle argumentsFront = new Bundle(); 
    argumentsFront.putParcelable(FragmentComments.ARG_ITEM_ID, link); 
    fragmentComments = new FragmentComments(); 
    fragmentComments.setArguments(argumentsFront); 
    getSupportFragmentManager().beginTransaction().replace(R.id.post_container, fragmentComments).commitAllowingStateLoss(); 
} 

Điều này hoạt động tốt khi ứng dụng được khởi chạy lần đầu tiên.

Nếu bạn xoay thiết bị để thay đổi hướng, hoạt động sẽ khởi động lại. Tất cả các mảnh vỡ tự khởi động lại khi tôi sử dụng setRetainInstance(true); (Tôi không gọi setRetainInstance (true) trong các mảnh vỡ trang của ViewPager con vì nó không được hỗ trợ). Tuy nhiên, nếu tôi nhấp vào một mục danh sách trong Phân đoạn của ViewPager con tôi nhận ngoại lệ này:

FATAL EXCEPTION: main 
java.lang.IllegalStateException: Activity has been destroyed 
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342) 
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595) 
at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578) 

Có ai biết tại sao điều này xảy ra không?

Cảm ơn

Trả lời

10

Khi bạn xoay thiết bị, Android tiết kiệm, phá hủy và tái tạo Activity của bạn và ViewPager của Fragments. Vì ViewPager sử dụng số FragmentManager của Activity, nó tiết kiệm và sử dụng lại Fragments cho bạn (và không tạo mới), vì vậy chúng sẽ giữ các tham chiếu cũ cho (Activity ban đầu của bạn) và bạn nhận được số IllegalStateException.

Trong con bạn Fragments thử một cái gì đó như thế này:

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    Log.v(TAG, "onAttach"); 

    // Check if parent activity implements our callback interface 
    if (activity != null) { 
     try { 
      mParentCallback = (Callbacks) activity; 
     } 
     catch (ClassCastException e) { 
     } 
    } 
} 

Sau đó, khi lựa chọn xảy ra:

if(mParentCallback != null) { 
    mParentCallback.onItemSelected(selectedLink); 
} 

Kể từ onAttach được gọi là một phần của Fragment vòng đời, Fragments bạn sẽ cập nhật của họ tham chiếu gọi lại khi xoay vòng.

+0

Thật không may điều này không hoạt động. Phương thức 'onAttach' của tôi trông giống như phương thức bạn đã cung cấp. Về định hướng thay đổi phương thức 'onAttach' của tôi không được gọi lại và kết quả là cuộc gọi lại của tôi không được cập nhật. Phân đoạn gốc có 'setRetainInstance (đúng)', tôi đoán điều này ngăn chặn phân đoạn con này bị tách ra? – Milo

+0

Hmm theo tài liệu 'onAttach' vẫn nên được gọi ngay cả khi' setRetainInstance (true) 'được thiết lập, vì vậy có thể có lỗi khác ở đây. Bạn có thể đăng thêm mã của mình xung quanh cài đặt và gọi lại cuộc gọi lại không? Ngoài ra, hãy kiểm tra câu trả lời cho câu hỏi này, bằng cách sử dụng 'setRetainInstance (true)' không phải là một thực hành tốt trong tình huống này, bạn nên lưu và khôi phục trạng thái - http://stackoverflow.com/questions/11182180/understanding-fragments- setretaininstanceboolean –

+3

Tôi tìm thấy một giải pháp. Bởi vì tôi đã lồng các mảnh vỡ như thế này: (FragmentActivity -> Fragment 1 -> Fragment 2 (với ViewPager) -> ViewPager Child Fragments) Tôi phải di chuyển callbacks đến Fragment 1 (trong đó onAttach và onDetach được gọi) . Sau đó, tôi đã thực hiện một cuộc gọi tĩnh từ phương thức 'onItemSelected' trong các phần tử con của ViewPager để gọi lại trong phần cha Fragment (Fragment 1). Điều này có vẻ hơi hack nhưng hoạt động tốt. Tôi sử dụng 'setRetainInstance (true)' trong Fragment 1 để các Fragment con giữ trạng thái. – Milo

0

Tôi đã có một vấn đề tương tự, tôi nghĩ rằng đó là vì các mảnh vỡ được giữ lại và đang giữ một tham chiếu đến một hoạt động destoryed, giải pháp của tôi là để giữ một tham chiếu đến đoạn trong hoạt động ví dụ như myfragment Fragment = null. Và sau đó sử dụng đoạn mã sau vào MyFragment:

public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     ((TestActivity)activity).contentFragment = this; 
} 
+0

Bạn có thể giải thích thêm một chút nữa không, tôi không chắc mình hiểu đầy đủ. Bạn có giữ một tham chiếu đến mọi mảnh vỡ trẻ em trong đoạn hoạt động gốc không? Phân đoạn con của tôi là một ViewPager chứa nhiều trang phân đoạn con nên tôi không muốn giữ các bản sao tĩnh của tất cả các trang này nếu tôi có thể trợ giúp nó. Cảm ơn. – Milo

0

Đã xảy ra sự cố tương tự. Về cơ bản nếu ViewPager chỉ có vài đoạn, sau đó lưu trữ các tham chiếu đến chúng trong hoạt động hiện tại. KHÔNG gọi getItem của pagerAdapter() vì nó tạo ra một đoạn mới và nó không gắn liền với bất kỳ hoạt động nào và đó là lý do tại sao chúng ta thấy ngoại lệ "Hoạt động đã bị phá hủy". Nếu bạn không muốn giữ tham chiếu mảnh, thì bạn có thể sử dụng phương thức findViewWithTag() để lấy đối tượng Fragment.

0

Tôi có vấn đề này với những mảnh lồng nhau và không ai trong số các giải pháp stackoverflow làm việc cho tôi.Có vẻ như, có lỗi với thư viện hỗ trợ, khi các đoạn bị loại bỏ vẫn lưu trữ con trỏ đến hoạt động trước đó (vì vậy getFragmentManager() chỉ trả về null, vì nó được gọi là hoạt động đã bị hủy), đó là lý do tại sao bạn cần quản lý con trỏ. Tôi đã kết thúc với một giải pháp sau đây:
1. Trong đoạn cấp độ đầu tiên tôi đã tiết kiệm con trỏ đến hoạt động trong phương pháp

public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     parentActivity = activity; // parentActivity is static variable 
} 

2. Trong hoạt động mà xử lý mảnh tôi đã kết thúc với mã này:

private void launchFragment(Fragment fragment, Activity parent) { 
      FragmentTransaction transaction; 
      if(parent == null) 
       transaction = mFragmentManager.beginTransaction(); 
      else // for nested child fragments, workaround for Android parent pointer bug 
       transaction = parent.getFragmentManager().beginTransaction(); 
      transaction.replace(R.id.container, fragment); 
      transaction.addToBackStack(null); 
      transaction.commit(); 
} 

Bạn chỉ nên truyền parentActivity của đoạn cấp FIRST khi bạn đang gọi các đoạn SECOND (nested), vì có vẻ như lỗi này chỉ có các phần tử lồng nhau sau khi bạn đưa ứng dụng của mình từ nền trước.

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