চ্যানেল ডেটা নিয়ে কাজ করুন

আপনার টিভি ইনপুট এর সেটআপ কার্যকলাপে অন্তত একটি চ্যানেলের জন্য ইলেকট্রনিক প্রোগ্রাম গাইড (EPG) ডেটা প্রদান করতে হবে। আপডেটের আকার এবং এটি পরিচালনাকারী প্রসেসিং থ্রেড বিবেচনা করে আপনাকে পর্যায়ক্রমে সেই ডেটা আপডেট করতে হবে। উপরন্তু, আপনি চ্যানেলগুলির জন্য অ্যাপ লিঙ্ক প্রদান করতে পারেন যা ব্যবহারকারীকে সম্পর্কিত বিষয়বস্তু এবং ক্রিয়াকলাপগুলিতে গাইড করে। এই পাঠটি এই বিবেচনাগুলি মাথায় রেখে সিস্টেম ডাটাবেসে চ্যানেল এবং প্রোগ্রাম ডেটা তৈরি এবং আপডেট করার বিষয়ে আলোচনা করে।

টিভি ইনপুট পরিষেবার নমুনা অ্যাপ ব্যবহার করে দেখুন।

অনুমতি নিন

আপনার টিভি ইনপুট ইপিজি ডেটার সাথে কাজ করার জন্য, এটিকে অবশ্যই তার Android ম্যানিফেস্ট ফাইলে লেখার অনুমতি নিম্নরূপ ঘোষণা করতে হবে:

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

ডাটাবেসে চ্যানেল নিবন্ধন করুন

অ্যান্ড্রয়েড টিভি সিস্টেম ডাটাবেস টিভি ইনপুটগুলির জন্য চ্যানেল ডেটার রেকর্ড বজায় রাখে। আপনার সেটআপ কার্যকলাপে, আপনার প্রতিটি চ্যানেলের জন্য, আপনাকে অবশ্যই আপনার চ্যানেলের ডেটা TvContract.Channels ক্লাসের নিম্নলিখিত ক্ষেত্রগুলিতে ম্যাপ করতে হবে:

  • COLUMN_DISPLAY_NAME - চ্যানেলের প্রদর্শিত নাম
  • COLUMN_DISPLAY_NUMBER - প্রদর্শিত চ্যানেল নম্বর
  • COLUMN_INPUT_ID - টিভি ইনপুট পরিষেবার ID৷
  • COLUMN_SERVICE_TYPE - চ্যানেলের পরিষেবার ধরন
  • COLUMN_TYPE - চ্যানেলের সম্প্রচারের মানক প্রকার
  • COLUMN_VIDEO_FORMAT - চ্যানেলের জন্য ডিফল্ট ভিডিও বিন্যাস

যদিও টিভি ইনপুট ফ্রেমওয়ার্ক প্রথাগত সম্প্রচার এবং ওভার-দ্য-টপ (OTT) উভয় বিষয়বস্তুকে কোনো পার্থক্য ছাড়াই পরিচালনা করার জন্য যথেষ্ট জেনেরিক, আপনি ঐতিহ্যগত সম্প্রচার চ্যানেলগুলিকে আরও ভালভাবে সনাক্ত করতে উপরের কলামগুলি ছাড়াও নিম্নলিখিত কলামগুলিকে সংজ্ঞায়িত করতে চাইতে পারেন:

আপনি যদি আপনার চ্যানেলগুলির জন্য অ্যাপ লিঙ্কের বিশদ বিবরণ দিতে চান তবে আপনাকে কিছু অতিরিক্ত ক্ষেত্র আপডেট করতে হবে। অ্যাপ লিঙ্ক ক্ষেত্র সম্পর্কে আরও তথ্যের জন্য, অ্যাপ লিঙ্ক তথ্য যোগ করুন দেখুন।

ইন্টারনেট স্ট্রিমিং ভিত্তিক টিভি ইনপুটগুলির জন্য, সেই অনুযায়ী উপরে আপনার নিজস্ব মানগুলি বরাদ্দ করুন যাতে প্রতিটি চ্যানেলকে স্বতন্ত্রভাবে চিহ্নিত করা যায়।

আপনার ব্যাকএন্ড সার্ভার থেকে আপনার চ্যানেলের মেটাডেটা (এক্সএমএল, জেএসওএন, বা যাই হোক না কেন) টেনে আনুন এবং আপনার সেটআপ কার্যকলাপে সিস্টেম ডাটাবেসের মানগুলি নিম্নরূপ মানচিত্র করুন:

কোটলিন

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)

জাভা

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

