Tối ưu hóa việc tải flow & paywall trong Android SDK

Một lần tải flow hoặc paywall đáng tin cậy trên Android cần đảm bảo ba điều: hiển thị nhanh, trả về biến thể đúng đối tượng mục tiêu, và có phương án dự phòng hợp lý khi mạng chậm. Các quy tắc dưới đây đề cập đến thời điểm, bộ nhớ đệm và các mô hình dự phòng để đạt được điều đó.

Tip

Các quy tắc này giả định rằng Adapty.activate() và Adapty.identify() đã hoàn thành. Xem Thứ tự gọi trong Android SDK.

Quy tắc và lưu ý

Làm điều nàyĐừng làm điều nàyLý do
Fetch placement bạn chuẩn bị hiển thị, hoặc làm ấm cache bằng preloadFlows (SDK 4.1+).Tự tạo các lệnh gọi getFlow đồng thời khi khởi động.Một vòng prefetch tự tạo sẽ chặn luồng chính và gây ra màn hình đen. preloadFlows được xây dựng cho mục đích này và chạy batch đồng thời cho bạn.
Fetch getFlow sau khi attribution có cơ hội xử lý xong — ví dụ: 1–2 giây sau activate hoặc sau khi setOnProfileUpdatedListener kích hoạt.Gọi getFlow trong Application.onCreate().Attribution chưa được xử lý. Flow sẽ được resolve dựa trên đối tượng mặc định và âm thầm bỏ qua các phân khúc và cá nhân hóa ASA.
Đặt loadTimeout và cấu hình paywall dự phòng cho mỗi placement.Chờ getFlow vô thời hạn.Không có timeout, người dùng có kết nối kém sẽ thấy màn hình trắng cho đến khi mạng phục hồi — hoặc họ đóng ứng dụng.

Xem Tải paywalls và sản phẩm để tham khảo tham số fetchPolicy và loadTimeout, và Placements để chọn đúng placement.

Tải trước các placement

Info

preloadFlows và preloadFlowsForDefaultAudience khả dụng từ SDK phiên bản 4.1 trở lên.

preloadFlows lưu flow JSON vào bộ nhớ đệm trước — một request cho mỗi placement. Sau đó bạn sử dụng như bình thường: getFlow để lấy flow, getFlowConfiguration để lấy cấu hình view của nó.

fetchPolicy quyết định layer nào mà getFlow gọi sau sẽ đọc trước, không phải quyết định có thể truy cập cache hay không:

  • ReturnCacheDataElseLoad đọc bản đã tải sẵn trước, chỉ kết nối mạng khi không có cache. ReturnCacheDataIfNotExpiredElseLoad(maxAgeMillis) hoạt động tương tự khi bản cache còn trẻ hơn maxAgeMillis.
  • Mặc định là ReloadRevalidatingCacheData — ưu tiên kết nối mạng, chỉ dùng bản đã tải sẵn khi request thất bại hoặc hết thời gian chờ.

Việc tải trước đều có lợi trong cả hai trường hợp, nhưng theo cách khác nhau: chính sách ưu tiên cache loại bỏ hoàn toàn request, còn chính sách mặc định vẫn gửi request nhưng có sẵn bản dự phòng đã được làm ấm.

Dùng cách này khi bạn biết trước placement nào sẽ cần trong phiên nhưng chưa muốn hiển thị ngay — ví dụ, ngay sau khi activate và identify hoàn thành, cho flow đằng sau một nút mà người dùng chưa nhấn.

Tham số:

  • placementIds (bắt buộc): các placement cần tải trước. Các ID trống và trùng lặp sẽ bị bỏ qua.
  • loadTimeout (tùy chọn): timeout áp dụng cho từng placement trong batch, không phải cho toàn bộ batch. Mặc định là 5 giây, và các giá trị dưới 1 giây sẽ được nâng lên thành 1 giây.

Những điều cần lưu ý về hành vi:

  • Callback chỉ được kích hoạt sau khi tất cả các placement đã được xử lý, và nó báo cáo các lỗi theo từng placement cùng nhau. Lỗi ở một placement không ảnh hưởng đến các placement khác.
  • Nếu một placement bị timeout, gặp lỗi server, hoặc lỗi mạng, SDK sẽ chuyển sang dùng các biến thể dự phòng cho placement đó. Các lỗi khác được báo cáo nguyên trạng.
  • Preloading chỉ làm ấm cache. Nó không trả về nội dung — bạn vẫn phải gọi getFlow để hiển thị.

Những gì preload bao gồm

Một flow hiển thị trên màn hình theo từng lớp. Preload bao gồm lớp đầu tiên, giống hệt như getFlow làm:

