Nhúng hoạt động

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Tính năng nhúng hoạt động tối ưu hoá các ứng dụng trên thiết bị có màn hình lớn bằng cách chia cửa sổ tác vụ của ứng dụng giữa hai hoạt động hoặc hai thực thể của cùng một hoạt động.

Hình 1. Cài đặt ứng dụng với các hoạt động song song.

Việc cập nhật các cơ sở mã cũ để hỗ trợ màn hình lớn tốn nhiều công sức và thời gian. Việc chuyển đổi ứng dụng dựa trên hoạt động sang bố cục nhiều ngăn bằng cách sử dụng mảnh đòi hỏi bạn phải tái cấu trúc đáng kể.

Việc nhúng hoạt động không cần nhiều hoặc thậm chí không cần tái cấu trúc ứng dụng. Bạn xác định cách ứng dụng cho thấy hoạt động song song hoặc xếp chồng bằng cách tạo tệp cấu hình XML hoặc thực hiện các lệnh gọi Jetpack WindowManager API.

Hoạt động hỗ trợ màn hình nhỏ được duy trì tự động. Khi ứng dụng đang chạy trên thiết bị có màn hình nhỏ, các hoạt động được xếp chồng lên nhau. Trên màn hình lớn, hoạt động được hiển thị cạnh nhau. Hệ thống sẽ xác định cách hiển thị dựa trên cấu hình bạn đã tạo mà không yêu cầu logic phân nhánh.

Tính năng nhúng hoạt động hỗ trợ các thay đổi về hướng của thiết bị và hoạt động trơn tru trên thiết bị có thể gập lại, hoạt động xếp chồng và huỷ xếp chồng khi thiết bị được gập và mở ra.

Việc phát triển Android hiện đại sử dụng cấu trúc hoạt động đơn với các mảnh, thành phần điều hướng và trình quản lý bố cục linh hoạt như SlidingPaneLayout.

Tuy nhiên, nếu ứng dụng bao gồm nhiều hoạt động, tính năng nhúng hoạt động sẽ cho phép bạn dễ dàng cung cấp trải nghiệm nâng cao cho người dùng trên máy tính bảng, thiết bị có thể gập lại và ChromeOS.

Chia cửa sổ tác vụ

Tính năng nhúng hoạt động chia cửa sổ tác vụ của ứng dụng thành hai vùng chứa: chính và phụ. Các vùng chứa giúp hoạt động khởi chạy từ hoạt động chính hoặc từ các hoạt động khác đã có trong vùng chứa.

Các hoạt động được xếp chồng trong vùng chứa phụ khi khởi chạy, đồng thời vùng chứa phụ được xếp chồng trên vùng chứa chính ở các màn hình nhỏ, vì vậy việc xếp chồng hoạt động và điều hướng quay lại nhất quán với thứ tự các hoạt động đã được tích hợp vào ứng dụng.

Tính năng nhúng hoạt động cho phép hiển thị các hoạt động theo nhiều cách khác nhau. Ứng dụng có thể chia cửa sổ tác vụ bằng cách chạy đồng thời hai hoạt động cùng lúc:

Hình 2. Hai hoạt động song song.

Hoặc một hoạt động chiếm toàn bộ cửa sổ tác vụ có thể tạo thao tác tách bằng cách chạy một hoạt động mới song song với:

Hình 3. Hoạt động A khởi động hoạt động B bên cạnh.

Các hoạt động đã được chia nhỏ và dùng chung cửa sổ tác vụ có thể chạy các hoạt động khác theo cách sau:

  • Ở bên cạnh phía trên một hoạt động khác:

    Hình 4. Hoạt động A khởi động hoạt động C bên cạnh hoạt động B.
  • Ở bên cạnh và dịch chuyển tách sang một bên, che hoạt động chính trước đó:

    Hình 5. Hoạt động B khởi động hoạt động C bên cạnh và di chuyển phần tách sang một bên.
  • Triển khai một hoạt động diễn ra ở trên cùng; tức là trong cùng ngăn xếp hoạt động:

    Hình 6. Hoạt động B khởi động hoạt động C mà không có thêm cờ hiệu ý định nào.
  • Khởi chạy hoạt động bằng cửa sổ tràn màn hình trong cùng một tác vụ:

    Hình 7. Hoạt động A hoặc hoạt động B sẽ khởi động hoạt động C, lấp đầy cửa sổ tác vụ.

Tính năng điều hướng quay lại

