Tiến thoái lưỡng nan: khi nào nên sử dụng Fragment vs Activity:


786

Tôi biết rằng nó Activitiesđược thiết kế để đại diện cho một màn hình duy nhất của ứng dụng của tôi, trong khi Fragmentsđược thiết kế để bố trí UI có thể sử dụng lại với logic được nhúng bên trong chúng.

Cho đến cách đây không lâu, tôi đã phát triển một ứng dụng vì nó nói rằng chúng nên được phát triển. Tôi đã tạo một Activityđể thể hiện một màn hình ứng dụng của mình và sử dụng Fragment cho ViewPagerhoặc Google Maps. Tôi hiếm khi tạo một ListFragmenthoặc một giao diện người dùng khác có thể được sử dụng lại nhiều lần.

Gần đây tôi tình cờ thấy một dự án chỉ có 2 Activitiescái là một SettingsActivityvà cái khác là cái MainActivity. Bố cục của MainActivityđược điền với nhiều đoạn UI toàn màn hình ẩn và chỉ có một đoạn được hiển thị. Trong Activitylogic có nhiều FragmentTransitionsgiữa các màn hình khác nhau của ứng dụng.

Điều tôi thích về cách tiếp cận này là vì ứng dụng sử dụng một ActionBar, nó vẫn nguyên vẹn và không di chuyển với hoạt hình chuyển đổi màn hình, đó là những gì xảy ra với Activityviệc chuyển đổi. Điều này mang lại cảm giác trôi chảy hơn cho những chuyển đổi màn hình.

Vì vậy, tôi đoán những gì tôi đang hỏi là chia sẻ cách phát triển hiện tại của bạn về chủ đề này, tôi biết nó có thể giống như một câu hỏi dựa trên ý kiến ​​từ cái nhìn đầu tiên nhưng tôi xem nó như một câu hỏi về thiết kế và kiến ​​trúc Android ... Không thực sự là một câu hỏi ý kiến ​​dựa trên một.

CẬP NHẬT (01.05.2014): Theo bài thuyết trình này của Eric Burke từ Square , (mà tôi phải nói là một bài thuyết trình tuyệt vời với rất nhiều công cụ hữu ích cho các nhà phát triển Android. Và tôi không liên quan đến Square)

http://www.infoq.com/presentations/Android-Design/

Từ kinh nghiệm cá nhân của tôi trong vài tháng qua, tôi thấy rằng cách tốt nhất để xây dựng các ứng dụng của mình là tạo các nhóm các mảnh vỡ để thể hiện một dòng chảy trong ứng dụng và trình bày tất cả các đoạn đó trong một Activity. Vì vậy, về cơ bản, bạn sẽ có cùng số lượng Activitiestrong ứng dụng của mình với số lượng luồng. Bằng cách đó, thanh hành động vẫn nguyên vẹn trên tất cả các màn hình của luồng, nhưng đang được tạo lại khi thay đổi luồng có ý nghĩa rất lớn. Như Eric Burke tuyên bố và như tôi đã nhận ra, triết lý sử dụng càng ít Activitiescàng tốt không thể áp dụng cho tất cả các tình huống vì nó tạo ra một mớ hỗn độn trong cái mà ông gọi là hoạt động "Thượng đế".


2
Kiểm tra bài đăng của tôi tại SO - stackoverflow.com/questions/24647078/ từ
Chúa ơi

Câu trả lời:


271

Các chuyên gia sẽ nói với bạn: "Khi tôi thấy UI, tôi sẽ biết nên sử dụng một Activityhay Fragment". Ban đầu điều này sẽ không có ý nghĩa gì, nhưng theo thời gian, bạn thực sự sẽ có thể nói nếu bạn cần Fragmenthay không.

Có một thực hành tốt tôi thấy rất hữu ích cho tôi. Nó xảy ra với tôi trong khi tôi đang cố gắng giải thích điều gì đó với con gái mình.

Cụ thể, hãy tưởng tượng một hộp đại diện cho một màn hình. Bạn có thể tải một màn hình khác trong hộp này? Nếu bạn sử dụng hộp mới, bạn sẽ phải sao chép nhiều mục từ hộp thứ 1 chứ? Nếu câu trả lời là Có, thì bạn nên sử dụng Fragments, vì gốc Activitycó thể chứa tất cả các phần tử trùng lặp để giúp bạn tiết kiệm thời gian trong việc tạo chúng và bạn chỉ cần thay thế các phần của hộp.

