Android N ve önceki sürümlerde öneriler

Kullanıcılar TV'lerle etkileşimde bulunurken genellikle içeriği izlemeden önce çok az giriş yapmayı tercih ederler. Birçok TV kullanıcısı için ideal senaryo, oturun, cihazınızı açın ve izleyin. Kullanıcıları beğendikleri içeriğe götürecek en az adım, genellikle tercih ettikleri yoldur.

Not: Yalnızca Android 7.1 (API düzeyi 25) dahil olmak üzere Android sürümlerinde çalışan uygulamalarda önerilerde bulunmak için burada açıklanan API'leri kullanın. Android 8.0 (API düzeyi 26) ve sonraki sürümlerde çalışan uygulamalara yönelik öneriler sağlamak için uygulamanızın öneri kanallarını kullanması gerekir.

Android çerçevesi, ana ekranda bir öneri satırı sağlayarak minimum giriş etkileşimine yardımcı olur. İçerik önerileri, cihaz ilk kullanıldıktan sonra TV ana ekranının ilk satırı olarak görünür. Uygulamanızın içerik kataloğundan katkıda bulunan öneriler, kullanıcıların uygulamanıza geri dönmesine yardımcı olabilir.

Şekil 1. Öneriler satırı örneği.

Bu kılavuzda, kullanıcıların uygulama içeriğinizi kolayca keşfedip keyfini çıkarabilmeleri için önerileri nasıl oluşturacağınızı ve Android çerçevesine nasıl sağlayacağınızı öğrenebilirsiniz. Leanback örnek uygulamasında örnek uygulamaya da bakın.

Öneriler için en iyi uygulamalar

Öneriler, kullanıcıların beğendikleri içerikleri ve uygulamaları hızlı bir şekilde bulmalarına yardımcı olur. Yüksek kaliteli ve kullanıcılar için alakalı öneriler oluşturmak, TV uygulamanızla mükemmel bir kullanıcı deneyimi oluşturmak için önemli bir faktördür. Bu nedenle, kullanıcıya hangi önerileri sunduğunuzu dikkatlice düşünmeli ve bu önerileri yakından yönetmelisiniz.

Öneri türleri

Öneriler oluşturduğunuzda, kullanıcıları tamamlanmamış görüntüleme etkinliklerine yönlendirmeli veya bunları alakalı içeriğe genişleten etkinlikler önermelisiniz. Dikkate almanız gereken bazı öneri türleri şunlardır:

  • Kullanıcıların bir diziyi izlemeye devam etmeleri için sonraki bölüm için devamlı içerik önerileri. Alternatif olarak, duraklatılmış filmlere, TV programlarına veya podcast'lere yönelik devam önerilerini kullanabilirsiniz. Böylece kullanıcılar, duraklatılmış içerikleri yalnızca birkaç tıklamayla izlemeye devam edebilir.
  • Yeni içerik önerileri (ör. kullanıcı başka bir diziyi izlemeyi bitirmişse yeni bir ilk bölüm için). Ayrıca uygulamanız, kullanıcıların içeriğe abone olma, takip etme veya takip etme olanağı sunuyorsa izlenen içerik listelerindeki izlenmemiş öğeler için yeni içerik önerilerinden yararlanın.
  • Kullanıcıların geçmişteki izleme davranışlarına dayalı alakalı içerik önerileri.

En iyi kullanıcı deneyimi için öneri kartlarının nasıl tasarlanacağı hakkında daha fazla bilgi edinmek için Android TV Tasarım Spesifikasyonu'nda Öneri Satırı bölümüne bakın.

Önerileri yenile

Önerileri yenilerken bunları kaldırıp yeniden yayınlamayın. Aksi takdirde öneriler, öneriler satırının sonunda gösterilir. Film gibi bir içerik öğesi oynatıldığında bu öğeyi önerilerden kaldırın.

Önerileri özelleştir

Kartın ön ve arka plan resmi, rengi, uygulama simgesi, başlığı ve alt başlığı gibi kullanıcı arayüzü öğelerini ayarlayarak marka bilgilerini iletmek için öneri kartlarını özelleştirebilirsiniz. Daha fazla bilgi edinmek için Android TV Tasarım Spesifikasyonu'nda Öneri Satırı bölümüne bakın.

