ব্রডকাস্টের ওভারভিউ

Android অ্যাপ, Android সিস্টেম ও অন্যান্য Android অ্যাপ থেকে ব্রডকাস্ট মেসেজ পাঠায় ও পায়। এটি প্রকাশ-সাবস্ক্রাইব ডিজাইন প্যাটার্নের মতো। নির্দিষ্ট কিছু ঘটনা ঘটলে সিস্টেম ও অ্যাপ সাধারণত ব্রডকাস্ট পাঠায়। যেমন, Android সিস্টেম সিস্টেম বুট বা ডিভাইস চার্জিংয়ের মতো বিভিন্ন সিস্টেম ইভেন্ট ঘটলে ব্রডকাস্ট পাঠায়। এছাড়াও, অ্যাপ কাস্টম ব্রডকাস্ট পাঠায়, যেমন, অন্য অ্যাপকে এমন কিছু সম্পর্কে বিজ্ঞপ্তি পাঠানো যা তাদের আগ্রহের বিষয় হতে পারে (যেমন, নতুন ডেটা ডাউনলোড)।

নির্দিষ্ট ব্রডকাস্ট পাওয়ার জন্য অ্যাপ রেজিস্টার করতে পারে। কোনও ব্রডকাস্ট পাঠানো হলে, সেই নির্দিষ্ট ধরনের ব্রডকাস্ট পাওয়ার জন্য সাবস্ক্রাইব করা অ্যাপে সিস্টেম অটোমেটিক ব্রডকাস্ট রাউট করে দেয়।

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

সিস্টেম ব্রডকাস্ট সম্পর্কে

বিভিন্ন সিস্টেম ইভেন্ট ঘটলে, সিস্টেম অটোমেটিক ব্রডকাস্ট পাঠায়, যেমন সিস্টেম বিমান মোড চালু ও বন্ধ করলে। সাবস্ক্রাইব করা সব অ্যাপ এইসব ব্রডকাস্ট পায়।

Intent অবজেক্ট ব্রডকাস্ট মেসেজকে র‍্যাপ করে। action স্ট্রিং থেকে কোন ইভেন্ট ঘটেছে তা বোঝা যায়, যেমন android.intent.action.AIRPLANE_MODE। এছাড়াও, অতিরিক্ত ফিল্ডে বান্ডেল করা অতিরিক্ত তথ্য ইনটেন্টে অন্তর্ভুক্ত থাকতে পারে। যেমন, বিমান মোড ইনটেন্টে একটি বুলিয়ান এক্সট্রা থাকে যা বিমান মোড চালু আছে কিনা তা নির্দেশ করে।

ইনটেন্ট থেকে কীভাবে অ্যাকশন স্ট্রিং পড়তে ও পেতে হয় সেই সম্পর্কে আরও জানতে, ইনটেন্ট ও ইনটেন্ট ফিল্টার দেখুন।

সিস্টেম ব্রডকাস্ট অ্যাকশন

সিস্টেম ব্রডকাস্ট অ্যাকশনের সম্পূর্ণ তালিকার জন্য, Android SDK-তে BROADCAST_ACTIONS.TXT ফাইল দেখুন। প্রতিটি ব্রডকাস্ট অ্যাকশনের সাথে একটি ধ্রুবক ফিল্ড যুক্ত থাকে। যেমন, ধ্রুবকের মান ACTION_AIRPLANE_MODE_CHANGED হল android.intent.action.AIRPLANE_MODE। প্রতিটি ব্রডকাস্ট অ্যাকশনের ডকুমেন্টেশন এর সংশ্লিষ্ট কনস্ট্যান্ট ফিল্ডে উপলভ্য।

সিস্টেম ব্রডকাস্টে পরিবর্তন

Android প্ল্যাটফর্মের বিবর্তনের সাথে সাথে, সিস্টেম ব্রডকাস্টের আচরণও পর্যায়ক্রমে পরিবর্তিত হয়। Android-এর সব ভার্সনে কাজ করার জন্য নিম্নলিখিত পরিবর্তনগুলি মনে রাখবেন।

Android 16

Android 16-এ, android:priority অ্যাট্রিবিউট বা IntentFilter.setPriority() ব্যবহার করে বিভিন্ন প্রসেস জুড়ে ব্রডকাস্ট ডেলিভারি অর্ডার নিশ্চিত করা যাবে না। ব্রডকাস্টের অগ্রাধিকার শুধুমাত্র একই অ্যাপ্লিকেশন প্রসেসের মধ্যে মান্য করা হয়, সব প্রসেস জুড়ে নয়।

