Kanal verileriyle çalışma

TV girişiniz, kurulum etkinliğinde en az bir kanal için Elektronik Program Rehberi (EPG) verileri sağlamalıdır. Ayrıca, güncellemenin boyutu ve bunu işleyen işleme iş parçacığı dikkate alınarak bu verileri düzenli olarak güncellemeniz gerekir. Ayrıca, kullanıcıyı ilgili içeriklere ve etkinliklere yönlendiren kanallar için uygulama bağlantıları da sağlayabilirsiniz. Bu derste, sistem veritabanında kanal ve program verilerinin oluşturulması ve güncellenmesiyle ilgili bilgiler verilmektedir.

TV Giriş Hizmeti örnek uygulamasını deneyin.

İzin alma

TV girişinizin EPG verileriyle çalışması için Android manifest dosyasında yazma iznini aşağıdaki şekilde tanımlaması gerekir:

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />

Kanalları veritabanına kaydetme

Android TV sistem veritabanı, TV girişleri için kanal verilerinin kayıtlarını tutar. Kurulum etkinliğinizde, her kanalınız için kanal verilerinizi TvContract.Channels sınıfının aşağıdaki alanlarıyla eşlemeniz gerekir:

TV girişi çerçevesi, geleneksel yayınları ve internet üzerinden yayınlanan (OTT) içerikleri herhangi bir ayrım yapmadan işleyecek kadar genel olsa da geleneksel yayın kanallarını daha iyi tanımlamak için aşağıdaki sütunları da tanımlamak isteyebilirsiniz:

Kanallarınız için uygulama bağlantısı ayrıntıları sağlamak istiyorsanız bazı ek alanları güncellemeniz gerekir. Uygulama bağlantısı alanları hakkında daha fazla bilgi için Uygulama bağlantısı bilgileri ekleme başlıklı makaleyi inceleyin.

İnternet üzerinden yayınlanan TV girişleri için her kanalın benzersiz şekilde tanımlanabilmesi amacıyla kendi değerlerinizi buna göre atayın.

Kanal meta verilerinizi (XML, JSON veya başka bir biçimde) arka uç sunucunuzdan çekin ve kurulum etkinliğinizde değerleri sistem veritabanıyla aşağıdaki gibi eşleyin:

Kotlin

val values = ContentValues().apply {
    put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, channel.number)
    put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.name)
    put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId)
    put(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId)
    put(TvContract.Channels.COLUMN_SERVICE_ID, channel.serviceId)
    put(TvContract.Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat)
}
val uri = context.contentResolver.insert(TvContract.Channels.CONTENT_URI, values)

Java

ContentValues values = new ContentValues();

values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.number);
values.put(Channels.COLUMN_DISPLAY_NAME, channel.name);
values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId);
values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId);
values.put(Channels.COLUMN_SERVICE_ID, channel.serviceId);
values.put(Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat);

Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);

Bu örnekte channel, arka uç sunucusundan gelen kanal meta verilerini içeren bir nesnedir.

Mevcut kanal ve program bilgileri

Sistem TV uygulaması, kullanıcılar kanallar arasında geçiş yaparken kanal ve program bilgilerini Şekil 1'de gösterildiği gibi sunar. Kanal ve program bilgilerinin, sistem TV uygulamasının kanal ve program bilgileri sunucusuyla çalıştığından emin olmak için aşağıdaki yönergeleri uygulayın:

  1. Kanal numarası (COLUMN_DISPLAY_NUMBER)
  2. Simge (TV girişinin manifest dosyasında android:icon)
  3. Program açıklaması (COLUMN_SHORT_DESCRIPTION)
  4. Program başlığı (COLUMN_TITLE)
  5. Kanal logosu (TvContract.Channels.Logo)
    • Çevredeki metinle eşleşmesi için #EEEEEE rengini kullanın
    • Dolgu malzemesi eklemeyin.
  6. Poster resmi (COLUMN_POSTER_ART_URI)
    • 16:9 ile 4:3 arasında en-boy oranı
Şekil 1. Sistem TV uygulaması kanal ve program bilgileri sunucusu.

Şekil 2'de gösterildiği gibi, sistem TV uygulaması, program rehberi aracılığıyla poster resmi de dahil olmak üzere aynı bilgileri sağlar.

Şekil 2. Sistem TV uygulaması program rehberi.

Kanal verilerini güncelleme

Mevcut kanal verilerini güncellerken verileri silip yeniden eklemek yerine update yöntemini kullanın. Güncellenecek kayıtları seçerken Channels.COLUMN_VERSION_NUMBER ve Programs.COLUMN_VERSION_NUMBER kullanarak verilerin mevcut sürümünü belirleyebilirsiniz.

Not: Kanal verilerinin ContentProvider'ye eklenmesi zaman alabilir. Yalnızca EpgSyncJobService öğenizi, kanal verilerinin geri kalanını arka planda güncelleyecek şekilde yapılandırdığınızda mevcut programları (mevcut saatten iki saat öncesine kadar olanlar) ekleyin. Örnek için Android TV'de Canlı TV Örnek Uygulaması'na bakın.

