1. 程式人生 > >藍芽小試牛刀之模擬藍芽客戶端向服務端傳資料

藍芽小試牛刀之模擬藍芽客戶端向服務端傳資料

今天我們來實現一下客戶端和服務端通過藍芽傳資料
效果圖如下:
這裡寫圖片描述
這個佈局太簡單了,我就不給出了,直接上邏輯.

MainActivity:

public class MainActivity extends Activity implements View.OnClickListener {

    private Button btn1;
    private Button btn2;
    private Button btn3;
    private Button btn4;
    private Button btn5;
    private Button btn6;
    private
Button btn7; private BluetoothAdapter mBlueToothAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); setListener(); } private void setListener
() { btn1.setOnClickListener(this); btn2.setOnClickListener(this); btn3.setOnClickListener(this); btn4.setOnClickListener(this); btn5.setOnClickListener(this); btn6.setOnClickListener(this); btn7.setOnClickListener(this); } private void
initView() { btn1 = ((Button) findViewById(R.id.btn1)); btn2 = ((Button) findViewById(R.id.btn2)); btn3 = ((Button) findViewById(R.id.btn3)); btn4 = ((Button) findViewById(R.id.btn4)); btn5 = ((Button) findViewById(R.id.btn5)); btn6 = ((Button) findViewById(R.id.btn6)); btn7 = ((Button) findViewById(R.id.btn7)); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn1://開啟藍芽 onOpen(); break; case R.id.btn2://關閉藍芽 onClose(); break; case R.id.btn3://允許搜尋 onAbleFound(); break; case R.id.btn4://開始搜尋 onFound(); break; case R.id.btn5://客戶端 Intent intent=new Intent(this,ClientSocketActivity.class); startActivity(intent); break; case R.id.btn6://伺服器端 Intent intent1=new Intent(this,ServerSocketActivity.class); startActivity(intent1); break; case R.id.btn7://OBEX伺服器端 break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode==300){ //藍芽已開啟 Toast.makeText(MainActivity.this,"藍芽已開啟",Toast.LENGTH_SHORT).show(); } } /* * 開啟藍芽 * */ public void onOpen(){ mBlueToothAdapter= BluetoothAdapter.getDefaultAdapter(); if (mBlueToothAdapter==null){ Toast.makeText(MainActivity.this,"手機不支援藍芽",Toast.LENGTH_SHORT).show(); return; } if (!mBlueToothAdapter.isEnabled()){//藍芽未開啟 則開啟藍芽 Intent enableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent,300); } } /* * 關閉藍芽 * */ public void onClose(){ if (mBlueToothAdapter.enable()) mBlueToothAdapter.disable(); Toast.makeText(MainActivity.this,"藍芽已關閉",Toast.LENGTH_SHORT).show(); } /* * 允許被搜尋到 時長300 * */ public void onAbleFound(){ if (mBlueToothAdapter!=null&&mBlueToothAdapter.isEnabled()){ if (mBlueToothAdapter.getScanMode()==BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){ Intent discoverableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //使本機在300秒內可被搜尋 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300); startActivity(discoverableIntent); Toast.makeText(MainActivity.this,"藍芽已允許被檢測",Toast.LENGTH_SHORT).show(); } } } public void onFound(){ Intent intent=new Intent(MainActivity.this,BlueListActivity.class); startActivity(intent); } @Override protected void onStart() { super.onStart(); } @Override protected void onDestroy() { super.onDestroy(); } @Override protected void onResume() { super.onResume(); } @Override protected void onRestart() { super.onRestart(); } }

客戶端邏輯:

/*
* 客戶端
*
* */
public class ClientSocketActivity extends AppCompatActivity implements View.OnClickListener {
    private BluetoothAdapter mBluetoothAdapter;
    private  static final int REQUEST_BLUELIST=200;
    BluetoothDevice device;
    private Button btn;
    BluetoothSocket socket=null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);
        initView();
        setListener();
        Log.i("onCreate----","onCreate");
        // 獲取到藍芽預設的介面卡
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!mBluetoothAdapter.isEnabled()){
            finish();
            return;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode!=REQUEST_BLUELIST){
            return;
        }
        if (resultCode!=RESULT_OK){
            return;
        }
         device=data.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

         new Thread(new Runnable() {
             @Override
             public void run() {
                //開始連線
                 connect();
             }
         }).start();
    }

    private void connect() {
        try {
           socket=device.createRfcommSocketToServiceRecord(UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3"));
            if (socket!=null){
                socket.connect();
                OutputStream outputStream=socket.getOutputStream();
                if (outputStream != null) {
                    // 需要傳送的資訊
                    String text ="向服務端"+device.getName()+"傳送的資訊";
                    // 以utf-8的格式傳送出去
                    outputStream.write(text.getBytes("UTF-8"));
//                    Toast.makeText(ClientSocketActivity.this,"訊息已發出,等待服務端接收",Toast.LENGTH_SHORT).show();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
//            Toast.makeText(ClientSocketActivity.this,"socket未連線",Toast.LENGTH_SHORT).show();
        }finally {
        }
    }
    private void setListener() {
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳轉到搜尋藍芽列表 選擇一個要連線的伺服器 回到客戶端 開始連線
                Intent intent=new Intent(ClientSocketActivity.this,BlueListActivity.class);
                startActivityForResult(intent,REQUEST_BLUELIST);
            }
        });
    }
    private void initView() {
        // 獲取到ListView元件
        btn=(Button)findViewById(R.id.btn);
    }
    @Override
    public void onClick(View v) {
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (socket!=null){
            socket=null;
        }
    }

}

