Search code examples
androidkotlinbroadcastreceiverlocalbroadcastmanager

Android Kotlin Broad Receiever in RecyclerAdapter Won't Communicate to Broadcast Receiever in MainActivity


Context: No receiver is declared in the manifest since I am not declaring a new receiver.

I am a bit confused about why the receiver in MainActivity does not receieve the broadcast sent from the recycler adapter.

RecyclerAdapter

        holder.checkBox.setOnClickListener {view ->
            item.completed = holder.checkBox.isChecked
            Log.i("wow", "is checked: ${holder.checkBox.isChecked}")
            val intent = Intent().apply {
                addCategory(Intent.CATEGORY_DEFAULT)
                setAction(changeCompletedForDeck)
                putExtra(changeCompletedForDeckItemID, item)
            }
            LocalBroadcastManager.getInstance(view.context).sendBroadcast(intent)

MainActivity

 private lateinit var broadcastReceiver: BroadcastReceiver

          broadcastReceiver = object: BroadcastReceiver() {
           override fun onReceive(context: Context?, intent: Intent?) {
               //get deck, if deck != null then update the checkmark response
               if (intent?.action == DeckRecyclerAdapter.changeCompletedForDeck) {
                   val deck = intent?.extras?.getParcelable<Deck>(DeckRecyclerAdapter.changeCompletedForDeckItemID)
                   Log.i("wow", "${deck?.title}")
                   deck?.let { deck ->
                       globalViewModel.update(deck)
                   }
               }
           }
       }
val filter = IntentFilter(DeckRecyclerAdapter.changeCompletedForDeck)
        LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, filter)


    //Destroy the BroadcastReceiver
    override fun onDestroy() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
        super.onDestroy()
    }


Solution

  • Your problem is Intent action . See at the time of register you have not provided any action so receiver will not be identified by the system. You can define a specific action with IntentFilter and use the same action during register and sendBroadcast.

    To identify different conditions you can do two things.

    1. you can set data in Bundle and validate the bundle value inside onReceive()
    2. you can also add multiple actions to IntentFilter and validate the action inside onReceive() See this.

    So with the first way have a constant action in MainActivity:-

    companion object{
        const val BROADCAST_ACTION="LIST_CHECK_ACTION"
    }
    
    
    LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter(BROADCAST_ACTION)).
    

    Then for sending broadcast use the code below addCategory(Intent.CATEGORY_DEFAULT) is not required:-

    val intent = Intent().apply {
            action = MainAcvity.BROADCAST_ACTION
            putExtra("item", item)
        }
        LocalBroadcastManager.getInstance(view.context).sendBroadcast(intent)
    

    PS- However i don't think you should be using a Broadcastreceiver just to provide a callback from Adapter its purpose is more than that. You should be using a callback listener for it . Since RecyclerView.Adapter will binds to a UI component a callback interface will be fine . I think a broadcastReceiver is overkill in this usecase .