Rekomendasi di Android N dan versi sebelumnya

Saat berinteraksi dengan TV, pengguna umumnya lebih suka memberi masukan minimum sebelum menonton konten. Skenario ideal untuk sebagian besar pengguna TV adalah: duduk, menyalakan TV, dan menontonnya. Langkah paling efektif untuk mengantar pengguna pada konten yang mereka nikmati secara umum telah menjadi jalur pilihan.

Catatan: Gunakan API yang dijelaskan di sini untuk membuat rekomendasi di aplikasi yang berjalan di versi Android hingga dan hanya termasuk Android 7.1 (API level 25). Untuk memberikan rekomendasi bagi aplikasi yang berjalan di Android 8.0 (API level 26) dan versi lebih baru, aplikasi Anda harus menggunakan saluran rekomendasi.

Framework Android membantu interaksi dengan masukan minimum, dengan memberikan baris rekomendasi di layar utama. Rekomendasi konten muncul sebagai baris pertama di layar utama TV setelah perangkat digunakan pertama kali. Kontribusi rekomendasi dari katalog konten aplikasi Anda dapat membantu mengembalikan pengguna ke aplikasi Anda.

Gambar 1. Contoh baris rekomendasi.

Tutorial ini mengajarkan Anda cara membuat rekomendasi dan memberikannya ke framework Android sehingga pengguna dapat menemukan dan menikmati konten aplikasi Anda dengan mudah. Diskusi ini mendeskripsikan beberapa kode dari aplikasi contoh Android Leanback di repositori GitHub Android TV.

Praktik terbaik untuk rekomendasi

Rekomendasi membantu pengguna menemukan konten dan aplikasi yang mereka nikmati dengan cepat. Pembuatan rekomendasi berkualitas tinggi dan relevan bagi pengguna adalah faktor penting dalam menciptakan pengalaman pengguna yang baik dengan aplikasi TV Anda. Karena itu, Anda harus mempertimbangkan dengan saksama rekomendasi yang disajikan kepada pengguna dan mengelolanya dengan cermat.

Jenis rekomendasi

Saat membuat rekomendasi, Anda harus menautkan pengguna kembali ke aktivitas tampilan yang belum lengkap atau menyarankan aktivitas yang akan memperluasnya ke konten terkait. Berikut adalah beberapa jenis rekomendasi spesifik yang harus Anda pertimbangkan:

  • Rekomendasi konten lanjutan untuk episode berikutnya bagi pengguna agar dapat melanjutkan menonton film serial. Selain itu, gunakan rekomendasi lanjutan untuk film, acara TV, atau podcast yang dijeda agar pengguna dapat kembali menonton konten tersebut hanya dalam beberapa klik.
  • Rekomendasi konten baru, seperti untuk episode yang baru tayang, jika pengguna selesai menonton film serial lain. Selain itu, jika aplikasi Anda memungkinkan pengguna untuk berlangganan, mengikuti, atau melacak konten, gunakan rekomendasi konten baru untuk item yang belum ditonton dalam daftar konten yang dilacak.
  • Rekomendasi konten terkait berdasarkan perilaku historis yang dilihat pengguna.

Untuk informasi selengkapnya tentang cara mendesain kartu rekomendasi untuk pengalaman pengguna terbaik, lihat Baris Rekomendasi di Spesifikasi Desain Android TV.

Memuat ulang rekomendasi

Saat memuat ulang rekomendasi, jangan hanya menghapus dan memposting ulang, karena hal itu menyebabkan rekomendasi muncul di akhir baris rekomendasi. Setelah item konten, misal film, telah diputar, hapus item dari rekomendasi.

Menyesuaikan rekomendasi

Anda dapat menyesuaikan kartu rekomendasi untuk menyampaikan informasi branding, dengan menetapkan elemen antarmuka pengguna seperti gambar latar belakang dan latar depan kartu, warna, ikon aplikasi, judul, dan subtitel. Untuk mempelajari lebih lanjut, lihat Baris Rekomendasi dalam Spesifikasi Desain Android TV.

