天天看點

android 藍牙之資料傳輸

因為項目需要,需要将本地資料庫的資料,通過藍牙傳輸到另一台裝置上。然後百度了蠻久,看了蠻多的,覺得有必要自己整理一下,藍牙的傳輸功能。

首先,我們都知道的,藍牙連接配接數需要先配對的,兩台手機配對後才可進行藍牙處理。對于藍牙配對的方法網上一大堆,我也就不具體說了,大概記錄一下。基本的我們可以通過手機原有的藍牙功能,進行搜尋配對後在自身的APK中,直接啟動藍牙,然後查詢已比對裝置就行了。因為項目目前沒有要求實作比對功能,我也就能省則省了...不過還是總體介紹一下吧。

在安卓源碼中,首先要知道有提供了一個藍牙類:BluetoothAdapter , 我們需要先初始化這個類,才能huod獲得藍牙的相關資料。 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  接着我們需要先注冊廣播,廣播的注冊有靜态注冊和動态注冊,我就不詳說了,我這用的是動态注冊: 

//注冊藍牙廣播
        IntentFilter filter = new IntentFilter(
                BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        getActivity().registerReceiver(receiver, filter);
        filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        getActivity().registerReceiver(receiver, filter);
           

然後再實作廣播的處理:

public class BluetoothReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(BluetoothDevice.ACTION_FOUND)) {
            //未比對
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            //搜尋完成
        }
    }

}
           

基本就是這樣,裡面的參數判斷的話,藍牙有各種不同的狀态,可以根據搜尋到的裝置進行檢查,然後區分目前藍牙處于什麼狀态。而我因為業務原因,暫時也不需要去監聽比對,是以,我用的是以下這個方法:

Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
        for (BluetoothDevice bondedDevice : bondedDevices) {
            bluetoothDevices.add(bondedDevice);
        }
           

當藍牙開啟後,通過此方法,獲得已比對的裝置。

另外補充一個開啟藍牙的方法:此方法為了讓其他裝置可以搜尋到本機,裡面的300表示暴露時間秒

//開啟顯示,讓本機可以被搜尋到
            if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
                Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                startActivity(discoverableIntent);
            } else {
                showToast("藍牙已開啟");
            }
           

好了,以上是一些基本的藍牙功能,到哪裡都可以找到一大堆的。下面開始記錄關鍵,藍牙資料傳輸

既然要傳輸資料,和給api通訊一樣,肯定是要有一個服務端,一個用戶端的。而服務端是需要在開啟狀态,監聽用戶端發送的資料。而服務屬于阻塞操作,是以要開啟一個線程,再來開啟一個服務:

BluetoothServerSocket mmServerSocket=mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Name", UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"));
 BluetoothSocket socket = mmServerSocket.accept();
           

通過以上方法來開啟一個服務,這裡“Name”,UUID,服務端和用戶端都必須一樣,這是識别用的。另外要注意mmServerSocket 是否為 null ,若未null 則也是無法開啟的。另外在之後若出現無法連接配接的情況,這裡我們可以查下緩一緩UUID的值,具體這個坑什麼原因我也說不清,反正換一換呗。

當以上的方法調用了之後,伺服器基本就算開啟了的。隻要沒抛異常的話。

然後我們需要一個輸入流,可以寫循環,也可以不寫循環。循環的話就通過傳輸過來的資料,做個标記結束它。這些都是一些廢話,就直接寫個流吧...

InputStream mmInStream = socket.getInputStream();

 bytes = mmInStream.read(buffer);
 String data = new String(buffer, 0, bytes, "UTF-8");
 Message msg = Message.obtain();
 msg.what = Constants.MESSAGE_READ;
 msg.obj = data;
 mHandler.sendMessage(msg);
           

這裡注意,我們在之前開啟服務端的時候,要獲得一個藍牙的操作類:BluetoothSocket ,這個類是用來操作流,服務的。ranho然後通過handler 将接收的資料回傳到主線程。服務端到這裡就完了。

接着寫用戶端的:

用戶端這邊就輕松多了,既然服務端已經開啟,我們就進行連接配接,通過BluetoothAdapter 我們已經得到了已經比對的裝置,然後選擇你要連接配接的藍牙裝置,不過記得先關閉藍牙搜尋功能:

