Cải thiện mức độ tương tác trên Watch Next for Movie/TV Episodes (Xem phim/tập phim truyền hình tiếp theo) trên Android TV

1. Giới thiệu

Watch Next (Xem tiếp)

Kênh Watch Next là một hàng xuất hiện trên màn hình chính của Android TV, hiện các video để người dùng có thể xem tiếp. Tuỳ thuộc vào phiên bản hệ thống, hàng Watch Next này có thể có tên là "Play Next" (Phát tiếp theo) hoặc "Continue watching" (Tiếp tục xem).

b0ca4ea7c72ba8f6.png

Hệ thống tạo ra và duy trì kênh này. Mỗi mục trong kênh này được gọi là một chương trình. Ứng dụng của bạn có thể thêm/cập nhật/xoá chương trình khỏi kênh Watch Next, chẳng hạn như nội dung mà người dùng dừng xem giữa chừng hoặc nội dung người dùng đã tương tác (như tập tiếp theo trong chương trình truyền hình dài tập hoặc phần tiếp theo của chương trình).

Khái niệm

Kênh Watch Next là một cách để ứng dụng của bạn có thể thúc đẩy tương tác với người dùng.

Bạn có thể thêm/cập nhật/xoá nội dung khỏi kênh Watch Next người dùng đã tương tác. Video đang xem dở hoặc đề xuất tập/loạt phim tiếp theo, v.v.

Các ứng dụng cũng có thể xoá một tập sau khi xem và thêm tập tiếp theo trong phần mới của chương trình truyền hình dài tập.

Có 4 trường hợp sử dụng kênh Watch Next:

  • Tiếp tục xem video mà người dùng đang xem dở.
  • Đề xuất xem video tiếp theo. Ví dụ: nếu người dùng xem xong tập 1 thì bạn có thể đề xuất tập 2.
  • Hiện các tập mới của chương trình truyền hình dài tập mà người dùng đang xem.
  • Duy trì danh sách xem các video thú vị do người dùng thêm vào.

Lớp học lập trình này sẽ hướng dẫn cách đưa một video vào kênh Watch Next khi người dùng tạm dừng video đó. Đồng thời, cũng hướng dẫn cách loại bỏ một video ra khỏi phần Watch Next khi video kết thúc và cách thêm tập tiếp theo (nếu có).

Lớp học lập trình này không bao gồm các trường hợp sử dụng Watch Next cho các danh sách xem và các tập mới phát hành.

Xem phim và tập phim truyền hình tiếp theo

Kênh Watch Next là một tính năng rất quan trọng trên màn hình chính của Android TV, giúp người dùng theo dõi phim và chương trình truyền hình đang xem dở. Tính năng này đặc biệt quan trọng đối với người dùng đang theo dõi các tập phim truyền hình vì một chương trình truyền hình dài tập sẽ có nhiều tập phim và người dùng sẽ xem tiếp từ thời điểm dừng lại trước đó.

Hãy tưởng tượng thời điểm người dùng quay lại và ngồi trước TV để quyết định sẽ xem chương trình gì. Với tính năng Watch Next, ứng dụng của bạn sẽ cho phép người dùng tiếp tục xem các tập phim truyền hình ngay trên màn hình chính từ đoạn người dùng dừng lại trước đó. Điều này sẽ làm tăng mức độ tương tác của người dùng, nhờ đó mang lại lợi ích cho cả ứng dụng và người dùng.

Lớp học lập trình này sẽ hướng dẫn bạn cách dùng ứng dụng truyền hình tham chiếu (TV reference app), cách xử lý các trường hợp sử dụng kênh Watch Next và giải thích nguyên tắc chất lượng của Google dành cho tính năng Watch Next này. Lớp học lập trình này tập trung vào quá trình xử lý các tập phim truyền hình nhưng bạn có thể áp dụng các quy tắc tương tự khi xử lý phim.

Phạm vi cung cấp

Mã cung cấp trong lớp học lập trình này sẽ hoạt động trên thiết bị Android TV, bao gồm cả những thiết bị chạy trải nghiệm Google TV.

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ thêm, xoá và cập nhật phim/tập phim truyền hình trên kênh Watch Next. Ứng dụng này sẽ:

  • Triển khai các trường hợp sử dụng cho quá trình xử lý phim
  • Triển khai các trường hợp sử dụng cho quá trình xử lý tập phim truyền hình

Kiến thức bạn sẽ học được

  • Nguyên tắc chất lượng của Google dành cho tính năng Watch Next

Bạn cần có

  • Kiến thức cơ bản về phát triển ứng dụng Android
  • Android Studio 4.1, bạn có thể tải xuống tại đây

2. Thiết lập

Nhân bản dự án khởi đầu

Bạn có thể tải mã nguồn xuống từ kho lưu trữ GitHub:

git clone https://github.com/android/codelab-watchnext-for-movie-tv-episodes.git

Hoặc bạn có thể tải xuống trực tiếp từ đường liên kết bên dưới.