Các ứng dụng khác nhau có thể có quy tắc điều hướng ngược khác nhau trong trạng thái cửa sổ tác vụ phân tách, tuỳ thuộc vào sự phụ thuộc giữa các hoạt động hoặc cách người dùng kích hoạt sự kiện quay lại, ví dụ:

  • Kết hợp với nhau: Nếu các hoạt động có liên quan với nhau và một hoạt động sẽ không hiển thị nếu không có hoạt động kia, bạn có thể định cấu hình tính năng điều hướng quay lại để kết thúc cả hai.
  • Riêng lẻ: Nếu các hoạt động hoàn toàn độc lập, việc điều hướng ngược lại một hoạt động không ảnh hưởng đến trạng thái của hoạt động khác trong cửa sổ tác vụ.

Sự kiện quay lại được gửi tới hoạt động tập trung gần đây nhất khi sử dụng nút điều hướng. Với thao tác bằng cử chỉ, sự kiện quay lại sẽ được gửi đến hoạt động xảy ra cử chỉ.

Bố cục nhiều ngăn

Phiên bản Jetpack WindowsManager 1.0 Beta03 cho phép tạo bố cục nhiều ngăn với các hoạt động trên thiết bị màn hình lớn 12L (API level 32) và một số thiết bị có phiên bản nền tảng cũ. Những ứng dụng hiện có dựa trên nhiều hoạt động thay vì các mảnh hoặc bố cục dựa trên chế độ xem, chẳng hạn như SlidingPaneLayout có thể cải thiện trải nghiệm người dùng màn hình lớn mà không cần tái cấu trúc đáng kể.

Một ví dụ thường gặp là cách phân chia chi tiết danh sách. Để đảm bảo giao diện trình bày chất lượng, hệ thống bắt đầu hoạt động danh sách, sau đó ứng dụng ngay lập tức hoạt động chi tiết. Hệ thống chuyển đổi sẽ chờ đến khi cả hai hoạt động được rút ra rồi hiển thị các hoạt động đó cùng lúc. Đối với người dùng, hai hoạt động sẽ khởi chạy như một.

Hình 8. Hai hoạt động bắt đầu cùng lúc trong một bố cục nhiều ngăn.

Phân tách tỷ lệ

Ứng dụng có thể chỉ định cách cửa sổ tác vụ được phân bổ theo thuộc tính ratio của cấu hình phân tách (xem phần Cấu hình phân tách bên dưới).

Hình 9. Hai phần tách hoạt động có tỷ lệ phân chia khác nhau.

Các trình giữ chỗ

Hoạt động giữ chỗ là các hoạt động phụ trống chiếm một phần chia tách hoạt động. Cuối cùng, chúng được thay thế bằng một hoạt động khác có chứa nội dung. Ví dụ: hoạt động giữ chỗ có thể nằm ở phía phụ của phần tách hoạt động trong bố cục chi tiết danh sách cho đến khi một mục từ danh sách được chọn, tại thời điểm đó là hoạt động chứa thông tin chi tiết cho mục danh sách đã chọn thay thế phần giữ chỗ.

Trình giữ chỗ chỉ hiển thị khi có đủ không gian để chia tách. Trình giữ chỗ tự động hoàn tất khi kích thước hiển thị thay đổi với chiều rộng nhỏ đến mức không thể hiển thị phần phân tách hoạt động, nhưng sẽ được tự động chạy lại (với trạng thái khởi chạy lại) khi không gian cho phép.

Hình 10. Thiết bị có thể gập lại và mở ra. Hoạt động trình giữ chỗ đã hoàn tất và được tạo lại khi kích thước hiển thị thay đổi.

Thay đổi kích thước cửa sổ

Khi thay đổi cấu hình thiết bị, người dùng sẽ giảm chiều rộng cửa sổ tác vụ để nó không đủ lớn cho bố cục nhiều ngăn (ví dụ: khi một thiết bị, có thể gập lại với màn hình lớn, gập từ kích thước máy tính bảng thành kích thước điện thoại hoặc cửa sổ ứng dụng được điều chỉnh kích thước ở chế độ nhiều cửa sổ), các hoạt động không nằm trong trình giữ chỗ tại ngăn phụ của cửa sổ tác vụ được xếp chồng lên trên các hoạt động trong ngăn chính.

Các hoạt động của trình giữ chỗ chỉ hiển thị khi có đủ chiều rộng cho một phần tách. Trên màn hình nhỏ hơn, trình giữ chỗ sẽ tự động bị loại bỏ. Khi diện tích hiển thị lại đủ lớn, trình giữ chỗ sẽ được tạo lại. (Xem Phần giữ chỗ ở trên.)