এছাড়াও, ব্রডকাস্টের অগ্রাধিকার অটোমেটিক রেঞ্জ (SYSTEM_LOW_PRIORITY + ১, SYSTEM_HIGH_PRIORITY - ১)-এর মধ্যে সীমাবদ্ধ থাকে। শুধুমাত্র সিস্টেম কম্পোনেন্টকে ব্রডকাস্ট অগ্রাধিকার হিসেবে SYSTEM_LOW_PRIORITY, SYSTEM_HIGH_PRIORITY সেট করার অনুমতি দেওয়া হয়।

Android 14

অ্যাপ ক্যাশেড স্টেটে থাকাকালীন, সিস্টেম হেল্থের জন্য সিস্টেম ব্রডকাস্ট ডেলিভারি অপ্টিমাইজ করে। যেমন, অ্যাপ ক্যাশেড অবস্থায় থাকলে, সিস্টেম কম গুরুত্বপূর্ণ সিস্টেম ব্রডকাস্ট যেমন ACTION_SCREEN_ON ডিফার করে। অ্যাপটি ক্যাশে করা অবস্থা থেকে অ্যাক্টিভ প্রসেস লাইফসাইকেলে গেলে, সিস্টেম কোনও ডিফার করা ব্রডকাস্ট ডেলিভার করে।

ম্যানিফেস্টে ঘোষণা করা গুরুত্বপূর্ণ ব্রডকাস্ট ডেলিভারির জন্য ক্যাশ করা অবস্থা থেকে অ্যাপ সাময়িকভাবে সরিয়ে দেয়।

Android 9

Android 9 (API লেভেল 28) থেকে শুরু করে, NETWORK_STATE_CHANGED_ACTION ব্রডকাস্ট ব্যবহারকারীর লোকেশন বা ব্যক্তিগতভাবে শনাক্তকরণযোগ্য ডেটা সংক্রান্ত তথ্য পায় না।

আপনার অ্যাপ Android 9.0 (API লেভেল ২৮) বা এর পরের যেকোনও ভার্সনে চলা ডিভাইসে ইনস্টল করা থাকলে, সিস্টেম ওয়াই-ফাই ব্রডকাস্টে SSID, BSSID, কানেকশন সংক্রান্ত তথ্য বা স্ক্যান ফলাফল অন্তর্ভুক্ত করে না। এই তথ্য পেতে, getConnectionInfo() নম্বরে কল করুন।

Android 8.0

Android 8.0 (API লেভেল ২৬) থেকে শুরু করে, সিস্টেম ম্যানিফেস্ট-ঘোষিত রিসিভারের উপর অতিরিক্ত বিধিনিষেধ আরোপ করে।

আপনার অ্যাপ Android 8.0 বা এর পরের যেকোনও ভার্সনকে টার্গেট করলে, আপনি ম্যানিফেস্ট ব্যবহার করে বেশিরভাগ ইমপ্লিসিট ব্রডকাস্টের (যেসব ব্রডকাস্ট বিশেষভাবে আপনার অ্যাপকে টার্গেট করে না) জন্য রিসিভার ঘোষণা করতে পারবেন না। ব্যবহারকারী আপনার অ্যাপ সক্রিয়ভাবে ব্যবহার করার সময়ও আপনি কনটেক্সট-রেজিস্টার্ড রিসিভার ব্যবহার করতে পারবেন।

Android 7.0

Android 7.0 (API লেভেল 24) ও তার পরবর্তী যেকোনও ভার্সন নিম্নলিখিত সিস্টেম ব্রডকাস্ট পাঠায় না:

এছাড়াও, Android 7.0 ও তার পরবর্তী যেকোনও ভার্সনের জন্য তৈরি অ্যাপকে অবশ্যই CONNECTIVITY_ACTION ব্রডকাস্ট রেজিস্টার করতে হবে, এর জন্য registerReceiver(BroadcastReceiver, IntentFilter) ব্যবহার করুন। ম্যানিফেস্টে রিসিভার ঘোষণা করলে কাজ হয় না।

ব্রডকাস্ট পাওয়া

দুটি উপায়ে অ্যাপ ব্রডকাস্ট পেতে পারে: কনটেক্সট-রেজিস্টার্ড রিসিভার ও ম্যানিফেস্ট-ডিক্লেয়ার্ড রিসিভারের মাধ্যমে।

প্রসঙ্গ-রেজিস্টার করা রিসিভার