উপরের উদাহরণে, channel হল একটি বস্তু যা ব্যাকএন্ড সার্ভার থেকে চ্যানেল মেটাডেটা ধারণ করে।

চ্যানেল এবং প্রোগ্রামের তথ্য উপস্থাপন করুন

সিস্টেম টিভি অ্যাপ ব্যবহারকারীদের চ্যানেল এবং প্রোগ্রামের তথ্য উপস্থাপন করে যখন তারা চ্যানেলের মাধ্যমে ফ্লিপ করে, যেমন চিত্র 1-এ দেখানো হয়েছে। চ্যানেল এবং প্রোগ্রাম তথ্য সিস্টেম টিভি অ্যাপের চ্যানেল এবং প্রোগ্রাম তথ্য উপস্থাপকের সাথে কাজ করে তা নিশ্চিত করতে, নীচের নির্দেশিকা অনুসরণ করুন।

  1. চ্যানেল নম্বর ( COLUMN_DISPLAY_NUMBER )
  2. আইকন ( android:icon )
  3. প্রোগ্রামের বিবরণ ( COLUMN_SHORT_DESCRIPTION )
  4. প্রোগ্রাম শিরোনাম ( COLUMN_TITLE )
  5. চ্যানেল লোগো ( TvContract.Channels.Logo )
    • আশেপাশের পাঠ্যের সাথে মেলে #EEEEEE রঙটি ব্যবহার করুন
    • প্যাডিং অন্তর্ভুক্ত করবেন না
  6. পোস্টার আর্ট ( COLUMN_POSTER_ART_URI )
    • 16:9 এবং 4:3 এর মধ্যে আকৃতির অনুপাত

চিত্র 1. সিস্টেম টিভি অ্যাপ চ্যানেল এবং প্রোগ্রাম তথ্য উপস্থাপক।

সিস্টেম টিভি অ্যাপটি প্রোগ্রাম গাইডের মাধ্যমে একই তথ্য প্রদান করে, পোস্টার আর্ট সহ, চিত্র 2 এ দেখানো হয়েছে।

চিত্র 2. সিস্টেম টিভি অ্যাপ প্রোগ্রাম গাইড।

চ্যানেল ডেটা আপডেট করুন

বিদ্যমান চ্যানেল ডেটা আপডেট করার সময়, ডেটা মুছে ফেলা এবং পুনরায় যোগ করার পরিবর্তে update() পদ্ধতি ব্যবহার করুন। আপনি Channels.COLUMN_VERSION_NUMBER ব্যবহার করে ডেটার বর্তমান সংস্করণ সনাক্ত করতে পারেন৷ COLUMN_VERSION_NUMBER এবং Programs.COLUMN_VERSION_NUMBER আপডেট করার জন্য রেকর্ডগুলি বেছে নেওয়ার সময়৷

দ্রষ্টব্য: ContentProvider এ চ্যানেল ডেটা যোগ করতে সময় লাগতে পারে। বর্তমান প্রোগ্রামগুলি যোগ করুন (যেগুলি বর্তমান সময়ের দুই ঘন্টার মধ্যে) শুধুমাত্র যখন আপনি আপনার EpgSyncJobService কনফিগার করবেন পটভূমিতে চ্যানেলের বাকি ডেটা আপডেট করতে৷ একটি উদাহরণের জন্য Android TV লাইভ টিভি নমুনা অ্যাপটি দেখুন।

ব্যাচ লোড হচ্ছে চ্যানেল ডেটা

প্রচুর পরিমাণে চ্যানেল ডেটা সহ সিস্টেম ডাটাবেস আপডেট করার সময়, ContentResolver applyBatch() বা bulkInsert() পদ্ধতি ব্যবহার করুন। এখানে applyBatch() ব্যবহার করে একটি উদাহরণ রয়েছে:

কোটলিন

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

জাভা

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

চ্যানেল ডেটা অ্যাসিঙ্ক্রোনাসভাবে প্রক্রিয়া করুন

ডেটা ম্যানিপুলেশন, যেমন সার্ভার থেকে একটি স্ট্রিম আনা বা ডাটাবেস অ্যাক্সেস করা, UI থ্রেড ব্লক করা উচিত নয়। একটি AsyncTask ব্যবহার করা অ্যাসিঙ্ক্রোনাসভাবে আপডেটগুলি সম্পাদন করার একটি উপায়। উদাহরণস্বরূপ, একটি ব্যাকএন্ড সার্ভার থেকে চ্যানেলের তথ্য লোড করার সময়, আপনি নিম্নরূপ AsyncTask ব্যবহার করতে পারেন:

কোটলিন

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