mBluetoothAdapter.cancelDiscovery();
BluetoothSocket mmSocket= device.createRfcommSocketToServiceRecord(UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"));
 mmSocket.connect();
           

然後用要連接配接的裝置device,輸入服務端的UUID,接着連接配接。當然,以上的操作也是需要在子線程中進行的。

連接配接結束後,可以寫個方法通知服務端,誰誰誰連接配接了。當然我們也要寫一個輸出流,用于一會輸出資料到服務端去。

最後,最最重要的,用完了li流一定要記得關閉。

為了以後友善,我也做了一個功能類,之後需要用時就直接調用。這裡就貢獻給大家分享一下吧!

public class BluetoothChatService {

    private static final String TAG = "BluetoothChatService";
    private static final String NAME_SECURE = "BluetoothChatSecure";
    private static final String NAME_INSECURE = "BluetoothChatInsecure";

    private static final UUID MY_UUID_SECURE =
            UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    public final BluetoothAdapter mAdapter;
    public final Handler mHandler;
    public AcceptThread mSecureAcceptThread;
    public AcceptThread mInsecureAcceptThread;
    public ConnectThread mConnectThread;
    public ConnectedThread mConnectedThread;
    private int mState;

    public static final int STATE_NONE = 0;
    public static final int STATE_LISTEN = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_CONNECTED = 3;


    public BluetoothChatService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
    }


    private synchronized void setState(int state) {
        Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;
        mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }


    public synchronized int getState() {
        return mState;
    }


    public synchronized void start() {
        Log.d(TAG, "start");

        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        setState(STATE_LISTEN);

        if (mSecureAcceptThread == null) {
            mSecureAcceptThread = new AcceptThread();
            mSecureAcceptThread.start();
        }
    }

    public synchronized void connect(BluetoothDevice device) {
        Log.d(TAG, "connect to: " + device);
        if (mState == STATE_CONNECTING) {
            if (mConnectThread != null) {
                mConnectThread.cancel();
                mConnectThread = null;
            }
        }

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        mConnectThread = new ConnectThread(device);
        mConnectThread.start();
        setState(STATE_CONNECTING);
    }


    public synchronized void connected(BluetoothSocket socket, BluetoothDevice
            device) {

        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        if (mSecureAcceptThread != null) {
            mSecureAcceptThread.cancel();
            mSecureAcceptThread = null;
        }
        if (mInsecureAcceptThread != null) {
            mInsecureAcceptThread.cancel();
            mInsecureAcceptThread = null;
        }

        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();

        Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(Constants.DEVICE_NAME, device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        setState(STATE_CONNECTED);
    }


    public synchronized void stop() {
        Log.d(TAG, "stop");

        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        if (mSecureAcceptThread != null) {
            mSecureAcceptThread.cancel();
            mSecureAcceptThread = null;
        }

        if (mInsecureAcceptThread != null) {
            mInsecureAcceptThread.cancel();
            mInsecureAcceptThread = null;
        }

        setState(STATE_NONE);

    }

    public void write(byte[] out) {
        ConnectedThread r;
        synchronized (this) {
            if (mState != STATE_CONNECTED)
                return;
            r = mConnectedThread;

        }
        r.write(out);
    }


    private void connectionFailed() {

        Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(Constants.TOAST, "無法連接配接裝置!");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
        BluetoothChatService.this.start();
    }


    private void connectionLost() {

        Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(Constants.TOAST, "裝置連接配接已斷開");
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        BluetoothChatService.this.start();
    }

    private class AcceptThread extends Thread {
        // The local server socket
        private final BluetoothServerSocket mmServerSocket;
        private String mSocketType;

        public AcceptThread() {
            BluetoothServerSocket tmp = null;

            try {
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, MY_UUID_SECURE);
            } catch (IOException e) {
               // Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
            }
            mmServerSocket = tmp;
        }

        public void run() {

            BluetoothSocket socket = null;

            while (mState != STATE_CONNECTED) {
                try {
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                  //  Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
                    break;
                }
                if (socket != null) {
                    synchronized (BluetoothChatService.this) {
                        switch (mState) {
                            case STATE_LISTEN:
                            case STATE_CONNECTING:
                                // Situation normal. Start the connected thread.
                                connected(socket, socket.getRemoteDevice());
                                break;
                            case STATE_NONE:
                            case STATE_CONNECTED:
                                try {
                                    socket.close();
                                } catch (IOException e) {
                                    //Log.e(TAG, "Could not close unwanted socket", e);
                                }
                                break;
                        }
                    }
                }
            }
        }

        public void cancel() {
           // Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
            try {
                mmServerSocket.close();
            } catch (IOException e) {
               // Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
            }
        }
    }

    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        public ConnectThread(BluetoothDevice device) {
            mmDevice = device;
            BluetoothSocket tmp = null;

            try {
                    tmp = device.createRfcommSocketToServiceRecord(
                            MY_UUID_SECURE);
            } catch (IOException e) {
              //  Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
           // Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
            mAdapter.cancelDiscovery();

            try {
                mmSocket.connect();
            } catch (IOException e) {

                try {
                    mmSocket.close();
                } catch (IOException e2) {
                 //   Log.e(TAG, "unable to close() " + mSocketType +
                   //         " socket during connection failure", e2);
                }
                connectionFailed();
                return;
            }

            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            connected(mmSocket, mmDevice);
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
              //  Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
            }
        }
    }

    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
           // Log.d(TAG, "create ConnectedThread: " + socketType);
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
              //  Log.e(TAG, "temp sockets not created", e);
            }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {

            synchronized (BluetoothChatService.class) {

                byte[] buffer = new byte[1024 * 4];
                int bytes;

                while (mState == STATE_CONNECTED) {
                    try {
                        bytes = mmInStream.read(buffer);
                        String data = new String(buffer, 0, bytes, "UTF-8");
                        Message msg = Message.obtain();
                        msg.what = Constants.MESSAGE_READ;
                        msg.obj = data;
                        mHandler.sendMessage(msg);

                    } catch (IOException e) {
                        connectionLost();
                        BluetoothChatService.this.start();
                        break;
                    }
                }
            }
        }

        public void write(byte[] buffer) {

            try {
                mmOutStream.write(buffer);
                mmOutStream.flush();
                mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                //Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
            //    Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
}
           
/**
 * @desc ${BluetoothService 中使用的常量}
 */
public class Constants {

    public static final int MESSAGE_STATE_CHANGE = 1;  //狀态改變
    public static final int MESSAGE_READ = 2; //讀取
    public static final int MESSAGE_WRITE = 3;   //寫出
    public static final int MESSAGE_DEVICE_NAME = 4;  //裝置 名稱
    public static final int MESSAGE_TOAST = 5;  //連接配接失敗


    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";

}
           
private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case Constants.MESSAGE_TOAST:
                    String statu = msg.getData().getString(Constants.TOAST);
                    showToast(statu + "");
                    break;
                case Constants.MESSAGE_DEVICE_NAME:
                    String string = msg.getData().getString(Constants.DEVICE_NAME);
                    showToast("已連接配接裝置" + string);
                    break;
                case Constants.MESSAGE_READ: //讀取接收資料
      
                    break;
                case Constants.MESSAGE_WRITE: //發送端,正在發送的資料
                   
                    break;

            }
        }
  };