activity_client佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.lzq.bluetoothmanager.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="客戶端"

        />
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="搜尋藍芽裝置"
            />

</LinearLayout>

服務端邏輯:

/*
* 服務端
*
* */
public class ServerSocketActivity extends Activity implements View.OnClickListener {
    private BluetoothAdapter mBluetoothAdapter;
    private Thread serverWorker=new Thread(){
        @Override
        public void run() {
            listen();
        }
    };
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // 通過msg傳遞過來的資訊,吐司一下收到的資訊
            Toast.makeText(ServerSocketActivity.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
        }
    };
    private BluetoothServerSocket serverSocket;
    private BluetoothSocket clientSocket;
    private ListView lv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server);
        initView();
        setListener();
        // 獲取到藍芽預設的介面卡
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!mBluetoothAdapter.isEnabled()){
            finish();
            return;
        }
        //開啟伺服器
        serverWorker.start();

    }

   /*
   * 監聽是否有客戶端連線
   * */
    private void listen() {
        try {
            serverSocket=mBluetoothAdapter.listenUsingRfcommWithServiceRecord("服務端",UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3"));
            /*
            * 客戶連線列表
            * */
            final List<String> lines=new ArrayList<>();
            handler.post(new Runnable() {
                @Override
                public void run() {
                    lines.add("Rfcomm server started...");
                    ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(ServerSocketActivity.this,android.R.layout.simple_list_item_1,lines);
                    lv.setAdapter(arrayAdapter);
                }
            });
            clientSocket=serverSocket.accept();
            //處理請求內容
            if (clientSocket!=null){
                Log.i("clientSocket---","已經連線上客戶端");
//                Toast.makeText(ServerSocketActivity.this,"已經連線上客戶端",Toast.LENGTH_SHORT).show();
                InputStream inputStream = clientSocket.getInputStream();
                // 無線迴圈來接收資料
                while (true) {
                    // 建立一個128位元組的緩衝
                    byte[] buffer = new byte[128];
                    // 每次讀取128位元組,並儲存其讀取的角標
                    int count = inputStream.read(buffer);
                    // 建立Message類,向handler傳送資料
                    Message msg = new Message();
                    // 傳送一個String的資料,讓他向上轉型為obj型別
                    msg.obj = new String(buffer, 0, count, "utf-8");
                    // 傳送資料
                    handler.sendMessage(msg);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void setListener() {
    }
    private void shutDownServer() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                serverWorker.interrupt();
                if (serverSocket!=null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    serverSocket=null;
                }
            }
        }).start();
    }
    private void initView() {
        lv = (ListView) findViewById(R.id.lv);
    }
    @Override
    public void onClick(View v) {
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        shutDownServer();
    }
}