প্রাপকের রেজিস্টার করা কনটেক্সট বৈধ থাকা পর্যন্ত কনটেক্সট-রেজিস্টার্ড প্রাপক ব্রডকাস্ট পান। এটি সাধারণত registerReceiver ও unregisterReceiver-এর মধ্যে হয়। সংশ্লিষ্ট প্রসঙ্গটি সিস্টেম ধ্বংস করে দিলে, রেজিস্টার করা প্রসঙ্গটিও অবৈধ হয়ে যায়। যেমন, আপনি যদি কোনও Activity কনটেক্সটে রেজিস্টার করেন, তাহলে অ্যাক্টিভিটি চালু থাকা পর্যন্ত আপনি ব্রডকাস্ট পাবেন। আপনি যদি অ্যাপ্লিকেশন কনটেক্সটের সাথে রেজিস্টার করেন, তাহলে অ্যাপ চলাকালীন আপনি ব্রডকাস্ট পাবেন।

প্রাপককে প্রসঙ্গ সহ রেজিস্টার করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের মডিউল-লেভেল বিল্ড ফাইলে, AndroidX Core লাইব্রেরির 1.9.0 বা তার পরের যেকোনও ভার্সন অন্তর্ভুক্ত করুন:

    খাঁজকাটা

    dependencies {
        def core_version = "1.19.1"
    
        // Java language implementation
        implementation "androidx.core:core:$core_version"
        // Kotlin
        implementation "androidx.core:core-ktx:$core_version"
    
        // To use RoleManagerCompat
        implementation "androidx.core:core-role:1.1.0"
    
        // To use the Animator APIs
        implementation "androidx.core:core-animation:1.0.0"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0"
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation "androidx.core:core-performance:1.0.0"
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation "androidx.core:core-google-shortcuts:1.1.0"
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation "androidx.core:core-remoteviews:1.1.0"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.2.0"
    }

    কোটলিন

    dependencies {
        val core_version = "1.19.1"
    
        // Java language implementation
        implementation("androidx.core:core:$core_version")
        // Kotlin
        implementation("androidx.core:core-ktx:$core_version")
    
        // To use RoleManagerCompat
        implementation("androidx.core:core-role:1.1.0")
    
        // To use the Animator APIs
        implementation("androidx.core:core-animation:1.0.0")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0")
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation("androidx.core:core-performance:1.0.0")
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation("androidx.core:core-google-shortcuts:1.1.0")
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation("androidx.core:core-remoteviews:1.1.0")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.2.0")
    }
  2. BroadcastReceiver-এর একটি ইনস্ট্যান্স তৈরি করুন:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    জাভা

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. IntentFilter-এর একটি ইনস্ট্যান্স তৈরি করুন:

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    জাভা

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. ব্রডকাস্ট রিসিভার এক্সপোর্ট করা হবে কিনা এবং ডিভাইসে থাকা অন্যান্য অ্যাপের কাছে দৃশ্যমান হবে কিনা তা বেছে নিন। এই রিসিভার যদি সিস্টেম বা অন্যান্য অ্যাপ থেকে পাঠানো ব্রডকাস্ট শোনে—এমনকি আপনার মালিকানাধীন অন্যান্য অ্যাপ থেকেও—তাহলে RECEIVER_EXPORTED ফ্ল্যাগ ব্যবহার করুন। পরিবর্তে, এই রিসিভার যদি শুধুমাত্র আপনার অ্যাপের পাঠানো ব্রডকাস্ট শোনে, তাহলে RECEIVER_NOT_EXPORTED ফ্ল্যাগ ব্যবহার করুন।

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    জাভা

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
  5. registerReceiver() নম্বরে কল করে প্রাপককে রেজিস্টার করুন:

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    জাভা

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. ব্রডকাস্ট পাওয়া বন্ধ করতে, কল করুন unregisterReceiver(android.content.BroadcastReceiver)। আপনি যখন আর রিসিভার ব্যবহার করবেন না বা প্রসঙ্গটি আর বৈধ থাকবে না, তখন রিসিভারটি আনরেজিস্টার করতে ভুলবেন না।

আপনার ব্রডকাস্ট রিসিভার আনরেজিস্টার করা

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

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

জাভা

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

সবচেয়ে ছোট স্কোপে রিসিভার রেজিস্টার করা

