Empfehlungen in Android N und früheren Versionen

Wenn Nutzer mit Fernsehern interagieren, geben sie in der Regel nur wenig Input, bevor sie sich Inhalte ansehen. Ein ideales Szenario für viele TV-Nutzer ist: Setz dich hin, schalte das Gerät ein und schaue zu. Am einfachsten gelangen Nutzer zu Inhalten, die ihnen gefallen, indem sie im Allgemeinen die von ihnen bevorzugte Methode wählen.

Hinweis:Verwenden Sie die hier beschriebenen APIs nur für Empfehlungen in Apps, die in 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) und höher ausgeführt werden, muss Ihre App Empfehlungskanäle verwenden.

Das Android-Framework unterstützt die Mindesteingabeinteraktion, indem es eine Empfehlungszeile auf dem Startbildschirm bereitstellt. Inhaltsempfehlungen werden nach der ersten Verwendung des Geräts in der ersten Zeile des Startbildschirms des Fernsehers angezeigt. Mit Empfehlungen aus dem Inhaltskatalog Ihrer App können Sie dafür sorgen, dass Nutzer wieder zu Ihrer App zurückkehren.

Abbildung 1: Beispiel für die Zeile „Empfehlungen“

In diesem Leitfaden erfährst du, wie du Empfehlungen erstellst und sie dem Android-Framework zur Verfügung stellst, damit Nutzer deine App-Inhalte leicht finden und verwenden können. Sehen Sie sich auch die Beispielimplementierung in der Leanback-Beispiel-App an.

Best Practices für Empfehlungen

Mithilfe von Empfehlungen finden Nutzer schnell die Inhalte und Apps, die ihnen gefallen. Das Erstellen von qualitativ hochwertigen und relevanten Empfehlungen für die Nutzerfreundlichkeit Ihrer TV-App ist ein wichtiger Faktor. Aus diesem Grund sollten Sie genau überlegen, welche Empfehlungen Sie dem Nutzer geben, und sie genau verwalten.

Arten von Empfehlungen

Beim Erstellen von Empfehlungen solltest du Nutzer zu unvollständigen Wiedergabeaktivitäten zurückverweisen oder Aktivitäten vorschlagen, die sich auf ähnliche Inhalte erstrecken. 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 du wählst Fortführungsempfehlungen für pausierte Filme, Serien oder Podcasts aus, damit die Nutzer sie mit nur wenigen Klicks wieder aufrufen können.
  • Empfehlungen für neue Inhalte, z. B. für eine neue Folge einer neuen Folge, wenn sich der Nutzer eine andere Serie zu Ende angesehen hat. Wenn Nutzer in Ihrer App Inhalte abonnieren, ihnen folgen oder sie nachverfolgen können, sollten Sie neue Inhaltsempfehlungen für nicht angesehene Elemente in der Liste der beobachteten Inhalte verwenden.
  • Empfehlungen zu ähnlichen Inhalten basierend auf dem bisherigen Wiedergabeverhalten der Nutzer.

Weitere Informationen zum Entwerfen von Empfehlungskarten für eine optimale Nutzererfahrung findest du in der Recommendation Row in den Android TV-Designspezifikationen.

Empfehlungen aktualisieren

Wenn Sie Empfehlungen aktualisieren, sollten Sie sie nicht einfach entfernen und neu posten, da sie dann am Ende der Empfehlungszeile erscheinen. Nachdem ein Inhaltselement wiedergegeben wurde, z. B. ein Film, entfernen Sie es aus den Empfehlungen.

Empfehlungen anpassen

Du kannst Empfehlungskarten so anpassen, dass sie Branding-Informationen enthalten, indem du Elemente der Benutzeroberfläche wie Vorder- und Hintergrundbild der Karte, Farbe, App-Symbol, Titel und Untertitel festlegst. Weitere Informationen findest du in der Recommendation Row in den Android TV-Designspezifikationen.

Empfehlungen für Gruppen

Optional können Sie Empfehlungen anhand der Empfehlungsquelle gruppieren. Ihre App könnte beispielsweise zwei Gruppen von Empfehlungen geben: Empfehlungen für Inhalte, die der Nutzer abonniert hat, und Empfehlungen für neue angesagte Inhalte, die der Nutzer möglicherweise noch nicht kennt.

Das System sortiert die Empfehlungen für jede Gruppe separat ein, wenn die Empfehlungszeile erstellt oder aktualisiert wird. Wenn Sie Gruppeninformationen für Ihre Empfehlungen angeben, werden diese nicht unter den irrelevanten Empfehlungen sortiert.

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

Empfehlungsdienst erstellen

Inhaltsempfehlungen werden im Hintergrund erstellt. Damit Ihre Anwendung Empfehlungen beisteuern kann, müssen Sie einen Dienst erstellen, der regelmäßig Einträge aus dem Anwendungskatalog zur Liste der Empfehlungen des Systems hinzufügt.

Das folgende Codebeispiel zeigt, wie Sie IntentService erweitern können, 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 den Dienst über Ihr App-Manifest, damit er 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>

Build-Empfehlungen

Sobald Ihr Empfehlungsdienst ausgeführt wird, müssen er Empfehlungen erstellen und an das Android-Framework übergeben. Das Framework erhält die Empfehlungen als Notification-Objekte, die eine bestimmte Vorlage verwenden und mit einer bestimmten Kategorie markiert sind.

Werte festlegen

Zum Festlegen der UI-Elementwerte für die Empfehlungskarte erstellen Sie eine Builder-Klasse, die dem unten beschriebenen Builder-Muster folgt. Zuerst legen Sie die Werte der Empfehlungskartenelemente 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.

Du musst setLocalOnly() aufrufen, 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, damit aktuelle Empfehlungen erstellt werden können. Erstellen Sie zum Ausführen Ihres Dienstes eine Klasse, die einen Timer ausführt und in regelmäßigen Abständen aufruft. Im folgenden Codebeispiel wird die Klasse BroadcastReceiver erweitert, um die regelmäßige Ausführung eines Empfehlungsdienstes alle halbe Stunde 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 Klasse BroadcastReceiver muss nach dem Start des TV-Geräts ausgeführt werden, auf dem sie installiert ist. Registriere diese Klasse dazu in deinem App-Manifest mit einem Intent-Filter, der den Abschluss des Gerätestartprozesses ü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:Wenn Sie eine Benachrichtigung über den Abschluss des Bootvorgangs erhalten, muss Ihre App die Berechtigung RECEIVE_BOOT_COMPLETED anfordern. Weitere Informationen findest du unter ACTION_BOOT_COMPLETED.

In der Methode onHandleIntent() Ihrer Empfehlungsdienstklasse geben Sie die Empfehlung so an den Manager weiter:

Kotlin

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

Java

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