Bạn có thể xếp chồng hoạt động vì WindowManager sắp xếp các hoạt động trong ngăn phụ ở phía trên các hoạt động trong ngăn chính.

Nhiều hoạt động trong ngăn phụ

Hoạt động B khởi động hoạt động C tại vị trí không có cờ hiệu ý định:

Phần tách hoạt động có chứa các hoạt động A, B và C, trong đó C nằm phía trên B.

dẫn đến thứ tự z hoạt động sau trong cùng một nhiệm vụ:

Ngăn xếp hoạt động phụ chứa hoạt động C xếp chồng lên trên B.
          Ngăn xếp phụ được xếp chồng lên trên ngăn xếp hoạt động chính chứa hoạt động A.

Vì vậy, trong cửa sổ tác vụ nhỏ hơn, ứng dụng sẽ thu gọn thành một hoạt động bằng C ở đầu ngăn xếp:

Cửa sổ nhỏ chỉ hiển thị hoạt động C.

Thao tác quay lại trong cửa sổ nhỏ hơn sẽ di chuyển qua các hoạt động xếp chồng lên nhau.

Nếu cấu hình cửa sổ tác vụ được khôi phục về kích thước lớn hơn có thể chứa nhiều ngăn, các hoạt động sẽ hiển thị cạnh nhau.

Chia ngăn xếp

Hoạt động B khởi động hoạt động C bên cạnh và di chuyển phần tách sang bên.

Cửa sổ tác vụ cho thấy các hoạt động A và B, sau đó là các hoạt động B và C.

Kết quả theo thứ tự z sau của các hoạt động trong cùng một nhiệm vụ:

Các hoạt động A, B và C trong một ngăn xếp. Các hoạt động được xếp chồng theo thứ tự từ trên xuống dưới: C, B, A.

Trong cửa sổ tác vụ nhỏ hơn, ứng dụng sẽ thu gọn thành một hoạt động duy nhất có C nằm trên cùng:

Cửa sổ nhỏ chỉ hiển thị hoạt động C.

Cấu hình phân tách

Thư viện WindowManager có thể tạo các vùng chứa và phần tách dựa trên quy tắc phân tách. Việc định cấu hình quy tắc phân tách bao gồm nhiều bước:

  1. Thêm phần phụ thuộc thư viện WindowManager vào tệp build.gradle:

    implementation("androidx.window:window:1.0.0-beta03")

  2. Tạo tệp tài nguyên thực hiện những việc sau:

    • Xác định các hoạt động sẽ được phân tách bằng bộ lọc
    • Định cấu hình các tuỳ chọn phân tách cho tất cả hoạt động có chung phần tách
    • Chỉ định các hoạt động không nên đưa vào để phân tách

    Ví dụ:

    <!-- The split configuration for activities. -->
    <resources
        xmlns:window="http://schemas.android.com/apk/res-auto">
    
        <!-- Automatically split the following activity pairs. -->
        <SplitPairRule
            window:splitRatio="0.3"
            window:splitMinWidth="600dp"
            window:finishPrimaryWithSecondary="true"
            window:finishSecondaryWithPrimary="true">
            <SplitPairFilter
                window:primaryActivityName=".SplitActivityList"
                window:secondaryActivityName=".SplitActivityDetail"/>
            <SplitPairFilter
                window:primaryActivityName="*"
                window:secondaryActivityName="*/*"
                window:secondaryActivityAction="android.intent.action.VIEW"/>
        </SplitPairRule>
    
        <!-- Automatically launch a placeholder for the list activity. -->
        <SplitPlaceholderRule
            window:placeholderActivityName=".SplitActivityListPlaceholder"
            window:splitRatio="0.3"
            window:splitMinWidth="600dp">
            <ActivityFilter
                window:activityName=".SplitActivityList"/>
        </SplitPlaceholderRule>
    
    </resources>
    
  3. Thông báo cho thư viện về các định nghĩa quy tắc.

    Ví dụ này đang sử dụng thư viện Khởi động Jetpack để thao tác việc khởi chạy trước khi bắt đầu các hoạt động khác trong quá trình tải và thao tác trong ứng dụng. Để bật chức năng khởi động, hãy thêm phần phụ thuộc thư viện vào tệp bản dựng của ứng dụng:

    implementation("androidx.startup:startup-runtime:1.1.0")

    đồng thời thêm mục nhập sau vào tệp kê khai ứng dụng:

    <!-- AndroidManifest.xml -->
    
    <provider android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <!-- This entry makes ExampleWindowInitializer discoverable. -->
        <meta-data  android:name="androidx.window.sample.embedding.ExampleWindowInitializer"
            android:value="androidx.startup" />
    </provider>
    
  4. Cuối cùng, hãy thêm tuỳ chọn triển khai lớp trình khởi chạy.

    Các quy tắc được đặt ra bằng cách cung cấp mã nhận dạng của tệp tài nguyên xml chứa các định nghĩa (main_split_config) cho SplitController.initialize():

    Kotlin

    class ExampleWindowInitializer : Initializer<SplitController> {
       override fun create(context: Context): SplitController {
           SplitController.initialize(context, R.xml.main_split_config)
           return SplitController.getInstance(context)
       }
    
       override fun dependencies(): List<Class<out Initializer<*>>> {
           return emptyList()
       }
    }
    

    Java

    class ExampleWindowInitializer extends Initializer<SplitController> {
       @Override
       SplitController create(Context context) {
           SplitController.initialize(context, R.xml.main_split_config);
           return SplitController.getInstance(context);
       }
    
       @Override
       List<Class<? extends Initializer<?>>> dependencies() {
           return emptyList();
       }
    }
    