আপনি যখন সত্যিই ফলাফল পেতে আগ্রহী হবেন, তখনই আপনার ব্রডকাস্ট রিসিভার রেজিস্টার করা উচিত। সম্ভাব্য সবচেয়ে ছোট প্রাপক স্কোপ বেছে নিন:

  • LifecycleResumeEffect বা অ্যাক্টিভিটি onResume/onPause লাইফসাইকেল মেথড: অ্যাপটি রিজিউম করা অবস্থায় থাকলেই ব্রডকাস্ট রিসিভার আপডেট পায়।
  • LifecycleStartEffect বা অ্যাক্টিভিটি onStart/onStop লাইফসাইকেল মেথড: অ্যাপটি রিজিউম করা অবস্থায় থাকলেই ব্রডকাস্ট রিসিভার আপডেট পায়।
  • DisposableEffect: কম্পোজ করার উপযুক্ত আইটেম কম্পোজিশন ট্রিতে থাকাকালীনই ব্রডকাস্ট রিসিভার শুধুমাত্র আপডেট পায়। এই স্কোপ অ্যাক্টিভিটি লাইফসাইকেল স্কোপের সাথে অ্যাটাচ করা নেই। প্রাপককে অ্যাপ্লিকেশন কনটেক্সটে রেজিস্টার করার কথা বিবেচনা করুন। এর কারণ হল, কম্পোজ করার উপযুক্ত আইটেম তাত্ত্বিকভাবে অ্যাক্টিভিটি লাইফসাইকেল স্কোপের থেকে বেশি সময় ধরে চলতে পারে এবং অ্যাক্টিভিটি লিক করতে পারে।
  • অ্যাক্টিভিটি onCreate/onDestroy: অ্যাক্টিভিটি তৈরি করা অবস্থায় থাকাকালীন ব্রডকাস্ট রিসিভার আপডেট পায়। onDestroy()-এ আনরেজিস্টার করেছেন কিনা তা নিশ্চিত করুন, onSaveInstanceState(Bundle)-এ নয়, কারণ এটি কল করা নাও হতে পারে।
  • কাস্টম স্কোপ: যেমন, আপনি নিজের ViewModel স্কোপে রিসিভার রেজিস্টার করতে পারেন, যাতে অ্যাক্টিভিটি আবার তৈরি হলেও সেটি বেঁচে থাকে। রিসিভার রেজিস্টার করার জন্য অ্যাপ্লিকেশন কনটেক্সট ব্যবহার করতে ভুলবেন না, কারণ রিসিভার অ্যাক্টিভিটি লাইফসাইকেল স্কোপের বাইরেও থাকতে পারে এবং অ্যাক্টিভিটি লিক করতে পারে।

স্টেটফুল ও স্টেটলেস কম্পোজ করার মতো আইটেম তৈরি করা

Compose-এ স্টেটফুল ও স্টেটলেস কম্পোজেবল থাকে। কোনও কম্পোজ করার মতো আইটেমের মধ্যে ব্রডকাস্ট রিসিভার রেজিস্টার বা আনরেজিস্টার করলে সেটি স্টেটফুল হয়ে যায়। কম্পোজেবলটি কোনও নির্ধারিত ফাংশন নয় যা একই প্যারামিটার পাস করা হলে একই কন্টেন্ট রেন্ডার করে। রেজিস্টার করা ব্রডকাস্ট রিসিভারকে কল করার ভিত্তিতে ইন্টার্নাল স্টেট পরিবর্তন হতে পারে।

Compose-এ পেশাদার পদ্ধতি হিসেবে, আমরা সাজেস্ট করি যে আপনার কম্পোজ করার উপযুক্ত আইটেমগুলিকে স্টেটফুল ও স্টেটলেস ভার্সনে ভাগ করে নিন। তাই, আমরা সাজেস্ট করি যে আপনি ব্রডকাস্ট রিসিভারের ক্রিয়েশনকে কম্পোজ করার মতো আইটেম থেকে আলাদা করে এটিকে স্টেটলেস করুন:

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

ম্যানিফেস্টে উল্লেখ করা রিসিভার

আপনি যদি নিজের ম্যানিফেস্টে কোনও ব্রডকাস্ট রিসিভার ঘোষণা করেন, তাহলে ব্রডকাস্ট পাঠানো হলে সিস্টেম আপনার অ্যাপ লঞ্চ করে। অ্যাপ আগে থেকেই না চললে, সিস্টেম অ্যাপটি লঞ্চ করে।

ম্যানিফেস্টে ব্রডকাস্ট রিসিভার ঘোষণা করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের ম্যানিফেস্টে <receiver> এলিমেন্ট নির্দিষ্ট করুন।

    <!-- If this receiver listens for broadcasts sent from the system or from
         other apps, even other apps that you own, set android:exported to "true". -->
    <receiver android:name=".MyBroadcastReceiver" android:exported="false">
        <intent-filter>
            <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    ইন্টেন্ট ফিল্টার, আপনার রিসিভার সাবস্ক্রাইব করা ব্রডকাস্ট অ্যাকশন নির্দিষ্ট করে ।

  2. সাবক্লাস BroadcastReceiver এবং প্রয়োগ করুন onReceive(Context, Intent)। নিচে দেওয়া লগের উদাহরণে ব্রডকাস্ট রিসিভার ব্রডকাস্টের কন্টেন্ট দেখায়:

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    জাভা

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

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