Grup önerileri

Dilerseniz önerileri öneri kaynağına göre gruplandırabilirsiniz. Örneğin, uygulamanız iki öneri grubu sunabilir: kullanıcının abone olduğu içerikle ilgili öneriler ve kullanıcının farkında olmayabileceği trend olan yeni içerikle ilgili öneriler.

Sistem, öneri satırını oluştururken veya güncellerken her grup için önerileri ayrı ayrı sıralar ve sıralar. Önerileriniz için grup bilgileri sağlayarak önerilerinizin alakasız önerilerin altında sıralanmamasını sağlayabilirsiniz.

Bir önerinin grup anahtarı dizesini ayarlamak için NotificationCompat.Builder.setGroup() kullanın. Örneğin, bir öneriyi trend olan yeni içerik barındıran bir gruba ait olarak işaretlemek için setGroup("trending") yöntemini çağırabilirsiniz.

Öneri hizmeti oluşturma

İçerik önerileri, arka planda işleme kullanılarak oluşturulur. Uygulamanızın önerilere katkıda bulunması için girişleri düzenli olarak uygulamanızın kataloğundan sistemin öneri listesine ekleyen bir hizmet oluşturun.

Aşağıdaki kod örneğinde, uygulamanız için bir öneri hizmeti oluşturmak amacıyla IntentService kapsamının nasıl genişletileceği gösterilmektedir:

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

Bu hizmetin sistem tarafından tanınabilmesi ve çalışması için uygulama manifestinizi kullanarak kaydedin. Aşağıdaki kod snippet'inde, bu sınıfın bir hizmet olarak nasıl tanımlanacağı gösterilmektedir:

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

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

Derleme önerileri

Öneri hizmetiniz çalışmaya başladıktan sonra öneriler oluşturması ve bunları Android çerçevesine iletmesi gerekir. Çerçeve, önerileri belirli bir şablonu kullanan ve belirli bir kategoriyle işaretlenmiş Notification nesneleri olarak alır.

Değerleri ayarlama

Öneri kartının kullanıcı arayüzü öğesi değerlerini ayarlamak için, aşağıda açıklanan oluşturucu kalıbını izleyen bir derleyici sınıfı oluşturursunuz. İlk olarak, öneri kartı öğelerinin değerlerini ayarlarsınız.

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

Bildirimi oluşturma

Değerleri ayarladıktan sonra, derleyici sınıfındaki değerleri bildirime atayarak bildirimi derler ve NotificationCompat.Builder.build() yöntemini çağırırsınız.

Ayrıca, NotificationCompat.BigPictureStyle bildiriminin diğer cihazlarda görünmemesi için setLocalOnly() adlı çağrıyı aramayı unutmayın.

Aşağıdaki kod örneği, önerilerin nasıl oluşturulacağını gösterir.

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

Öneri hizmetini çalıştır

Güncel öneriler oluşturmak için uygulamanızın öneri hizmeti düzenli aralıklarla çalışmalıdır. Hizmetinizi çalıştırmak için bir zamanlayıcı çalıştıran ve bunu düzenli aralıklarla çağıran bir sınıf oluşturun. Aşağıdaki kod örneği, BroadcastReceiver sınıfını, bir öneri hizmetinin yarım saatte bir periyodik olarak yürütmesini başlatacak şekilde genişletir:

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

BroadcastReceiver sınıfının bu uygulaması, yüklü olduğu TV cihazı başlatıldıktan sonra çalıştırılmalıdır. Bunu başarmak için bu sınıfı uygulama manifestinizde, cihaz başlatma işleminin tamamlanmasını izleyen bir intent filtresiyle kaydedin. Aşağıdaki örnek kod, bu yapılandırmanın manifest dosyasına nasıl ekleneceğini göstermektedir:

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

Önemli: Başlatma tamamlandı bildirimi almak için uygulamanızın RECEIVE_BOOT_COMPLETED iznini istemesi gerekir. Daha fazla bilgi için ACTION_BOOT_COMPLETED başlıklı makaleyi inceleyin.

Öneri hizmet sınıfınızın onHandleIntent() yönteminde öneriyi yöneticiye aşağıdaki şekilde yayınlayın:

Kotlin

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

Java

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