আপনি Data Layer API-তে কল করলে, কলটি সম্পূর্ণ হওয়ার পরে আপনি সেটির স্ট্যাটাস পাবেন। এছাড়াও, আপনার অ্যাপ Wear OS by Google নেটওয়ার্কে যেখানেই ডেটা পরিবর্তন করুক না কেন, তার ফলে হওয়া ডেটা ইভেন্ট আপনি শুনতে পাবেন।
Data Layer API-এর সাথে কীভাবে কার্যকরভাবে কাজ করা যায় তার একটি উদাহরণ পেতে, Android DataLayer Sample অ্যাপ দেখুন।
ডেটা লেয়ার কলের স্ট্যাটাসের জন্য অপেক্ষা করুন
Data Layer API-তে করা কল—যেমন, putDataItem মেথড ব্যবহার করে করা কল
DataClient ক্লাস—কখনও কখনও একটি Task<ResultType> অবজেক্ট রিটার্ন করে। Task অবজেক্ট তৈরি
হওয়ার সাথে সাথেই, অপারেশনটি ব্যাকগ্রাউন্ডে সারিবদ্ধ করা হয়।
এর পরে আপনি আর কিছু না করলে, অপারেশনটি নীরবে সম্পূর্ণ হয়ে যাবে।
তবে, অপারেশন সম্পূর্ণ হওয়ার পরে আপনি সাধারণত ফলাফল নিয়ে কিছু করতে চান, তাই Task অবজেক্ট আপনাকে ফলাফল স্ট্যাটাসের জন্য অপেক্ষা করতে দেয়, তা
অ্যাসিঙ্ক্রোনাস বা সিঙ্ক্রোনাস যাই হোক না কেন।
অ্যাসিঙ্ক্রোনাস কল
আপনার কোড যদি মূল UI থ্রেডে চলে, তাহলে
ডেটা লেয়ার API-তে ব্লকিং কল করবেন না এবং putDataItem কল করতে কোরাউটিন ব্যবহার করুন:
private suspend fun Context.sendDataAsync(count: Int) { try { val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } val dataItem = Wearable.getDataClient(this).putDataItem(putDataReq).await() handleDataItem(dataItem) } catch (e: Exception) { handleDataItemError(e) } finally { handleTaskComplete() } } private fun handleDataItem(dataItem: DataItem) { } private fun handleDataItemError(exception: Exception) { } private fun handleTaskComplete() { }
বিভিন্ন টাস্কের এক্সিকিউশন চেইন করা সহ অন্যান্য সম্ভাবনার জন্য টাস্ক API দেখুন।
সিঙ্ক্রোনাস কল
আপনার কোড যদি ব্যাকগ্রাউন্ড সার্ভিসে আলাদা হ্যান্ডলার থ্রেডে চলে,
যেমন WearableListenerService-এ, তাহলে putDataItem-এ
ব্লকিং কল করতে runBlocking ব্যবহার করুন।
মনে রাখবেন: মূল থ্রেডে থাকাকালীন এটি কল করবেন না।
private fun Context.sendDataSync(count: Int) = runBlocking { val putDataReq = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } try { val result = Wearable.getDataClient(this@sendDataSync) .putDataItem(putDataReq) .await() // Logic for success } catch (e: Exception) { // Handle failure } }
ডেটা লেয়ার ইভেন্ট শোনা
হ্যান্ডহেল্ড ও পরিধানযোগ্য ডিভাইস জুড়ে ডেটা লেয়ার ডেটা সিঙ্ক্রোনাইজ ও পাঠায় বলে, আপনাকে সাধারণত ডেটা আইটেম তৈরি হওয়া ও মেসেজ পাওয়ার মতো গুরুত্বপূর্ণ ইভেন্ট শুনতে হয়।
ডেটা লেয়ার ইভেন্ট শোনার জন্য আপনার কাছে দুটি বিকল্প আছে:
WearableListenerServiceএক্সটেন্ড করে এমন একটি পরিষেবা তৈরি করুন।- এমন অ্যাক্টিভিটি বা ক্লাস তৈরি করুন যা
DataClient.OnDataChangedListenerইন্টারফেস প্রয়োগ করে।
এই দুটি বিকল্পের সাহায্যে, আপনি যেসব ইভেন্ট হ্যান্ডেল করতে আগ্রহী সেগুলির জন্য ডেটা ইভেন্ট কলব্যাক পদ্ধতি ওভাররাইড করেন।
মনে রাখবেন: লিসনার
ইমপ্লিমেন্টেশন বেছে নেওয়ার সময় আপনার অ্যাপের ব্যাটারি ব্যবহারের কথা বিবেচনা করুন। অ্যাপের ম্যানিফেস্টে একটি WearableListenerService রেজিস্টার করা থাকে
এবং এটি আগে থেকে না চললে অ্যাপটি লঞ্চ করতে পারে। আপনার অ্যাপ আগে থেকেই চলছে এমন অবস্থায় যদি শুধুমাত্র ইভেন্ট শোনার
প্রয়োজন হয়, যা সাধারণত ইন্ট্যার্যাক্টিভ অ্যাপ্লিকেশনের
ক্ষেত্রে হয়, তাহলে WearableListenerService ব্যবহার করবেন না। পরিবর্তে,
লাইভ শ্রোতাকে রেজিস্টার করুন। যেমন, DataClient ক্লাসের addListener পদ্ধতি ব্যবহার করুন।
এর ফলে সিস্টেমের উপর চাপ কমতে পারে এবং ব্যাটারির ব্যবহার
কমে যেতে পারে।
WearableListenerService ব্যবহার করা
আপনি সাধারণত নিজের পরিধানযোগ্য ও হ্যান্ডহেল্ড
অ্যাপ, দুটিতেই WearableListenerService-এর ইনস্ট্যান্স তৈরি করেন। তবে, আপনি যদি কোনও একটি অ্যাপের
ডেটা ইভেন্টে আগ্রহী না হন, তাহলে সেই অ্যাপে আপনাকে পরিষেবা প্রয়োগ করতে হবে না।
যেমন, আপনার কাছে এমন একটি হ্যান্ডহেল্ড অ্যাপ থাকতে পারে যা ডেটা আইটেম অবজেক্ট সেট করে ও পায় এবং একটি পরে থাকা যায় এমন অ্যাপ যা নিজের UI আপডেট করার জন্য এইসব আপডেট শোনে। ওয়্যারেবল অ্যাপ কখনও কোনও ডেটা আইটেম আপডেট করে না, তাই হ্যান্ডহেল্ড অ্যাপ ওয়্যারেবল অ্যাপ থেকে কোনও ডেটা ইভেন্ট শোনে না।
WearableListenerService ব্যবহার করে আপনি যেসব ইভেন্ট শুনতে পারেন, সেগুলি হল:
নিচে উল্লেখ করা ইভেন্ট:
onDataChanged(): কোনও ডেটা আইটেম অবজেক্ট তৈরি, মুছে ফেলা বা পরিবর্তন করা হলে, সিস্টেম সব কানেক্ট করা নোডে এই কলব্যাক ট্রিগার করে।onMessageReceived(): কোনও নোড থেকে পাঠানো মেসেজ টার্গেট নোডে এই কলব্যাক ট্রিগার করে।onCapabilityChanged(): আপনার অ্যাপের কোনও ইনস্ট্যান্স বিজ্ঞাপন দেয় এমন কোনও ক্ষমতা নেটওয়ার্কে উপলভ্য হলে, সেই ইভেন্ট এই কলব্যাক ট্রিগার করে। আপনি যদি কাছাকাছি কোনও নোড খুঁজছেন, তাহলে কলব্যাকে দেওয়া নোডেরisNearby()মেথড কোয়েরি করতে পারেন।
এছাড়াও, আপনি ChannelClient.ChannelCallback থেকে ইভেন্ট শুনতে পারবেন, যেমন
onChannelOpened()।
আগের সব ইভেন্ট ব্যাকগ্রাউন্ড থ্রেডে এক্সিকিউট করা হয়, মূল থ্রেডে নয়।
WearableListenerService তৈরি করতে, এইসব ধাপ অনুসরণ করুন:
WearableListenerServiceএক্সটেন্ড করে এমন একটি ক্লাস তৈরি করুন।onDataChanged()-এর মতো আপনার আগ্রহের ইভেন্ট শুনুন।- আপনার Android ম্যানিফেস্টে একটি ইনটেন্ট ফিল্টার ঘোষণা করুন যাতে সিস্টেমকে আপনার
WearableListenerServiceসম্পর্কে জানানো যায়। এই ঘোষণাটি সিস্টেমকে প্রয়োজনমতো আপনার পরিষেবা বাইন্ড করতে দেয়।
WearableListenerService কীভাবে প্রয়োগ করতে হয় তা নিম্নলিখিত উদাহরণ থেকে দেখুন:
class DataLayerListenerService : WearableListenerService() { override fun onDataChanged(dataEvents: DataEventBuffer) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onDataChanged: $dataEvents") } // Loop through the events and send a message // to the node that created the data item. dataEvents .map { it.dataItem.uri } .forEach { uri -> // Get the node ID from the host value of the URI. val nodeId: String = uri.host!! // Set the data of the message to be the bytes of the URI. val payload: ByteArray = uri.toString().toByteArray() // Send the RPC. Wearable.getMessageClient(this) .sendMessage( nodeId, DATA_ITEM_RECEIVED_PATH, payload ) } } }
এই লিসনারের সাথে কীভাবে ইনটেন্ট ফিল্টার ব্যবহার করতে হয় তা নিম্নলিখিত বিভাগে ব্যাখ্যা করা হয়েছে।
WearableListenerService-এর সাথে ফিল্টার ব্যবহার করা
আগের বিভাগে দেখানো WearableListenerService উদাহরণের জন্য ইনটেন্ট ফিল্টার
এইরকম হতে পারে:
<service android:name=".snippets.datalayer.DataLayerListenerService" android:exported="true" tools:ignore="ExportedService" > <intent-filter> <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> <data android:scheme="wear" android:host="*" android:path="/start-activity" /> </intent-filter> </service>
DATA_CHANGED অ্যাকশন ফিল্টার সিস্টেমকে জানায় যে আপনার অ্যাপ ডেটা
লেয়ার ইভেন্টে আগ্রহী।
এই উদাহরণে, ওয়াচ /start-activity ডেটা আইটেম শোনার জন্য অপেক্ষা করে এবং
ফোন /data-item-received (DATA_ITEM_RECEIVED_PATH) মেসেজ
উত্তর শোনার জন্য অপেক্ষা করে।
ম্যাচিং সংক্রান্ত স্ট্যান্ডার্ড Android ফিল্টার নিয়ম প্রযোজ্য। আপনি ম্যানিফেস্ট পিছু একাধিক পরিষেবা, পরিষেবা পিছু একাধিক ইনটেন্ট ফিল্টার, ফিল্টার পিছু একাধিক অ্যাকশন,
এবং ফিল্টার পিছু একাধিক ডেটা স্ট্যাঞ্জা নির্দিষ্ট করতে পারবেন। ফিল্টার ওয়াইল্ডকার্ড হোস্টের সাথে অথবা
নির্দিষ্ট কোনও হোস্টের সাথে ম্যাচ করতে পারে। ওয়াইল্ডকার্ড হোস্টের সাথে ম্যাচ করাতে, host="*" ব্যবহার করুন। নির্দিষ্ট হোস্টের সাথে
ম্যাচ করতে, host=<node_id> নির্দিষ্ট করুন।
এছাড়াও, আপনি আক্ষরিক পাথ বা পাথ প্রিফিক্স ম্যাচ করতে পারেন। এটি করতে, আপনাকে অবশ্যই একটি ওয়াইল্ডকার্ড বা নির্দিষ্ট হোস্ট উল্লেখ করতে হবে। অন্যথায়, আপনার উল্লেখ করা পাথ সিস্টেম উপেক্ষা করে।
Wear OS-এ কাজ করে এমন ফিল্টারের ধরন সম্পর্কে আরও জানতে, WearableListenerService-এর জন্য API
রেফারেন্স ডকুমেন্টেশন দেখুন।
ডেটা ফিল্টার ও ম্যাচিং নিয়ম সম্পর্কে আরও জানতে, <data> ম্যানিফেস্ট এলিমেন্টের জন্য API রেফারেন্স
ডকুমেন্টেশন দেখুন।
ইনটেন্ট ফিল্টার ম্যাচ করার সময়, দুটি গুরুত্বপূর্ণ নিয়ম মনে রাখবেন:
- ইন্টেন্ট ফিল্টারের জন্য কোনও স্কিম নির্দিষ্ট করা না থাকলে, সিস্টেম অন্যান্য URI অ্যাট্রিবিউট উপেক্ষা করে।
- ফিল্টারের জন্য কোনও হোস্ট নির্দিষ্ট করা না থাকলে, সিস্টেম সব পাথ অ্যাট্রিবিউট উপেক্ষা করে।
লাইভ শ্রোতা ব্যবহার করা
ব্যবহারকারী যখন অ্যাপের সাথে ইন্টার্যাক্ট করছেন তখন আপনার অ্যাপ যদি শুধুমাত্র ডেটা-লেয়ার ইভেন্ট সম্পর্কেই আগ্রহী হয়, তাহলে প্রতিটি ডেটা পরিবর্তনের জন্য এটি দীর্ঘ-সময় ধরে চলতে থাকা পরিষেবার প্রয়োজন নাও হতে পারে। এই ধরনের ক্ষেত্রে, আপনি অ্যাক্টিভিটিতে ইভেন্ট শুনতে পারেন।
আরও পরিষ্কার ও নিরাপদ পদ্ধতির জন্য, লাইফসাইকেল অবজারভার ব্যবহার করুন। লাইফসাইকেল অবজারভার ব্যবহার করে, আপনি রেজিস্ট্রেশন লজিককে অ্যাক্টিভিটির
LifecycleResumeEvent থেকে সরিয়ে একটি আলাদা, আবার ব্যবহারযোগ্য ক্লাসে নিয়ে যান যা
DefaultLifecycleObserver প্রয়োগ করে।
এই পদ্ধতি আপনার অ্যাক্টিভিটি কম রাখে এবং লিসনারকে আনরেজিস্টার করতে ভুলে যাওয়ার মতো সাধারণ বাগ প্রতিরোধ করে।
১. লাইফসাইকেল-অ্যাওয়ার লিসনার তৈরি করা
এই ক্লাস DataClient.OnDataChangedListener-কে র্যাপ করে এবং অটোমেটিক
অ্যাক্টিভিটির লাইফসাইকেলের উপর ভিত্তি করে নিজের সাবস্ক্রিপশন ম্যানেজ করে।
class WearDataLayerObserver( private val dataClient: DataClient, private val onDataReceived: (DataEventBuffer) -> Unit ) : DefaultLifecycleObserver, DataClient.OnDataChangedListener { // Implementation of the DataClient listener override fun onDataChanged(dataEvents: DataEventBuffer) { onDataReceived(dataEvents) } // Automatically register when the Activity starts override fun onResume(owner: LifecycleOwner) { dataClient.addListener(this) } // Automatically unregister when the Activity pauses override fun onPause(owner: LifecycleOwner) { dataClient.removeListener(this) } }
২. আপনার অ্যাক্টিভিটিতে ব্যবহার
এখন, Wear API-এর জন্য আপনার অ্যাক্টিভিটিকে LifecycleResumeEvent বা
onPause ব্যবহার করতে হবে না। আপনি একবারই পর্যবেক্ষককে
LaunchedEvent (বা onCreate)-এ রেজিস্টার করেন।
class DataLayerLifecycleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val dataClient = Wearable.getDataClient(this) // Create the observer and link it to the activity's lifecycle val wearObserver = WearDataLayerObserver(dataClient) { dataEvents -> handleDataEvents(dataEvents) } lifecycle.addObserver(wearObserver) } private fun handleDataEvents(dataEvents: DataEventBuffer) { // ... filter and process events ... } }
এটি কেন আরও ভালো:
- পরিষ্কার অ্যাক্টিভিটি: আপনি অ্যাক্টিভিটি লাইফসাইকেল মেথড থেকে বয়লারপ্লেট সরিয়ে দেন।
- নিরাপত্তা:
DefaultLifecycleObserverসাহায্য করে যে লিসনারকে সরিয়ে দেওয়া হয়েছে তা যাচাই করতে, এমনকি যদি অ্যাক্টিভিটি অপ্রত্যাশিতভাবে ধ্বংস হয়ে যায়, তাহলে মেমরি লিক হওয়া আটকায়। - পুনর্ব্যবহারযোগ্যতা: আপনি রেজিস্ট্রেশন লজিক আবার না লিখে এই
WearDataLayerObserverযেকোনও অ্যাক্টিভিটি বা কম্পোজেবলে প্লাগ-ইন করতে পারবেন। - ডিকাপলিং: কখন শুনতে হবে সেই লজিককে ডেটা নিয়ে কী করতে হবে সেই লজিক থেকে আলাদা করা হয়।
লাইভ শ্রোতাদের সাথে ফিল্টার ব্যবহার করা
আগে উল্লেখ করা হয়েছে, ঠিক যেভাবে আপনি
ম্যানিফেস্ট-ভিত্তিক WearableListenerService অবজেক্টের জন্য ইনটেন্ট ফিল্টার নির্দিষ্ট করতে পারেন, সেইভাবে Wearable API-এর মাধ্যমে লাইভ লিসনার রেজিস্টার করার সময় আপনি ইনটেন্ট ফিল্টার
ব্যবহার করতে পারেন। API-ভিত্তিক লাইভ শ্রোতা এবং ম্যানিফেস্ট-ভিত্তিক শ্রোতা, উভয়ের ক্ষেত্রেই একই নিয়ম
প্রযোজ্য।
নির্দিষ্ট পাথ বা পাথ প্রিফিক্স সহ লিসনার রেজিস্টার করা
collectAsStateWithLifecycle() ব্যবহার করা হল একটি সাধারণ প্যাটার্ন। এইভাবে লিসনার প্রয়োগ করার মাধ্যমে, আপনার অ্যাপ আরও বেশি বেছে বেছে ইভেন্ট গ্রহণ করতে পারবে, এর ফলে এর ডিজাইন ও
দক্ষতা উন্নত হবে।