Ví dụ về cách phân tách

Tách khỏi toàn bộ cửa sổ

Hình 11. Hoạt động A khởi động hoạt động B bên cạnh.

Không cần tái cấu trúc. Có thể xác định cấu hình cho chế độ phân tách tĩnh hoặc trong thời gian chạy, sau đó gọi Context#startActivity() mà không cần thêm tham số nào.

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Tách theo mặc định

Khi trang đích của ứng dụng được thiết kế để chia thành hai vùng chứa trên màn hình lớn, trải nghiệm người dùng được cho là tối ưu nhất khi cả hai hoạt động được tạo và trình bày đồng thời. Tuy nhiên, nội dung có thể không có sẵn cho vùng chứa phụ của phần tách cho đến khi người dùng tương tác với hoạt động trong vùng chứa chính (ví dụ: người dùng chọn một mục từ menu điều hướng). Hoạt động trình giữ chỗ có thể lấp đầy khoảng trống cho đến khi nội dung có thể hiển thị trong vùng chứa phụ của phần tách (xem Phần giữ chỗ ở trên).

Hình 12. Có thể tạo chia tách bằng cách mở đồng thời hai hoạt động. Mỗi hoạt động là một trình giữ chỗ.

Để tạo phần tách với phần giữ chỗ, hãy tạo phần giữ chỗ rồi liên kết phần đó với hoạt động chính:

<SplitPlaceholderRule
    window:placeholderIntentName=".Placeholder">
    <ActivityFilter
        window:activityName=".Main"/>
</SplitPlaceholderRule>

Khi một ứng dụng nhận được ý định, hoạt động mục tiêu có thể được hiển thị dưới dạng phần phụ của phần tách hoạt động; ví dụ: yêu cầu hiển thị một màn hình chi tiết có thông tin về một mục trong danh sách. Trên màn hình nhỏ, chi tiết sẽ hiển thị trong cửa sổ tác vụ tràn màn hình; trên các thiết bị lớn hơn và bên cạnh danh sách.

Hình 13. Hoạt động chi tiết của liên kết sâu chỉ hiển thị trên một màn hình nhỏ, nhưng cùng với hoạt động trên danh sách ở một màn hình lớn.

Bạn phải chuyển yêu cầu hiển thị đến hoạt động chính và đưa hoạt động chi tiết mục tiêu vào hoạt động phân tách. SplitController tự động chọn bản trình bày đúng — xếp chồng hoặc xếp cạnh nhau — dựa trên chiều rộng hiển thị.

Kotlin

override fun onCreate(savedInstanceState Bundle?) {
    …
    splitController.registerRule(SplitPairRule(newFilters))
    startActivity(Intent(this, DetailActivity::class.java))
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    …
    splitController.registerRule(new SplitPairRule(newFilters));
    startActivity(new Intent(this, DetailActivity.class));
}

Đích liên kết sâu có thể là hoạt động duy nhất hiển thị cho người dùng trong ngăn điều hướng phía sau, bạn nên tránh loại bỏ hoạt động chi tiết và chỉ để lại hoạt động chính:

Màn hình lớn hiển thị kèm theo hoạt động liên quan đến danh sách và hoạt động chi tiết.
          Thao tác quay lại không thể đóng hoạt động chi tiết và rời khỏi hoạt động danh sách trên màn hình.

