как установить цвет RecyclerView.ViewHolder в BroadcastReceiver.onReceive?

Я создаю приложение, которое сканирует и соединяется с устройствами Bluetooth. Я показываю устройства в RecyclerView и указываю состояние связи, окрашивая ViewHolder для этого устройства. моя проблема в том, что цвет ViewHolder изменяется только после сканирования для устройств снова, и я хочу, чтобы он сразу обновлял цвет на пару или несанкционированный доступ. Я пытаюсь сделать это с помощью широковещательного приемника, но я не могу получить ссылку на правильный ViewHolder. как я могу это достичь? Я включил мой код ниже для моего RecyclerView.Adapter и моего файла BluetoothUtils, содержащего широковещательный приемник. заранее спасибо. мой адаптер:

class DeviceAdapter(val mContext : Context) : RecyclerView.Adapter<DeviceAdapter.DeviceHolder>() { companion object { val TAG = "Device Adapter" fun DeviceHolder.setColor(bonded: Boolean):Unit{ val background = if (bonded)Color.CYAN else Color.TRANSPARENT this.itemView.setBackgroundColor(background) } } val mDevices = ArrayList<BluetoothDevice>() fun updateItems(list: ArrayList<BluetoothDevice>) { mDevices.clear() mDevices.addAll(list) Log.d(TAG, "updating items : $mDevices") notifyDataSetChanged() } fun ViewGroup.inflate(@LayoutRes res: Int, attachToRoot: Boolean = false): View { return LayoutInflater.from(mContext).inflate(res, this, attachToRoot) } override fun onBindViewHolder(holder: DeviceHolder, position: Int) { Log.d(TAG, "onBindViewHolder called!") holder.bindItems(mDevices.get(position)) if (mDevices.get(position).bondState==BluetoothDevice.BOND_BONDED) { holder.itemView.setBackgroundColor(CYAN) } else { holder.itemView.setBackgroundColor(Color.TRANSPARENT) } } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeviceAdapter.DeviceHolder { Log.d(TAG, "onCreateViewHolder called!") val v = parent!!.inflate(R.layout.device_item, false) return DeviceHolder(v) } override fun getItemCount(): Int { return mDevices.size } inner class DeviceHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val nameView = itemView.findViewById(R.id.nameView) as TextView val addrView = itemView.findViewById(R.id.addressView) as TextView var dialog: AlertDialog? = null; fun bindItems(btDevice: BluetoothDevice) { Log.d(TAG, "holder created!") nameView.text = btDevice.name ?: "Unknown" addrView.text = btDevice.address itemView.setOnClickListener { dialog = AlertDialog.Builder(it.context) .setTitle("Options") .setView(R.layout.options_dialog_layout) .setNegativeButton("Cancel", DialogInterface.OnClickListener { _, which -> }) .create() dialog!!.show() val ops = listOf( dialog!!.findViewById(R.id.statOp), dialog!!.findViewById(R.id.pairOp), dialog!!.findViewById(R.id.connectOp), dialog!!.findViewById(R.id.sendOp), dialog!!.findViewById(R.id.unPairOp) ) ops.forEach { it.setOnClickListener { Toast.makeText(it.context, it.id.toString(), Toast.LENGTH_SHORT).show() when(it.id){ R.id.statOp -> {} R.id.connectOp -> { Log.d(TAG, "connectOp reached") BluetoothReflection.connectDevice(btDevice) dialog!!.dismiss() }// BluetoothUtils.connect(BluetoothAdapter.getDefaultAdapter(), btDevice) R.id.pairOp -> { Log.d(TAG, "pairOp reached") BluetoothUtils.startPair(BluetoothAdapter.getDefaultAdapter(), btDevice) if (btDevice.bondState==BluetoothDevice.BOND_BONDED){ this@DeviceHolder.itemView.setBackgroundColor(CYAN) //doesn't work } Log.d(TAG, "start pair complete") dialog!!.dismiss() }// R.id.unPairOp -> {//no executable code found here Log.d(TAG, "unPairOp reached") BluetoothUtils.unPair(btDevice) if (btDevice.bondState==BluetoothDevice.BOND_NONE){ this@DeviceHolder.itemView.setBackgroundColor(Color.TRANSPARENT) //doesn't work } Log.d(TAG, "unpair complete") dialog!!.dismiss() } R.id.sendOp -> {} } } } } } } } 

и мой BluetoothUtils:

