2017-10-17 127 views
1

我正在创建扫描并配对蓝牙设备的应用程序。我在RecyclerView中显示设备,并通过为该设备着色ViewHolder来指示绑定状态。我的问题是ViewHolder的颜色只有在再次扫描设备后才会更改,我希望它立即更新配对或未配对的颜色。我试图通过使用广播接收器来做到这一点,但我无法获得正确的ViewHolder的参考。我怎么能做到这一点?我将下面的代码包含在我的RecyclerView.Adapter和包含广播接收器的BluetoothUtils文件中。提前致谢。我的适配器:如何在BroadcastReceiver.onReceive中设置RecyclerView.ViewHolder的颜色?

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){ 
          [email protected](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){ 
          [email protected](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")} 
      } 
     } 
    } 
} 

回答

1

添加booleanintBluetoothDevice模型管理视图。

例如,

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

我喜欢上面的回答很好,但我得到这个工作的方式是向广播接收器传递到DeviceAdapter:

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

,然后做了一个ViewHolder的广播接收器和一个成员用于名为setFocus的ViewHolder的setter函数。在从BluetoothUtils类调用任何函数之前,我调用setFocus函数,然后广播接收器修改焦点当前设置的视图的颜色。我确实有一些担心,这可能是不可靠的,因为它是每次修改正确ViewHolder的最准确方法。如果您发现有任何问题,请发表评论让我知道。

我更新的广播接收器:

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([email protected]) 
         BluetoothUtils.startPair(BluetoothAdapter.getDefaultAdapter(), btDevice) 
         Log.d(TAG, "start pair complete") 
         dialog!!.dismiss() 
        } 
        R.id.unPairOp -> { 
         Log.d(TAG, "unPairOp reached") 
         mReceiver.setFocus([email protected]) 
         BluetoothUtils.unPair(btDevice) 
         Log.d(TAG, "unpair complete") 
         dialog!!.dismiss() 
        }