Mở Android Studio rồi nhấp vào File (Tệp) > Open (Mở) từ thanh trình đơn hoặc Open an Existing Android Studio Project (Mở Dự án Android Studio hiện có) trên màn hình chào mừng và chọn thư mục nhân bản gần nhất.

8271a7b581390845.png

Tìm hiểu về dự án khởi đầu

34641bc2c9f71f0f.png

Dự án bao gồm 4 bước. Trong mỗi bước, bạn sẽ thêm mã dựa trên các hướng dẫn trong bước hiện hành. Sau khi hoàn thành một bước, bạn có thể so sánh mã của mình với mã trong step_x_complete.

Để đơn giản, chúng tôi bổ sung thêm một số mã cơ bản để tạo danh sách video và trình phát Exoplayer để xem nội dung trong ứng dụng. Thao tác này sẽ tạo một khung sườn cơ bản cho một ứng dụng xem tivi, một chủ đề nằm ngoài phạm vi lớp học lập trình này.

Mục tiêu của chúng ta ở đây là tìm hiểu cách thêm/xoá/cập nhật những video đang xem dở hoặc xem xong trên kênh Watch Next. Đồng thời, chúng ta cũng sẽ đề cập đến cách tạo tương tác cho ứng dụng.

Dưới đây là các thành phần chính trong ứng dụng:

  • FileVideoRepository là lớp tải và truy vấn siêu dữ liệu video.
  • PlaybackFragment là mảnh (fragment) phát video.
  • WatchNextPlaybackStateListener là trình nghe thay đổi trạng thái phát; trình nghe này sẽ theo dõi các sự kiện phát video và kích hoạt các hoạt động liên quan.
  • WatchNextWorker đóng vai trò như một "nhân viên" chịu trách nhiệm cập nhật kênh Watch Next.
  • WatchNextHelper là một lớp trợ giúp, cho phép đơn giản hoá quá trình làm việc với kênh Watch Next.

Lớp học lập trình này sử dụng dữ liệu phương tiện trong res/raw/api.json để điền vào các mục Watch Next.

Chạy dự án khởi đầu

Chạy step_1. Nếu gặp bất cứ sự cố gì, hãy tham khảo tài liệu hướng dẫn bắt đầu.

  1. Kết nối Android TV của bạn hoặc khởi động trình mô phỏng.
  1. Chọn cấu hình step_1, chọn thiết bị Android của bạn rồi nhấn nút run (chạy) trong thanh trình đơn. 249ea91a556fbd61.png
  2. Bạn sẽ thấy một đường viền ứng dụng truyền hình đơn giản gồm bốn bộ sưu tập video tương tự như ảnh chụp màn hình bên dưới.
  3. Di chuyển qua màn hình chính của ứng dụng để làm quen với ứng dụng truyền hình tham chiếu. Có bốn loại video:
  4. Các đoạn video Supercharged
  5. Đoạn video linh tinh khác
  6. Beverly Hillbillies: một số tập phim truyền hình trong hai phần;
  7. Phim Charlie Chaplin.
  8. Nhấp vào một trong các tập phim truyền hình trong danh mục Beverly Hillbillies rồi xem tập đó. Lớp học lập trình này sẽ hướng dẫn bạn cách thêm các chương trình Watch Next cho những tập phim truyền hình này

d7b51de54f4a1199.png

Kiến thức bạn học được

Trong phần giới thiệu này, bạn tìm hiểu về:

  • Cấu trúc mã và các lớp chính được dùng trong lớp học lập trình này.
  • Cách thiết lập và chạy ứng dụng mẫu.

Tiếp theo là gì?

Nguyên tắc chất lượng dành cho tính năng Watch Next

3. Tìm hiểu nguyên tắc chất lượng dành cho tính năng Watch Next

Để mang lại trải nghiệm tốt hơn trên màn hình chính, tất cả ứng dụng phải xử lý nhất quán khi thêm nội dung vào kênh Watch Next.

Cụ thể, nhà phát triển cần phải đáp ứng một số kịch bản đối với các tập phim truyền hình. Google đã tóm tắt một danh sách các nguyên tắc chất lượng cần được tuân thủ để đảm bảo chất lượng của kênh Watch Next này.

Cách xây dựng tính năng Watch Next nhằm đáp ứng các tiêu chuẩn về chất lượng của Google

Khi đánh giá tính năng Watch Next, Google sẽ kiểm tra những điểm sau đây

  1. Chương trình sẽ được thêm vào Watch Next khi tạm dừng/dừng
  2. Ứng dụng có thể tiếp tục phát từ mục Watch Next
  3. Ứng dụng sẽ cập nhật kịp thời vị trí phát video trong Watch Next
  4. Chương trình sẽ bị xoá khỏi Watch Next sau khi phát xong
  5. Tập tiếp theo sẽ được thêm khi tập hiện tại kết thúc
  6. Ứng dụng không thêm những nội dung mà người dùng chưa tương tác với Watch Next
  7. Đẩy tất cả nội dung đang xem dở sang Watch Next
  8. Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ, chẳng hạn như số phần/số tập phim
  9. Ứng dụng không thêm nhiều tập trong cùng một chương trình truyền hình dài tập

