Android蓝牙遥控器

这是以前做的一个手机蓝牙遥控器,原本是用来控制一个微型四旋翼的。四旋翼做了第二版后改NRF2401控制了,所以这个程序最终还是没用,下面介绍一下这个程序的关键代码。

连接的对象是一个蓝牙4.0模块,连接上了之后通过串口对飞机进行控制。说一下蓝牙模块的距离,可能因为是用的是蓝牙4.0的缘故,我在走廊里面测试是33米的距离,还是挺远的,足够了。这个程序连接的上蓝牙模块的是有概率失败的,我使用的魅族手机,失败的概率非常高,但是换成的华为手机后,失败概率就小多了,所以这个成功率还是跟手机厂商的优化有关的,但是连接上了还是非常稳定的。

下面介绍程序功能,该程序该程序包括两个Activity,主Activity如下图所示:

主Activity

主Activity是一个遥控界面(按钮是随便拉进去的,各种没对齐-_-),点击蓝牙连接按钮,可以跳到第二个Activity,如下图:

从Activity

这个Activity包括一个ListView,点击开启蓝牙Button查找设备,并把所查找到的设备名称放在ListView里面,点击ListView中要连接的设备,就会跳回主Activity,同时进行蓝牙连接。在屏幕的中间显示连接状态,连接成功后即可传输数据。

总的来说,要使用Android的蓝牙,主要分下面几步:

  • 开启蓝牙
  • 查找设备
  • 蓝牙连接
  • 接收或发送数据

因为开启蓝牙Button在从Activity里面,所以开启蓝牙的操作应该是在从Activity中的,因此需要从主Activity切换到从Activity,这里很简单就省略了。下面是开启蓝牙的代码:

Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//3600为蓝牙设备可见时间
enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); 
startActivity(enable);

通过Intent开启蓝牙,写到按钮事件中就可以点击按钮开启蓝牙。
开启蓝牙蓝牙之后,就可以调用适配器来查找蓝牙设备了,其代码如下:

private BluetoothAdapter adapter;
private BluetoothReceiver receiver;

adapter = BluetoothAdapter.getDefaultAdapter();//得到默认的蓝牙适配器
if (adapter.getState() != BluetoothAdapter.STATE_ON) {// 如果蓝牙还没开启
    Toast.makeText(MyBlueTooth.this, "请开启蓝牙", Toast.LENGTH_SHORT).show();
}else {
    adapter.startDiscovery();//开始搜索
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    receiver = new BluetoothReceiver();
    registerReceiver(receiver, filter);//注册广播
}

首先通过adtapter查看蓝牙是否开启,如开启则开始搜索,其中adapter.startDiscovery()是一个异步方法,调用后在后台对周围的蓝牙设备进行搜索,然后将搜索结果通过广播的形式发送,所以这里要注册广播,BluetoothReceiver是自定义的一个广播接收器,继承自BroadcastReceiver类,这里定义成了一内部类,代码如下:

private ListView listView; 
private List<String> deviceNames;                                                                                             
private List deviceList; 

listView = (ListView)findViewById(R.id.listView);
deviceNames = new ArrayList<String>();                                                
deviceList = new ArrayList();
//内部类
private class BluetoothReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {//发现设备
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (deviceNames.indexOf(device.getName()) == -1) {//列表中没有名字
                deviceNames.add(device.getName());//添加
            }
            deviceList.add(device);
        }
        showDevices();
    }
}
private void showDevices() {
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,deviceNames);
    listView.setAdapter(adapter);
}

这里涉及到了一些ListView的用法,就不展开了。
前面几步进展地还比较顺利,但到了蓝牙连接这里就出现了很多问题。第一是BluetoothSocket的两种创建方式,一种是通过特定的UUID来创建,我试了很多次连接都成问题,然后查到了第二种方法,通过调用BlueDevice的隐藏方法createRfcommSocket()来创建socket,应用到了Java的反射机制,这种方法只能说能够连上,失败的概率还是很大的(之后测试了其他手机,连接成功率就上去了,可能跟不同的手机厂商的优化有关,问题也可能出在代码本身上)。第二是连接耗时比较长,所以不能放到主线程中,需要新开一个线程进行连接,用Handler接收连接状态,更新UI界面。第三是前面所有的操作都是在从Activity中完成的,但是蓝牙连接的操作需要放到主Activity中,所以要实现主Activity与从Activity 的数据传输。先说Activity间的数据传输问题,我用了Android的Application类来传输,代码如下:

BluetoothDevice device = deviceList.get(position);//获取蓝牙设备
adapter.cancelDiscovery();//取消搜索
bridge.setDate(device);//传递数据
MainActivity.back = true;
//返回操作界面
Intent backIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(backIntent);

需要说明的是,在连接之前需要取消搜索,就是调用cancelDiscovery()方法,否则连接会变得异常缓慢。其中的 bridge继承自Application类,用于传递数据,可以看到,这里是把一个BluetoothDevice的实例化对象传递了过去。然后在主Activity中接收该对象:

public static boolean back = false;
private BluetoothConnect client;
//onCreate()
if(back){//返回后开始读数据
    device = bridge.getDate();
    client = new BluetoothConnect(device,handler);
    client.connect();//开始连接
}

可以看到,这里蓝牙设备的获取是在从Activity中,而创建连接是在主Activity中。在主Activity中接收到了device,通过device就可以创建socket进行连接了,这个过程我封装到一个BluetoothConnect类中,方便以后调用,下面是其中的connect()方法:

private BluetoothSocket socket;

