IT虾米网

Android蓝牙开发经验总结(三)

sharpest 2022年11月07日 手机开发 128 0

前两篇已经写了主要的东西了,已经可以实现请求连接和接受连接的操作了,但是主控制界面的代码还没有贴上,其实Android官方自带的那个界面还是挺不错的,就是一个聊天的界面,但是我们项目需求的话用不到那样的,只是需要用到一个数据传输,而不是那种聊天式的界面。所以我改了一下。

public class BluetoothControl extends Activity {
    
    private String address; 
    private String Devicename; 
    private String TAG = "BluetoothControl"; 
    private boolean D = true; 
    private BluetoothAdapter mBluetoothAdapter; 
    private Button scan, discoverable; 
    private TextView mTitle; 
    private AcceptThread mAcceptThread; 
    private ConnectThread mConnectThread; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        // TODO Auto-generated method stub 
        super.onCreate(savedInstanceState); 
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); 
        setContentView(R.layout.activity_bluetoothcontrol); 
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title); 
        init(); 
    } 
 
    @Override 
    protected void onResume() { 
        // TODO Auto-generated method stub 
        super.onResume(); 
    } 
 
    // 对需要使用到的资源进行初始化 
    private void init() { 
        mTitle = (TextView) this.findViewById(R.id.title_left_text); 
        mTitle.setText("未连接"); 
        // 获得系统默认蓝牙适配器 
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
        if (mBluetoothAdapter == null) { 
            Toast.makeText(getApplicationContext(), 
                    getResources().getString(R.string.none_bluetooth), 
                    Toast.LENGTH_LONG).show(); 
            finish(); 
        } else { 
            openBluetooth(); 
        } 
        scan = (Button) this.findViewById(R.id.scan); 
        discoverable = (Button) this.findViewById(R.id.discoverable); 
        scan.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View arg0) { 
                // TODO Auto-generated method stub 
                // 跳转到DeviceList类 
                Intent intent = new Intent(BluetoothControl.this, 
                        DeviceList.class); 
                startActivityForResult(intent, Constant.REQUEST_CONNECT_DEVICE); 
                scan.setEnabled(false); 
                discoverable.setEnabled(false); 
            } 
        }); 
 
        discoverable.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View arg0) { 
                // TODO Auto-generated method stub 
                Intent discoverableIntent = new Intent( 
                        BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); 
                discoverableIntent.putExtra( 
                        BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120); 
                startActivity(discoverableIntent); 
                mTitle.setText("正在等待连接"); 
                mAcceptThread = Constant.getAcceptThread(); 
                if (mAcceptThread == null) { 
                    mAcceptThread = new AcceptThread(mHandler); 
                    mAcceptThread.start(); 
                    Constant.setAcceptThread(mAcceptThread); 
                } else if (mAcceptThread != null) { 
                    mAcceptThread = null; 
                    mAcceptThread = new AcceptThread(mHandler); 
                    mAcceptThread.start(); 
                    Constant.setAcceptThread(mAcceptThread); 
                } 
            } 
        }); 
 
    } 
 
    private void openBluetooth() {
  // 打开蓝牙的方法 
        if (!mBluetoothAdapter.isEnabled()) { 
            Intent enableIntent = new Intent( 
                    BluetoothAdapter.ACTION_REQUEST_ENABLE); 
            startActivityForResult(enableIntent, 2); 
        } 
    } 
 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 
        if (D) 
            Log.d(TAG, "onActivityResult " + resultCode); 
        switch (requestCode) { 
        case Constant.REQUEST_CONNECT_DEVICE: 
            if (resultCode == Activity.RESULT_OK) { 
                address = data.getExtras().getString( 
                        DeviceList.EXTRA_DEVICE_ADDRESS); 
                Log.i(TAG, address); 
                BluetoothDevice device = mBluetoothAdapter 
                        .getRemoteDevice(address); 
                mConnectThread = Constant.getConnectThread(); 
                mConnectThread = new ConnectThread(mHandler, device); 
                mConnectThread.start(); 
                Constant.setConnectThread(mConnectThread); 
                mTitle.setText("正在连接" + device.getName()); 
 
            } 
            break; 
        case Constant.REQUEST_ENABLE_BT: 
            if (resultCode == Activity.RESULT_OK) { 
                openBluetooth(); 
            } else { 
                Log.d(TAG, "BT not enabled"); 
                Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_SHORT).show(); 
                finish(); 
            } 
        } 
    } 
 
    private final Handler mHandler = new Handler() { 
        public void handleMessage(Message msg) { 
            switch (msg.what) { 
            case Constant.MESSAGE_STATE_CHANGE: 
                if (D) 
                    Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); 
                // 显示现在处在的状态 
 
                // switch (msg.arg1) {
    
                // case BluetoothControlService.STATE_CONNECTED: 
                // mTitle.setText(R.string.title_connected_to); 
                // mTitle.append(Devicename); 
                // break; 
                // case BluetoothControlService.STATE_CONNECTING: 
                // mTitle.setText(R.string.title_connecting); 
                // break; 
                // case BluetoothControlService.STATE_LISTEN: 
                // mTitle.setText(R.string.title_not_connected); 
                // break; 
                // case BluetoothControlService.STATE_NONE: 
                // mTitle.setText(R.string.title_not_connected); 
                // break; 
                // } 
                // break; 
            case Constant.MESSAGE_READ: 
                // 读取获得的信息 
                byte[] readBuf = (byte[]) msg.obj; 
                String readMessage = new String(readBuf, 0, msg.arg1); 
                System.out.println("readMessage" + readMessage); 
                // UnityPlayer.UnitySendMessage(readMessage.substring(0, 
                // readMessage.indexOf(",")), readMessage.substring( 
                // readMessage.indexOf(",") + 1, 
                // readMessage.lastIndexOf(",")), readMessage 
                // .substring(readMessage.lastIndexOf(",") + 1)); 
                break; 
            case Constant.MESSAGE_DEVICE_NAME: 
                // 获得连接到的设备名字,显示 
                Devicename = msg.getData().getString(Constant.DEVICE_NAME); 
                Toast.makeText(getApplicationContext(), "连接到:" + Devicename, 
                        Toast.LENGTH_SHORT).show(); 
                mTitle.setText("已连接到:" + Devicename); 
                // UnityPlayer.UnitySendMessage("BluetoothObjects", 
                // "BluetoothConnected", ""); 
                finish(); 
                break; 
            case Constant.MESSAGE_TOAST: 
                Toast.makeText(getApplicationContext(), 
                        msg.getData().getString(Constant.TOAST), 
                        Toast.LENGTH_SHORT).show(); 
                mTitle.setText("未连接"); 
                scan.setEnabled(true); 
                discoverable.setEnabled(true); 
                // UnityPlayer.UnitySendMessage("BluetoothObjects", 
                // "BluetoothDisconnected", ""); 
                break; 
            } 
        } 
    }; 
}