Dưới đây là phần giải thích cho từng yêu cầu chất lượng

  1. Chương trình sẽ được thêm vào Watch Next khi tạm dừng/dừng
  • Ứng dụng sẽ thêm phim và chương trình truyền hình truyền thống vào hàng Watch Next khi chưa phát xong
  1. Ứng dụng có thể tiếp tục phát từ mục Watch Next
  • Nội dung được thêm vào kênh Watch Next sẽ tiếp tục phát từ vị trí phát gần nhất; video phải bắt đầu phát ngay sau khi tải xong nội dung
  1. Ứng dụng sẽ cập nhật kịp thời vị trí phát video trong Watch Next
  • Ứng dụng cần theo dõi tiến trình phát và cập nhật chương trình Watch Next lên vị trí phát gần nhất sau khi người dùng rời khỏi video
  1. Chương trình sẽ bị xoá khỏi Watch Next sau khi phát xong
  • Ứng dụng phải là một công dân gương mẫu và biết tự dọn dẹp sau khi phát xong. Watch Next là một hàng dùng chung cho tất cả ứng dụng và chúng ta cần đảm bảo nội dung trong hàng này phải chính xác để giữ chân người dùng
  1. Tập tiếp theo sẽ được thêm khi tập hiện tại kết thúc.
  • Khi người dùng xem một chương trình truyền hình dài tập, ứng dụng này sẽ giúp người dùng xem tiếp dễ dàng hơn bằng cách thêm tập tiếp theo của bộ phim đó vào hàng Watch Next
  1. Ứng dụng không thêm những nội dung mà người dùng chưa tương tác với Watch Next
  • Theo nguyên tắc dành cho tính năng Watch Next, ứng dụng chỉ nên thêm một bộ phim hoặc tập phim truyền hình vào kênh Watch Next khi người dùng "bắt đầu" xem
  • Bạn không nên thêm đoạn giới thiệu, đoạn video ngắn vào kênh Watch Next vì lượt tương tác ở đó rất ít
  1. Đẩy tất cả nội dung đang xem dở sang Watch Next
  • Nhà cung cấp không được giới hạn giả tạo số lượng thẻ chuyển sang phần Watch Next. Nếu có nội dung nào đó đang xem dở, người dùng nên đẩy phần nội dung này vào hàng Watch Next
  1. Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ.
  • Đảm bảo tính chính xác của siêu dữ liệu gắn với tập phim đó
  • Số tập, số phần và tiêu đề phải chính xác
  • Thanh tiến trình phải tương ứng với thời lượng xem
  • Tập phim hoặc hình ảnh của bộ phim nên hiển thị trong ô này
  1. Ứng dụng nên tránh việc thêm nhiều tập cho cùng một chương trình truyền hình dài tập.
  • Ứng dụng chỉ được phép chứa tối đa một mục Watch Next cho mỗi chương trình truyền hình dài tập; nếu người dùng chỉ xem một nửa của hai tập khác nhau thì Watch Next chỉ nên hiển thị tập được xem gần nhất

Những yêu cầu về chất lượng này sẽ giúp ứng dụng của bạn cung cấp trải nghiệm người dùng tuyệt vời trên kênh Watch Next.

Được rồi, hãy bắt đầu xây dựng tính năng Watch Next trên cơ sở những hướng dẫn chất lượng này.

Kiến thức bạn học được

Trong phần này, bạn đã tìm hiểu về:

  • Các yêu cầu về chất lượng đối với tính năng Watch Next

Nội dung tiếp theo là gì?

Thêm một tập phim đang xem dở vào kênh Watch Next

4. Thêm nội dung đang xem dở vào Watch Next

Chúng ta sẽ bắt đầu từ chức năng cơ bản: Thêm một tập phim đang xem dở vào Watch Next.

Lớp học lập trình này sẽ hướng dẫn bạn cách tạo một WatchNextProgram, điền siêu dữ liệu chính xác cho tập phim, chẳng hạn như số tập, số phần và loại video, v.v. Mục Watch Next có thể cập nhật được, đảm bảo mục này bắt kịp vị trí phát gần nhất của người dùng. Nhờ vậy, người dùng có thể nhấp vào chương trình để tiếp tục phát tập phim đó.

Phần này sẽ đề cập đến những nội dung sau:

  • Chương trình sẽ được thêm vào Watch Next khi tạm dừng/dừng
  • Ứng dụng có thể tiếp tục phát từ mục Watch Next
  • Ứng dụng sẽ cập nhật kịp thời vị trí phát video trong Watch Next
  • Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ.

Thêm video đang xem dở – điểm khác biệt giữa phim và tập phim

Quy trình thêm một phim và tập phim vào kênh Watch Next rất giống nhau. Điểm khác biệt duy nhất nằm ở siêu dữ liệu của phim và tập phim.

