如何使用 kotlin 扫描蓝牙设备

How to scan for bluetooth devices with kotlin

我正在用 kotlin 编写 android 应用程序,我想扫描附近的蓝牙设备,不是 之前配对的设备,我是 使用 BLE。

到目前为止,我已尝试使用蓝牙适配器的函数 startDiscovery(),该函数可能会开始发现设备,但没有任何反应。根据 developer.android.com 它应该扫描 12 秒。在我的代码中,它在启动后立即停止。下面的代码是我到目前为止所拥有的。我会把recycleView adapter也放上去,方便大家测试app。

RecycleView 适配器

package com.example.andruino_bt

import android.bluetooth.BluetoothDevice
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.activity_main_recycle_view.view.*

class RecyclerAdapter(private val devices: ArrayList<BluetoothDevice>) : RecyclerView.Adapter<RecyclerAdapter.DeviceHolder>(){

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceHolder {
        val inflatedView = parent.inflate(R.layout.activity_main_recycle_view, false)
        return DeviceHolder(inflatedView)
    }

    override fun getItemCount(): Int {
        Log.i("", devices.size.toString())
        return devices.size
    }

    override fun onBindViewHolder(holder: DeviceHolder, position: Int) {
        val itemDevice = devices[position]
        holder.bindDevice(itemDevice)
    }


    class DeviceHolder(v: View) : RecyclerView.ViewHolder(v), View.OnClickListener {

        private var view: View = v
        private var device : BluetoothDevice? = null


        init {
            v.setOnClickListener(this)
        }


        override fun onClick(v: View) {
            Log.i("RecyclerView", "CLICK!")
        }

        fun bindDevice(device: BluetoothDevice) {
            this.device = device
            val name = "Name: ${device.name}"
            view.device_name.text = name
            val address = "Address: ${device.address}"
            view.device_add.text = address
            Log.i("RecyclerView", device.name.toString())
        }

        companion object {
            private val PHOTO_KEY = "PHOTO"
        }
    }
}

膨胀函数(在单独的文件中)

package com.example.andruino_bt

import android.support.annotation.LayoutRes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
    return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}

主要Activity

package com.example.andruino_bt

import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import android.support.v4.widget.SwipeRefreshLayout



class MainActivity : AppCompatActivity(){
    private lateinit var linearLayoutManager: LinearLayoutManager
    private lateinit var m_pairedDevices: Set<BluetoothDevice>
    private lateinit var adapter: RecyclerAdapter

    private var m_bluetoothAdapter: BluetoothAdapter? = null
    private val REQUEST_ENABLE_BLUETOOTH = 1
    private val devices_list : ArrayList<BluetoothDevice> = ArrayList()
    private val swipeContainer: SwipeRefreshLayout? = null


    companion object {
        val EXTRA_ADDRESS: String = "Device_address"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        supportActionBar?.hide()



        m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        if(m_bluetoothAdapter == null) {
            Toast.makeText(this, "this device doesn't support bluetooth", Toast.LENGTH_SHORT).show()
            return
        }
        if(!m_bluetoothAdapter!!.isEnabled) {
            val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH)

            val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
                putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
            }
            startActivity(discoverableIntent)

        }else{
            discoverDevices()
        }

        findViewById<SwipeRefreshLayout>(R.id.swipeContainer).setOnRefreshListener{

            devices_list.clear()
            discoverDevices()
        }

    }

    private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            if (BluetoothDevice.ACTION_FOUND == action) {
                // A Bluetooth device was found
                // Getting device information from the intent
                val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                devices_list.add(device)
            }
        }
    }

    private fun discoverDevices(){
        if (m_bluetoothAdapter!!.isDiscovering) {
            // Bluetooth is already in mode discovery mode, we cancel to restart it again
            m_bluetoothAdapter!!.cancelDiscovery()
        }
        val bool = m_bluetoothAdapter?.startDiscovery()
        Log.i("", bool.toString())
        val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
        registerReceiver(mReceiver, filter)


        linearLayoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = linearLayoutManager

        adapter = RecyclerAdapter(devices_list)
        recyclerView.adapter = adapter
        findViewById<SwipeRefreshLayout>(R.id.swipeContainer).isRefreshing = false
        unregisterReceiver(mReceiver)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
            if (resultCode == Activity.RESULT_OK) {
                if (m_bluetoothAdapter!!.isEnabled) {
                    Toast.makeText(this, "Bluetooth enabled", Toast.LENGTH_SHORT).show()
                    discoverDevices()
                } else {
                    Toast.makeText(this, "Bluetooth disabled", Toast.LENGTH_SHORT).show()
                }
            } else if (resultCode == Activity.RESULT_CANCELED) {
                Toast.makeText(this, "Bluetooth enabling has been canceled", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

作为布局,我在 swipeContainer 中使用 RecycleView 进行刷新。同样在清单中我有以下权限:

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

已找到代码的最大部分 here (recycleView) and here (bluetooth)。请注意,link 中的初始蓝牙代码设置为查找先前配对的设备。那部分对我来说很管用,但这不是我想要的。

抱歉拖了这么久 post 如果您需要更多信息,请在评论中告诉我,我也会添加。提前致谢。

尝试在getDefaultAdapter()之前使用startDiscovery()方法,甚至enable()方法。 有关更多信息,请查看:BluetoothAdapter

您在开始发现时注销了接收器。 将此:unregisterReceiver(Received) 移至 onStop 并将 registerReceiver 到 onStart