সিস্টেম, এটি গ্রহণ করে এমন প্রতিটি ব্রডকাস্ট হ্যান্ডেল করার জন্য একটি নতুন BroadcastReceiver কম্পোনেন্ট অবজেক্ট তৈরি করে। এই অবজেক্টটি শুধুমাত্র onReceive(Context, Intent)-এ কল করার সময়সীমার জন্য বৈধ। এই মেথড থেকে আপনার কোড ফিরে আসার পরে, সিস্টেম কম্পোনেন্টকে আর অ্যাক্টিভ হিসেবে বিবেচনা করে না।

প্রসেস স্টেটের উপর প্রভাব

আপনার BroadcastReceiver কাজ করছে কিনা তা সেটির মধ্যে থাকা প্রসেসকে প্রভাবিত করে, যা সিস্টেম-কিলিংয়ের সম্ভাবনাকে পরিবর্তন করতে পারে। একটি ফোরগ্রাউন্ড প্রসেস প্রাপকের onReceive() পদ্ধতি এক্সিকিউট করে। অত্যন্ত কম মেমরি ছাড়া সিস্টেম এই প্রসেস চালায়।

onReceive() পরে সিস্টেম BroadcastReceiver বন্ধ করে দেয়। প্রাপকের হোস্ট প্রসেসের গুরুত্ব তার অ্যাপ কম্পোনেন্টের উপর নির্ভর করে। সেই প্রসেসে যদি শুধুমাত্র ম্যানিফেস্ট-ঘোষিত রিসিভার থাকে, তাহলে সিস্টেম onReceive() সেটি বন্ধ করে দিতে পারে, যাতে অন্যান্য আরও গুরুত্বপূর্ণ প্রসেসের জন্য রিসোর্স ফ্রি করা যায়। ব্যবহারকারী কখনও বা সম্প্রতি ইন্টার‍্যাক্ট করেননি এমন অ্যাপের ক্ষেত্রে এটি সাধারণ ঘটনা।

তাই, ব্রডকাস্ট রিসিভারদের দীর্ঘ সময় ধরে চলতে থাকা ব্যাকগ্রাউন্ড থ্রেড শুরু করা উচিত নয়। মেমরি রিক্লেম করার জন্য onReceive()-এর পরে সিস্টেম যেকোনও মুহূর্তে প্রসেস বন্ধ করে দিতে পারে এবং এর ফলে তৈরি হওয়া থ্রেড বন্ধ হয়ে যায়। প্রসেস চালু রাখতে, JobScheduler ব্যবহার করে প্রাপকের থেকে একটি JobService শিডিউল করুন যাতে সিস্টেম বুঝতে পারে যে প্রসেসটি এখনও কাজ করছে। ব্যাকগ্রাউন্ডে চলা প্রসেস ওভারভিউ আরও বিবরণ দেয়।

ব্রডকাস্ট পাঠানো

Android অ্যাপকে ব্রডকাস্ট পাঠানোর জন্য দুটি উপায় প্রদান করে:

  • sendOrderedBroadcast(Intent, String) পদ্ধতিতে একবারে একজন প্রাপককে ব্রডকাস্ট পাঠানো হয়। যেহেতু প্রতিটি রিসিভার এক এক করে এক্সিকিউট করে, তাই এটি পরবর্তী রিসিভারের কাছে ফলাফল প্রোপাগেট করতে পারে। এছাড়াও, এটি সম্প্রচার সম্পূর্ণ বাতিল করতে পারে যাতে এটি অন্যান্য রিসিভারের কাছে না পৌঁছায়। আপনি একই অ্যাপ প্রসেসের মধ্যে রিসিভাররা যে ক্রমে রান করে তা কন্ট্রোল করতে পারবেন। এটি করতে, মিলে যাওয়া ইনটেন্ট-ফিল্টারের android:priority অ্যাট্রিবিউট ব্যবহার করুন। একই অগ্রাধিকার থাকা রিসিভাররা অনির্দিষ্ট ক্রমে রান করে।
  • sendBroadcast(Intent) পদ্ধতিতে সব রিসিভারকে অনির্দিষ্ট ক্রম অনুসারে ব্রডকাস্ট পাঠানো হয়। এটি হল সাধারণ ব্রডকাস্ট। এটি আরও বেশি কার্যকর, কিন্তু এর অর্থ হল যে প্রাপকরা অন্য প্রাপকদের থেকে ফলাফল পড়তে, ব্রডকাস্ট থেকে পাওয়া ডেটা প্রচার করতে বা ব্রডকাস্ট বাতিল করতে পারবেন না।

নিম্নলিখিত কোড স্নিপেট দেখায় যে কীভাবে একটি Intent তৈরি করে এবং sendBroadcast(Intent) কল করে একটি ব্রডকাস্ট পাঠানো যায়।

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