Màn hình nhỏ chỉ hoạt động chi tiết. Thao tác quay lại không thể bỏ qua hoạt động chi tiết và hiển thị hoạt động của danh sách.

Thay vào đó, bạn có thể hoàn tất cả hai hoạt động cùng một lúc bằng thuộc tính finishPrimaryWithSecondary:

<SplitPairRule
    window:finishPrimaryWithSecondary="true">
    <SplitPairFilter
        window:primaryActivityName=".List"
        window:secondaryActivityName=".Detail"/>
</SplitPairRule>

Nhiều hoạt động trong vùng chứa phân tách

Việc xếp chồng nhiều hoạt động trong một vùng chứa phân tách cho phép người dùng truy cập vào nội dung chuyên sâu. Ví dụ: với cách phân chia chi tiết danh sách, người dùng có thể chuyển đến mục chi tiết phụ nhưng vẫn giữ nguyên hoạt động chính:

Hình 14. Hoạt động đã mở tại ngăn phụ của cửa sổ tác vụ.

Kotlin

class DetailActivity {
    …
    fun onOpenSubDetail() {
      startActivity(Intent(this, SubDetailActivity::class.java))
    }
}

Java

public class DetailActivity {
    …
    void onOpenSubDetail() {
        startActivity(new Intent(this, SubDetailActivity.class));
    }
}

Hoạt động chi tiết phụ được đặt ở đầu hoạt động chi tiết, che đi hoạt động đó:

Sau đó, người dùng có thể quay lại cấp chi tiết trước đó thông qua ngăn xếp:

Hình 15. Đã xoá hoạt động khỏi đầu ngăn xếp.

Hoạt động xếp chồng lên nhau là hành vi mặc định khi các hoạt động bắt đầu từ một hoạt động trong cùng vùng chứa phụ. Các hoạt động khởi chạy từ vùng chứa chính trong phần tách hoạt động cũng sẽ kết thúc trong vùng chứa phụ ở đầu ngăn xếp hoạt động.

Hoạt động trong một nhiệm vụ mới

Khi các hoạt động trong cửa sổ tác vụ chia tách khởi động các hoạt động trong một tác vụ mới, tác vụ mới đó sẽ tách biệt khỏi tác vụ chứa phần chia tách và được hiển thị trong cửa sổ tràn màn hình. Màn hình Gần đây cho thấy hai nhiệm vụ: nhiệm vụ dạng chia tách và nhiệm vụ mới.

Hình 16. Khởi động hoạt động C trong một nhiệm vụ mới từ hoạt động B.

Thay thế hoạt động

Bạn có thể thay thế hoạt động trong ngăn xếp vùng chứa phụ; ví dụ: khi hoạt động chính được dùng cho thanh điều hướng cấp cao nhất và hoạt động phụ là điểm đến được chọn. Mỗi lựa chọn từ thanh điều hướng cấp cao nhất sẽ bắt đầu một hoạt động mới trong vùng chứa phụ và xoá hoạt động hoặc hoạt động đã có trước đó.

Hình 17. Hoạt động điều hướng cấp cao nhất trong ngăn chính sẽ thay thế hoạt động đích trong ngăn phụ.

Nếu ứng dụng không hoàn tất hoạt động trong vùng chứa phụ khi lựa chọn điều hướng thay đổi, thao tác điều hướng quay lại có thể nhầm lẫn khi thu gọn phần tách (khi thiết bị được gập). Ví dụ: nếu bạn có một trình đơn trong ngăn chính, các màn hình A và B được xếp chồng trong ngăn phụ, khi người dùng gấp điện thoại, B nằm phía trên A và A ở phía trên trình đơn. Khi người dùng quay lại từ B, A sẽ xuất hiện thay vì trình đơn.

Màn hình A cần được xoá khỏi ngăn xếp lui trong những trường hợp như vậy.

Hành vi mặc định khi khởi chạy sang một bên trong vùng chứa mới trên phần tách hiện có là đặt các vùng chứa phụ mới lên trên và giữ lại các vùng chứa cũ trong ngăn xếp phía sau. Bạn có thể định cấu hình các phần phân tách để xoá vùng chứa phụ trước đó bằng clearTop và khởi chạy các hoạt động mới như bình thường.

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

Kotlin

class MenuActivity {
    …
    fun onMenuItemSelected(selectedMenuItem: Int) {
        startActivity(Intent(this, classForItem(selectedMenuItem)))
    }
}

Java

