开始

最近整理了一下在安卓系统下使用蓝牙收发数据的代码。蓝牙的操作,类似于网络socket的
使用。
首先我们需要获取蓝牙适配器,也就是BluetoothAdapter,通过BluetoothAdapter对蓝牙
进行操作。
流程如下:
获取BluetoothAdapter----->打开蓝牙------->搜索蓝牙设备------>绑定------>建立连接----
--->收发数据(通信)----->断开连接------>关闭蓝牙

完整代码地址
https://github.com/huijizyf/bluetoothchat.git

界面效果

screenshot

关键代码

package com.donute.bluetoothchat;

import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
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.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
    /**
     * ******************************************控件定义******************************************
     */
    @Bind(R.id.btn_open_bluetooth_intent)
    Button btnOpenBluetoothIntent;
    @Bind(R.id.btn_open_bluetooth_silence)
    Button getBtnOpenBluetoothSilence;
    @Bind(R.id.lv_blue_devices_list)
    ListView lvDevicesList;
    @Bind(R.id.tv_data_received)
    TextView tvDataReceived;
    @Bind(R.id.et_data_to_send)
    EditText etDataToSend;
    @Bind(R.id.btn_send_data)
    Button btnSendData;
    @Bind(R.id.btn_close_bluetooth)
    Button btnCloseBluetooth;
    @Bind(R.id.btn_search_devices)
    Button btnSearchDevices;
    @Bind(R.id.btn_open_bluetooth_service)
    Button btnOpenService;
    @Bind(R.id.btn_bluetooth_disconnect)
    Button btnDisconnect;

    /**
     ******************************************变量声明*********************************************
     */
    private BluetoothAdapter mAdapter;               //蓝牙适配器
    private static final int REQUEST_CODE=1001;      //请求码,自定义整数即可
    private BluetoothServerSocket serverSocket;       //服务端连接套接字
    private BluetoothSocket clienSocket;               //客户端套接字
    private List<BluetoothDevice> deviceList;       //扫描接收到的蓝牙设备
    private DeviceViewAdapter viewAdapter;           //ListView的数据适配器
    private BluetoothSocket socket;                 //服务端套接字
    private static final UUID uuid=UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    private int type=0;               //当前连接类型   1为服务端    2为客户端
    private DateFormat format;
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        //设置TextView允许滚动
        tvDataReceived.setMovementMethod(ScrollingMovementMethod.getInstance());
        //获取蓝牙适配器
        mAdapter= BluetoothAdapter.getDefaultAdapter();
        if (mAdapter==null){
            TipManager.showDialog(this,"提示","当前设备不支持蓝牙");
        }
        //日期字符串格式化
        format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //将已经绑定的设备加入列表中
        deviceList=new ArrayList<>(mAdapter.getBondedDevices());
        viewAdapter=new DeviceViewAdapter(this,deviceList);
        //给ListView设置数据适配器
        lvDevicesList.setAdapter(viewAdapter);
        //设置ListView点击事件处理
        lvDevicesList.setOnItemClickListener(this);

        //注册广播接收,会接收到开始扫描,扫描到设备,介绍扫描 三个事件,事件交由mReceiver处理

        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        registerReceiver(mReceiver, filter);

        //等待进度Dialog
        progressDialog=new ProgressDialog(this);
        progressDialog.setTitle("请稍等");
        progressDialog.setMessage("正在扫描蓝牙设备,请稍等...");
        progressDialog.setCancelable(false);

        //设置点击事件处理
        btnOpenBluetoothIntent.setOnClickListener(this);
        getBtnOpenBluetoothSilence.setOnClickListener(this);
        btnSendData.setOnClickListener(this);
        btnCloseBluetooth.setOnClickListener(this);
        btnSearchDevices.setOnClickListener(this);
        btnOpenService.setOnClickListener(this);
        btnDisconnect.setOnClickListener(this);
    }

    /**
     * 点击事件处理
     * @param v
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_open_bluetooth_intent:
                Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enabler, REQUEST_CODE);      //调用系统弹框开启蓝牙
                break;
            case R.id.btn_open_bluetooth_silence:
                mAdapter.enable();//静默方式开启蓝牙
                break;
            case R.id.btn_send_data:
                sendData();     //发送数据
                break;
            case R.id.btn_close_bluetooth:
                mAdapter.disable(); //关闭蓝牙
                break;
            case R.id.btn_search_devices:
                if (mAdapter.isDiscovering()){  //开始扫描蓝牙,如果已经正在扫描了,则不继续执行
                    return;
                }
                deviceList.clear();
                mAdapter.startDiscovery();
                break;
            case R.id.btn_open_bluetooth_service:
                startServer("my-service");      //开启服务端
                break;
            case R.id.btn_bluetooth_disconnect:
                disconnect();                   //断开连接
                break;
        }
    }

    private void disconnect() {
        //根据当前类型断开连接
        switch (type){
            case 1:     //作为服务端
                try {
                    if (socket.isConnected())
                        socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case 2:     //作为客户端
                try {
                    if (clienSocket.isConnected())
                        clienSocket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    /**
     * 发送数据
     */
    private void sendData(){
        Thread sendThread=new Thread(){
            @Override
            public void run() {
                super.run();
                final String msg=etDataToSend.getText().toString();
                if (TextUtils.isEmpty(msg)){
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            TipManager.showDialog(MainActivity.this,"提示","内容为空,不能发送数据");
                        }
                    });
                    return;
                }
                OutputStream os = null;
                try {
                    switch (type){
                        case 1:
                            if (socket!=null)
                                os=socket.getOutputStream();
                            break;
                        case 2:
                            if (clienSocket!=null)
                                 os=clienSocket.getOutputStream();
                            break;
                        default:
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    TipManager.showDialog(MainActivity.this,"提示","还未建立连接,或者连接错误,不能发送数据");
                                }
                            });
                            break;
                    }
                    if (os != null) {
                        //向输出流写入数据
                        os.write(msg.getBytes("utf-8"));
                        tvDataReceived.post(new Runnable() {
                            @Override
                            public void run() {
                                //在UI线程操作界面,将发送的消息显示到界面,同时清空消息输入框
                                String m=tvDataReceived.getText().toString();
                                m=m+format.format(new Date())+"\t"+"发送:"+msg+"\n";
                                tvDataReceived.setText(m);
                                etDataToSend.setText("");
                            }
                        });
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        sendThread.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //界面销毁时解除广播接收器的注册
        unregisterReceiver(mReceiver);
    }

    //定义广播接收器,接收与蓝牙相关的系统广播
    BroadcastReceiver mReceiver = new BroadcastReceiver() {
        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 (device.getBondState()==BluetoothDevice.BOND_NONE){
                    deviceList.add(device);
                    progressDialog.setMessage("正在扫描,已经扫描到设备数量:"+deviceList.size());
                    viewAdapter.notifyDataSetChanged();
                }
            }
            //扫描完成
            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                progressDialog.dismiss();
                TipManager.showDialog(MainActivity.this,"提示","蓝牙设备扫描完成,总共扫描到蓝牙设备数量:"+deviceList.size());
                //开始扫描
            }else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
                TipManager.showToast(MainActivity.this,"开始扫描设备");
                progressDialog.show();
            }
        }
    };

    /**
     * 开启服务端
     */
    private void startServer(final String name){
        Thread serverThread=new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    type=1;
                    serverSocket = mAdapter. listenUsingRfcommWithServiceRecord(name,uuid);
                    socket=serverSocket.accept();      //等待服务端连接,accept函数为阻塞函数,会等待到有客户端连接成功后才会继续执行
                    InputStream is = socket.getInputStream();//客户端连接成功,获取输入流
                    while(true) {           //从输入流读取数据
                        byte[] buffer =new byte[1024];
                        int count = is.read(buffer);
                        final String s= new String(buffer, 0, count, "utf-8");
                        tvDataReceived.post(new Runnable() {
                            @Override
                            public void run() {
                                //在UI线程操作界面,将接收到的消息显示到界面
                                String msg=tvDataReceived.getText().toString();
                                msg=msg+format.format(new Date())+"\t"+"接收:"+s+"\n";
                                tvDataReceived.setText(msg);
                            }
                        });
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        serverThread.start();
    }
    /**
     * 连接到服务端
     */
    private void connectServer(final BluetoothDevice device){
        final ProgressDialog dialog=new ProgressDialog(this);
        dialog.setTitle("请稍等");
        dialog.setMessage("正在连接");
        Thread connectThread=new Thread(){
            public void run(){
                super.run();
                try {
                    type=2;
                    clienSocket=device.createRfcommSocketToServiceRecord(uuid);
                    clienSocket.connect();
                    lvDevicesList.post(new Runnable() {
                        @Override
                        public void run() {
                            dialog.dismiss();
                            TipManager.showDialog(MainActivity.this,"提示","连接成功,现在可以发送数据了");
                            startReceive();//连接到服务端成功,开启接收线程
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        dialog.show();
        connectThread.start();
    }
    private void startReceive(){
        Thread receiveThread=new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    InputStream is=clienSocket.getInputStream();
                    if (is!=null){
                        while(true) {
                            byte[] buffer =new byte[1024];
                            int count = is.read(buffer);
                            final String s= new String(buffer, 0, count, "utf-8");
                            tvDataReceived.post(new Runnable() {
                                @Override
                                public void run() {
                                    //在UI线程操作界面,将接收到的消息显示到界面
                                    String msg=tvDataReceived.getText().toString();
                                    msg=msg+format.format(new Date())+"\t"+"接收:"+s+"\n";
                                    tvDataReceived.setText(msg);
                                }
                            });
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        receiveThread.start();
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        BluetoothDevice device= (BluetoothDevice) viewAdapter.getItem(position);
        connectServer(device);
    }
}