Mengelompokkan rekomendasi

Anda dapat secara opsional mengelompokkan rekomendasi berdasarkan sumber rekomendasi. Misalnya, aplikasi Anda mungkin menyediakan dua grup rekomendasi: rekomendasi untuk konten langganan pengguna, dan rekomendasi untuk konten trending baru yang mungkin tidak diperhatikan pengguna.

Sistem memberi peringkat dan menyusun rekomendasi untuk setiap grup secara terpisah saat membuat atau mengupdate baris rekomendasi. Dengan memberikan informasi grup untuk rekomendasi, Anda dapat memastikan bahwa rekomendasi Anda tidak disusun di bawah rekomendasi yang tidak terkait.

Gunakan NotificationCompat.Builder.setGroup() untuk menetapkan string kunci grup dari rekomendasi. Misalnya, untuk menandai rekomendasi sebagai milik grup yang berisi konten trending baru, Anda dapat memanggil setGroup("trending").

Membuat layanan rekomendasi

Rekomendasi konten dibuat dengan pemrosesan latar belakang. Agar aplikasi Anda berkontribusi pada rekomendasi, buat layanan yang secara berkala menambahkan daftar dari katalog aplikasi Anda ke daftar rekomendasi sistem.

Contoh kode berikut menggambarkan cara memperluas IntentService untuk membuat layanan rekomendasi bagi aplikasi Anda:

Kotlin

    class UpdateRecommendationsService : IntentService("RecommendationService") {
        override protected fun onHandleIntent(intent: Intent) {
            Log.d(TAG, "Updating recommendation cards")
            val recommendations = VideoProvider.getMovieList()
            if (recommendations == null) return

            var count = 0

            try {
                val builder = RecommendationBuilder()
                        .setContext(applicationContext)
                        .setSmallIcon(R.drawable.videos_by_google_icon)

                for (entry in recommendations.entrySet()) {
                    for (movie in entry.getValue()) {
                        Log.d(TAG, "Recommendation - " + movie.getTitle())

                        builder.setBackground(movie.getCardImageUrl())
                                .setId(count + 1)
                                .setPriority(MAX_RECOMMENDATIONS - count)
                                .setTitle(movie.getTitle())
                                .setDescription(getString(R.string.popular_header))
                                .setImage(movie.getCardImageUrl())
                                .setIntent(buildPendingIntent(movie))
                                .build()
                        if (++count >= MAX_RECOMMENDATIONS) {
                            break
                        }
                    }
                    if (++count >= MAX_RECOMMENDATIONS) {
                        break
                    }
                }
            } catch (e: IOException) {
                Log.e(TAG, "Unable to update recommendation", e)
            }
        }

        private fun buildPendingIntent(movie: Movie): PendingIntent {
            val detailsIntent = Intent(this, DetailsActivity::class.java)
            detailsIntent.putExtra("Movie", movie)

            val stackBuilder = TaskStackBuilder.create(this)
            stackBuilder.addParentStack(DetailsActivity::class.java)
            stackBuilder.addNextIntent(detailsIntent)

            // Ensure a unique PendingIntents, otherwise all
            // recommendations end up with the same PendingIntent
            detailsIntent.setAction(movie.getId().toString())

            val intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
            return intent
        }

        companion object {
            private val TAG = "UpdateRecommendationsService"
            private val MAX_RECOMMENDATIONS = 3
        }
    }
    