public class MenuActivity {
    …
    void onMenuItemSelected(int selectedMenuItem) {
        startActivity(new Intent(this, classForItem(selectedMenuItem)));
    }
}

Ngoài ra, hãy sử dụng cùng một hoạt động phụ gửi các ý định mới giải quyết cho cùng một trường hợp từ hoạt động chính (menu) nhưng kích hoạt cập nhật trạng thái hoặc giao diện người dùng trong vùng chứa phụ.

Nhiều phần tách

Các ứng dụng có thể cung cấp điều hướng sâu nhiều cấp độ bằng cách đưa ra các hoạt động bổ sung bên cạnh.

Khi một hoạt động trong vùng chứa phụ kích hoạt một hoạt động mới bên cạnh, phần phân tách mới sẽ được tạo ra phía trên phần phân tách hiện có.

Hình 18. Hoạt động B bắt đầu hoạt động C sang một bên.

Ngăn xếp lui chứa tất cả các hoạt động đã mở trước đó, vì vậy người dùng có thể chuyển đến phần tách A/B sau khi hoàn tất C.

Các hoạt động A, B và C trong một ngăn xếp. Các hoạt động được sắp xếp theo thứ tự từ trên xuống dưới: C, B, A.

Để tạo phần tách mới, hãy chạy hoạt động mới bên cạnh vùng chứa phụ hiện có. Khai báo cấu hình cho phần tách A/B và B/C đồng thời khởi chạy hoạt động C từ B:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
    <SplitPairFilter
        window:primaryActivityName=".B"
        window:secondaryActivityName=".C"/>
</SplitPairRule>

Kotlin

class B {
    fun onOpenC() {
        startActivity(Intent(this, C::class.java))
    }
}

Java

public class B {
    …
    void onOpenC() {
        startActivity(new Intent(this, C.class));
    }
}

Phản hồi để phân tách các thay đổi ở trạng thái

Nhiều hoạt động trong một ứng dụng có thể có phần tử giao diện người dùng thực hiện cùng một chức năng; ví dụ: một chế độ kiểm soát mở ra một cửa sổ chứa chế độ cài đặt tài khoản.

Hình 19. Hoạt động khác nhau với các thành phần giao diện người dùng có chức năng giống hệt nhau.

Nếu hai hoạt động có chung một phần tử giao diện người dùng bị chia tách, việc hiển thị phần tử này trong cả hai hoạt động sẽ không cần thiết và có thể gây nhầm lẫn.

Hình 20. Các phần tử giao diện người dùng trùng lặp trong phần phân tách hoạt động.

Để biết khi nào các hoạt động diễn ra trong phần phân tách, hãy đăng ký trình xử lý với SplitController để biết các thay đổi ở trạng thái chia tách. Sau đó, điều chỉnh giao diện người dùng theo hàm:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    splitController
        .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback())
}

inner class SplitInfoChangeCallback : Consumer<List<SplitInfo>> {
    override fun accept(splitInfoList: List<SplitInfo>) {
        findViewById<View>(R.id.infoButton).visibility =
            if (!splitInfoList.isEmpty()) View.GONE else View.VISIBLE
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    splitController
        .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback());
}

class SplitInfoChangeCallback extends Consumer<List<SplitInfo>> {
    public void accept(List<SplitInfo> splitInfoList) {
        findViewById<View>(R.id.infoButton).visibility =
            !splitInfoList.isEmpty()) ? View.GONE : View.VISIBLE;
    }
}

Bạn có thể thực hiện các lệnh gọi lại ở bất kỳ trạng thái nào trong vòng đời hoạt động, kể cả khi một hoạt động ngừng diễn ra. Bạn thường phải đăng ký trình nghe này trong onStart() và huỷ đăng ký tại onStop().

Chế độ cửa sổ toàn màn hình

Một số hoạt động chặn người dùng tương tác với ứng dụng cho đến khi thực hiện hành động được chỉ định; ví dụ: hoạt động trên màn hình đăng nhập, màn hình xác nhận chính sách hoặc thông báo lỗi. Cần chặn các hoạt động mô-đun xuất hiện trong phần phân tách.

Một hoạt động có thể buộc phải luôn lấp đầy cửa sổ tác vụ bằng cách sử dụng cấu hình mở rộng:

<ActivityRule
    window:alwaysExpand="true">
    <ActivityFilter
        window:activityName=".FullWidthActivity"/>
</ActivityRule>

Hoàn tất hoạt động