Nhưng đừng quên rằng bạn luôn cần một hộp chứa ( Activity) hoặc các bộ phận của bạn sẽ bị phân tán. Vì vậy, một hộp với các bộ phận bên trong.

Cẩn thận đừng lạm dụng hộp. Các chuyên gia Android UX khuyên (bạn có thể tìm thấy chúng trên YouTube) khi chúng ta nên tải một cách rõ ràng khác Activity, thay vào đó để sử dụng một Fragment(như khi chúng ta đối phó với Ngăn kéo Điều hướng có các danh mục). Một khi bạn cảm thấy thoải mái Fragments, bạn có thể xem tất cả các video của họ. Thậm chí nhiều hơn họ là tài liệu bắt buộc.

Bây giờ bạn có thể nhìn vào UI của bạn và tìm ra nếu bạn cần một Activityhoặc một Fragment? Bạn đã có được một quan điểm mới? Tôi nghĩ bạn đã làm.


4
Bạn có một liên kết đến nguồn cấp dữ liệu youtube mà bạn đề cập? Tôi tìm kiếm "chuyên gia Android UX" và "Android UX" nhưng tôi không hoàn toàn chắc chắn về video nào bạn đang nói đến.
tôi--

2
Không còn nữa, xem nó hơn một năm trước. Tìm kiếm chính thức cho nhà phát triển Android nói về UX
sandfish

1
Một ví dụ về sự cân nhắc: hoạt động có ParentActivity để chúng tôi có thể tổng hợp backstack trong khi nhập từ thông báo, nhưng tôi không nghĩ rằng có ParentFragment như vậy.
fikr4n


@ToolmakerSteve vâng, đó là getParentFragment, nhưng đó không phải là ý tôi, hãy xem developer.android.com/guide/topics/manifest/iêu
fikr4n

129

Triết lý của tôi là thế này:

Tạo một hoạt động chỉ khi nó hoàn toàn bắt buộc. Với ngăn xếp phía sau có sẵn để thực hiện một loạt các giao dịch phân đoạn, tôi cố gắng tạo ra càng ít hoạt động trong ứng dụng của mình càng tốt. Ngoài ra, giao tiếp giữa các mảnh khác nhau dễ dàng hơn nhiều so với việc gửi dữ liệu qua lại giữa các hoạt động.

Chuyển đổi hoạt động là đắt tiền, phải không? Ít nhất tôi tin như vậy - vì hoạt động cũ phải bị hủy / tạm dừng / dừng lại, được đẩy lên ngăn xếp, và sau đó hoạt động mới phải được tạo / bắt đầu / tiếp tục.

Đó chỉ là triết lý của tôi kể từ khi những mảnh vỡ được giới thiệu.


2
đúng, nhưng như bạn đã viết, đôi khi cần phải sử dụng các hoạt động. một ví dụ là màn hình camera, trong đó tốt hơn là sử dụng nó ở chế độ ngang. một ví dụ khác là màn hình cấu hình được hiển thị khi bạn đặt một appWidget tùy chỉnh (trên "máy tính để bàn" - ứng dụng launcher).
nhà phát triển Android

Cảm ơn bạn đã trả lời và chia sẻ kinh nghiệm của bạn Vì vậy, bạn nghĩ rằng đó là một cách thực hành tốt trong Android để giới hạn ứng dụng trong một Hoạt động và sử dụng Fragment cho tất cả màn hình nếu kiến ​​trúc ứng dụng cho phép?
Emil Adz

1
Sau đó, làm thế nào để bạn giải quyết vấn đề của các mảnh cần phải vượt qua "trạng thái" nhau? Tất cả các trạng thái trên tất cả các phân đoạn của bạn cần phải sống trong một hoạt động, nếu không, bạn buộc phải sử dụng một đơn vị.
Mr_E

36
Tôi không tin rằng việc liên lạc giữa các mảnh khác nhau dễ dàng hơn nhiều so với việc gửi dữ liệu qua lại giữa các hoạt động.
Denny

3
Ít nhất, onActivityResult()an toàn và dễ dàng hơn các cuộc gọi lại của các mảnh vỡ.
CoolMind

59

Chà, theo các bài giảng của Google (có thể ở đây , tôi không nhớ), bạn nên cân nhắc sử dụng Fragment bất cứ khi nào có thể, vì nó giúp mã của bạn dễ bảo trì và kiểm soát hơn.

