Podczas korzystania z telewizora użytkownicy zwykle wolą ograniczyć liczbę czynności przed rozpoczęciem oglądania treści. Idealny scenariusz dla wielu użytkowników telewizora to: usiąść, włączyć i oglądać. Najkrótsza droga do treści, które podobają się użytkownikom, jest zwykle preferowana.
Uwaga: interfejsów API opisanych w tym dokumencie używaj tylko do tworzenia rekomendacji w aplikacjach działających w Androidzie w wersji 7.1 (interfejs API na poziomie 25) lub starszej. Aby dostarczać rekomendacje do aplikacji działających w Androidzie w wersji 8.0 (interfejs API na poziomie 26) lub nowszej, aplikacja musi korzystać z kanałów rekomendacji.
Android Framework ułatwia interakcję z minimalną liczbą czynności, udostępniając wiersz rekomendacji na ekranie głównym. Rekomendacje treści pojawiają się jako pierwszy wiersz na ekranie głównym telewizora po pierwszym użyciu urządzenia. Dostarczanie rekomendacji z katalogu treści aplikacji może pomóc w przyciągnięciu użytkowników z powrotem do aplikacji.
Z tego przewodnika dowiesz się, jak tworzyć rekomendacje i udostępniać je Android Framework aby użytkownicy mogli odkrywać i oglądać treści w Twojej aplikacji. Zobacz też przykładową implementację w przykładowej aplikacji Leanback .
Sprawdzone metody dotyczące rekomendacji
Rekomendacje pomagają użytkownikom szybko znajdować treści i aplikacje, które im się podobają. Tworzenie rekomendacji wysokiej jakości i odpowiednich dla użytkowników jest ważnym czynnikiem wpływającym na komfort korzystania z aplikacji TV. Z tego powodu należy dokładnie rozważyć, jakie rekomendacje wyświetlać użytkownikowi, i starannie nimi zarządzać.
Typy rekomendacji
Podczas tworzenia rekomendacji należy kierować użytkowników z powrotem do niedokończonych działań związanych z oglądaniem lub sugerować działania, które rozszerzają je na powiązane treści. Oto kilka konkretnych typów rekomendacji, które warto wziąć pod uwagę:
- Rekomendacje kontynuacji treści , np. następnego odcinka, aby użytkownicy mogli wznowić oglądanie serialu. Możesz też używać rekomendacji kontynuacji w przypadku wstrzymanych filmów, programów telewizyjnych lub podcastów, aby użytkownicy mogli wrócić do oglądania wstrzymanych treści za pomocą kilku kliknięć.
- Rekomendacje nowych treści, np. nowego odcinka, jeśli użytkownik skończył oglądać inny serial. Jeśli Twoja aplikacja umożliwia użytkownikom subskrybowanie, obserwowanie lub śledzenie treści, używaj rekomendacji nowych treści w przypadku nieobejrzanych pozycji na liście śledzonych treści.
- Rekomendacje powiązanych treści na podstawie historii oglądania użytkowników.
Więcej informacji o projektowaniu kart rekomendacji, które zapewniają najlepsze wrażenia użytkownikom, znajdziesz w sekcji Wiersz rekomendacji w specyfikacji projektu Android TV.
Odśwież rekomendacje
Podczas odświeżania rekomendacji nie usuwaj ich i nie publikuj ponownie, ponieważ spowoduje to, że rekomendacje pojawią się na końcu wiersza rekomendacji. Gdy użytkownik odtworzy element treści, np. film, usuń go z rekomendacji.
Dostosuj rekomendacje
Możesz dostosować karty rekomendacji, aby przekazywać informacje o marce, ustawiając elementy interfejsu użytkownika, takie jak obraz pierwszego planu i tła karty, kolor, ikona aplikacji, tytuł i podtytuł. Więcej informacji znajdziesz w sekcji Wiersz rekomendacji w specyfikacji projektu Android TV.
Rekomendacje grup
Możesz opcjonalnie grupować rekomendacje na podstawie źródła rekomendacji. Na przykład Twoja aplikacja może udostępniać 2 grupy rekomendacji: rekomendacje treści, które subskrybuje użytkownik, oraz rekomendacje nowych, popularnych treści, o których użytkownik może nie wiedzieć.
Podczas tworzenia lub aktualizowania wiersza rekomendacji system osobno ocenia i porządkuje rekomendacje w każdej grupie. Dzięki podawaniu informacji o grupach w rekomendacjach możesz mieć pewność, że Twoje rekomendacje nie będą porządkowane w ramach niezwiązanych rekomendacji.
Aby ustawić ciąg klucza grupy rekomendacji, użyj NotificationCompat.Builder.setGroup(). Aby na przykład oznaczyć rekomendację jako należącą do grupy zawierającej nowe, popularne treści, możesz wywołać setGroup("trending").
Tworzenie usługi rekomendacji
Rekomendacje treści są tworzone w ramach przetwarzania w tle. Aby aplikacja mogła dostarczać rekomendacje, utwórz usługę, która okresowo dodaje wpisy z katalogu aplikacji do listy rekomendacji systemu.
Poniższy przykład kodu pokazuje, jak rozszerzyć IntentService, aby
utworzyć usługę rekomendacji dla aplikacji:
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; } }
Aby ta usługa była rozpoznawana przez system i mogła działać, zarejestruj ją w manifeście aplikacji. Poniższy fragment kodu pokazuje, jak zadeklarować tę klasę jako usługę:
<manifest ... > <application ... > ... <service android:name="com.example.android.tvleanback.UpdateRecommendationsService" android:enabled="true" /> </application> </manifest>
Tworzenie rekomendacji
Gdy usługa rekomendacji zacznie działać, musi tworzyć rekomendacje i przekazywać je do
Android Framework. Framework otrzymuje rekomendacje jako obiekty Notification, które używają określonego szablonu i są oznaczone określoną
kategorią.
Ustawianie wartości
Aby ustawić wartości elementów interfejsu rekomendacji, utwórz klasę konstruktora, która jest zgodna z wzorcem konstruktora opisanym poniżej. Najpierw ustaw wartości elementów karty rekomendacji.
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; } ...
Tworzenie powiadomienia
Po ustawieniu wartości utwórz powiadomienie, przypisując do niego wartości z klasy konstruktora
i wywołując NotificationCompat.Builder.build().
Pamiętaj też, aby wywołać
setLocalOnly()
aby powiadomienie NotificationCompat.BigPictureStyle nie wyświetlało się
na innych urządzeniach.
Poniższy przykład kodu pokazuje, jak utworzyć rekomendację.
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; } }
Uruchamianie usługi rekomendacji biegowych
Usługa rekomendacji aplikacji musi działać okresowo, aby tworzyć aktualne
rekomendacje. Aby uruchomić usługę, utwórz klasę, która uruchamia timer i wywołuje
go w regularnych odstępach czasu. Poniższy przykład kodu rozszerza klasę BroadcastReceiver, aby uruchamiać usługę rekomendacji
co pół godziny:
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); } }
Ta implementacja klasy BroadcastReceiver musi działać po uruchomieniu telewizora, na którym jest zainstalowana. Aby to zrobić, zarejestruj tę klasę w manifeście aplikacji
za pomocą filtra intencji, który nasłuchuje zakończenia procesu uruchamiania urządzenia. Poniższy
przykładowy kod pokazuje, jak dodać tę konfigurację do manifestu:
<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>
Ważne: aby otrzymywać powiadomienie o zakończeniu uruchamiania, aplikacja musi
poprosić o uprawnienie RECEIVE_BOOT_COMPLETED.
Więcej informacji znajdziesz w artykule ACTION_BOOT_COMPLETED.
W metodzie onHandleIntent() klasy usługi rekomendacji opublikuj rekomendację w menedżerze w ten sposób:
Kotlin
val notification = notificationBuilder.build() notificationManager.notify(id, notification)
Java
Notification notification = notificationBuilder.build(); notificationManager.notify(id, notification);