Người dùng có thể hoàn tất các hoạt động ở một trong hai bên của phần chia tách bằng cách vuốt từ cạnh của màn hình:

Hình 21. Cử chỉ vuốt kết thúc hoạt động B.
Hình 22. Cử chỉ vuốt kết thúc hoạt động A.

Nếu thiết bị được thiết lập để sử dụng nút quay lại thay vì thao tác bằng cử chỉ, phương thức nhập sẽ được gửi đến hoạt động tập trung (hoạt động được nhấn hoặc chạy lần cuối).

Kết quả của việc hoàn tất một hoạt động trong phần phân tách phụ thuộc vào cấu hình phân tách.

Cấu hình mặc định

Khi một hoạt động trong phần phân tách kết thúc, hoạt động còn lại sẽ chiếm toàn bộ cửa sổ:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Phân tách chứa các hoạt động A và B. A kết thúc để lại B lấp đầy toàn bộ cửa sổ.

Phân tách chứa các hoạt động A và B. B kết thúc để lại A lấp đầy toàn bộ cửa sổ.

Cùng hoàn tất hoạt động

Tự động kết thúc hoạt động chính khi hoàn tất hoạt động phụ:

<SplitPairRule
    window:finishPrimaryWithSecondary="true">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Phân tách chứa các hoạt động A và B. B đã kết thúc và A cũng hoàn tất, để trống cửa sổ tác vụ.

Phân tách chứa các hoạt động A và B. A đã kết thúc để lại B trong cửa sổ tác vụ.

Tự động hoàn tất hoạt động phụ khi kết thúc hoạt động chính:

<SplitPairRule
    window:finishSecondaryWithPrimary="true">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Phân tách chứa các hoạt động A và B. A đã kết thúc và B cũng hoàn tất, để trống cửa sổ tác vụ.

Phân tách chứa các hoạt động A và B. B đã kết thúc để lại A trong cửa sổ tác vụ.

Cùng kết thúc khi đã hoàn thành các hoạt động chính hoặc phụ:

<SplitPairRule
    window:finishPrimaryWithSecondary="true"
    window:finishSecondaryWithPrimary="true">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Phân tách chứa các hoạt động A và B. A đã kết thúc và B cũng hoàn tất, để trống cửa sổ tác vụ.

Phân tách chứa các hoạt động A và B. B đã kết thúc và A cũng hoàn tất, để trống cửa sổ tác vụ.

Hoàn tất nhiều hoạt động trong vùng chứa

Nếu nhiều hoạt động được xếp chồng trong một vùng chứa phân tách, việc hoàn tất một hoạt động ở cuối ngăn xếp không tự động hoàn thành các hoạt động ở trên cùng.

Ví dụ: nếu hai hoạt động nằm trong vùng chứa phụ, C nằm phía trên B:

Ngăn xếp hoạt động phụ chứa hoạt động C xếp chồng lên trên B được xếp chồng ở đầu ngăn xếp hoạt động chính có chứa hoạt động A.

và cấu hình phân tách được xác định bởi cấu hình của hoạt động A và B:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

khi kết thúc hoạt động trên cùng, ứng dụng sẽ tách ra.

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. C kết thúc để lại A và B trong phần tách hoạt động.

Việc hoàn tất hoạt động ở dưới cùng (gốc) của vùng chứa phụ sẽ không xoá các hoạt động phía trên vùng chứa đó; đồng thời giữ nguyên cách phân chia.

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. B kết thúc, để lại A và C trong phần tách hoạt động.

Mọi quy tắc bổ sung để cùng hoàn tất các hoạt động, chẳng hạn như hoàn tất hoạt động phụ với hoạt động chính, cũng được thực thi:

<SplitPairRule
    window:finishSecondaryWithPrimary="true">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. A kết thúc cũng hoàn tất luôn B và C.

Và khi cách phân chia này được định cấu hình để cùng hoàn tất mục chính và phụ:

<SplitPairRule
    window:finishPrimaryWithSecondary="true"
    window:finishSecondaryWithPrimary="true">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. C kết thúc để lại A và B trong phần tách hoạt động.

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. B kết thúc, để lại A và C trong phần tách hoạt động.

Tách hoạt động A trong vùng chứa chính với các hoạt động B và C ở vùng phụ, C được xếp chồng lên trên B. A kết thúc cũng hoàn tất luôn B và C.

Thay đổi thuộc tính chia tách trong thời gian chạy