Ví dụ: đối với các tập phim, chúng ta có các phương thức siêu dữ liệu cụ thể trong WatchNextProgram.Builder như setEpisodeNumber, setSeasonNumber(), setSeasonTitle()setEpisodeTitle()

Thêm video đang xem dở (phim/tập) vào Kênh Watch Next

Để thêm một video đang xem dở vào kênh Watch Next, nhà phát triển có thể sử dụng WatchNextProgram.Builder để tạo một thực thể WatchNextProgram và gọi PreviewChannelHelper.publishWatchNextProgram để xuất bản video đó lên kênh Watch Next.

Trước tiên, hãy tạo một thực thể Builder của WatchNextProgram và thiết lập tất cả siêu dữ liệu để mô tả video.

Tìm phương thức setBuilderMetadata trong PlayNextHelper.ktstep_1, sao chép và dán mã sau giữa các nhận xét "Step 1.1 - Set video metadata for WatchNextProgram.".

WatchNextHelper.kt

builder.setType(type)
   .setWatchNextType(watchNextType)
   .setLastPlaybackPositionMillis(watchPosition)
   .setLastEngagementTimeUtcMillis(System.currentTimeMillis())
   .setTitle(video.name)
   .setDurationMillis(duration.toMillis().toInt())
   .setPreviewVideoUri(Uri.parse(video.videoUri))
   .setDescription(video.description)
   .setPosterArtUri(Uri.parse(video.thumbnailUri))
   // Intent uri used to deep link video when the user clicks on watch next item.
   .setIntentUri(Uri.parse(video.uri))
   .setInternalProviderId(video.id)
   // Use the contentId to recognize the same content across different channels.
   .setContentId(video.id)

if (type == TYPE_TV_EPISODE) {
   builder.setEpisodeNumber(video.episodeNumber.toInt())
       .setSeasonNumber(video.seasonNumber.toInt())
       // User TV series name and season number to generate a fake season name.
       .setSeasonTitle(context.getString(
           R.string.season, video.category, video.seasonNumber))
       // Use the name of the video as the episode name.
       .setEpisodeTitle(video.name)
       // Use TV series name as the tile, in this sample,
       // we use category as a fake TV series.
       .setTitle(video.category)
}

Đọc qua mã ở bước 1.1. và cố gắng tìm hiểu lý do tại sao chúng ta thiết lập các siêu dữ liệu này.

  1. setLastPlaybackPositionMillis()setDurationMillis() giúp hiển thị tiến trình phát chính xác và cập nhật tiến trình này khi người dùng tương tác với video.
  2. setLastEngagementTimeUtcMillis() đặt dấu thời gian khi người dùng xem video này, qua đó giúp kênh Watch Next thiết lập ưu tiên các mục nhập.

Thêm bộ phim đang xem dở vào Watch Next

Chúng ta có thể sử dụng WATCH_NEXT_TYPE_NEXT để thêm một bộ phim đang xem dở vào kênh Watch Next.

Thiết lập siêu dữ liệu cho phim: tiêu đề và nội dung mô tả

Đối với phim, hãy thiết lập tiêu đề và nội dung mô tả cũng như các thuộc tính khác, cho phép người dùng biết rằng họ đang xem đúng nội dung mà không cần nhấp vào video.

builder.setType(type)
   .setWatchNextType(watchNextType)
   .setLastPlaybackPositionMillis(watchPosition)
   .setLastEngagementTimeUtcMillis(System.currentTimeMillis())
   .setTitle(video.name)
   .setDurationMillis(duration.toMillis().toInt())
   .setPreviewVideoUri(Uri.parse(video.videoUri))
   .setDescription(video.description)
   .setPosterArtUri(Uri.parse(video.thumbnailUri))
...

Ảnh chụp màn hình mẫu cho một bộ phim.

99a21ecd22268f2d.png

Thêm tập phim đang xem dở vào Watch Next

Có 4 loại bạn có thể sử dụng cho setWatchNextType(), sử dụng WATCH_NEXT_TYPE_CONTINUE cho các tập phim truyền hình đang xem dở, WATCH_NEXT_TYPE_NEXT cho tập tiếp theo.

Thiết lập siêu dữ liệu cho tập phim: tập/phần thứ mấy và tiêu đề tương ứng

Đối với các tập phim truyền hình, hãy thiết lập số của tập phim cũng như số phần của tập phim để người dùng biết được họ đang xem đúng tập mà không cần nhấp vào video.

if (type == TYPE_TV_EPISODE) {
   Builder.setType(PreviewPrograms.TYPE_EPISODE)
       .setEpisodeNumber(video.episodeNumber.toInt())
       .setSeasonNumber(video.seasonNumber.toInt())
       // Use TV series name and season number to generate a fake season name.
       .setSeasonTitle(context.getString(
           R.string.season, video.category, video.seasonNumber))
       // Use the name of the video as the episode name.
       .setEpisodeTitle(video.name)
       // Use TV series name as the tile, in this sample,
       // we use category as a fake TV series.
       .setTitle(video.category)
}