জাভা

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

ব্রডকাস্ট মেসেজটি একটি Intent অবজেক্টে মোড়ানো থাকে। ইনটেন্টের action স্ট্রিংয়ে অবশ্যই অ্যাপের জাভা প্যাকেজ নামের সিনট্যাক্স থাকতে হবে এবং ব্রডকাস্ট ইভেন্টকে অনন্যভাবে শনাক্ত করতে হবে। আপনি putExtra(String, Bundle)-এর মাধ্যমে ইন্টেন্টের সাথে অতিরিক্ত তথ্য অ্যাটাচ করতে পারবেন। এছাড়াও, আপনি একই সংস্থার একগুচ্ছ অ্যাপে ব্রডকাস্ট সীমিত করতে পারেন, এর জন্য ইনটেন্টে setPackage(String) কল করুন।

অনুমতির মাধ্যমে ব্রডকাস্ট সীমাবদ্ধ করা

অনুমতি আপনাকে সেইসব অ্যাপের সেটে ব্রডকাস্ট সীমাবদ্ধ করতে দেয় যেগুলি নির্দিষ্ট অনুমতি হোল্ড করে। আপনি কোনও ব্রডকাস্টের প্রেরক বা প্রাপকের উপর বিধিনিষেধ প্রয়োগ করতে পারবেন।

অনুমতি সহ ব্রডকাস্ট পাঠানো

আপনি sendBroadcast(Intent, String) বা sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) নম্বরে কল করলে, আপনি একটি অনুমতির প্যারামিটার নির্দিষ্ট করতে পারবেন। শুধুমাত্র সেইসব রিসিভারই ব্রডকাস্ট পাবেন যারা তাদের ম্যানিফেস্টে <uses-permission> ট্যাগ সহ সেই অনুমতির জন্য অনুরোধ করেছেন। অনুমতি বিপজ্জনক হলে, ব্রডকাস্ট গ্রহণকারীর ব্রডকাস্ট পাওয়ার আগে আপনাকে অবশ্যই অনুমতি দিতে হবে। যেমন, নিম্নলিখিত কোডটি অনুমতি সহ একটি ব্রডকাস্ট পাঠায়:

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

জাভা

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

ব্রডকাস্ট পেতে, গ্রহণকারী অ্যাপকে নিম্নলিখিতভাবে অনুমতি অনুরোধ করতে হবে:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

আপনি BLUETOOTH_CONNECT-এর মতো আগে থেকে থাকা সিস্টেম অনুমতি নির্দিষ্ট করতে পারেন অথবা <permission> এলিমেন্ট দিয়ে কাস্টম অনুমতি নির্ধারণ করতে পারেন। সাধারণভাবে অনুমতি ও নিরাপত্তা সম্পর্কে তথ্য পেতে, সিস্টেমের অনুমতি দেখুন।

অনুমতি সহ ব্রডকাস্ট পাওয়া

আপনি যদি কোনও ব্রডকাস্ট রিসিভার রেজিস্টার করার সময় অনুমতি প্যারামিটার নির্দিষ্ট করেন (হয় registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)-এর সাথে বা আপনার ম্যানিফেস্টে <receiver> ট্যাগে), তাহলে শুধুমাত্র সেইসব ব্রডকাস্টার যারা তাদের ম্যানিফেস্টে <uses-permission> ট্যাগ সহ অনুমতির জন্য অনুরোধ করেছেন, তারাই রিসিভারকে ইনটেন্ট পাঠাতে পারবেন। অনুমতি বিপজ্জনক হলে, ব্রডকাস্টারকেও সেই অনুমতি দিতে হবে।

যেমন, ধরে নিন আপনার রিসিভিং অ্যাপে ম্যানিফেস্ট-ঘোষিত রিসিভার হিসেবে এগুলি আছে:

<!-- If this receiver listens for broadcasts sent from the system or from
     other apps, even other apps that you own, set android:exported to "true". -->
<receiver
    android:name=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

অথবা আপনার গ্রহণকারী অ্যাপে নিম্নলিখিতভাবে একটি প্রসঙ্গ-রেজিস্টার করা রিসিভার আছে:

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

জাভা

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

তারপরে, সেইসব রিসিভারকে ব্রডকাস্ট পাঠাতে, প্রেরক অ্যাপকে নিম্নলিখিতভাবে অনুমতি চেয়ে অনুরোধ করতে হবে:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

একই প্রসেসের মধ্যে ব্রডকাস্ট করা এড়িয়ে যান