Bạn không thể thay đổi thuộc tính của phần phân tách hiện đang hoạt động và hiển thị. Việc thay đổi quy tắc phân tách sẽ ảnh hưởng đến các hoạt động khởi chạy khác và vùng chứa mới, tuy nhiên nó không ảnh hưởng đến phần phân tách hiện có và đang hoạt động.

Để thay đổi thuộc tính của phần phân tách đang hoạt động, hãy hoàn tất hoạt động hoặc các hoạt động bên trong phần phân tách đồng thời khởi chạy lại sang bên cạnh bằng cấu hình mới.

Trích xuất hoạt động từ chế độ chia tách thành chế độ cửa sổ toàn màn hình

Tạo một cấu hình mới sẽ hiển thị hoạt động bên cạnh trên cửa sổ toàn màn hình, sau đó khởi chạy lại hoạt động với ý định giải quyết cùng một đối tượng.

Kiểm tra chế độ hỗ trợ phân tách trong thời gian chạy

Tính năng nhúng hoạt động dành cho 12L (API cấp 32), nhưng cũng có sẵn trên một số thiết bị sử dụng các phiên bản nền tảng cũ. Để kiểm tra nếu có tính năng trong thời gian chạy, hãy sử dụng phương thức SplitController.isSplitSupported():

Kotlin

val splitController = SplitController.Companion.getInstance()
if (splitController.isSplitSupported()) {
    // Device supports split activity features.
}

Java

SplitController splitController = SplitController.Companion.getInstance();
if (splitController.isSplitSupported()) {
  // Device supports split activity features.
}

Nếu chế độ phân tách không được hỗ trợ, các hoạt động sẽ được bắt đầu ở trên cùng (theo mô hình thông thường).

Giới hạn, hạn chế và cảnh báo

  • Chỉ có ứng dụng máy chủ lưu trữ của tác vụ được xác định là chủ sở hữu của hoạt động gốc trong tác vụ, có thể sắp xếp và nhúng các hoạt động khác trong nhiệm vụ. Nếu các hoạt động hỗ trợ tính năng nhúng và phân tách chạy trong một thao tác thuộc về ứng dụng khác, thì việc nhúng và phân tách sẽ không hiệu quả đối với các hoạt động đó.
  • Các hoạt động chỉ có thể được tổ chức trong một nhiệm vụ duy nhất. Khi chạy hoạt động trong một tác vụ mới, hoạt động đó sẽ luôn được mở trong cửa sổ mở rộng mới bên ngoài mọi hoạt động phân tách hiện có.
  • Bạn chỉ có thể sắp xếp và tách riêng các hoạt động trong cùng một quy trình. Lệnh gọi lại SplitInfo chỉ báo cáo các hoạt động thuộc cùng một quy trình vì không có cách nào nhận biết các hoạt động ở các quy trình khác nhau.
  • Mỗi cặp hoặc quy tắc hoạt động đơn lẻ chỉ áp dụng cho các lần khởi chạy hoạt động xảy ra sau khi quy tắc được đăng ký. Hiện chưa có cách cập nhật phần phân tách hiện có hoặc thuộc tính trực quan của các phần tách đó.
  • Cấu hình bộ lọc cặp phân tách phải khớp với ý định dùng khi khởi chạy các hoạt động hoàn toàn. Việc so khớp xảy ra tại thời điểm một hoạt động mới bắt đầu từ quá trình ứng dụng. Vì vậy, tính năng này có thể không nhận biết tên các thành phần sẽ được phân giải sau này trong quá trình hệ thống sử dụng các ý định ngầm ẩn. Nếu không xác định tên thành phần tại thời điểm khởi chạy, bạn có thể sử dụng ký tự đại diện ("*/*") và thao tác lọc hành động theo ý định.
  • Hiện tại, không có cách nào để di chuyển hoạt động giữa các vùng chứa hoặc trong và ngoài các phần tách sau khi đã tạo. Tính năng phân tách chỉ do thư viện WindowManager tạo ra khi các hoạt động mới có quy tắc so khớp được khởi chạy và các phần phân tách bị huỷ khi hoạt động gần đây nhất trong vùng chứa phân tách đã hoàn tất.
  • Các hoạt động có thể được chạy lại khi cấu hình thay đổi, vì vậy, khi phân tách được tạo hoặc loại bỏ và giới hạn hoạt động thay đổi, hoạt động có thể huỷ bỏ hoàn toàn đối tượng trước đó và tạo một đối tượng mới. Do đó, các nhà phát triển ứng dụng nên thận trọng với những việc như khởi chạy hoạt động mới từ các lệnh gọi lại trong vòng đời.

Tài nguyên khác