SeasonTitle, EpisodeTitle và Title phải được thiết lập chính xác. Mỗi tập phim đều có tiêu đề riêng để mô tả nội dung của tập phim đó, chúng ta có thể sử dụng tiêu đề này cho trường EpisodeTitle. Hãy sử dụng tiêu đề của chương trình truyền hình dài tập cho thuộc tính tiêu đề của chương trình truyền hình, giúp người dùng biết được tập phim đó nhằm mục đích gì. Nếu có tiêu đề phần, hãy sử dụng tiêu đề đó cho trường SeasonTitle. Nếu không, bạn có thể kết hợp tên bộ phim và số phần, ví dụ: <TV Series name> phần <season number>.

Ảnh chụp màn hình mẫu cho một tập phim.

658c430b13bcb3a6.png

Tiếp tục phát lại

setLastPlaybackPositionMillis(watchPosition) được dùng để chuyển thời điểm người dùng dừng bộ phim/tập phim đó; tiến trình này sẽ hiển thị trên thẻ Watch Next. Trong ứng dụng truyền hình tham chiếu, mã này sử dụng WatchProgressDatabase để theo dõi tiến trình phát của từng video. Điều này cho phép người dùng tiếp tục xem từ thời điểm trước đó bất kể họ di chuyển đến video bằng cách nào.

Theo Nguyên tắc về việc phát lại hành động xem (Watch Action Playback guidelines), tập phim sẽ bắt đầu phát ngay sau khi nội dung video được tải. Bạn không cần hiển thị lại thông tin về chương trình truyền hình đó khi người dùng bắt đầu xem phim.

Tiếp theo, hãy gọi PreviewChannelHelper.publishWatchNextProgram để xuất bản video lên kênh Watch Next. Hãy tìm "Step 1.2" trong cùng tệp đó và dán mã sau:

WatchNextHelper.kt

try {
   programId = PreviewChannelHelper(context)
       .publishWatchNextProgram(updatedProgram)
   Timber.v("Added New program to Watch Next row: ${updatedProgram.title}")
} catch (exc: IllegalArgumentException) {
   Timber.e(
       exc, "Unable to add program to Watch Next row. ${exc.localizedMessage}"
   )
   exc.printStackTrace()
}

Làm mới tiến trình phát

Nếu thẻ Watch Next đã tồn tại trên kênh Watch Next, ứng dụng cần cập nhật thẻ này nếu người dùng xem thêm video để phản ánh tiến trình xem mới nhất.

Khi cập nhật WatchNextProgram, hãy sử dụng cùng một lớp Builder để tạo WatchNextProgram và gọi updateWatchNextProgram của PreviewChannelHelper để cập nhật mục nhập hiện có. Dán mã sau vào "Step 1.3" trong WatchNextHelper.kt.

WatchNextHelper.kt

programId = existingProgram.id
PreviewChannelHelper(context).updateWatchNextProgram(updatedProgram, programId)

Kiểm tra kết quả

Duyệt qua mã của bạn, so sánh các thay đổi so với bản gốc trong step_1_complete. Chạy step_1_complete và xem một phần của tập phim. Kiểm tra xem tập phim đó được thêm vào kênh Watch Next hay chưa.

Xác nhận kết quả

  • ✅ ĐẠT YÊU CẦU: Chương trình được thêm vào Watch Next khi tạm dừng/dừng
  • ✅ ĐẠT YÊU CẦU: Ứng dụng có thể tiếp tục phát nội dung từ mục Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng cập nhật kịp thời vị trí phát trong Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ
  • ✅ ĐẠT YÊU CẦU: Đẩy tất cả nội dung đang xem dở sang Watch Next
  • ❗ CHƯA ĐẠT: Chương trình sẽ bị xoá khỏi Watch Next sau khi phát xong
  • ❗ CHƯA ĐẠT: Tập tiếp theo được thêm vào khi tập hiện tại kết thúc
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nội dung mà người dùng chưa tương tác với Watch Next
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nhiều tập trong cùng một chương trình truyền hình dài tập

Kiến thức bạn học được

Trong phần này, bạn đã tìm hiểu cách để:

  • Tạo một WatchNextProgram
  • Chèn hoặc cập nhật WatchNextProgram trong kênh Watch Next
  • Cập nhật tiến trình phát
  • Tiếp tục phát lại
  • Thiết lập siêu dữ liệu chính xác cho một tập phim truyền hình

Nội dung tiếp theo là gì?

Thêm một tập phim đang xem dở vào kênh Watch Next

5. Xoá nội dung (Phim/Tập) khỏi phần Watch Next sau khi phát xong

Các thẻ trong Kênh Watch Next được sắp xếp theo thời gian tương tác gần nhất. Video có lượt tương tác gần nhất sẽ được đặt ở đầu kênh. Ứng dụng nên xoá chương trình này khỏi kênh Watch Next sau khi người dùng xem xong và hiện quảng cáo có nội dung phù hợp hơn với người dùng.

Nhà phát triển cần theo dõi tiến trình phát của video. Sau khi người dùng xem xong một video, ứng dụng cần xoá video đó khỏi kênh Watch Next.

