Những mảnh vỡ trong những mảnh vỡ


145

Tôi tự hỏi liệu đây có thực sự là một lỗi trong API Android không:

Tôi có một thiết lập như vậy:

┌----┬---------┐
|    |         |
|  1 |    2    |
|    |┌-------┐|
|    ||       ||
|    ||   3   ||
└----┴┴-------┴┘
  1. Là một menu tải đoạn # 2 (Màn hình tìm kiếm) trong khung bên phải.
  2. Là màn hình tìm kiếm chứa đoạn 3, là danh sách kết quả.
  3. Danh sách kết quả được sử dụng ở một số nơi (bao gồm cả phân đoạn cấp cao hoạt động theo quyền riêng của nó).

Chức năng này hoạt động hoàn hảo trên điện thoại (Trong đó 1 & 2 và 3 là ActivityFragments).

Tuy nhiên, khi tôi sử dụng mã này:

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();       
    Fragment frag = new FragmentNumber2();
    if(toLoad != null) frag.setArguments(toLoad);
    transaction.replace(R.id.rightPane, frag);      
    transaction.commit();

Trường hợp R.id.leftPaneR.id.rightPane<fragment>s trong một bố trí tuyến tính ngang.

Theo hiểu biết của tôi, đoạn mã trên sẽ loại bỏ đoạn được cư trú và sau đó thay thế nó bằng một đoạn mới. Rực rỡ ... Rõ ràng đó không phải là điều xảy ra bởi vì khi mã này chạy lần thứ hai, bạn sẽ có ngoại lệ sau:

07-27 15:22:55.940: ERROR/AndroidRuntime(8105): Caused by: java.lang.IllegalArgumentException: Binary XML file line #57: Duplicate id 0x7f080024, tag null, or parent id 0x0 with another fragment for FragmentNumber3

Điều này được gây ra bởi vì bộ chứa cho FragmentNumber3 đã được sao chép và nó không còn có ID duy nhất. Mảnh vỡ ban đầu chưa bị phá hủy (?) Trước khi mảnh mới được thêm vào (trong tâm trí của tôi có nghĩa là nó chưa được thay thế ).

Ai đó có thể cho tôi biết nếu điều này là có thể ( câu trả lời này cho thấy không phải vậy) hoặc đó là một lỗi?


1
bản sao có thể của Fragment Inside Fragment
rds

6
@rds đây là một câu hỏi cổ xưa, bit vô nghĩa để đánh dấu là trùng lặp.
pietv8x

Câu trả lời:


203

Các mảnh lồng nhau hiện không được hỗ trợ. Cố gắng đặt một đoạn trong giao diện người dùng của một đoạn khác sẽ dẫn đến hành vi không xác định và có khả năng bị hỏng.

Cập nhật : Các đoạn lồng nhau được hỗ trợ kể từ Android 4.2 (và Thư viện hỗ trợ Android phiên bản 11): http://developer.android.com/about/versions/android-4.2.html#NestedFragments

LƯU Ý (theo tài liệu này ): " Lưu ý: Bạn không thể tăng bố cục thành một đoạn khi bố cục đó bao gồm a <fragment>. Các đoạn lồng nhau chỉ được hỗ trợ khi được thêm vào một đoạn động. "


14
Không được hỗ trợ vì đó không phải là mục tiêu thiết kế cho việc triển khai ban đầu. Tôi đã nghe rất nhiều yêu cầu cho tính năng này, vì vậy có thể nó sẽ được thực hiện vào một lúc nào đó, nhưng như thường lệ, có rất nhiều thứ khác cạnh tranh với nó được ưu tiên.
hackbod

