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

Kullanıcılar TV'lerle etkileşim kurarken genellikle içerik izlemeden önce minimum giriş yapmayı tercih eder. Birçok TV kullanıcısı için ideal senaryo şudur: Otur, aç ve izle. Kullanıcıları keyif aldıkları içeriğe ulaştırmak için gereken en az adım genellikle tercih ettikleri yoldur.

Not: Yalnızca Android 7.1 (API düzeyi 25) dahil olmak üzere bu sürümlerde çalışan uygulamalarda öneri sunmak için burada açıklanan API'leri kullanın. Android 8.0 (API düzeyi 26) ve sonraki sürümlerde çalışan uygulamalar için öneriler sunmak istiyorsanız uygulamanız öneri kanallarını kullanmalıdır.

Android çerçevesi, ana ekranda bir öneri satırı sağlayarak minimum girişli etkileşime yardımcı olur. İçerik önerileri, cihaz ilk kez kullanıldıktan sonra TV'nin ana ekranının ilk satırında gösterilir. Uygulamanızın içerik kataloğundan öneriler sunmak, kullanıcıları uygulamanıza geri çekmenize yardımcı olabilir.

Android TV ana ekranındaki öneriler satırının örneği
Şekil 1. Öneriler satırı örneği.

Bu kılavuzda, kullanıcıların uygulama içeriğinizi keşfedip keyifle kullanabilmesi için nasıl öneriler oluşturacağınız ve bunları Android çerçevesine nasıl sağlayacağınız açıklanmaktadır. Ayrıca Leanback örnek uygulamasındaki örnek uygulamaya da göz atın.

Önerilerle ilgili en iyi uygulamalar

Öneriler, kullanıcıların beğendikleri içerikleri ve uygulamaları hızlıca bulmalarına yardımcı olur. Yüksek kaliteli ve kullanıcılarla alakalı öneriler oluşturmak, TV uygulamanızla harika bir kullanıcı deneyimi oluşturmanın önemli bir faktörüdür. Bu nedenle, kullanıcıya sunduğunuz önerileri dikkatlice değerlendirmeniz ve yakından yönetmeniz gerekir.

Öneri türleri

Öneriler oluştururken kullanıcıları tamamlanmamış izleme etkinliklerine geri yönlendirmeli veya bu etkinlikleri ilgili içeriklerle genişleten etkinlikler önermelisiniz. Dikkate almanız gereken bazı öneri türleri şunlardır:

  • Kullanıcıların bir diziyi izlemeye devam etmesi için sonraki bölümle ilgili devam niteliğindeki içerik önerileri Alternatif olarak, duraklatılmış filmler, TV programları veya podcast'ler için devam ettirme önerilerini kullanabilirsiniz. Böylece kullanıcılar, duraklatılmış içerikleri birkaç tıklamayla izlemeye devam edebilir.
  • Kullanıcı başka bir diziyi bitirdiyse yeni içerik önerileri (ör. ilk gösterimdeki yeni bir bölüm) Ayrıca, uygulamanız kullanıcıların içeriğe abone olmasına, takip etmesine veya içeriği izlemesine olanak tanıyorsa, izlenen içerik listesindeki izlenmemiş öğeler için yeni içerik önerileri kullanın.
  • Kullanıcıların geçmiş görüntüleme davranışlarına dayalı ilgili içerik önerileri.

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

Önerileri yenile

Önerileri yenilerken bunları yalnızca kaldırıp yeniden yayınlamayın. Aksi takdirde öneriler, öneri satırının sonunda görünür. Bir içerik öğesi (ör. film) oynatıldıktan sonra önerilerden kaldırılır.

Ö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 öneri kartlarını markalama bilgilerini iletecek şekilde özelleştirebilirsiniz. Daha fazla bilgi edinmek için Android TV Tasarım Spesifikasyonu'ndaki Öneri Satırı bölümüne bakın.

Grup önerileri

İsteğe bağlı olarak önerileri öneri kaynağına göre gruplandırabilirsiniz. Örneğin, uygulamanız iki grup öneri sunabilir: kullanıcının abone olduğu içeriklerle ilgili öneriler ve kullanıcının farkında olmayabileceği yeni trend olan içeriklerle ilgili öneriler.

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

Bir önerinin grup anahtarı dizesini ayarlamak için NotificationCompat.Builder.setGroup() kullanın. Örneğin, bir öneriyi yeni trend olan içeriklerin bulunduğu bir gruba ait olarak işaretlemek için setGroup("trending") işlevini çağırabilirsiniz.

Bir öneri hizmeti oluşturun

İçerik önerileri arka planda işlenerek oluşturulur. Uygulamanızın önerilere katkıda bulunabilmesi için uygulamanızın kataloğundaki listelemeleri düzenli olarak sistemin öneri listesine ekleyen bir hizmet oluşturun.

Aşağıdaki kod örneğinde, uygulamanız için bir öneri hizmeti oluşturmak üzere IntentService'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 servisin sistem tarafından tanınması ve çalıştırılması için, uygulama manifestinizi kullanarak kaydınızı yaptırın. Aşağıdaki kod parçası, bu sınıfı bir hizmet olarak nasıl tanımlayacağınızı göstermektedir:

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

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

Öneriler oluşturun

Öneri servisiniz çalışmaya başladıktan sonra, öneriler oluşturmalı ve bunları Android çerçevesine iletmelidir. Çerçeve, önerileri belirli bir şablon kullanan ve belirli bir kategoriyle işaretlenmiş Notification nesneler olarak alır.

Değerlerin ayarlanması

Öneri kartı için kullanıcı arayüzü öğesi değerlerini ayarlamak için, aşağıdaki gibi açıklanan oluşturucu desenini izleyen bir oluşturucu sınıfı oluşturursunuz. Öncelikle, ö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ştur

Değerleri ayarladıktan sonra, oluşturucu sınıftan gelen değerleri bildirime atayarak ve NotificationCompat.Builder.build()'ı çağırarak bildirimi oluşturursunuz.

Ayrıca, NotificationCompat.BigPictureStyle bildiriminin diğer cihazlarda görünmemesi için setLocalOnly()'ı çağırdığınızdan emin olun.

Aşağıdaki kod örneği, bir öneri sisteminin nasıl oluşturulacağını göstermektedir.

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ın.

Uygulamanızın öneri servisi, güncel öneriler oluşturmak için düzenli aralıklarla çalışmalıdır. Servisinizi ç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, öneri hizmetinin her yarım saatte bir periyodik olarak çalıştırılmasını başlatmak için BroadcastReceiver sınıfını 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üklendiği TV cihazının başlatılmasından sonra çalıştırılmalıdır. Bunu yapmak için bu sınıfı, cihaz başlatma işleminin tamamlanmasını dinleyen bir intent filtresiyle uygulama manifestinize 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: Önyükleme tamamlandı bildirimini almak için uygulamanızın RECEIVE_BOOT_COMPLETED iznini istemesi gerekir. Daha fazla bilgi için ACTION_BOOT_COMPLETED sayfasına bakın.

Öneri hizmeti sınıfınızın onHandleIntent() yönteminde, öneriyi yöneticiye aşağıdaki şekilde gönderin:

Kotlin

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

Java

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