LớpĐược tải bởiĐược làm ấm bởi preload
Flow JSON — biến thể đã chọn, ID sản phẩm của nó và Remote ConfiggetFlowCó
Bố cục giao diện — cấu trúc, kiểu dáng và văn bản của màn hìnhgetFlowConfigurationKhông
Hình ảnh, bao gồm khung tĩnh thay thế cho phần tử videogetFlowConfiguration, chạy nềnKhông
Tệp videoTrình phát hệ thống, khi màn hình renderSDK không cache

getFlowConfiguration chờ layout được tải về, nên lần đầu tiên yêu cầu một layout nhất định vẫn tốn một round trip dù đã preload trước. SDK sau đó lưu layout đó vào bộ nhớ đệm trên đĩa, bộ nhớ này tồn tại qua các lần khởi động lại ứng dụng và được đọc trước mọi lần gọi mạng, vì vậy chi phí chỉ xảy ra ở lần yêu cầu đầu tiên chứ không phải mỗi lần. Khi SDK đã có layout, nó bắt đầu cache ảnh độc lập với lần gọi: việc này không làm chặn màn hình, và không có callback hay lỗi nào thông báo khi hoàn tất.

Tìm hiểu placement nào gặp lỗi

Callback nhận về một AdaptyPreloadPlacementsError bao quát toàn bộ batch, với mã lỗi REQUEST_FAILED (2005). Để xem chi tiết từng lỗi riêng lẻ, hãy đọc thuộc tính preloadErrors — một map được đánh key theo placement ID:

Adapty.preloadFlows(listOf("onboarding", "main_paywall")) { error ->
    if (error is AdaptyPreloadPlacementsError) {
        error.preloadErrors.forEach { (placementId, placementError) ->
            // log or retry the individual placement
        }
    }
}

preloadErrors exists only on AdaptyPreloadPlacementsError, so confirm the type first — any other AdaptyError came from something other than a per-placement failure.

Bỏ qua phân khúc đối tượng

Để làm ấm cache mà không cần chờ phân khúc đối tượng, hãy dùng biến thể default-audience. Cách này không cần loadTimeout:

Adapty.preloadFlowsForDefaultAudience(listOf("main_paywall")) { error -> }

Hiển thị media màn hình đầu tiên từ app bundle

Một flow tải hình ảnh và video từ Adapty. Để hiển thị media của màn hình đầu tiên ngay lập tức, hãy phục vụ nó từ app bundle thay thế. Đây là cách hay để tái sử dụng media bạn đã đóng gói sẵn, chẳng hạn như hình ảnh của một onboarding gốc hiện có.

  1. Trong Flow & Paywall Builder, đặt ID media tùy chỉnh cho hình ảnh hoặc video. File bạn tải lên đó sẽ là file dự phòng.
  2. Thêm file vào thư mục res/raw hoặc assets của ứng dụng.
  3. Khi tạo flow view bằng getFlowView, truyền file đã đóng gói sẵn cho ID đó vào customAssets:
// "welcome_video" is the custom media ID set in the Flow & Paywall Builder
val bundledAssets = AdaptyCustomAssets.of(
    "welcome_video" to
            AdaptyCustomVideoAsset.file(
                FileLocation.fromResId(requireContext(), R.raw.welcome),
                preview = AdaptyCustomImageAsset.file(
                    FileLocation.fromResId(requireContext(), R.drawable.welcome_poster),
                ),
                resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920),
            ),
)

val flowView = AdaptyUI.getFlowView(
    activity,
    flowConfiguration,
    products,
    eventListener,
    insets,
    bundledAssets,
)

Các tệp đã đóng gói sẽ làm tăng dung lượng tải xuống của ứng dụng, vì vậy chỉ nên đóng gói những media mà người dùng nhìn thấy đầu tiên.

Media không được đóng gói vẫn hiển thị ngay lập tức: cấu hình view mang theo một bản sao độ phân giải thấp nhỏ của mỗi hình ảnh, bao gồm cả khung tĩnh của video, và hiển thị cho đến khi tệp đầy đủ được tải xong.

Để xem tài liệu tham khảo đầy đủ về customAssets, xem Tùy chỉnh assets.

Điều chỉnh cho kết nối kém

Đối với các thị trường có kết nối kém liên tục (vùng nông thôn, phương tiện giao thông, khu vực bị ảnh hưởng bởi định tuyến):

  • Đặt fetchPolicy thành AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad cho mọi lần tải trừ lần đầu tiên.
  • Cấu hình paywall dự phòng cho mọi placement trong Adapty Dashboard.
  • Đặt loadTimeout từ 3–5 giây và chấp nhận paywall dự phòng khi hết thời gian chờ.
  • Đừng chặn việc hiển thị flow khi chờ getProfile. Gọi getFlow độc lập để hồ sơ người dùng tải chậm không chặn giao diện.