private void iniData(){
省******
******
******略
  BluetoothChatService chatService = new BluetoothChatService(getActivity(), mHandler);

  Listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long        id) {
                // 判斷目前是否還是正在搜尋周邊裝置,如果是則暫停搜尋
                if (mBluetoothAdapter.isDiscovering()) {
                    mBluetoothAdapter.cancelDiscovery();
                }
                BluetoothDevice bluetoothDevice = bluetoothDevices.get(position);
                //用戶端連接配接
                chatService.connect(bluetoothDevice);
            }
        });

//如果要開啟服務端直接調用以下語句
//chatService.start();

}

  /**
     * 準備開始發送資料
     */
    private void snedInfo() {
        if (chatService.getState() != BluetoothChatService.STATE_CONNECTED) {
            showToast("連接配接失敗");
            return;
        }
      String toSendJson = new Gson().toJson(“Bean資料”);
       if (toSendJson.length() > 0) {
            byte[] send = new byte[0];
             try {
               send = toSendJson.getBytes();
              } catch (Exception e) {
               e.printStackTrace();
              }
               chatService.write(send);
              }
            }
        });
    }
           

以上就是我目前做的藍牙傳輸功能了,先這樣吧...然後再慢慢優化改進的。各種狀态也都有了的,自己慢慢調整一下吧..

繼續閱讀