Android手机蓝牙互联,并传递数据。


今晚整理下,实验室没开门,只好在一教将就一下了


关于蓝牙,看了好些天,但是看完后想想也没啥,都是谷歌做好了的东西,我们只要用用API就ok了,哎。

首先,如果是互相传递数据的,两部android设备各自都必须充当两种角色。

1、服务端 2、客户端。

其实也不难理解,毕竟通信是两者之间建立的,而且必须实现收发并用。所以理所当然了,客户端发送消息给服务端。

两部设备是通过使用相同的UUID建立起一个Rfcomm什么的通道,这个通道连接两台设备以供数据的传递。

当然要如何建立呢?(我也不知道)

我们先分析客户端,他是通过Socket的一个主动连接函数connect()来请求服务端的连接(服务端接收到请求..才会有数据传递 后面再说),那么这个socket是怎样来的呢?

是通过device.createRfcommSocketToServiceRecord(UUID);来的,这个device是由你相连服务端的地址得到的,通过蓝牙适配器mBluetoothAdapter.getRemoteDevice(address);来的。address又是怎么来的呢? 是通过扫描附近蓝牙,被广播接收器接收到的。

好的整理一下,就是通过广播接收器扫描到附近的蓝牙设备(当然机智的你肯定准备好了两台设备) 然后能通过扫描到的设备得到他们的地址。通过这个地址就能实例化出device

然后Socket也就出来了。最后通过Socket.getOutputStream() 得到输出流,想输出流内写入数据 即可完成客户端的任务。


//以下是客户端负责发送消息的代码(布局和manifest文件自己添加以下,很简单)

package com.example.single_bt1;


import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

public class AsClient extends Activity implements OnItemClickListener {

    private static final String TAG = "MainActivity";
    // 本地蓝牙适配器
    private BluetoothAdapter mBluetoothAdapter;
    // 列表
    private ListView lvDevices;
    // 存储搜索到的蓝牙
    private List<String> bluetoothDevices = new ArrayList<String>();
    // listview的adapter
    private ArrayAdapter<String> arrayAdapter;
    // UUID.randomUUID()随机获取UUID
    private final UUID MY_UUID = UUID
            .fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
    // 连接对象的名称
    private final String NAME = "LGL";

    // 这里本身即是服务端也是客户端,需要如下类
    private BluetoothSocket clientSocket;
    private BluetoothDevice device;
    // 输出流_客户端需要往服务端输出
    private OutputStream os;

    private EditText et;

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

    private void initView() {

        // 获取本地蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // 判断手机是否支持蓝牙
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();
            finish();
        }

        // 判断是否打开蓝牙
        if (!mBluetoothAdapter.isEnabled()) {
            // 弹出对话框提示用户是后打开
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 1);
            // 不做提示,强行打开
//             mBluetoothAdapter.enable();
        }
        et = (EditText) findViewById(R.id.edit_input2);
        // 初始化listview
        lvDevices = (ListView) findViewById(R.id.lvDevices);
        lvDevices.setOnItemClickListener(this);

        // 获取已经配对的设备
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
                .getBondedDevices();

        // 判断是否有配对过的设备
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                // 遍历到列表中
                bluetoothDevices.add("已配对\n" + device.getName() + ":"
                        + device.getAddress());
            }
        }

        // adapter
        arrayAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1,
                bluetoothDevices);
        lvDevices.setAdapter(arrayAdapter);

        //启动服务

        /**
         * 异步搜索蓝牙设备——广播接收
         */
        // 找到设备的广播
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        // 注册广播
        registerReceiver(receiver, filter);
        // 搜索完成的广播
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        // 注册广播
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

    // 广播接收器
    private final BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // 收到的广播类型
            String action = intent.getAction();
            // 发现设备的广播
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 从intent中获取设备
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 判断是否配对过
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    // 添加到列表
                    bluetoothDevices.add("未配对\n" + device.getName() + ":"
                            + device.getAddress());
                    arrayAdapter.notifyDataSetChanged();
                }
                // 搜索完成
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
                    .equals(action)) {
                // 关闭进度条
                setProgressBarIndeterminateVisibility(true);
                setTitle("搜索完成!");
            }
        }
    };

    // 客户端
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
                            long id) {
        // 先获得蓝牙的地址和设备名
        String s = arrayAdapter.getItem(position);
        // 单独解析地址
        String address = s.substring(s.indexOf(":") + 1).trim();

        // 主动连接蓝牙
        try {
            // 判断是否在搜索,如果在搜索,就取消搜索
            if (mBluetoothAdapter.isDiscovering()) {
                mBluetoothAdapter.cancelDiscovery();
            }
            try {
                // 获得远程设备
                device = mBluetoothAdapter.getRemoteDevice(address);
                Log.e(TAG, "device:" + device);

                clientSocket = device
                        .createRfcommSocketToServiceRecord(MY_UUID);
                // 连接
                clientSocket.connect();
                // 获得输出流
                os = clientSocket.getOutputStream();
               // 判断是否可以获得
                if (device == null) {
                    // 获得远程设备
                    device = mBluetoothAdapter.getRemoteDevice(address);
                    Log.e(TAG, "device:" + device);
                }
                // 开始连接
                if (clientSocket == null) {
                    clientSocket = device
                            .createRfcommSocketToServiceRecord(MY_UUID);
                    // 连接
                    clientSocket.connect();
                    // 获得输出流
                    os = clientSocket.getOutputStream();
                }
            } catch (Exception e) {

            }
            // 如果成功获得输出流
            if (os != null) {
//                os.write("Hello Bluetooth!".getBytes());
                os.write(et.getText().toString().getBytes("GBK"));
                Log.e(TAG, "write");
                et.setText("");
            }
        } catch (Exception e) {

        }
    }

}