ব্রডকাস্টকে বিভিন্ন অ্যাপ জুড়ে বা সিস্টেম ও অ্যাপের মধ্যে মেসেজ পাঠানোর জন্য ইন্টারপ্রসেস কমিউনিকেশন (IPC) মেকানিজম হিসেবে ডিজাইন করা হয়েছে। একই প্রসেসের মধ্যে চলছে এমন কোনও রিসিভারকে কোনও প্রসেস থেকে ব্রডকাস্ট পাঠানো খুবই অদক্ষ, এর ফলে অপ্রয়োজনীয় সিস্টেম ওভারহেড তৈরি হয় এবং এটি করতে বারণ করা হয়।

দুটি সাধারণ পরিস্থিতি যেখানে অ্যাপ নিজেকে ব্রডকাস্ট পাঠায়:

  • একই প্রসেসে কম্পোনেন্টগুলির মধ্যে যোগাযোগ করা: যেমন, অ্যাক্টিভিটি, ফ্র্যাগমেন্ট, পরিষেবা বা ব্যাকগ্রাউন্ড থ্রেডের মধ্যে ইভেন্ট বা ডেটা পাস করা। ব্রডকাস্ট পাঠানোর পরিবর্তে, স্ট্যান্ডার্ড ইন-প্রসেস যোগাযোগের মেকানিজম ব্যবহার করুন, যেমন অবজার্ভার প্যাটার্ন বা রিঅ্যাক্টিভ স্ট্রিম:

    • Kotlin Flows (SharedFlow ও StateFlow): আপনার অ্যাপের কোরাউটিন ও কম্পোনেন্ট জুড়ে ইভেন্ট স্ট্রিম বা স্টেট আপডেট এমিট ও পর্যবেক্ষণ করার জন্য Kotlin-এ একটি আধুনিক, বাগধারা-ভিত্তিক সমাধান।
    • শেয়ার করা ViewModel: একই অ্যাক্টিভিটির মধ্যে বিভিন্ন UI কম্পোনেন্ট (যেমন, ফ্র্যাগমেন্ট বা কম্পোজ করার উপযুক্ত) এর মধ্যে ডেটা ও ইভেন্ট শেয়ার করার সুবিধা দেয়।
    • কলব্যাক ও লিসনার: স্ট্যান্ডার্ড ইন্টারফেস কলব্যাক বা ফাংশন রেফারেন্স সরাসরি কম্পোনেন্টের মধ্যে পাস করা হয় অথবা সেন্ট্রাল রিপোজিটরি বা কন্ট্রোলারের সাথে রেজিস্টার করা হয়।
  • সিস্টেম ইভেন্ট, জব বা অ্যালার্ম ম্যানেজ করা: যেমন, কোনও শিডিউল করা জব, অ্যালার্ম বা সিস্টেম কলব্যাক পাওয়া এবং তারপরে আসল কাজ ট্রিগার করার জন্য ব্রডকাস্ট পাঠানো। ব্রডকাস্ট পাঠানোর পরিবর্তে, সরাসরি সেই জবের মধ্যে কাজ সম্পূর্ণ করুন (যেমন JobService বা WorkManager ওয়ার্কার), অ্যালার্ম হ্যান্ডলার বা সিস্টেম কলব্যাক কম্পোনেন্ট অথবা সরাসরি আপনার অ্যাপের বিজনেস লজিক ক্লাসে ডেলিগেট করুন।

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

অ্যাপ কম্পোনেন্টগুলির মধ্যে যোগাযোগ ডিজাইন করা সম্পর্কে আরও তথ্যের জন্য, অ্যাপ আর্কিটেকচার সংক্রান্ত নির্দেশিকা দেখুন।

নিরাপত্তা সংক্রান্ত বিষয়