Kanal verilerini toplu yükleme

Sistem veritabanını büyük miktarda kanal verisiyle güncellerken ContentResolver applyBatch veya bulkInsert yöntemini kullanın. applyBatch kullanan bir örneği aşağıda bulabilirsiniz:

Kotlin

val ops = ArrayList<ContentProviderOperation>()
val programsCount = channelInfo.mPrograms.size
channelInfo.mPrograms.forEachIndexed { index, program ->
    ops += ContentProviderOperation.newInsert(
            TvContract.Programs.CONTENT_URI).run {
        withValues(programs[index])
        withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000)
        withValue(
                TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
                (programStartSec + program.durationSec) * 1000
        )
        build()
    }
    programStartSec += program.durationSec
    if (index % 100 == 99 || index == programsCount - 1) {
        try {
            contentResolver.applyBatch(TvContract.AUTHORITY, ops)
        } catch (e: RemoteException) {
            Log.e(TAG, "Failed to insert programs.", e)
            return
        } catch (e: OperationApplicationException) {
            Log.e(TAG, "Failed to insert programs.", e)
            return
        }
        ops.clear()
    }
}

Java

ArrayList<ContentProviderOperation> ops = new ArrayList<>();
int programsCount = channelInfo.mPrograms.size();
for (int j = 0; j < programsCount; ++j) {
    ProgramInfo program = channelInfo.mPrograms.get(j);
    ops.add(ContentProviderOperation.newInsert(
            TvContract.Programs.CONTENT_URI)
            .withValues(programs.get(j))
            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
                    programStartSec * 1000)
            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
                    (programStartSec + program.durationSec) * 1000)
            .build());
    programStartSec = programStartSec + program.durationSec;
    if (j % 100 == 99 || j == programsCount - 1) {
        try {
            getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
        } catch (RemoteException | OperationApplicationException e) {
            Log.e(TAG, "Failed to insert programs.", e);
            return;
        }
        ops.clear();
    }
}

Kanal verilerini eşzamansız olarak işleme

Sunucudan veri akışı alma veya veritabanına erişme gibi veri manipülasyonu işlemleri, kullanıcı arayüzü iş parçacığını engellememelidir. Güncellemeleri eşzamansız olarak gerçekleştirmek için AsyncTask kullanabilirsiniz. Örneğin, arka uç sunucusundan kanal bilgileri yüklerken AsyncTask öğesini aşağıdaki gibi kullanabilirsiniz:

Kotlin

private class LoadTvInputTask(val context: Context) : AsyncTask<Uri, Unit, Unit>() {

    override fun doInBackground(vararg uris: Uri) {
        try {
            fetchUri(uris[0])
        } catch (e: IOException) {
            Log.d("LoadTvInputTask", "fetchUri error")
        }
    }

    @Throws(IOException::class)
    private fun fetchUri(videoUri: Uri) {
        context.contentResolver.openInputStream(videoUri).use { inputStream ->
            Xml.newPullParser().also { parser ->
                try {
                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
                    parser.setInput(inputStream, null)
                    sTvInput = ChannelXMLParser.parseTvInput(parser)
                    sSampleChannels = ChannelXMLParser.parseChannelXML(parser)
                } catch (e: XmlPullParserException) {
                    e.printStackTrace()
                }
            }
        }
    }
}

Java

private static class LoadTvInputTask extends AsyncTask<Uri, Void, Void> {

    private Context mContext;

    public LoadTvInputTask(Context context) {
        mContext = context;
    }

    @Override
    protected Void doInBackground(Uri... uris) {
        try {
            fetchUri(uris[0]);
        } catch (IOException e) {
          Log.d("LoadTvInputTask", "fetchUri error");
        }
        return null;
    }

    private void fetchUri(Uri videoUri) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = mContext.getContentResolver().openInputStream(videoUri);
            XmlPullParser parser = Xml.newPullParser();
            try {
                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
                parser.setInput(inputStream, null);
                sTvInput = ChannelXMLParser.parseTvInput(parser);
                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }
}

EPG verilerini düzenli olarak güncellemeniz gerekiyorsa, aşağıdaki yöntemi kullanmayı düşünün.WorkManager Güncelleme işlemini, örneğin her gün sabah 3:00'te olduğu gibi, boş zamanlarda çalıştırmak.

Veri güncelleme görevlerini kullanıcı arayüzü iş parçacığından ayırmak için HandlerThread sınıfını kullanabilirsiniz. Alternatif olarak, Looper ve Handler sınıflarını kullanarak kendi çözümünüzü de uygulayabilirsiniz. Daha fazla bilgi için İşlemler ve iş parçacıkları başlıklı makaleyi inceleyin.