接下来就是服务端了,服务端相比来说就稍微省事一点了,坐在那里等人来请求,所以他要一直在那里等,言下之意就是一个耗时操作,所以放在一个新的线程中是自然的事情。通过ServerScoket的accept()会产生一个socket负责与客户端的socket通信, 那么这个serversocket哪来的呢,直接上代码吧:

serverSocket = mBluetoothAdapter .listenUsingRfcommWithServiceRecord(NAME, MY_UUID); name是自己定义的,随便写就好(String类型)

然后就是通过serverSocket.getInputStream() 得到输入流,就能读出数据了。


package com.example.single_bt2_server;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;


public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    // 本地蓝牙适配器
    private BluetoothAdapter mBluetoothAdapter;
    // UUID.randomUUID()随机获取UUID
    private final UUID MY_UUID = UUID
            .fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
    // 连接对象的名称
    private final String NAME = "LGL";
    //线程类的实例
    private AcceptThread ac;

//    private EditText edit_Get;
    private ListView list_Get;
    private List<String> content = new ArrayList<String>();
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.received);
//        edit_Get = (EditText) findViewById(R.id.edit_get);
        initView();
    }

    private void initView() {
        list_Get = (ListView) findViewById(R.id.list_get);
        adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,content);
        list_Get.setAdapter(adapter);
        // 获取本地蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // 判断手机是否支持蓝牙
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();
            finish();
        }

        // 判断是否打开蓝牙
        if (!mBluetoothAdapter.isEnabled()) {
            // 弹出对话框提示用户是后打开
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 1);
            // 不做提示,强行打开
//             mBluetoothAdapter.enable();
        }

        ac = new AcceptThread();
        ac.start();

    }


    // 服务端,需要监听客户端的线程类
    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            Toast.makeText(MainActivity.this, String.valueOf(msg.obj),
                    Toast.LENGTH_SHORT).show();
            String result = String.valueOf(msg.obj);
//            edit_Get.setText(String.valueOf(msg.obj));
            content.add(result);
            adapter.notifyDataSetChanged();
            Log.e(TAG, msg.obj + ":服务端");
            super.handleMessage(msg);
        }
    };

    // 线程服务类
    private class AcceptThread extends Thread {
        private BluetoothServerSocket serverSocket;
        private BluetoothSocket socket;
        // 输入 输出流
        private OutputStream os;
        private InputStream is;

        public AcceptThread() {
            try {
                serverSocket = mBluetoothAdapter
                        .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            // 截获客户端的蓝牙消息
            try {
                socket = serverSocket.accept(); // 如果阻塞了,就会一直停留在这里
                is = socket.getInputStream();
                os = socket.getOutputStream();
                while (true) {
                    synchronized (MainActivity.this) {
                        byte[] tt = new byte[is.available()];
                        if (tt.length > 0) {
                            is.read(tt, 0, tt.length);
                            Message msg = new Message();
                            msg.obj = new String(tt, "GBK");
                            Log.e(TAG, msg.obj + ":客户端");
                            handler.sendMessage(msg);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, e.getMessage());
            }
        }
    }

}

至于两者都有的角色 让我放到文件中吧,是网上参考


  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值