Java

    public class UpdateRecommendationsService extends IntentService {
        private static final String TAG = "UpdateRecommendationsService";
        private static final int MAX_RECOMMENDATIONS = 3;

        public UpdateRecommendationsService() {
            super("RecommendationService");
        }

        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d(TAG, "Updating recommendation cards");
            HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList();
            if (recommendations == null) return;

            int count = 0;

            try {
                RecommendationBuilder builder = new RecommendationBuilder()
                        .setContext(getApplicationContext())
                        .setSmallIcon(R.drawable.videos_by_google_icon);

                for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) {
                    for (Movie movie : entry.getValue()) {
                        Log.d(TAG, "Recommendation - " + movie.getTitle());

                        builder.setBackground(movie.getCardImageUrl())
                                .setId(count + 1)
                                .setPriority(MAX_RECOMMENDATIONS - count)
                                .setTitle(movie.getTitle())
                                .setDescription(getString(R.string.popular_header))
                                .setImage(movie.getCardImageUrl())
                                .setIntent(buildPendingIntent(movie))
                                .build();

                        if (++count >= MAX_RECOMMENDATIONS) {
                            break;
                        }
                    }
                    if (++count >= MAX_RECOMMENDATIONS) {
                        break;
                    }
                }
            } catch (IOException e) {
                Log.e(TAG, "Unable to update recommendation", e);
            }
        }

        private PendingIntent buildPendingIntent(Movie movie) {
            Intent detailsIntent = new Intent(this, DetailsActivity.class);
            detailsIntent.putExtra("Movie", movie);

            TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
            stackBuilder.addParentStack(DetailsActivity.class);
            stackBuilder.addNextIntent(detailsIntent);
            // Ensure a unique PendingIntents, otherwise all
            // recommendations end up with the same PendingIntent
            detailsIntent.setAction(Long.toString(movie.getId()));

            PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
            return intent;
        }
    }
    

Agar layanan ini dapat dikenali oleh sistem dan dijalankan, daftarkan menggunakan manifes aplikasi Anda. Cuplikan kode berikut menggambarkan cara mendeklarasikan class ini sebagai layanan:

    <manifest ... >
      <application ... >
        ...

        <service
                android:name="com.example.android.tvleanback.UpdateRecommendationsService"
                android:enabled="true" />
      </application>
    </manifest>
    

Membuat rekomendasi

Setelah layanan rekomendasi Anda mulai berjalan, layanan tersebut harus membuat rekomendasi dan meneruskannya ke framework Android. Framework ini menerima rekomendasi sebagai objek Notification yang menggunakan template spesifik dan ditandai dengan kategori spesifik.

Menyetel nilai

Untuk menyetel nilai elemen UI bagi kartu rekomendasi, Anda harus membuat class builder yang mengikuti pola builder yang dijelaskan seperti berikut. Pertama, Anda harus menyetel nilai-nilai elemen kartu rekomendasi.

