5

Tôi có một ứng dụng với hệ thống phân cấp như thế này:Android FragmentTab chủ và Những mảnh vỡ bên trong mảnh vỡ

FragmentTabHost (Main Activity) 
    - Fragment (tab 1 content - splitter view) 
    - Fragment (lhs, list) 
    - Framment (rhs, content view) 
    - Fragment (tab 2 content) 
    - Fragment (tab 2 content) 

Tất cả các quan điểm đoạn đang được thổi phồng từ nguồn lực.

Khi ứng dụng bắt đầu mọi thứ xuất hiện và có vẻ ổn. Khi tôi chuyển từ tab đầu tiên sang tab khác và ngược lại, tôi nhận được các ngoại lệ thổi phồng cố gắng tạo lại các giao diện của tab 1.

Đào sâu hơn một chút, đây là những gì đang xảy ra:

  • Trên tải đầu tiên, lạm phát quan điểm chia làm hai mảnh con của nó sẽ được bổ sung cho người quản lý mảnh.
  • Khi chuyển đổi khỏi tab đầu tiên, chế độ xem của nó bị hủy nhưng các đoạn con sẽ được để trong trình quản lý phân đoạn
  • Khi chuyển trở lại tab đầu tiên, chế độ xem được tăng lại và vì các đoạn con cũ vẫn còn trong quản lý mảnh vỡ, một ngoại lệ được ném ra khi các mảnh con mới được khởi tạo (bằng cách lạm phát)

Tôi đã loại bỏ các mảnh con từ trình quản lý phân đoạn (tôi đang sử dụng Mono) và bây giờ tôi có thể chuyển đổi các tab mà không có ngoại lệ.

public override void OnDestroyView() 
{ 
    var ft = FragmentManager.BeginTransaction(); 
    ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ListFragment)); 
    ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ContentFragment)); 
    ft.Commit(); 

    base.OnDestroyView(); 
} 

Vì vậy, tôi có một vài câu hỏi:

  1. Sản phẩm trên cách chính xác để làm điều này?
  2. Nếu không, tôi nên làm như thế nào?
  3. Dù bằng cách nào, việc lưu trạng thái thể hiện buộc vào tất cả điều này để tôi không bị mất trạng thái xem khi chuyển đổi tab?

Trả lời

2

Tôi không chắc chắn cách thực hiện điều này trong Mono, nhưng để thêm đoạn con vào đoạn khác, bạn không thể sử dụng số FragmentManager của số Activity. Thay vào đó, bạn phải sử dụng các ChildFragmentManager của lưu trữ Fragment:

http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager() http://developer.android.com/reference/android/support/v4/app/Fragment.html#getChildFragmentManager()

Các chính FragmentManager của Activity xử lý các tab của bạn.
ChildFragmentManager của tab1 xử lý các chế độ xem chia tách.

+0

OK, điều đó có vẻ đầy hứa hẹn. Làm thế nào để tôi nói với người thổi phồng để sử dụng người quản lý phân đoạn con thay vì người quản lý con cái? –

+0

Bạn thêm đoạn con vào bên trong đoạn cha của bạn bằng cách sử dụng mã của đoạn cha mẹ sử dụng ChildFragmentManager để thêm các phần con của nó. Sau đó, inflater rằng phương thức gọi lại onCreateView của bạn (đoạn con) của bạn cung cấp: https://developer.android.com/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle). –

+0

Bạn có thể cần phải làm một số googling/stackoverlowing hơn để xem làm thế nào để đối phó với các mảnh con trong Mono. Tôi không thể giúp bạn ở đó (tôi sử dụng Java). –

2

OK, cuối cùng tôi figured này ra:

Như đã đề cập ở trên, đầu tiên tôi đã thay đổi việc tạo ra đoạn được thực hiện programatically và họ đã bổ sung vào quản lý đoạn đứa trẻ, như vậy:

public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance) 
{ 
    var view = inflater.Inflate(Resource.Layout.MyView, viewGroup, false); 

    // Add fragments to the child fragment manager 
    // DONT DO THIS, SEE BELOW 
    var tx = ChildFragmentManager.BeginTransaction(); 
    tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment()); 
    tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment()); 
    tx.Commit(); 

    return view; 
} 

Theo dự kiến, mỗi khi tôi chuyển đổi các tab, một thể hiện bổ sung của Lhs/RhsFragment sẽ được tạo, nhưng tôi nhận thấy rằng OnCreateView cũ của Lhs/RhsFragment cũng sẽ được gọi. Vì vậy, sau mỗi lần chuyển đổi tab, sẽ có thêm một cuộc gọi nữa vào OnCreateView. Chuyển đổi tab 10 lần = 11 cuộc gọi thành OnCreateView. Điều này rõ ràng là sai.

Nhìn vào mã nguồn cho FragmentTabHost, tôi có thể thấy rằng nó chỉ đơn giản là tách và gắn lại đoạn nội dung của tab khi chuyển đổi tab. Có vẻ như ChildFragmentManager của Fragment cha mẹ đang giữ các mảnh con xung quanh và tự động tái tạo các khung nhìn của chúng khi đoạn cha mẹ được đính kèm lại.

Vì vậy, tôi chuyển việc tạo ra các mảnh vỡ để OnCreate, và chỉ khi chúng ta không tải từ trạng thái lưu trữ:

public override void OnCreate(Bundle savedInstanceState) 
{ 
    base.OnCreate(savedInstanceState); 

    if (savedInstanceState == null) 
    { 
     var tx = ChildFragmentManager.BeginTransaction(); 
     tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment()); 
     tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment()); 
     tx.Commit(); 
    } 
} 


public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance) 
{ 
    // Don't instatiate child fragments here 

    return inflater.Inflate(Resource.Layout.MyView, viewGroup, false); 
} 

này cố định tạo ra các quan điểm bổ sung và chuyển đổi tab về cơ bản làm việc bây giờ.

Câu hỏi tiếp theo là lưu và khôi phục trạng thái xem. Trong các mảnh con, tôi cần lưu và khôi phục mục hiện được chọn. Ban đầu tôi có một cái gì đó như thế này (đây là OnCreateView đoạn con của)

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) 
{ 
    var view = inflater.Inflate(Resource.Layout.CentresList, container, false); 

    // ... other code ommitted ... 

    // DONT DO THIS, SEE BELOW 
    if (savedInstance != null) 
    { 
     // Restore selection 
     _selection = savedInstance.GetString(KEY_SELECTION); 
    } 
    else 
    { 
     // Select first item 
     _selection =_items[0]; 
    } 

    return view; 
} 

Vấn đề ở đây là các máy chủ tab không gọi OnSaveInstanceState khi chuyển đổi các tab. Thay vì đoạn con được giữ sống và biến _selection có thể chỉ còn lại một mình.

Vì vậy, tôi chuyển mã để quản lý lựa chọn để OnCreate:

public override void OnCreate(Bundle savedInstance) 
{ 
    base.OnCreate(savedInstance); 

    if (savedInstance != null) 
    { 
     // Restore Selection 
     _selection = savedInstance.GetString(BK_SELECTION); 
    } 
    else 
    { 
     // Select first item 
     _selection = _items[0]; 
    } 
} 

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) 
{ 
    // Don't restore/init _selection here 

    return inflater.Inflate(Resource.Layout.CentresList, container, false); 
} 

Bây giờ tất cả dường như được làm việc một cách hoàn hảo, cả khi chuyển đổi các tab và thay đổi hướng.

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