Tuy nhiên, tôi nghĩ rằng trong một số trường hợp, nó có thể trở nên quá phức tạp, vì hoạt động lưu trữ các mảnh cần điều hướng / liên lạc giữa chúng.

Tôi nghĩ bạn nên tự quyết định những gì tốt nhất cho bạn. Thông thường không khó để chuyển đổi một hoạt động thành một đoạn và ngược lại.

Tôi đã tạo một bài viết về dillema này ở đây , nếu bạn muốn đọc thêm.


5
Cảm ơn bạn đã trả lời và chia sẻ kinh nghiệm của bạn Vì vậy, bạn nghĩ rằng đó là một cách thực hành tốt trong Android để giới hạn ứng dụng trong một Hoạt động và sử dụng Fragment cho tất cả màn hình nếu kiến ​​trúc ứng dụng cho phép?
Emil Adz

Nó phụ thuộc vào dự án, nhưng nếu nó quá phức tạp với bạn, bạn cũng có thể tách ra thành nhiều hoạt động. Đừng ngại sử dụng bất kỳ phương pháp nào. Bạn cũng có thể sử dụng cả hai. Có lẽ đôi khi sẽ quá khó để bạn sử dụng các mảnh thay vì các hoạt động. Tôi nghĩ bạn nên cố gắng sử dụng các mảnh vỡ, nhưng đừng ép nó ở mọi nơi nếu nó trở nên quá nhiều theo cách của bạn ...
nhà phát triển Android

Điều gì xảy ra nếu tôi muốn giữ cho ảnh hưởng của ActionBar được giữ nguyên và tất cả nội dung đang được chuyển đổi? Có thể đạt được điều này với Hoạt động?
Emil Adz


27

Tại sao tôi thích Fragment hơn Activity trong TẤT CẢ CÁC TRƯỜNG HỢP.

  • Hoạt động là tốn kém. Trong Fragment, các khung nhìn và trạng thái thuộc tính được tách ra - bất cứ khi nào một mảnh được đặt vào backstack, các khung nhìn của nó sẽ bị phá hủy. Vì vậy, bạn có thể xếp nhiều mảnh hơn nhiều so với Hoạt động.

  • BackstackThao tác. Với FragmentManager, thật dễ dàng để xóa tất cả các Mảnh vỡ, chèn nhiều hơn vào Mảnh vỡ và etcs. Nhưng đối với Activity, sẽ là một cơn ác mộng khi thao túng những thứ đó.

  • Một vòng đời dự đoán nhiều . Miễn là hoạt động của máy chủ không được tái chế. Các mảnh vỡ trong backstack sẽ không được tái chế. Vì vậy, có thể sử dụng FragmentManager::getFragments()để tìm Fragment cụ thể (không được khuyến khích).


HI, tôi đã đọc bài đánh giá của bạn về những ưu điểm của Frag over Act, Bạn có dự án nào để thể hiện điều tương tự trong Github Repo của bạn không?
Ümañg ßürmån

24

Kể từ Jetpack , ứng dụng Single-Activity là kiến ​​trúc được ưa thích. Đặc biệt hữu ích với Thành phần Kiến trúc Điều hướng .

nguồn


Cảm ơn vì điều này!
Simão Garcia

1
Tôi đọc về Jetpack lần đầu tiên ngày hôm nay. :) Chúng tôi xây dựng các ứng dụng hoạt động duy nhất kể từ khi các mảnh được giới thiệu. Đa hoạt động phức tạp hơn nhiều.
Ngày

1
@TheincredibleJan Bạn nói đúng, Kiến trúc ứng dụng một hoạt động là giải pháp tốt hơn từ lâu trước Jetpack
Francis

12

Theo tôi nó không thực sự phù hợp. Yếu tố quan trọng để xem xét là

  1. tần suất bạn sẽ sử dụng lại các phần của giao diện người dùng (ví dụ: menu),
  2. ứng dụng này cũng dành cho máy tính bảng?

Công dụng chính của các mảnh vỡ là để xây dựng các hoạt động đa năng, làm cho nó hoàn hảo cho các ứng dụng đáp ứng Máy tính bảng / Điện thoại.


Tôi muốn nói rằng công dụng chính của các đoạn là tạo ra các khung nhìn tùy chỉnh mà không nghĩ chúng là các khung nhìn tùy chỉnh. Dù sao đó cũng là những gì xảy ra. Các mảnh vỡ ban đầu chúng tôi được hiển thị từ Google như một cách tiện dụng để tạo các ứng dụng đáp ứng máy tính bảng, do đó bạn có thể gắn chúng vào các hoạt động khác nhau nếu bạn muốn. một cách để đính kèm mã vào một khung nhìn, nhiều hay ít và để chúng có thể gắn vào nơi bạn muốn (mà không cần thực hiện các chế độ xem tùy chỉnh).
Lassi Kinnunen