Kanallar, kullanıcıların kanal içeriğini izlerken ilgili bir etkinliği başlatmasına olanak tanımak için uygulama bağlantılarını kullanabilir. Kanal uygulamaları, ilgili bilgileri veya ek içerikleri gösteren etkinlikler başlatarak kullanıcı etkileşimini artırmak için uygulama bağlantılarını kullanır. Örneğin, uygulama bağlantılarını aşağıdaki amaçlarla kullanabilirsiniz:

  • Kullanıcıyı ilgili içerikleri keşfetmeye ve satın almaya yönlendirin.
  • Oynatılmakta olan içerikle ilgili ek bilgiler sağlayın.
  • Bölümler halinde yayınlanan içerikleri izlerken, dizinin bir sonraki bölümünü izlemeye başlayın.
  • Kullanıcının içerikle etkileşim kurmasına (örneğin, içeriği değerlendirmesine veya yorumlamasına) olanak tanıyın, ancak içerik oynatımını kesintiye uğratmayın.

Kullanıcı, kanal içeriğini izlerken TV menüsünü göstermek için Seç'e bastığında uygulama bağlantıları gösterilir.

Şekil 1. Kanal içeriği gösterilirken Kanallar satırında gösterilen örnek bir uygulama bağlantısı.

Kullanıcı uygulama bağlantısını seçtiğinde sistem, kanal uygulaması tarafından belirtilen bir intent URI'si kullanarak bir etkinlik başlatır. Uygulama bağlantısı etkinliği devam ederken kanal içeriği oynatılmaya devam eder. Kullanıcı, Geri'ye basarak kanal içeriğine dönebilir.

Uygulama bağlantısı kanal verilerini sağlama

Android TV, kanal verilerinden aldığı bilgileri kullanarak her kanal için otomatik olarak bir uygulama bağlantısı oluşturur. Uygulama bağlantısı bilgilerini sağlamak için, TvContract.Channels alanlarınızda aşağıdaki ayrıntıları belirtin:

  • COLUMN_APP_LINK_COLOR - Bu kanal için uygulama bağlantısının vurgu rengi. Örnek bir vurgu rengi için Şekil 2, açıklama metni 3'e bakın.
  • COLUMN_APP_LINK_ICON_URI - Bu kanalın uygulama bağlantısına ait uygulama rozeti simgesinin URI'si. Örnek uygulama rozeti simgesi için şekil 2, açıklama metni 2'ye bakın.
  • COLUMN_APP_LINK_INTENT_URI - Bu kanal için uygulama bağlantısının intent URI'si. URI'yi toUri(int) ile URI_INTENT_SCHEME kullanarak oluşturabilir ve parseUri ile URI'yi orijinal amaca geri dönüştürebilirsiniz.
  • COLUMN_APP_LINK_POSTER_ART_URI - Bu kanalın uygulama bağlantısının arka planı olarak kullanılan poster resminin URI'si. Örnek poster resmi için Şekil 2, açıklama metni 1'e bakın.
  • COLUMN_APP_LINK_TEXT: Bu kanal için uygulama bağlantısının açıklayıcı bağlantı metni. Örnek bir uygulama bağlantısı açıklaması için Şekil 2'deki 3 numaralı açıklama metnine bakın.
Şekil 2. Uygulama bağlantı detayları.

Kanal verilerinde uygulama bağlantısı bilgileri belirtilmemişse sistem varsayılan bir uygulama bağlantısı oluşturur. Sistem, varsayılan ayrıntıları aşağıdaki şekilde seçer:

  • Amaç URI'si (COLUMN_APP_LINK_INTENT_URI) için sistem, genellikle uygulama manifestinde tanımlanan CATEGORY_LEANBACK_LAUNCHER kategorisi için ACTION_MAIN etkinliğini kullanır. Bu etkinlik tanımlanmazsa çalışmayan bir uygulama bağlantısı gösterilir. Kullanıcı bu bağlantıyı tıkladığında hiçbir şey olmaz.
  • Açıklayıcı metin için (COLUMN_APP_LINK_TEXT) sistem "app-name uygulamasını aç" ifadesini kullanır. Geçerli bir uygulama bağlantısı amaç URI'si tanımlanmamışsa sistem "Bağlantı yok" ifadesini kullanır.
  • Vurgu rengi (COLUMN_APP_LINK_COLOR) için sistem, varsayılan uygulama rengini kullanır.
  • Sistem, poster resmi ( COLUMN_APP_LINK_POSTER_ART_URI) için uygulamanın ana ekran banner'ını kullanır. Uygulama banner sağlamıyorsa sistem varsayılan bir TV uygulaması resmi kullanır.
  • Rozet simgesi (COLUMN_APP_LINK_ICON_URI) için sistem, uygulama adını gösteren bir rozet kullanır. Sistem, poster resmi için uygulama banner'ını veya varsayılan uygulama resmini de kullanıyorsa uygulama rozeti gösterilmez.

Kanallarınız için uygulama bağlantısı ayrıntılarını uygulamanızın kurulum etkinliğinde belirtirsiniz. Bu uygulama bağlantısı ayrıntılarını istediğiniz zaman güncelleyebilirsiniz. Bu nedenle, bir uygulama bağlantısının kanal değişiklikleriyle eşleşmesi gerekiyorsa uygulama bağlantısı ayrıntılarını güncelleyin ve gerektiğinde ContentResolver.update işlevini çağırın. Kanal verilerini güncelleme hakkında daha fazla bilgi için Kanal verilerini güncelleme başlıklı makaleyi inceleyin.