 class BluetoothUtils { companion object { var listener: ListenThread? = null val _UUID = UUID.fromString("a0e7e4c7-0e4e-43b7-9d18-659192512164") val TAG = "BluetoothUtils" val receiver = MainBTStatusReceiver() fun initPairingServer(adapter: BluetoothAdapter){ var mmServerSocket: BluetoothServerSocket? try { var tmp = adapter.listenUsingRfcommWithServiceRecord(TAG, _UUID) mmServerSocket = tmp listener = ListenThread(mmServerSocket) listener!!.start() }catch (ioe: IOException){ Log.e(TAG, "Error initializing Bluetooth", ioe) } } fun cancelListener() = listener!!.cancel() fun connect(adapter: BluetoothAdapter, device: BluetoothDevice){ var btSocket: BluetoothSocket? try { adapter.cancelDiscovery() btSocket = device.createRfcommSocketToServiceRecord(_UUID) PairingThread(btSocket).start() }catch (ioe: IOException){ Log.e(TAG, "error connecting", ioe) } } fun startPair(adapter: BluetoothAdapter, device: BluetoothDevice): Unit{ adapter.cancelDiscovery() Log.d(TAG, device.bondState.toString()) device.createBond() } fun unPair(device: BluetoothDevice): Any = device::class.java.getMethod("removeBond").invoke(device) } } class ListenThread(val btServSock: BluetoothServerSocket) : Thread(){ companion object { val TAG = "ListenThread" } var btSocket: BluetoothSocket? = null override fun run() { super.run() while (true){ try { Log.d(TAG, "listening . . . ") btSocket = btServSock.accept() }catch (ioe: IOException){ Log.e(TAG, "Error", ioe) // SHOULD HANDLE FAILURE OF LISTENER INSTANTIATION break } //manage connection here //with either BluetoothUtils function //or BluetoothSocket extension } } fun cancel() = btServSock.close() } class PairingThread(val btSocket: BluetoothSocket) : Thread(){ companion object { val TAG = "Pairing Thread" } override fun run() { super.run() try { Log.d(TAG, "attempting to connect") btSocket.connect() }catch (ioe: IOException){ Log.e(TAG, "error connecting", ioe) btSocket.close() } } } class MainBTStatusReceiver(): BroadcastReceiver(){ val TAG = "MainBTStatusReceiver" var mAdapter: DeviceAdapter? = null fun setAdapter(adapter: DeviceAdapter){ mAdapter = adapter } override fun onReceive(context: Context?, intent: Intent) { val action = intent.action val devExtra = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) as BluetoothDevice when(action){ BluetoothDevice.ACTION_BOND_STATE_CHANGED -> { val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) when(device.bondState){ BluetoothDevice.BOND_BONDED -> { Log.d(TAG, "BONDED") } BluetoothDevice.BOND_BONDING -> {Log.d(TAG, "BONDING")} BluetoothDevice.BOND_NONE -> {Log.d(TAG, "NONE")} } } } } 

    Добавьте boolean или int в модель BluetoothDevice для управления представлением.

    Например,

    BluetoothDevice: добавлено состояние isOn . (Извините, это Java)

     class BluetoothDevice { boolean isOn; public boolean isOn() { return isOn; } public void setOn(boolean isOn) { this.isOn = isOn; } } 

    DeviceHolder: измененный цвет представления

     fun bindItems(btDevice: BluetoothDevice) { stateView.textColor = btDevice.isOn() ? Color.RED : Color.GREEN } 

    DeviceAdapter: добавлен getItems

     fun getItems() { return mDevices } 

    Если вы хотите изменить состояние isOn , измените модель и сообщите об этом.

     adapter.getItems().get(i).setOn(true); adapter.notifyDataSetChanged(); 

    Мне тоже нравится этот ответ, но способ, которым я это сделал, – передать BroadcastReceiver в DeviceAdapter:

     class DeviceAdapter(val mContext:Context, val mReceiver:MainBTStatusReceiver) : RecyclerView.Adapter<DeviceAdapter.DeviceHolder>() 

    а затем сделал ViewHolder членом BroadcastReceiver и функцию setter для ViewHolder с именем setFocus. перед вызовом каких-либо функций из класса BluetoothUtils я назвал функцию setFocus, а затем широковещательный приемник изменяет цвет представления, которое в настоящее время установлено в фокусе. Я действительно беспокоюсь, что это может быть ненадежным, как самый точный метод для изменения правильного ViewHolder каждый раз. если вы видите какие-либо проблемы с этим, прокомментируйте, чтобы сообщить мне.

    мой обновленный BroadcastReceiver:

     class MainBTStatusReceiver(): BroadcastReceiver() { val TAG = "MainBTStatusReceiver" var holder: DeviceAdapter.DeviceHolder? = null fun setFocus(holder: DeviceAdapter.DeviceHolder) { this.holder = holder } override fun onReceive(context: Context?, intent: Intent) { val action = intent.action when (action) { BluetoothDevice.ACTION_BOND_STATE_CHANGED -> { val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) when (device.bondState) { BluetoothDevice.BOND_BONDED -> { holder!!.itemView.setBackgroundColor(Color.CYAN) Log.d(TAG, "BONDED") } BluetoothDevice.BOND_BONDING -> { Log.d(TAG, "BONDING") } BluetoothDevice.BOND_NONE -> { holder!!.itemView.setBackgroundColor(Color.TRANSPARENT) Log.d(TAG, "NONE") } } } } } } 

    и два утверждения в моем выражении, которое вызывает setFocus ():

      R.id.pairOp -> { Log.d(TAG, "pairOp reached") mReceiver.setFocus(this@DeviceHolder) BluetoothUtils.startPair(BluetoothAdapter.getDefaultAdapter(), btDevice) Log.d(TAG, "start pair complete") dialog!!.dismiss() } R.id.unPairOp -> { Log.d(TAG, "unPairOp reached") mReceiver.setFocus(this@DeviceHolder) BluetoothUtils.unPair(btDevice) Log.d(TAG, "unpair complete") dialog!!.dismiss() }