11

Đừng quên rằng một hoạt động là khối / thành phần của ứng dụng có thể được chia sẻ và bắt đầu thông qua Ý định! Vì vậy, mỗi hoạt động trong ứng dụng của bạn chỉ nên giải quyết một loại nhiệm vụ. Nếu bạn chỉ có một nhiệm vụ trong ứng dụng của mình thì tôi nghĩ bạn chỉ cần một hoạt động và nhiều phân đoạn nếu cần. Tất nhiên bạn có thể sử dụng lại các đoạn trong các hoạt động trong tương lai để giải quyết các nhiệm vụ khác. Cách tiếp cận này sẽ được phân tách rõ ràng và hợp lý các nhiệm vụ. Và bạn không cần phải duy trì một hoạt động với các tham số bộ lọc mục đích khác nhau cho các bộ phân đoạn khác nhau. Bạn xác định các nhiệm vụ ở giai đoạn thiết kế của quá trình phát triển dựa trên các yêu cầu.


Trong các ứng dụng của chúng tôi, một loại nhiệm vụ của hoạt động là giữ ngăn kéo điều hướng để nhập các mảnh khác nhau. :) Tại sao tôi nên vật lộn với ý định cho các mảnh vỡ? Thật rõ ràng và hợp lý khi giữ một tham chiếu tĩnh cho lớp dữ liệu "toàn cầu" cho dữ liệu toàn cầu và chuyển một số giá trị cho phương thức tạo cá thể của một đoạn.
Ngày

9

Có nhiều điều hơn bạn nghĩ, bạn phải nhớ hơn một hoạt động được khởi chạy không hoàn toàn phá hủy hoạt động gọi điện. Chắc chắn, bạn có thể thiết lập nó để người dùng của bạn nhấp vào nút để đi đến một trang, bạn bắt đầu hoạt động của trang đó và phá hủy trang hiện tại. Điều này gây ra rất nhiều chi phí. Hướng dẫn tốt nhất tôi có thể cung cấp cho bạn là:

** Chỉ bắt đầu một hoạt động mới nếu có ý nghĩa để có hoạt động chính và hoạt động này mở cùng một lúc (nghĩ về nhiều cửa sổ).

Một ví dụ tuyệt vời khi có nhiều hoạt động là Google Drive. Các hoạt động chính cung cấp một trình thám hiểm tập tin. Khi một tệp được mở, một hoạt động mới được khởi chạy để xem tệp đó. Bạn có thể nhấn nút ứng dụng gần đây sẽ cho phép bạn quay lại trình duyệt mà không cần đóng tài liệu đã mở, thậm chí có thể mở tài liệu khác song song với tài liệu đầu tiên.


Re "Bắt đầu một hoạt động mới chỉ khi nó có ý nghĩa để có hoạt động chính và hoạt động này mở cùng một lúc (nghĩ về nhiều cửa sổ)." Tôi không nghĩ vậy. Tình huống đó được giải quyết tốt bằng cách sử dụng các đoạn attach / detachphương pháp.
ToolmakerSteve

7

Điều tôi đã làm: Sử dụng ít mảnh hơn khi có thể. Thật không may, nó có thể trong hầu hết các trường hợp. Vì vậy, tôi kết thúc với rất nhiều mảnh vỡ và một ít hoạt động. Một số nhược điểm tôi đã nhận ra:

  • ActionBar& Menu: Khi 2 đoạn có tiêu đề, menu khác nhau, điều đó
    sẽ khó xử lý. Ví dụ: khi thêm đoạn mới, bạn có thể thay đổi tiêu đề thanh hành động, nhưng khi bật nó từ backstackđó, không có cách nào để khôi phục tiêu đề cũ. Bạn có thể cần một Thanh công cụ trong mọi phân đoạn cho trường hợp này, nhưng hãy tin tôi, điều đó sẽ khiến bạn mất nhiều thời gian hơn.
  • Khi chúng ta cần startForResult, hoạt động có nhưng phân đoạn thì không.
  • Không có hình ảnh chuyển tiếp theo mặc định