ব্রডকাস্ট পাঠানো ও পাওয়ার ক্ষেত্রে নিরাপত্তা সংক্রান্ত কিছু বিষয় এখানে দেওয়া হল:

  • অনেক অ্যাপ যদি তাদের ম্যানিফেস্টে একই ব্রডকাস্ট পাওয়ার জন্য রেজিস্টার করে থাকে, তাহলে সিস্টেম অনেক অ্যাপ লঞ্চ করতে পারে, যার ফলে ডিভাইস পারফর্ম্যান্স ও ব্যবহারকারীর অভিজ্ঞতার উপর গুরুতর প্রভাব পড়তে পারে। এটি এড়াতে, ম্যানিফেস্ট ঘোষণার পরিবর্তে প্রসঙ্গ রেজিস্ট্রেশন ব্যবহার করুন। কখনও কখনও, Android সিস্টেম নিজেই কন্টেক্সট-রেজিস্টার্ড রিসিভার ব্যবহার করতে বাধ্য করে। যেমন, CONNECTIVITY_ACTION ব্রডকাস্ট শুধুমাত্র প্রসঙ্গ-রেজিস্টার্ড রিসিভারদের কাছে ডেলিভার করা হয়।

  • ইমপ্লিসিট ইনটেন্ট ব্যবহার করে সংবেদনশীল তথ্য ব্রডকাস্ট করবেন না। কোনও অ্যাপ সম্প্রচার পাওয়ার জন্য রেজিস্টার করলে, সেটি তথ্য পড়তে পারবে। আপনার ব্রডকাস্ট কে পাবেন তা নিয়ন্ত্রণ করার তিনটি উপায় আছে:

    • ব্রডকাস্ট পাঠানোর সময় আপনি অনুমতি নির্দিষ্ট করতে পারবেন।
    • Android 4.0 (API লেভেল 14) ও এর পরের যেকোনও ভার্সনে, ব্রডকাস্ট পাঠানোর সময় আপনি setPackage(String) সহ একটি প্যাকেজ নির্দিষ্ট করতে পারবেন। সিস্টেম, প্যাকেজের সাথে ম্যাচ করে এমন অ্যাপের সেটে ব্রডকাস্ট সীমাবদ্ধ করে।
  • আপনি কোনও রিসিভার রেজিস্টার করলে, যেকোনও অ্যাপ আপনার অ্যাপের রিসিভারকে সম্ভাব্য ক্ষতিকারক ব্রডকাস্ট পাঠাতে পারে। আপনার অ্যাপ যেসব ব্রডকাস্ট পায় সেগুলি সীমিত করার বিভিন্ন উপায় আছে:

    • ব্রডকাস্ট রিসিভার রেজিস্টার করার সময় আপনি অনুমতি নির্দিষ্ট করতে পারবেন।
    • ম্যানিফেস্ট-ঘোষিত রিসিভারের জন্য, আপনি ম্যানিফেস্টে android:exported অ্যাট্রিবিউটকে "false" হিসেবে সেট করতে পারবেন। প্রাপক অ্যাপের বাইরের সোর্স থেকে ব্রডকাস্ট পান না।
  • ব্রডকাস্ট অ্যাকশনের নেমস্পেস গ্লোবাল। নিশ্চিত করুন যে অ্যাকশনের নাম এবং অন্যান্য স্ট্রিং আপনার মালিকানাধীন নেমস্পেসে লেখা আছে। অন্যথায়, আপনি অনিচ্ছাকৃতভাবে অন্যান্য অ্যাপের সাথে সমস্যা তৈরি করতে পারেন।

  • কারণ রিসিভারের onReceive(Context, Intent) পদ্ধতিটি মূল থ্রেডে রান করে, এটি দ্রুত এক্সিকিউট ও রিটার্ন করা উচিত। দীর্ঘ সময় ধরে চলতে পারে এমন কোনও কাজ করতে হলে, থ্রেড স্পন করা বা ব্যাকগ্রাউন্ড পরিষেবা শুরু করার ব্যাপারে সতর্ক থাকুন, কারণ onReceive() রিটার্ন করার পরে সিস্টেম সম্পূর্ণ প্রসেসটি বন্ধ করে দিতে পারে। আরও তথ্যের জন্য, প্রসেস স্টেটের উপর প্রভাব দেখুন। দীর্ঘ সময় ধরে চলতে থাকা কাজ করার জন্য, আমরা সাজেস্ট করি:

    • আপনার রিসিভারের onReceive() পদ্ধতিতে goAsync() কল করা এবং ব্যাকগ্রাউন্ড থ্রেডে BroadcastReceiver.PendingResult পাস করা। এর ফলে, onReceive() থেকে ফিরে আসার পরেও ব্রডকাস্ট অ্যাক্টিভ থাকে। তবে, এই পদ্ধতি অনুসরণ করলেও, সিস্টেম আশা করে যে আপনি খুব দ্রুত (১০ সেকেন্ডের মধ্যে) সম্প্রচার শেষ করবেন। এটি আপনাকে মূল থ্রেডে গ্লিচ এড়াতে অন্য থ্রেডে কাজ সরানোর অনুমতি দেয়।
    • JobScheduler-এর মাধ্যমে কোনও জব শিডিউল করা। আরও তথ্যের জন্য, ইন্টেলিজেন্ট জব শিডিউলিং দেখুন।
  • ব্রডকাস্ট রিসিভার থেকে অ্যাক্টিভিটি শুরু করবেন না, কারণ ব্যবহারকারীর অভিজ্ঞতা খুবই খারাপ হয়; বিশেষ করে একাধিক রিসিভার থাকলে। পরিবর্তে, বিজ্ঞপ্তি দেখানোর কথা বিবেচনা করুন।