由于我们的项目需要用到到的是Unity3D,所以有调用U3D的接口,但是这需求是很特别的,一般来说是用不到这些的,所以我把它注释掉了,但是也算是为了防止以后有可能再次用到,就先把它放这上面了。

这个类里面定义了一个Handler对象,用来进行进程之间数据的传递,上一篇里用到的handler就是从这里面传递过去的,定义AcceptThread和ConnectThread线程的时候都将Handler对象作为构造函数的参数传递了过去,这样在子线程中发生了什么就可以通过Handler向主线程发送提示,比如连接突然断开,就可以通过Handler发送消息告知主线程,主线程这时可以弹出一个Toast来告知用户连接已经断开。

另外需要注意的是

 requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

这个方法是官方demo里的,我对这类主题窗口类的方法还不是很了解,所以我就在网上查了一下,这个类是用来显示自定义的Title的,我们Android系统的主题里面给我们定义了一些Title,但这些Title的功能往往不适合我们的项目,所以我们需要自定义一个Title,这个方法就是用来告知系统我要用自己定义的一个Title了,就直接取代了系统的Title了。至于Title的样式则需要在XML文件中自己来定义啦。

最后再讲一下蓝牙的断开,蓝牙连接是可以了,但是要是想在程序里断开,官方demo里是没有这个功能的,于是我就想着怎么能给用户提供一个断开的方法呢,总不能总是让用户一直连着,或者需要用户关闭程序或者关闭蓝牙才能实现这样的需求吧。
后来还真是找到了办法,思路就是断开Socket,在ConnectedThread里面,我们可以看到连接之后传过来的Socket对象,就是它,蓝牙之间通信就是像网络通信一样用的是Socket。所以,我们只要断开了Socket,两个蓝牙设备之间的通信就会断开,于是,就可以用以下代码了。

    Button off = (Button) findViewById(R.id.off); 
        off.setOnClickListener(new OnClickListener() { 
 
            @Override 
            public void onClick(View arg0) { 
                // TODO Auto-generated method stub 
                mConnectedThread = Constant.getConnectedThread(); 
                if (mConnectedThread != null) { 
                    mConnectedThread.cancel(); 
                    mConnectedThread = null; 
                    Constant.setConnectedThread(mConnectedThread); 
                } 
                finish(); 
            } 
        });

因为前面的线程里,我已经把ConnectedThread的对象存入到了Constant中,现在只需要通过getConnectedThread()这个方法就能获得,获得之后判断是否为空,如果不为空的话,就调用mConnectedThread对象里的cancle方法,在这个方法里会执行关闭Socket的操作,这样就算是断开了,断开之后将mConnceted设为空即可。
蓝牙的部分基本上就是这些了!有什么问题可以找我共同探讨沟通^_^


本文参考链接:https://blog.csdn.net/q1406689423/article/details/50381844
评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Java多线程中Lock锁如何使用