Lưu ý: Bạn có thể dùng logic tương tự để xoá phim hoặc tập phim khỏi kênh Watch Next.

Xoá WatchNextProgram

Để xoá một mục khỏi kênh Watch Next, nhà phát triển cần tìm đúng WatchNextProgram và dùng URI của chương trình này để xoá mục đó khỏi nhà cung cấp nội dung. Để thực hiện thao tác này, nhà phát triển cần phải so khớp WatchNextProgram với các thực thể video trong chính cơ sở dữ liệu của mình. Chúng ta có thể tận dụng trường internalProviderId để thiết lập một giá trị nhận dạng video duy nhất và liên kết giá trị đó với một trong các thực thể trong cơ sở dữ liệu của nhà phát triển.

Trước tiên, hãy tìm đúng WatchNextProgram bằng cách tra cứu mã video. Bạn có thể truy cập internalProviderId từ phương thức WatchNextProgram. getInternalProviderId hoặc truy cập trường này thông qua nhà cung cấp nội dung WatchNextProgram, sau đó xoá nội dung đó khỏi kênh Watch Next dựa trên URI.

Tìm cụm từ "Step 2.1", sau đó sao chép và dán nội dung sau:

WatchNextHelper.kt

val foundProgram = getWatchNextProgramByVideoId(video.id, context)
if (foundProgram == null) {
   Timber.e(
       "Unable to delete. No program found with videoID ${video.id}"
   )
   return null
}

// Use the found program's URI to delete it from the content resolver
return foundProgram.let {
   val programUri = TvContractCompat.buildWatchNextProgramUri(it.id)
   // delete returns the number of rows deleted.
   val deleteCount = context.contentResolver.delete(
       programUri, null, null
   )

   if (deleteCount == 1) {
       Timber.v("Content successfully removed from Watch Next")
       programUri
   } else {
       Timber.e("Content failed to be removed from Watch Next, delete count $deleteCount")
       null
   }
}

Nếu muốn xoá nhiều WatchNextProgram cùng một lúc, bạn nên yêu cầu thực hiện một loạt thao tác để tối ưu hoá lượt truy cập vào nhà cung cấp nội dung của chương trình truyền hình. Tìm cụm từ "Step 2.2", sao chép và dán đoạn mã sau vào WatchNextHelper.kt.

WatchNextHelper.kt

val foundPrograms = getWatchNextProgramByVideoIds(videos.map { it.id }, context)
val operations = foundPrograms.map {
   val programUri = TvContractCompat.buildWatchNextProgramUri(it.id)
   ContentProviderOperation.newDelete(programUri).build()
} as ArrayList<ContentProviderOperation>

val results = context.contentResolver.applyBatch(TvContractCompat.AUTHORITY, operations)

results.forEach { result ->
   if (result.count != 1) {
       Timber.e("Content failed to be removed from Watch Next: ${result.uri}")
   }
}

Theo nguyên tắc dành cho tính năng Watch Next, một tập phim sẽ bị xoá khi người dùng xem xong. Người dùng "xem xong" một tập nếu phần ghi công bắt đầu. Trong trường hợp này, bạn không nên thêm tập đó vào kênh Watch Next (hoặc xoá tập này khỏi kênh Watch Next nếu được thêm vào trước đó). Bạn có thể xác định trạng thái này bằng công nghệ để tự động phát hiện phần ghi công hoặc sử dụng giá trị gần đúng dựa trên thời lượng nội dung (ví dụ: dưới 3 phút trong một tập).

Nhìn vào phương thức handleWatchNextForEpisodes() trong WatchNextHelper.kt, bạn có thể thấy đoạn mã sau:

WatchNextHelper.kt

video.isAfterEndCreditsPosition(watchPosition.toLong()) -> {
   removeVideoFromWatchNext(context, video)

   ...
}

Trong lớp học lập trình này, chúng ta sẽ sử dụng VIDEO_COMPLETED_DURATION_MAX_PERCENTAGE để mô phỏng vị trí cảnh ghi công. Bạn có thể thay thế mã này trong isAfterEndCreditsPosition() theo logic của mình.

Kiểm tra kết quả

Duyệt qua mã của bạn, so sánh các thay đổi so với bản gốc trong step_2_complete. Chạy step_2_complete và xem một tập phim, Kiểm tra xem tập phim đó đã bị xoá khỏi kênh Watch Next sau khi bạn xem xong hay chưa.

Xác nhận kết quả

  • ✅ ĐẠT YÊU CẦU: Chương trình được thêm vào Watch Next khi tạm dừng/dừng
  • ✅ ĐẠT YÊU CẦU: Ứng dụng có thể tiếp tục phát nội dung từ mục Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng cập nhật kịp thời vị trí phát trong Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ
  • ✅ ĐẠT YÊU CẦU: Đẩy tất cả nội dung đang xem dở sang Watch Next
  • ✅ ĐẠT YÊU CẦU: Chương trình bị xoá khỏi Watch Next sau khi phát xong
  • ❗ CHƯA ĐẠT: Tập tiếp theo được thêm vào khi tập hiện tại kết thúc
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nội dung mà người dùng chưa tương tác với Watch Next
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nhiều tập trong cùng một chương trình truyền hình dài tập