activity_server佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.lzq.bluetoothmanager.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="服務端"

        />
        <ListView
            android:id="@+id/lv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></ListView>
</LinearLayout>

BlueListActivity

/*
* 搜尋藍芽列表
*
* */
public class BlueListActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {


    private ListView lvDevices;
    private ArrayAdapter<String> arrayAdapter;
    //藍芽裝置資訊集合包括 name address
    private List<String> bluetoothDevicesStr = new ArrayList<String>();

    //藍芽裝置物件集合
    private List<BluetoothDevice> bluetoothDevices = new ArrayList<BluetoothDevice>();
    private BluetoothAdapter mBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_blue_list);
        initView();
        setListener();


        // 為listview設定字元換陣列介面卡
        arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevicesStr);
        // 為listView繫結介面卡
        lvDevices.setAdapter(arrayAdapter);
        // 為listView設定item點選事件偵聽
        lvDevices.setOnItemClickListener(this);

        // 獲取到藍芽預設的介面卡
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter==null){
            Toast.makeText(BlueListActivity.this,"手機不支援藍芽",Toast.LENGTH_SHORT).show();
            return;
        }
        if (!mBluetoothAdapter.isEnabled()){//藍芽未開啟 則開啟藍芽
            Intent enableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent,200);
        }

        // 獲取曾經匹配的藍芽裝置  用Set集合保持已匹配的藍芽裝置
        Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
        if (devices.size() > 0) {
            for (BluetoothDevice bluetoothDevice : devices) {
                // 儲存到arrayList集合中
                bluetoothDevicesStr.add("曾經匹配過的藍芽--"+bluetoothDevice.getName() + ":"
                        + bluetoothDevice.getAddress() + "\n");
                bluetoothDevices.add(bluetoothDevice);
            }
        }

        // 因為藍芽搜尋到裝置和完成搜尋都是通過廣播來告訴其他應用的
        // 這裡註冊找到裝置和完成搜尋廣播
        IntentFilter filter=new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);   //裝置已經連線廣播
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); //裝置斷開連線廣播
        registerReceiver(receiver, filter);
        //開始搜尋
        Search();

    }

    private void setListener() {
    }

    private void initView() {
        // 獲取到ListView元件
        lvDevices = (ListView) findViewById(R.id.lv);
    }
    public void Search() {
        setTitle("正在掃描...");
        // 點選搜尋周邊裝置,如果正在搜尋,則暫停搜尋
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        mBluetoothAdapter.startDiscovery();
    }

    // 註冊廣播接收者
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context arg0, Intent intent) {
            // 獲取到廣播的action
            String action = intent.getAction();
            // 判斷廣播是搜尋到裝置還是搜尋完成
            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
                // 找到裝置後獲取其裝置
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 判斷這個裝置是否是之前已經繫結過了,如果是則不需要新增,在程式初始化的時候已經添加了
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    // 裝置沒有繫結過,則將其保持到arrayList集合中
                    bluetoothDevicesStr.add(device.getName() + ":"
                            + device.getAddress() + "\n");
                    // 更新字串陣列介面卡,將內容顯示在listView中
                    arrayAdapter.notifyDataSetChanged();
                    bluetoothDevices.add(device);
                }
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                setTitle("搜尋完成");
            }
        }
    };
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn1://開啟藍芽
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
        if (bluetoothDevicesStr!=null){
            bluetoothDevicesStr=null;
        }
        if (bluetoothDevices!=null){
            bluetoothDevices=null;
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            mBluetoothAdapter.cancelDiscovery();
            Intent intent=new Intent();
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE,bluetoothDevices.get(position));
            setResult(RESULT_OK,intent);
            finish();
    }
}

注意:測試時要在兩個手機同時安裝app,且一個開啟伺服器,作為服務端,另一個開啟客戶端,模擬向服務端傳送資料。