Kanal verileriyle çalışma

TV girişiniz, kurulum etkinliğindeki en az bir kanal için Elektronik Program Rehberi (EPG) verileri sağlamalıdır. Ayrıca, güncellemenin boyutunu ve bunu yapan işleme iş parçacığını göz önünde bulundurarak bu verileri düzenli olarak güncellemeniz gerekir. Ayrıca, kullanıcıyı ilgili içerik ve etkinliklere yönlendiren kanallar için uygulama bağlantıları sağlayabilirsiniz. Bu derste, bu hususlar göz önünde bulundurularak sistem veritabanında kanal ve program verileri oluşturma ve güncelleme konuları ele alınmaktadır.

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

İzin al

TV girişinizin EPG verileriyle çalışması için Android manifest dosyasında yazma iznini aşağıdaki gibi beyan etmesi gerekir:

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

Kanalları veritabanına kaydet

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

TV giriş çerçevesi, hem geleneksel yayını hem de baypas (OTT) içeriğini herhangi bir ayrım olmaksızın işleyecek kadar genel olsa da geleneksel yayın kanallarını daha iyi tanımlamak için yukarıdakilere ek olarak 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 bölümüne bakın.

İnternet akışı tabanlı TV girişleri için yukarıdakilere kendi değerlerinizi atayın. Böylece her kanal benzersiz bir şekilde tanımlanabilir.

Kanal meta verilerinizi (XML, JSON veya başka bir şekilde) arka uç sunucunuzdan alın 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);

Yukarıdaki örnekte channel, kanal meta verilerini arka uç sunucusundan tutan bir nesnedir.

Kanal ve program bilgilerini sunma

Sistem TV uygulaması, kanallar arasında gezinirken kullanıcılara kanal ve program bilgilerini sunar. Örnek olarak Şekil 1'de gösterildiği gibi. Kanal ve program bilgilerinin sistem TV uygulamasının kanal ve program bilgisi 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ştirmek için #EEEEEE rengini kullanın
    • Dolgu 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 bilgisi sunucusu.

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

2. Şekil. Sistem TV uygulaması program rehberi.

Kanal verilerini güncelle

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 güncel sürümünü belirleyebilirsiniz.

Not: Kanal verilerinin ContentProvider öğesine eklenmesi zaman alabilir. Mevcut programları (geçerli saatten sonraki iki saat içindekiler) yalnızca EpgSyncJobService cihazınızı, geri kalan kanal verilerini arka planda güncelleyecek şekilde yapılandırdığınızda ekleyin. Örnek için Android TV Canlı TV Örnek Uygulaması'na göz atın.

Kanal verilerini toplu yükleme

Sistem veritabanını büyük miktarda kanal verisi içerecek şekilde 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şleyin

Sunucudan akış getirme veya veritabanına erişme gibi veri manipülasyonları, kullanıcı arayüzü iş parçacığını engellememelidir. Güncellemeleri eşzamansız olarak gerçekleştirmenin bir yolu da AsyncTask kullanmaktır. Örneğin, bir arka uç sunucusundan kanal bilgilerini yüklerken AsyncTask öğesini aşağıdaki şekilde 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 güncelleme işlemini boşta kalma sürelerinde (ör.her gün saat 03:00'te) çalıştırmak için WorkManager kullanabilirsiniz.

Veri güncelleme görevlerini kullanıcı arayüzü iş parçacığından ayırmak için kullanılan diğer teknikler arasında HandlerThread sınıfını kullanmak yer alır. Dilerseniz Looper ve Handler sınıflarını kullanarak kendi analizinizi de uygulayabilirsiniz. Daha fazla bilgi için İşlemler ve iş parçacıkları bölümüne bakın.

Kanallar, kullanıcıların kanal içeriğini izlerken ilgili bir etkinliği kolayca başlatmalarını sağlamak için uygulama bağlantılarını kullanabilir. Kanal uygulamaları, alakalı bilgiler veya ek içerikler gösteren etkinlikler başlatarak kullanıcı etkileşimini artırmak için uygulama bağlantılarını kullanır. Örneğin, aşağıdakileri yapmak için uygulama bağlantılarını kullanabilirsiniz:

  • Kullanıcıyı ilgili içeriği keşfetmeye ve satın almaya yönlendirin.
  • Şu anda oynatılan içerik hakkında ek bilgi sağlayın.
  • Bölümlerden oluşan içerikleri görüntülerken dizideki bir sonraki bölümü izlemeye başlayın.
  • Kullanıcının içerik oynatmayı kesintiye uğratmadan içerikle etkileşim kurmasına (örneğin, içeriği derecelendirmesine veya incelemesine) izin verin.

Uygulama bağlantıları, kullanıcı kanal içeriğini izlerken TV menüsünü göstermek için Seç'e bastığında 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 amaç URI'sını kullanarak bir etkinlik başlatır. Uygulama bağlantısı etkinliği etkinken kanal içeriği oynatılmaya devam eder. Kullanıcı, Geri'ye basarak kanal içeriğine geri dönebilir.

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

Android TV, kanal verilerindeki bilgileri kullanarak her kanal için otomatik olarak bir uygulama bağlantısı oluşturur. Uygulama bağlantısı bilgileri 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. Vurgu rengi örneği için Şekil 2, açıklama metni 3'e bakın.
  • COLUMN_APP_LINK_ICON_URI - Bu kanalın uygulama bağlantısının uygulama rozeti simgesine ait URI. Örnek bir 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'sı. URI'yı URI_INTENT_SCHEME ile toUri(int) kullanarak oluşturabilir ve URI'yı parseUri() ile tekrar orijinal amaca 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ın uygulama bağlantısının açıklayıcı bağlantı metni. Örnek bir uygulama bağlantısı açıklaması için şekil 2, açıklama metni 3'teki metne bakın.

2. Şekil. Uygulama bağlantısı ayrıntıları.

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'sı (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ımlanmamışsa çalışmayan bir uygulama bağlantısı görüntülenir. Kullanıcı bu bağlantıyı tıklarsa hiçbir şey olmaz.
  • Açıklayıcı metin (COLUMN_APP_LINK_TEXT) için sistem, "app-name uygulamasını aç" seçeneğini kullanır. Geçerli bir uygulama bağlantısı amacı URI'si tanımlanmamışsa sistem, "Kullanılabilir bağlantı yok" ifadesini kullanır.
  • Vurgu rengi (COLUMN_APP_LINK_COLOR) için sistem, varsayılan uygulama rengini kullanır.
  • Poster resmi (COLUMN_APP_LINK_POSTER_ART_URI) için sistem, uygulamanın ana ekran banner'ını kullanır. Uygulama banner sağlamıyorsa sistem, varsayılan TV uygulaması resmini kullanır.
  • Sistem, rozet simgesi (COLUMN_APP_LINK_ICON_URI) için uygulama adını gösteren bir rozet kullanır. Sistem ayrıca poster resmi için uygulama banner'ını veya varsayılan uygulama resmini kullanıyorsa uygulama rozeti gösterilmez.

Kanallarınızın 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. Böylece 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() numaralı telefonu arayın. Kanal verilerini güncelleme hakkında daha fazla bilgi için Kanal verilerini güncelleme bölümüne bakın.