Empfehlungen in Android N und früheren Versionen

Bei der Interaktion mit Fernsehern bevorzugen Nutzer im Allgemeinen nur minimales Eingreifen, bevor sie sich Inhalte ansehen. Ein ideales Szenario für viele TV-Nutzer ist: hinsetzen, einschalten und zusehen. In der Regel bevorzugen sie es, Nutzer auf einfache Weise auf Inhalte aufmerksam zu machen, die ihnen gefallen.

Hinweis:Verwende die hier beschriebenen APIs nur für Empfehlungen in Apps, die unter Android-Versionen bis einschließlich Android 7.1 (API-Level 25) ausgeführt werden. Damit Sie Empfehlungen für Apps bereitstellen können, die unter Android 8.0 (API-Level 26) oder höher ausgeführt werden, muss Ihre App Empfehlungskanäle verwenden.

Das Android-Framework unterstützt die Interaktion mit minimaler Eingabe, indem auf dem Startbildschirm eine Zeile mit Empfehlungen angezeigt wird. Inhaltsempfehlungen werden nach der ersten Verwendung des Geräts in der ersten Zeile des Startbildschirms des Fernsehers angezeigt. Mit Empfehlungen aus dem Inhaltskatalog deiner App kannst du Nutzer dazu bringen, zu deiner App zurückzukehren.

Abbildung 1: Ein Beispiel für die Zeile „Empfehlung“.

In diesem Leitfaden erfährst du, wie du Empfehlungen erstellst und im Android-Framework bereitstellst, damit Nutzer deine App-Inhalte leicht finden und genießen können. Weitere Informationen finden Sie in der Beispielimplementierung in der Leanback-Beispiel-App.

Best Practices für Empfehlungen

Mithilfe von Empfehlungen finden Nutzer schnell die Inhalte und Apps, die ihnen gefallen. Das Erstellen von qualitativ hochwertigen und für Nutzer relevanten Empfehlungen ist ein wichtiger Faktor für eine positive Nutzererfahrung mit deiner TV-App. Aus diesem Grund solltest du dir gut überlegen, welche Empfehlungen du dem Nutzer unterbreitest, und diese sorgfältig umsetzen.

Arten von Empfehlungen

Wenn du Empfehlungen erstellst, solltest du Nutzer auf unvollständige Wiedergabeaktivitäten verweisen oder Aktivitäten vorschlagen, die sich auf ähnliche Inhalte ausdehnen. Hier sind einige spezifische Empfehlungen, die Sie berücksichtigen sollten:

  • Empfehlungen für Fortsetzungsinhalte für die nächste Folge, damit Nutzer die Wiedergabe einer Serie fortsetzen können. Oder verwenden Sie Empfehlungen für das Fortsetzen von pausierten Filmen, TV-Sendungen oder Podcasts, damit Nutzer mit nur wenigen Klicks wieder pausierte Inhalte ansehen können.
  • Empfehlungen für neue Inhalte, z. B. für eine neue Folge, wenn der Nutzer sich eine andere Serie angesehen hat. Wenn deine App es Nutzern ermöglicht, Inhalte zu abonnieren, zu folgen oder zu verfolgen, verwenden Sie neue Inhaltsempfehlungen für nicht angesehene Elemente in der Liste der beobachteten Inhalte.
  • Empfehlungen für ähnliche Inhalte, die auf dem bisherigen Wiedergabeverhalten der Nutzer basieren.

Weitere Informationen zum Erstellen von Empfehlungskarten für eine optimale Nutzererfahrung finden Sie in den Android TV-Designspezifikationen unter Empfehlungszeile.

Empfehlungen aktualisieren

Wenn Sie Empfehlungen aktualisieren, sollten Sie sie nicht nur entfernen und neu posten, da sie dann am Ende der Zeile mit Empfehlungen angezeigt werden. Nachdem ein Inhaltselement, z. B. ein Film, abgespielt wurde, entfernen Sie es aus den Empfehlungen.

Empfehlungen anpassen

Sie können Empfehlungskarten anpassen, um Branding-Informationen zu vermitteln, indem Sie Elemente der Benutzeroberfläche wie Vorder- und Hintergrundbild der Karte, Farbe, App-Symbol, Titel und Untertitel festlegen. Weitere Informationen findest du in den Android TV-Designspezifikationen in der Empfehlungszeile.

Empfehlungen für Gruppen