Kiến thức bạn học được

Trong phần giới thiệu này, bạn tìm hiểu về:

  • Xác định cảnh ghi công của các tập phim truyền hình
  • Tìm WatchNextProgram theo mã video
  • Xoá một WatchNextProgram
  • Xoá nhiều WatchNextProgram

Nội dung tiếp theo là gì?

Thêm tập tiếp theo vào kênh Watch Next

6. Thêm tập tiếp theo

Không giống như phim, chương trình truyền hình thường có nhiều phần và mỗi phần có nhiều tập. Nếu người dùng xem hết một tập, thay vì chỉ xoá tập đó khỏi kênh Watch Next, bạn nên thay thế bằng tập tiếp theo. Tập tiếp theo có thể là tập ngay sau tập đã xem trong cùng phần hoặc tập đầu tiên của phần tiếp theo nếu tập đã xem là tập cuối cùng của phần hiện tại.

Khi thêm tập tiếp theo vào kênh Watch Next, hãy thiết lập loại Watch Next thành WATCH_NEXT_TYPE_NEXT. Thao tác này cho biết tập này không phải là chương trình đã xem trước đó mà hoàn toàn là một tập mới mà người dùng có thể theo dõi. Ứng dụng phải cho phép người dùng xem tập tiếp theo ngay từ đầu. Tìm cụm từ "TODO: Step 3.1 - Add next episode from TV series.", sao chép và dán mã sau vào bước 3.1:

WatchNextHelper.kt

videoRepository.getNextEpisodeInSeries(video)?.let {
       insertOrUpdateVideoToWatchNext(
           it,
           0,
           WATCH_NEXT_TYPE_NEXT,
           context
       )
       newWatchNextVideo = it
   }

Tập tiếp theo được lưu giữ bằng phương thức getNextEpisodeInSeries().

Tập tiếp theo trong cùng một phần

Nếu phần hiện tại vẫn còn các tập khác, ứng dụng nên chọn tập có sẵn tiếp theo và gán tập đó thành tập tiếp theo.

Tập đầu tiên của phần tiếp theo

Nếu người dùng xem xong phần hiện tại nhưng phần mới hơn đã sẵn sàng, ứng dụng nên chọn tập đầu tiên của phần tiếp theo làm tập tiếp theo.

Tập mới đã phát hành

Nếu không có thêm tập nào thì ứng dụng không cần thêm tập tiếp theo. Tuy nhiên, khi có một tập mới đã phát hành, bạn nên đẩy tập đó sang phía máy khách rồi thêm tập đó vào kênh Watch Next. Các tập mới sẽ sử dụng loại WatchNextProgram là WATCH_NEXT_TYPE_NEW. Giải pháp này cần có các thông báo đẩy từ phía máy chủ. Lớp học lập trình này không bao hàm phần nội dung này.

Kiểm tra kết quả

Duyệt qua mã của bạn, so sánh các thay đổi so với bản gốc trong step_3_complete. Chạy step_3_complete và xem một tập phim, kiểm tra xem tập tiếp theo được thêm vào kênh Watch Next sau khi bạn xem xong hay chưa.

Xác nhận kết quả

  • ✅ ĐẠT YÊU CẦU: Chương trình được thêm vào Watch Next khi tạm dừng/dừng
  • ✅ ĐẠT YÊU CẦU: Ứng dụng có thể tiếp tục phát nội dung từ mục Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng cập nhật kịp thời vị trí phát trong Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ
  • ✅ ĐẠT YÊU CẦU: Đẩy tất cả nội dung đang xem dở sang Watch Next
  • ✅ ĐẠT YÊU CẦU: Chương trình bị xoá khỏi Watch Next sau khi phát xong
  • ✅ ĐẠT YÊU CẦU: Tập tiếp theo được thêm khi tập hiện tại kết thúc
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nội dung mà người dùng chưa tương tác với Watch Next
  • ❗ CHƯA ĐẠT: Ứng dụng không thêm nhiều tập trong cùng một chương trình truyền hình dài tập

Kiến thức bạn học được

Trong phần này, bạn đã tìm hiểu về:

  • Cách chọn tập tiếp theo
  • Thêm tập tiếp theo cho chương trình truyền hình dài tập

Nội dung tiếp theo là gì?

Hiểu được mối quan tâm của người dùng.

7. Hiểu được mối quan tâm của người dùng

Để người dùng tập trung vào nội dung phù hợp nhất trong kênh Watch Next, khi thêm một tập phim truyền hình vào kênh Watch Next hoặc xoá tập đó khỏi kênh, ứng dụng cần xem xét một số cân nhắc bổ sung.

Nhiều tập trong cùng một chương trình dài tập