4
Tôi đã quản lý điều này bằng cách mở rộng FragmentActivity, FragmentManager và FragmentTransaction. Tiền đề cơ bản là mở rộng DeferringFragmentActivity trong các hoạt động của tôi, cung cấp cùng một api để không có thay đổi mã nào khác. Khi tôi gọi getFragmentManager, tôi nhận được một ví dụ là DeferringFragmentManager và khi tôi gọi startTransaction, tôi nhận được DeferredTransaction. Giao dịch này lưu trữ POJO với phương thức và đối số được gọi. Khi cam kết là cuộc gọi, trước tiên chúng tôi sẽ tìm kiếm bất kỳ Giao dịch hoãn lại đang chờ xử lý nào. Khi tất cả các giao dịch đã được cam kết, chúng tôi bắt đầu một giao dịch thực sự và chạy tất cả các phương thức được lưu trữ với args.
dskinner

11
Đó là điểm bây giờ. Các lồng nhau Fragmenthiện là một phần của API Android, yay! developer.android.com/about/versions/ trên .
Alex Lockwood

9
Ồ, thật là một cơn ác mộng: nếu bạn sử dụng <Fragment> trên Fragment và Fragment đó xảy ra để sử dụng các đoạn con, thì nó không thất bại với một lỗi rõ ràng ("không thể thêm các mảnh con vào các mảnh bố cục") - nó thất bại một cách bí ẩn với các ngoại lệ như "đoạn không tạo ra một cái nhìn". Phải mất vài giờ để gỡ lỗi ...
Glenn Maynard

6
@ MartínMarconcini chắc chắn nhưng điều đó hoàn toàn không rõ ràng dựa trên chức năng được cung cấp bởi API. Nếu một cái gì đó không được phép thì nó phải được ghi lại rõ ràng, không được để nhà phát triển kéo tóc ra vì một cái gì đó không hoạt động theo cách bạn mong đợi.
dcow

98

Các đoạn lồng nhau được hỗ trợ trong Android 4.2 trở lên

Thư viện hỗ trợ Android hiện cũng hỗ trợ các phân đoạn lồng nhau , vì vậy bạn có thể triển khai các thiết kế phân đoạn lồng nhau trên Android 1.6 trở lên.

Để lồng một đoạn, chỉ cần gọi getChildFragmentManager () trên Đoạn mà bạn muốn thêm một đoạn. Điều này trả về một FragmentManager mà bạn có thể sử dụng như bạn thường làm từ hoạt động cấp cao nhất để tạo các giao dịch phân đoạn. Ví dụ: đây là một số mã có thêm một đoạn từ trong một lớp Fragment hiện có:

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

Để có thêm ý tưởng về các đoạn lồng nhau, vui lòng xem qua các hướng dẫn này
Phần 1
Phần 2
Phần 3

và đây là một bài viết SO thảo luận về các thực tiễn tốt nhất cho các đoạn lồng nhau .