Optional können Sie Empfehlungen basierend auf der Empfehlungsquelle gruppieren. Ihre App könnte beispielsweise zwei Gruppen von Empfehlungen bereitstellen: Empfehlungen für Inhalte, die der Nutzer abonniert hat, und Empfehlungen für neue angesagte Inhalte, die dem Nutzer möglicherweise nicht bekannt sind.

Beim Erstellen oder Aktualisieren der Empfehlungszeile stuft das System Empfehlungen für jede Gruppe separat ein. Mit Gruppeninformationen für Ihre Empfehlungen sorgen Sie dafür, dass die Empfehlungen nicht unter irrelevanten Empfehlungen sortiert werden.

Verwenden Sie NotificationCompat.Builder.setGroup(), um den Gruppenschlüsselstring einer Empfehlung festzulegen. Wenn Sie beispielsweise eine Empfehlung so kennzeichnen möchten, dass sie zu einer Gruppe gehört, die neue Trendinhalte enthält, können Sie setGroup("trending") aufrufen.

Empfehlungsdienst erstellen

Inhaltsempfehlungen werden im Hintergrund verarbeitet. Damit Ihre Anwendung zu Empfehlungen beitragen kann, müssen Sie einen Dienst erstellen, der regelmäßig Einträge aus dem Katalog Ihrer App zur Liste der Empfehlungen des Systems hinzufügt.

Das folgende Codebeispiel zeigt, wie Sie IntentService erweitern, um einen Empfehlungsdienst für Ihre Anwendung zu erstellen:

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;
    }
}

Registrieren Sie ihn mithilfe Ihres App-Manifests, damit dieser Dienst vom System erkannt und ausgeführt werden kann. Das folgende Code-Snippet zeigt, wie diese Klasse als Dienst deklariert wird:

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

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

Empfehlungen erstellen

Sobald Ihr Empfehlungsdienst ausgeführt wird, muss er Empfehlungen erstellen und an das Android-Framework übergeben. Das Framework empfängt die Empfehlungen als Notification-Objekte, die eine bestimmte Vorlage verwenden und mit einer bestimmten Kategorie gekennzeichnet sind.

Werte festlegen

Zum Festlegen der UI-Elementwerte für die Empfehlungskarte erstellen Sie eine Builder-Klasse, die dem so beschriebenen Builder-Muster folgt. Zuerst legen Sie die Werte der Elemente der Empfehlungskarte fest.

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;
        }
...

Benachrichtigung erstellen

Nachdem Sie die Werte festgelegt haben, erstellen Sie die Benachrichtigung, weisen der Benachrichtigung die Werte aus der Builder-Klasse zu und rufen NotificationCompat.Builder.build() auf.

Rufe außerdem setLocalOnly() auf, damit die NotificationCompat.BigPictureStyle-Benachrichtigung nicht auf anderen Geräten angezeigt wird.

Das folgende Codebeispiel zeigt, wie eine Empfehlung erstellt wird.

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;
    }
}

Empfehlungsdienst ausführen

Der Empfehlungsdienst Ihrer Anwendung muss regelmäßig ausgeführt werden, um aktuelle Empfehlungen zu erstellen. Erstellen Sie zum Ausführen Ihres Dienstes eine Klasse, die einen Timer ausführt und in regelmäßigen Intervallen aufruft. Im folgenden Codebeispiel wird die Klasse BroadcastReceiver erweitert, um alle halbe Stunde die regelmäßige Ausführung eines Empfehlungsdienstes zu starten:

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);
    }
}

Diese Implementierung der BroadcastReceiver-Klasse muss nach dem Start des Fernsehers ausgeführt werden, auf dem sie installiert ist. Registriere diese Klasse zu diesem Zweck in deinem App-Manifest mit einem Intent-Filter, der den Abschluss des Geräte-Bootvorgangs überwacht. Der folgende Beispielcode zeigt, wie diese Konfiguration dem Manifest hinzugefügt wird:

<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>

Wichtig: Für den Erhalt einer Benachrichtigung nach abgeschlossenem Bootvorgang muss Ihre Anwendung die Berechtigung RECEIVE_BOOT_COMPLETED anfordern. Weitere Informationen findest du unter ACTION_BOOT_COMPLETED.

So senden Sie die Empfehlung in der Methode onHandleIntent() Ihrer Empfehlungsdienstklasse an den Manager:

Kotlin

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

Java

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