Giải pháp của tôi cho việc này là sử dụng một Activity để bọc một đoạn bên trong. Vì vậy, chúng tôi có thanh hành động, menu startActivityForResult, hoạt hình, ...


1
Điểm rất hữu ích, cảm ơn. Bạn có thể làm rõ " một hoạt động để bọc một mảnh "? Bạn đã tạo một Hoạt động riêng cho từng phân đoạn chưa? Nếu vậy, bạn có cần Fragment không?
ToolmakerSteve

3
có một cách để khôi phục tiêu đề và công cụ. sử dụng getSupportFragmentManager().addOnBackStackChangedListenerđể thêm một người nghe. nhận đoạn hiện tại trong trình nghe đó và sau đó đặt tiêu đề và nội dung.
babay

4

Một lợi thế lớn của fragmenthoạt động quá mức là, mã được sử dụng cho đoạn có thể được sử dụng cho các hoạt động khác nhau. Ngoài ra, nó cung cấp khả năng sử dụng lại mã trong phát triển ứng dụng.


3
Làm sao? COuld bạn cung cấp một số ví dụ xin vui lòng?
sofs1

1
@ sofs1 Câu hỏi của bạn không có nhiều ý nghĩa. Bất kỳ mã nào trong một đoạn vẫn giữ nguyên cho dù hoạt động của đoạn đó là gì.
Ngày

@TheincredibleJan Nhưng chúng ta cũng không thể nói "Bất kỳ mã nào trong một hoạt động vẫn giữ nguyên cho dù hoạt động thứ hai được khởi tạo từ hoạt động nào."? Tôi không thấy sự khác biệt.
iforce2d

3

sử dụng một hoạt động cho mỗi ứng dụng để cung cấp cơ sở cho việc fragment sử dụng fragmentcho màn hình, fragmentstrọng lượng bản nhẹ so với activites các mảnh vỡ là tái sử dụng mảnh vỡ được phù hợp hơn cho các ứng dụng có hỗ trợ cả điện thoại & tablet


2

Bạn có thể tự do sử dụng một trong số đó.
Về cơ bản, bạn phải đánh giá cái nào là tốt nhất cho ứng dụng của bạn. Hãy suy nghĩ về cách bạn sẽ quản lý luồng kinh doanh và cách lưu trữ / quản lý tùy chọn dữ liệu.

Hãy suy nghĩ về cách thức lưu trữ dữ liệu rác. Khi bạn triển khai đoạn, bạn có một gốc hoạt động để điền vào đoạn (s). Vì vậy, nếu bạn cố gắng thực hiện nhiều hoạt động với quá nhiều phân đoạn, bạn phải xem xét hiệu suất trên ứng dụng của mình, vì bạn đang thao tác (nói một cách thô thiển) hai vòng đời bối cảnh, hãy nhớ sự phức tạp.

Hãy nhớ rằng: tôi có nên sử dụng các mảnh vỡ? Tại sao tôi không nên?

Trân trọng.


1

Tôi sử dụng Fragment cho trải nghiệm người dùng tốt hơn. Ví dụ: nếu bạn có Nút và bạn muốn chạy, hãy nói dịch vụ web khi bạn nhấp vào nút đó, tôi đính kèm một Đoạn vào Hoạt động chính.

if (id == R.id.forecast) {

    ForecastFragment forecastFragment = new ForecastFragment();
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.main_content, forecastFragment);
    ft.addToBackStack("backstack");
    forecastFragment.setArguments(b);
    ft.commit();
}

Theo cách đó, người dùng sẽ không phải chuyển sang hoạt động khác.

Và thứ hai tôi thích Fragment hơn vì bạn có thể xử lý chúng dễ dàng trong quá trình quay.


Điều gì làm cho ví dụ đó là một trải nghiệm người dùng tốt hơn? Làm sao họ biết (hoặc quan tâm) rằng họ đang thực hiện một hoạt động hoặc một đoạn?
iforce2d

1

Nó phụ thuộc vào những gì bạn muốn xây dựng thực sự. Ví dụ như navigation drawersử dụng các đoạn. Tab sử dụng fragmentslà tốt. Một thực hiện tốt, là nơi bạn có một listview. Khi bạn xoay điện thoại và nhấp vào một hàng, hoạt động được hiển thị ở nửa còn lại của màn hình. Cá nhân, tôi sử dụng fragmentsfragment dialogs, vì nó chuyên nghiệp hơn. Thêm vào đó chúng được xử lý dễ dàng hơn trong vòng quay.

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.