Nhược điểm chính của Nestedfragment là chúng ta không thể gọi tùy chọn từ tính năng bảo vệ trẻ em :( nếu chúng ta đang sử dụng ABS!
LOGiah

Bạn có thể vui lòng xem trong vấn đề của tôi ?? Nó rất giống nhau .. stackoverflow.com/questions/32240138/ . Đối với tôi, khung hình con không bị thổi phồng từ mã
Nicks

33

.. bạn có thể dọn sạch đoạn lồng nhau của mình trong destroyviewphương thức của đoạn cha mẹ :

@Override
    public void onDestroyView() {

      try{
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();

        transaction.remove(nestedFragment);

        transaction.commit();
      }catch(Exception e){
      }

        super.onDestroyView();
    }

4
Nếu bạn thực hiện một số thử nghiệm vòng đời với SetAlwaysFinish ( bricolsoftconsulting.com/2011/12/23/ Khăn ), bạn sẽ thấy mã này gây ra lỗi khi một hoạt động khác lên đầu với luôn luôn kết thúc (IllegalStateException: Không thể thực hiện hành động này sau onSaveInstanceState). Gói mã ở trên trong thử / bắt không phải là giải pháp tao nhã nhất nhưng nó dường như làm mọi thứ hoạt động.
Theo

Điều này gần như đã làm việc. Sau đó tôi có một Stackoverflow về vẽ UI. Chắc chắn tránh các mảnh vỡ lồng nhau ...
neteinstein

14

Tôi có một ứng dụng mà tôi đang phát triển được đặt tương tự với các Tab trong Action Bar để khởi chạy các đoạn, một số Mảnh vỡ này có nhiều Mảnh vỡ được nhúng trong đó.

Tôi đã nhận được cùng một lỗi khi tôi cố gắng chạy ứng dụng. Có vẻ như nếu bạn khởi tạo các Đoạn trong bố cục xml sau khi một tab không được chọn và sau đó được chọn lại, tôi sẽ gặp lỗi bơm hơi.

Tôi đã giải quyết vấn đề này thay thế tất cả các mảnh vỡ trong xml bằng Linearlayouts và sau đó sử dụng giao dịch mảnh / quản lý mảnh vỡ để khởi tạo các mảnh vỡ mọi thứ dường như hoạt động chính xác ít nhất là ở cấp độ thử nghiệm ngay bây giờ.

Tôi hy vọng điều này sẽ giúp bạn ra ngoài.


Bất cứ ai có thể nhận xét về hiệu quả của phương pháp này? Tôi thấy thật không may khi có thể sử dụng Mảnh vỡ chỉ sâu một cấp - cũng có thể không sử dụng chúng cả. Thêm chúng theo chương trình vào các nhóm xem giữ chỗ sẽ hoạt động mà không cần cảnh giác?
Rafael Nobre

Dường như vẫn đang làm việc cho tôi, tôi trao đổi chúng trong và ngoài tầm nhìn cũng không có vấn đề gì. Một cảnh báo tôi chỉ làm điều này trên tổ ong không tương thích với bánh sandwich kem.
Draksia

4

Tôi đã phải đối mặt với cùng một vấn đề, đã phải vật lộn một vài ngày với nó và nên nói rằng cách khắc phục dễ dàng nhất tôi thấy điều này là sử dụng Fragment. Suede () / Fragment.show () khi tab được chọn / không được chọn ().

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
    if (mFragment != null)
        ft.hide(mFragment);
}

Khi xoay màn hình xảy ra, tất cả các mảnh cha mẹ và con bị phá hủy chính xác.

Cách tiếp cận này cũng có một lợi thế bổ sung - sử dụng ẩn () / show () không làm cho các chế độ xem phân đoạn bị mất trạng thái của chúng, do đó không cần phải khôi phục vị trí cuộn trước đó cho ScrollViews.

Vấn đề là tôi không biết liệu có đúng không khi tách các mảnh vỡ khi chúng không nhìn thấy được. Tôi nghĩ rằng ví dụ chính thức về TabListener được thiết kế với ý nghĩ rằng các mảnh vỡ có thể tái sử dụng và bạn không nên làm ô nhiễm bộ nhớ của chúng, tuy nhiên, tôi nghĩ rằng nếu bạn chỉ có một vài tab và bạn biết rằng người dùng sẽ thường xuyên chuyển đổi giữa chúng sẽ thích hợp để giữ chúng gắn liền với hoạt động hiện tại.

Tôi muốn nghe ý kiến ​​từ các nhà phát triển có kinh nghiệm hơn.


0

Nếu bạn thấy đoạn lồng nhau của mình không bị xóa hoặc bị trùng lặp (ví dụ: khi khởi động lại Activity, trên màn hình xoay) hãy thử thay đổi:

transaction.add(R.id.placeholder, newFragment);

đến

transaction.replace(R.id.placeholder, newFragment);

Nếu ở trên không có ích, hãy thử:

Fragment f = getChildFragmentManager().findFragmentById(R.id.placeholder);

FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

if (f == null) {
    Log.d(TAG, "onCreateView: fragment doesn't exist");
    newFragment= new MyFragmentType();
    transaction.add(R.id.placeholder, newFragment);
} else {
    Log.d(TAG, "onCreateView: fragment already exists");
    transaction.replace(R.id.placeholder, f);
}
transaction.commit();

Học ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.