public void connect(){
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            Method method;
            state = CONNECT_SUCCESS;
            try {
                //利用反射机制创建socket
                method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                socket = (BluetoothSocket) method.invoke(device, 1);
                socket.connect();                                                                                                                               
                isConnect = ture;
            } catch (IOException e) {
                state = CONNECT_FAILED;
                Log.e("TAG", e.toString());
            } catch (InvocationTargetException e) {
                state = CONNECT_FAILED;
                Log.e("TAG", e.toString());
            } catch (NoSuchMethodException e) {
                state = CONNECT_FAILED;
                Log.e("TAG", e.toString());
            } catch (IllegalAccessException e) {
                state = CONNECT_FAILED;
                Log.e("TAG", e.toString());
            }
            //发送连接状态
            Message msg = handler.obtainMessage();
            msg.what = state;
            handler.sendMessage(msg);
        }
    });
thread.start();
}

因为连接过程必须放到子线程中,因此这是一个异步方法,该方法中通过调用createRfcommSocket()方法创建socket,然后向主Activity中的Handler发送消息,需要用到消息机制,主线程接收消息并更新UI,即在屏幕的中间显示连接状态。接下来代码是主Activity中的Handler,作用是更新UI:

private final Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BluetoothConnect.CONNECT_FAILED:
                Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
                break;
            case BluetoothConnect.CONNECT_SUCCESS:
                Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
                client.receive();//接收数据
                break;
            case BluetoothConnect.READ_FAILED:
                Toast.makeText(MainActivity.this, "读取失败", Toast.LENGTH_SHORT).show();
                break;
            case BluetoothConnect.WRITE_FAILED:
                Toast.makeText(MainActivity.this, "写入失败", Toast.LENGTH_SHORT).show();
                break;
            case BluetoothConnect.DATA:
                Toast.makeText(MainActivity.this, ""+msg.arg1, Toast.LENGTH_SHORT).show();
                break;
        }
    }
};

可以在此Handler中用TextView等来显示连接状态,这里简单起见就用只用了Toast。可以看到这里有一个receive()方法,这个方法也是封装到BluetoothConnect中的一个异步方法,该方法如下:

public void receive(){
    //连接成功则接收数据
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            if(isConnect){
                try {
                    InputStream inputStream = socket.getInputStream();
                    int data;
                    while (true){
                        try {
                            data = inputStream.read();
                            Message msg = handler.obtainMessage();
                            msg.what = BluetoothConnect.DATA;
                            msg.arg1 = data;
                            handler.sendMessage(msg);
                        }catch (IOException e){
                            Log.e("TAG", e.toString());
                            break;
                        }
                    }
                } catch (IOException e) {
                    Log.e("TAG", e.toString());
                }
            }
        }
    });
    thread.start();

主要是通过不断读取输入流的内容来接收数据,可以看到,这里又利用了消息机制,将接收到的数据通过消息打包发回了主线程,在主线程的Handle中接收消息即可更新UI,显示所接收的内容。
最后不要忘了加上相关的蓝牙权限。

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

本文参考来源:http://www.cnblogs.com/wenjiang/p/3200138.html#!comments

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要实现一个基于Android蓝牙遥控器应用,需要完成以下几个步骤: 1. 在应用中添加UI元素,如按钮、滑块等,用于控制遥控器的功能; 2. 在应用中实现蓝牙连接功能,包括搜索设备、建立连接等; 3. 在应用中实现蓝牙数据传输功能,包括向蓝牙设备发送数据和接收蓝牙设备发送的数据; 4. 根据具体需求,将UI元素和蓝牙数据传输功能进行绑定,实现遥控器的功能。 下面是一个简单的示例代码,演示了如何在应用中实现蓝牙遥控器的功能: ```java public class MainActivity extends AppCompatActivity { private static final String TAG = "BluetoothControl"; private BluetoothAdapter mBluetoothAdapter; private BluetoothDevice mBluetoothDevice; private BluetoothSocket mBluetoothSocket; private OutputStream mOutputStream; private Button mButtonUp; private Button mButtonDown; private Button mButtonLeft; private Button mButtonRight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取BluetoothAdapter实例 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 获取UI元素 mButtonUp = findViewById(R.id.button_up); mButtonDown = findViewById(R.id.button_down); mButtonLeft = findViewById(R.id.button_left); mButtonRight = findViewById(R.id.button_right); // 设置UI元素的点击事件 mButtonUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendBluetoothData("UP"); } }); mButtonDown.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendBluetoothData("DOWN"); } }); mButtonLeft.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendBluetoothData("LEFT"); } }); mButtonRight.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendBluetoothData("RIGHT"); } }); } // 搜索蓝牙设备 private void searchBluetoothDevice() { if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } mBluetoothAdapter.startDiscovery(); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if ("蓝牙设备名称".equals(device.getName())) { mBluetoothAdapter.cancelDiscovery(); mBluetoothDevice = device; connectBluetoothDevice(); } } } }; IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(receiver, filter); } // 建立蓝牙连接 private void connectBluetoothDevice() { try { UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(uuid); mBluetoothSocket.connect(); mOutputStream = mBluetoothSocket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "connectBluetoothDevice: ", e); } } // 向蓝牙设备发送数据 private void sendBluetoothData(String data) { try { mOutputStream.write(data.getBytes()); } catch (IOException e) { Log.e(TAG, "sendBluetoothData: ", e); } } @Override protected void onDestroy() { super.onDestroy(); try { mBluetoothSocket.close(); } catch (IOException e) { Log.e(TAG, "onDestroy: ", e); } } } ``` 需要注意的是,上述示例代码仅适用于演示如何实现蓝牙遥控器的功能,实际应用中需要根据具体需求进行修改和完善。同时,还需要考虑蓝牙连接和数据传输过程中可能出现的异常情况,并进行相应的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值