জাভা

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 ডেটা আপডেট করার প্রয়োজন হয়, অলস সময়ে আপডেট প্রক্রিয়া চালানোর জন্য WorkManager ব্যবহার করার কথা বিবেচনা করুন, যেমন প্রতিদিন সকাল 3:00 এ

UI থ্রেড থেকে ডেটা আপডেটের কাজগুলিকে আলাদা করার অন্যান্য কৌশলগুলির মধ্যে রয়েছে HandlerThread ক্লাস ব্যবহার করা, অথবা আপনি Looper এবং Handler ক্লাস ব্যবহার করে আপনার নিজস্ব প্রয়োগ করতে পারেন। আরও তথ্যের জন্য প্রসেস এবং থ্রেড দেখুন।

ব্যবহারকারীরা চ্যানেলের বিষয়বস্তু দেখার সময় একটি সম্পর্কিত কার্যকলাপ সহজে চালু করতে চ্যানেলগুলি অ্যাপ লিঙ্কগুলি ব্যবহার করতে পারে৷ চ্যানেল অ্যাপ্লিকেশানগুলি সম্পর্কিত তথ্য বা অতিরিক্ত সামগ্রী দেখায় এমন ক্রিয়াকলাপগুলি চালু করে ব্যবহারকারীর ব্যস্ততা বাড়াতে অ্যাপ লিঙ্কগুলি ব্যবহার করে৷ উদাহরণস্বরূপ, আপনি নিম্নলিখিতগুলি করতে অ্যাপ্লিকেশন লিঙ্কগুলি ব্যবহার করতে পারেন:

  • সংশ্লিষ্ট বিষয়বস্তু আবিষ্কার ও ক্রয় করতে ব্যবহারকারীকে গাইড করুন।
  • বর্তমানে কন্টেন্ট প্লে করা সম্পর্কে অতিরিক্ত তথ্য প্রদান করুন।
  • এপিসোডিক বিষয়বস্তু দেখার সময়, একটি সিরিজের পরবর্তী পর্ব দেখা শুরু করুন।
  • ব্যবহারকারীকে কন্টেন্টের সাথে ইন্টারঅ্যাক্ট করতে দিন—উদাহরণস্বরূপ, কন্টেন্ট রেট বা পর্যালোচনা করুন—কন্টেন্ট প্লেব্যাকে বাধা না দিয়ে।

চ্যানেলের বিষয়বস্তু দেখার সময় ব্যবহারকারী টিভি মেনু দেখানোর জন্য নির্বাচন চাপলে অ্যাপের লিঙ্কগুলি প্রদর্শিত হয়।

চিত্র 1. চ্যানেলের বিষয়বস্তু দেখানোর সময় চ্যানেলের সারিতে প্রদর্শিত একটি উদাহরণ অ্যাপ লিঙ্ক।

যখন ব্যবহারকারী অ্যাপ লিঙ্কটি নির্বাচন করে, সিস্টেমটি চ্যানেল অ্যাপ দ্বারা নির্দিষ্ট করা একটি অভিপ্রায় URI ব্যবহার করে একটি কার্যকলাপ শুরু করে। অ্যাপ লিঙ্ক অ্যাক্টিভিটি সক্রিয় থাকাকালীন চ্যানেলের বিষয়বস্তু চলতে থাকে। ব্যাক টিপে ব্যবহারকারী চ্যানেলের বিষয়বস্তুতে ফিরে যেতে পারেন।

অ্যাপ লিঙ্ক চ্যানেল ডেটা প্রদান করুন