Có nhiều lý do khiến người dùng chưa xem hết các tập phim tại một thời điểm nào đó. Ví dụ:

  1. Phim truyền hình dài tập có trên nhiều ứng dụng hoặc trên mạng;
  2. Người dùng muốn tăng tốc và bỏ qua một số nội dung;

Kênh Watch Next chứa rất ít mục trên màn hình chính. Google đề xuất các ứng dụng chỉ nên giữ lại tối đa một tập cho mỗi chương trình truyền hình dài tập trên kênh Watch Next. Đồng thời, tập được giữ lại nên là tập phim mà người dùng xem gần nhất.

Chúng ta xử lý điều này trong phương thức handlePlayNextForEpisode() của lớp WatchNextHelper. Tìm cụm từ "Step 4.1", sao chép và dán mã sau vào khoảng trống trong bước 4.1.

WatchNextHelper.kt

newWatchNextVideo?.let { videoToKeep ->
   videoRepository.getAllVideosFromSeries(videoToKeep.seriesUri)?.let { allEpisodes ->
           filterWatchNextVideos(allEpisodes, context)
               ?.let { watchedEpisodes ->
                   removeVideosFromWatchNext(
                       context, watchedEpisodes.filter { it.id != videoToKeep.id })
               }
       }
}

Ở bước 4.1, chúng ta tiếp tục theo dõi tập mới nhất mà người dùng đã xem, xoá tất cả tập khác trong cùng một chương trình truyền hình dài tập. Bước này sẽ xoá nhiều tập cùng lúc nên chúng ta sử dụng phương thức mới tạo là removeVideosFromWatchNext() để tận dụng giải pháp xử lý hàng loạt của nhà cung cấp nội dung Android.

Nội dung ít tương tác

Theo nguyên tắc dành cho tính năng Watch Next, một tập phim chỉ được thêm vào kênh Watch Next nếu người dùng bắt đầu xem và người dùng "bắt đầu" một tập phim nếu xem trên 2 phút. Tìm cụm từ "Step 4.2", sao chép và dán mã sau vào khoảng trống trong bước 4.2.

WatchNextHelper.kt

val durationInMilliSeconds = duration.toMillis().toInt()
// Return true if either X minutes or Y % have passed
// Following formatting spans over multiple lines to accommodate max 100 limit
val watchNextMinStartedMillis = TimeUnit.MINUTES.toMillis(WATCH_NEXT_STARTED_MIN_MINUTES)
// Check if either X minutes or Y% has passed
val hasVideoStarted =
   (currentPosition >= (durationInMilliSeconds * WATCH_NEXT_STARTED_MIN_PERCENTAGE)) or
           (currentPosition >= watchNextMinStartedMillis)
val hasVideoStartedWithValidPosition =
   ((currentPosition <= durationInMilliSeconds) and hasVideoStarted)
Timber.v(
   "Has video started: %s, duration: %s, watchPosition: %s",
   hasVideoStartedWithValidPosition,
   duration,
   currentPosition
)
return hasVideoStartedWithValidPosition

Kiểm tra kết quả

Duyện qua mã của bạn, so sánh các thay đổi so với bản gốc trong step_4_complete. Chạy step_4_complete và xem một tập phim, kiểm tra xem liệu:

  1. Mã này sẽ xoá tập bổ sung khỏi chương trình truyền hình dài tập
  2. Chỉ thêm vào kênh Watch Next nếu người dùng bắt đầu xem

Xác nhận kết quả

  • ✅ ĐẠT YÊU CẦU: Chương trình được thêm vào Watch Next khi tạm dừng/dừng
  • ✅ ĐẠT YÊU CẦU: Ứng dụng có thể tiếp tục phát nội dung từ mục Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng cập nhật kịp thời vị trí phát trong Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng thiết lập siêu dữ liệu chính xác và đầy đủ
  • ✅ ĐẠT YÊU CẦU: Đẩy tất cả nội dung đang xem dở sang Watch Next
  • ✅ ĐẠT YÊU CẦU: Chương trình bị xoá khỏi Watch Next sau khi phát xong
  • ✅ ĐẠT YÊU CẦU: Tập tiếp theo được thêm khi tập hiện tại kết thúc
  • ✅ ĐẠT YÊU CẦU: Ứng dụng không thêm nội dung mà người dùng chưa tương tác trong Watch Next
  • ✅ ĐẠT YÊU CẦU: Ứng dụng không thêm nhiều tập trong cùng một chương trình truyền hình dài tập

Kiến thức bạn học được

Trong phần này, bạn đã tìm hiểu về:

  • Tránh thêm nhiều tập trong cùng một chương trình truyền hình dài tập
  • Tránh thêm nội dung có ít tương tác

Nội dung tiếp theo là gì?

Xin chúc mừng

8. Xin chúc mừng

Xin chúc mừng! Bạn đã xây dựng thành công tính năng Watch Next cho tập phim truyền hình và tìm hiểu yêu cầu về chất lượng đối với tính năng Watch Next.

Tuyệt vời!

Tài liệu đọc thêm

Tài liệu tham khảo