Kotlin

    class RecommendationBuilder {
        ...

        fun setTitle(title: String): RecommendationBuilder {
            this.title = title
            return this
        }

        fun setDescription(description: String): RecommendationBuilder {
            this.description = description
            return this
        }

        fun setImage(uri: String): RecommendationBuilder {
            imageUri = uri
            return this
        }

        fun setBackground(uri: String): RecommendationBuilder {
            backgroundUri = uri
            return this
        }

    ...
    

Java

    public class RecommendationBuilder {
        ...

        public RecommendationBuilder setTitle(String title) {
                this.title = title;
                return this;
            }

            public RecommendationBuilder setDescription(String description) {
                this.description = description;
                return this;
            }

            public RecommendationBuilder setImage(String uri) {
                imageUri = uri;
                return this;
            }

            public RecommendationBuilder setBackground(String uri) {
                backgroundUri = uri;
                return this;
            }
    ...
    

Membuat notifikasi

Setelah menetapkan nilai, Anda kemudian harus mem-build notifikasi, menetapkan nilai dari class builder ke notifikasi, lalu memanggil NotificationCompat.Builder.build().

Selain itu, pastikan untuk memanggil setLocalOnly() sehingga notifikasi NotificationCompat.BigPictureStyle tidak akan muncul di perangkat lain.

Contoh kode berikut menunjukkan cara membuat rekomendasi.

Kotlin

    class RecommendationBuilder {
        ...

        @Throws(IOException::class)
        fun build(): Notification {
            ...

            val notification = NotificationCompat.BigPictureStyle(
            NotificationCompat.Builder(context)
                    .setContentTitle(title)
                    .setContentText(description)
                    .setPriority(priority)
                    .setLocalOnly(true)
                    .setOngoing(true)
                    .setColor(context.resources.getColor(R.color.fastlane_background))
                    .setCategory(Notification.CATEGORY_RECOMMENDATION)
                    .setLargeIcon(image)
                    .setSmallIcon(smallIcon)
                    .setContentIntent(intent)
                    .setExtras(extras))
                    .build()

            return notification
        }
    }
    

Java

    public class RecommendationBuilder {
        ...

        public Notification build() throws IOException {
            ...

            Notification notification = new NotificationCompat.BigPictureStyle(
                    new NotificationCompat.Builder(context)
                            .setContentTitle(title)
                            .setContentText(description)
                            .setPriority(priority)
                            .setLocalOnly(true)
                            .setOngoing(true)
                            .setColor(context.getResources().getColor(R.color.fastlane_background))
                            .setCategory(Notification.CATEGORY_RECOMMENDATION)
                            .setLargeIcon(image)
                            .setSmallIcon(smallIcon)
                            .setContentIntent(intent)
                            .setExtras(extras))
                    .build();

            return notification;
        }
    }
    

Menjalankan layanan rekomendasi

Layanan rekomendasi aplikasi Anda harus berjalan secara berkala agar dapat membuat rekomendasi saat ini. Untuk menjalankan layanan Anda, buat class yang menjalankan timer dan memanggilnya secara berkala. Contoh kode berikut memperluas class BroadcastReceiver untuk memulai eksekusi layanan rekomendasi secara berkala setiap setengah jam:

Kotlin

    class BootupActivity : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Log.d(TAG, "BootupActivity initiated")
            if (intent.action.endsWith(Intent.ACTION_BOOT_COMPLETED)) {
                scheduleRecommendationUpdate(context)
            }
        }

        private fun scheduleRecommendationUpdate(context: Context) {
            Log.d(TAG, "Scheduling recommendations update")
            val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
            val recommendationIntent = Intent(context, UpdateRecommendationsService::class.java)
            val alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0)
            alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    INITIAL_DELAY,
                    AlarmManager.INTERVAL_HALF_HOUR,
                    alarmIntent
            )
        }

        companion object {
            private val TAG = "BootupActivity"
            private val INITIAL_DELAY:Long = 5000
        }
    }
    

Java

    public class BootupActivity extends BroadcastReceiver {
        private static final String TAG = "BootupActivity";

        private static final long INITIAL_DELAY = 5000;

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "BootupActivity initiated");
            if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
                scheduleRecommendationUpdate(context);
            }
        }

        private void scheduleRecommendationUpdate(Context context) {
            Log.d(TAG, "Scheduling recommendations update");

            AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class);
            PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0);

            alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    INITIAL_DELAY,
                    AlarmManager.INTERVAL_HALF_HOUR,
                    alarmIntent);
        }
    }
    

Implementasi class BroadcastReceiver harus dijalankan setelah memulai perangkat TV tempat penginstalan. Untuk menyelesaikannya, daftarkan class ini di manifes aplikasi Anda dengan filter intent yang memproses penyelesaian proses booting perangkat. Kode contoh berikut menunjukkan cara menambahkan konfigurasi ini ke manifes:

    <manifest ... >
      <application ... >
        <receiver android:name="com.example.android.tvleanback.BootupActivity"
                  android:enabled="true"
                  android:exported="false">
          <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
          </intent-filter>
        </receiver>
      </application>
    </manifest>
    

Penting: Penerimaan notifikasi proses booting selesai mewajibkan aplikasi Anda untuk meminta izin RECEIVE_BOOT_COMPLETED. Untuk informasi selengkapnya, lihat ACTION_BOOT_COMPLETED.

Dalam metode onHandleIntent() class layanan rekomendasi, posting rekomendasi ke manajer seperti berikut:

Kotlin

    val notification = notificationBuilder.build()
    notificationManager.notify(id, notification)
    

Java

    Notification notification = notificationBuilder.build();
    notificationManager.notify(id, notification);