চ্যানেল ডেটা থেকে তথ্য ব্যবহার করে Android TV স্বয়ংক্রিয়ভাবে প্রতিটি চ্যানেলের জন্য একটি অ্যাপ লিঙ্ক তৈরি করে। অ্যাপ লিঙ্কের তথ্য প্রদান করতে, আপনার TvContract.Channels ক্ষেত্রগুলিতে নিম্নলিখিত বিবরণগুলি উল্লেখ করুন:

  • COLUMN_APP_LINK_COLOR - এই চ্যানেলের জন্য অ্যাপ লিঙ্কের উচ্চারণ রঙ। অ্যাকসেন্ট রঙের উদাহরণের জন্য, চিত্র 2, কলআউট 3 দেখুন।
  • COLUMN_APP_LINK_ICON_URI - এই চ্যানেলের অ্যাপ লিঙ্কের অ্যাপ ব্যাজ আইকনের জন্য URI। একটি উদাহরণ অ্যাপ ব্যাজ আইকনের জন্য, চিত্র 2, কলআউট 2 দেখুন।
  • COLUMN_APP_LINK_INTENT_URI - এই চ্যানেলের জন্য অ্যাপ লিঙ্কের উদ্দেশ্য URI। আপনি URI_INTENT_SCHEME এর সাথে toUri(int) ব্যবহার করে URI তৈরি করতে পারেন এবং parseUri() দিয়ে URI কে মূল অভিপ্রায়ে রূপান্তর করতে পারেন।
  • COLUMN_APP_LINK_POSTER_ART_URI - এই চ্যানেলের অ্যাপ লিঙ্কের পটভূমি হিসেবে ব্যবহৃত পোস্টার আর্ট-এর URI। একটি উদাহরণ পোস্টার ছবির জন্য, চিত্র 2, কলআউট 1 দেখুন।
  • COLUMN_APP_LINK_TEXT - এই চ্যানেলের জন্য অ্যাপ লিঙ্কের বর্ণনামূলক লিঙ্ক পাঠ্য। একটি উদাহরণ অ্যাপ লিঙ্কের বিবরণের জন্য, চিত্র 2, কলআউট 3-এ পাঠ্যটি দেখুন।

চিত্র 2. অ্যাপ লিঙ্কের বিবরণ।

যদি চ্যানেল ডেটা অ্যাপ লিঙ্কের তথ্য নির্দিষ্ট না করে, তাহলে সিস্টেম একটি ডিফল্ট অ্যাপ লিঙ্ক তৈরি করে। সিস্টেমটি নিম্নরূপ ডিফল্ট বিবরণ নির্বাচন করে:

  • উদ্দেশ্য URI ( COLUMN_APP_LINK_INTENT_URI ) এর জন্য, সিস্টেম CATEGORY_LEANBACK_LAUNCHER বিভাগের জন্য ACTION_MAIN কার্যকলাপ ব্যবহার করে, সাধারণত অ্যাপ ম্যানিফেস্টে সংজ্ঞায়িত করা হয়। যদি এই ক্রিয়াকলাপটি সংজ্ঞায়িত না হয়, একটি অ-কার্যকর অ্যাপ লিঙ্ক প্রদর্শিত হয়-যদি ব্যবহারকারী এটিতে ক্লিক করেন, কিছুই হবে না।
  • বর্ণনামূলক পাঠ্যের জন্য ( COLUMN_APP_LINK_TEXT ), সিস্টেমটি " app-name খুলুন" ব্যবহার করে৷ যদি কোনও কার্যকর অ্যাপ লিঙ্কের উদ্দেশ্য URI সংজ্ঞায়িত করা না থাকে, তাহলে সিস্টেম "কোন লিঙ্ক উপলব্ধ নেই" ব্যবহার করে।
  • অ্যাকসেন্ট রঙের জন্য ( COLUMN_APP_LINK_COLOR ), সিস্টেমটি ডিফল্ট অ্যাপ রঙ ব্যবহার করে।
  • পোস্টার ইমেজের জন্য ( COLUMN_APP_LINK_POSTER_ART_URI ), সিস্টেম অ্যাপের হোম স্ক্রীন ব্যানার ব্যবহার করে। যদি অ্যাপটি একটি ব্যানার প্রদান না করে, তাহলে সিস্টেমটি একটি ডিফল্ট টিভি অ্যাপের ছবি ব্যবহার করে।
  • ব্যাজ আইকনের জন্য ( COLUMN_APP_LINK_ICON_URI ), সিস্টেমটি একটি ব্যাজ ব্যবহার করে যা অ্যাপের নাম দেখায়। যদি সিস্টেমটি পোস্টার ইমেজের জন্য অ্যাপ ব্যানার বা ডিফল্ট অ্যাপ ইমেজও ব্যবহার করে, তাহলে কোনো অ্যাপ ব্যাজ দেখানো হয় না।

আপনি আপনার অ্যাপের সেটআপ কার্যকলাপে আপনার চ্যানেলগুলির জন্য অ্যাপ লিঙ্কের বিশদ উল্লেখ করুন। আপনি যেকোন সময়ে এই অ্যাপ লিঙ্কের বিবরণ আপডেট করতে পারেন, তাই যদি কোনও অ্যাপ লিঙ্কের চ্যানেল পরিবর্তনের সাথে মেলে, অ্যাপ লিঙ্কের বিবরণ আপডেট করুন এবং প্রয়োজনে ContentResolver.update() এ কল করুন। চ্যানেল ডেটা আপডেট করার বিষয়ে আরও বিশদ বিবরণের জন্য, চ্যানেল ডেটা আপডেট করুন দেখুন।