蓝牙通讯

2023-11-16

简介

蓝牙,是一种支持设备短距离通信(一般10m内,且无阻隔媒介)的无线电技术。能在包括移动电话、PDA、无线耳机、笔记本电脑等众多设备之间进行无线信息交换。利用“蓝牙”技术,能够有效的简化移动通信终端设备之间的通信,也能够成功的简化设备与Internet之间的通信,这样数据传输变得更加迅速高效,为无线通信拓宽道路。

蓝牙API

Android所有关于蓝牙开发的类都在android.bluetooth包下,只有8个类:

BluetoothAdapter     本地蓝牙适配器 
BluetoothClass      蓝牙类(主要包括服务和设备) 
BluetoothClass.Device    蓝牙设备类 
BluetoothClass.Device.Major    蓝牙设备管理 
BluetoothClass.Service   蓝牙服务类 
BluetoothDevice     蓝牙设备(远程蓝牙设备) 
BluetoothServiceSocket    监听蓝牙连接的类 
BluetoothSocket     蓝牙连接类

所需权限

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />

使用蓝牙的步骤

1、获取本地蓝牙适配器

BluetoothAdapter mAdapter= BluetoothAdapter.getDefaultAdapter();

2、打开蓝牙

//弹出对话框提示用户是否打开
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler, REQUEST_ENABLE);
//不做提示,强行打开
// mAdapter.enable();
}
补充一下,使设备能够被搜索
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(enabler,REQUEST_DISCOVERABLE);

3、搜索设备

1)mAdapter.startDiscovery()是第一步,可是你会发现没有返回的蓝牙设备,怎么知道查找到了呢?
2)定义BroadcastReceiver,代码如下
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_BONDED) {
Log.v(TAG, "find device:" + device.getName()+ device.getAddress());
}
//搜索完成
}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setTitle("搜索完成");
if (mNewDevicesAdapter.getCount() == 0) {
Log.v(TAG,"find over");
}
}//执行更新列表的代码
}

需要注册BroadcastReceiver

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

4、建立连接

1)服务器端:

BluetoothServerSocket serverSocket = mAdapter. listenUsingRfcommWithServiceRecord(serverSocketName,UUID);
serverSocket.accept();

2)客户端:

BluetoothSocket clienSocket=dcvice. createRfcommSocketToServiceRecord(UUID);
clienSocket.connect();

5、数据传递

1)获取流
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
2)写出、读入
BluetoothServerSocket
BluetoothServerSocket  BluetoothAdapter.listenUsingRfcommWithServiceRecord(String name, UUID)
通过此方法监听BluetoothSocket的连接
BluetoothServerSocket.accept() 开始接收BluetoothSocket
BluetoothServerSocket.close() 关闭服务
BluetoothSocket
BluetoothSocket BluetoothDevice.createInsecureRfcommSocketToServiceRecord(UUID uuid)
通过此方法向指定的BluetoothDevice发送Socket连接
UUID:00001101-0000-1000-8000-00805F9B34FBconnect() 尝试连接boolean isConnected() 是否已连接,要求最低sdk 14+
BluetoothDevice getRemoteDevice() 获取当前正在或已连接的设备
InputStream getInputStream() 获取输入流
OutputStream getOutputStream() 获取输出流
在读取数据时用数据流
DataInputStream/DataOutputStream
基于Socket技术实现蓝牙聊天
蓝牙的配对
查找已配对的蓝牙设备
Set<BluetoothDevice>  BluetoothAdapter.getBondedDevices()查找附件的蓝牙设备
BluetoothAdapter.startDiscovery())
BluetoothAdapter.isDiscovering() 是否正在查找
BluetoothAdapter.cancelDiscovery() 取消查找
注册广播接收器接收查到的设备信息
BluetoothAdapter.ACTION_DISCOVERY_STARTED 开始查找
BluetoothDevice.ACTION_FOUND 查找到蓝牙设备
BluetoothDevice.EXTRA_DEVICE 获取查找到的设备信息,此数据为ParcelableExtra,
需要intent.getParcelableExtra()获取到BluetoothDevice对象
BluetoothAdapter.ACTION_DISCOVERY_FINISHED 查找结束
判断配对状态int BluetoothDevice.getBondState()  获取设备的配对状态
BluetoothDevice.BOND_BONDED 已配对
BluetoothDevice.BOND_BONDING 正在配对
BluetoothDevice.BOND_NONE 未配对
与指定未配对的设备配对
配对:通过反射获取BluetoothDevice的boolean createBond()方法,并执行
取消配对:通过反射获取BluetoothDevice的boolean removeBond()方法,并执行

普通调用案例

activity_main.xml

   <?xml version="1.0" encoding="utf-8"?>
	<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xiaofei.app.bluetooth.MainActivity">


    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="打开蓝牙设备"
        android:id="@+id/open"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="关闭蓝牙设备"
        android:id="@+id/close"
        android:layout_below="@+id/open"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索蓝牙设备"
        android:id="@+id/button_scan"
        android:layout_below="@+id/close"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
</RelativeLayout>

MainActivity.java

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.util.Set;

public class MainActivity extends Activity implements View.OnClickListener {
    private Button open, close,button_scan;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        open = (Button) findViewById(R.id.open);
        close = (Button) findViewById(R.id.close);
        button_scan = (Button) findViewById(R.id.button_scan);
        open.setOnClickListener(this);
        close.setOnClickListener(this);
        button_scan.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.open:
                //第一种方法,打开蓝牙设备(提示对话框)
               /* Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                startActivity(discoverableIntent);*/

                //第二种方法,打开蓝牙,静默打开
                BluetoothAdapter bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
             bluetoothAdapter.enable();
                break;
            case R.id.close:
                BluetoothAdapter bluetoothAdapter1=BluetoothAdapter.getDefaultAdapter();
                bluetoothAdapter1.disable();
                break;
            case R.id.button_scan:
                //开始扫描蓝牙设备
                BluetoothAdapter bluetoothAdapter2=BluetoothAdapter.getDefaultAdapter();
                bluetoothAdapter2.startDiscovery();
                System.out.println("开始扫描蓝牙设备");
                Set<BluetoothDevice> set=bluetoothAdapter2.getBondedDevices();
                for (BluetoothDevice bd : set)
                {
                    System.out.println("name"+bd.getName());
                    System.out.println("address"+bd.getAddress());

                }
                break;
            default:
                break;

        }
    }
}

通讯案例

MainActivity.java

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.util.Set;

public class MainActivity extends Activity implements View.OnClickListener {
    private Button open, close, button_scan, button_server, button_client;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        open = (Button) findViewById(R.id.open);
        close = (Button) findViewById(R.id.close);
        button_scan = (Button) findViewById(R.id.button_scan);
        button_server = (Button) findViewById(R.id.button_server);
        button_client = (Button) findViewById(R.id.button_client);

        open.setOnClickListener(this);
        close.setOnClickListener(this);
        button_scan.setOnClickListener(this);
        button_server.setOnClickListener(this);
        button_client.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.open:
                //第一种方法,打开蓝牙设备(提示对话框)
               /* Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                startActivity(discoverableIntent);*/

                //第二种方法,打开蓝牙,静默打开
                BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                bluetoothAdapter.enable();
                break;
            case R.id.close:
                BluetoothAdapter bluetoothAdapter1 = BluetoothAdapter.getDefaultAdapter();
                bluetoothAdapter1.disable();
                break;
            case R.id.button_scan:
                //开始扫描蓝牙设备
                BluetoothAdapter bluetoothAdapter2 = BluetoothAdapter.getDefaultAdapter();
                bluetoothAdapter2.startDiscovery();
                System.out.println("开始扫描蓝牙设备");
                Set<BluetoothDevice> set = bluetoothAdapter2.getBondedDevices();
                for (BluetoothDevice bd : set) {
                    System.out.println("name" + bd.getName());
                    System.out.println("address" + bd.getAddress());

                }
                break;
            case R.id.button_server:
                Intent intent = new Intent(this, ServerBluetoothActivity.class);
                startActivity(intent);
                break;
            case R.id.button_client:
                Intent intent1 = new Intent(this, ClientBluetoothActivity.class);
                startActivity(intent1);
                break;
            default:
                break;

        }
    }
}

ServerBluetoothActivity.java

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.util.UUID;

public class ServerBluetoothActivity extends Activity {
 private static final int CONN_SUCCESS=0x1;
 private static final int CONN_FAIL=0x2;
    private static final int RECEIVER_INFO=0x3;
    private static final int SET_EDITTEXT_NULL=0x4;
    private static Button button_send;
    private static TextView textView_content;
    private static EditText editText_info;

    BluetoothAdapter bluetooth=null;//本地蓝牙设备
    BluetoothServerSocket serverSocket=null;//蓝牙设备Socket服务端
    BluetoothSocket socket=null;//蓝牙设备Socket客户端

    //输入输出流
    PrintStream out;
    BufferedReader in;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server_bluetooth);
        setTitle("蓝牙服务端");
        textView_content= (TextView) findViewById(R.id.textView_content);
        editText_info= (EditText) findViewById(R.id.editText_info);
        button_send= (Button) findViewById(R.id.button_send);
        init();
    }
//创建蓝牙服务器端的Socket
    private void init() {
    textView_content.setText("服务器已启动,正在等待连接...\n");
        new Thread(new Runnable() {
            @Override
            public void run() {
               //1.得到本地设备
                bluetooth=BluetoothAdapter.getDefaultAdapter();
                //2.创建蓝牙Socket服务器
                try
                {
                    serverSocket=bluetooth.listenUsingRfcommWithServiceRecord("text", UUID.fromString("00000000-2527-eef3-ffff-ffffe3160865"));
                    //3.阻塞等待Socket客户端请求
                    socket=serverSocket.accept();
                    if (socket!=null)
                    {
                        out=new PrintStream(socket.getOutputStream());
                        in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    }
                    handler.sendEmptyMessage(CONN_SUCCESS);
                }
                catch (IOException e)
                {
              e.printStackTrace();
                    Message msg=handler.obtainMessage(CONN_FAIL,e.getLocalizedMessage());
                    handler.sendMessage(msg);
                }

            }
        }).start();

    }

    //防止内存泄漏 正确的使用方法
    private final MyHandler handler = new MyHandler(this);

    public  class MyHandler extends Handler {
        //软引用
        WeakReference<ServerBluetoothActivity> weakReference;

        public MyHandler(ServerBluetoothActivity activity) {
            weakReference = new WeakReference<ServerBluetoothActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            ServerBluetoothActivity activity = weakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    case RECEIVER_INFO:
                        setInfo(msg.obj.toString() + "\n");
                        break;
                    case SET_EDITTEXT_NULL:
                        editText_info.setText("");
                        break;
                    case CONN_SUCCESS:
                        setInfo("连接成功!\n");
                        button_send.setEnabled(true);
                        new Thread(new ReceiverInfoThread()).start();
                        break;
                    case CONN_FAIL:
                        setInfo("连接失败!\n");
                        setInfo(msg.obj.toString() + "\n");
                        break;
                    default:
                        break;
                }
            }
        }
    }
 private boolean isReceiver=true;
        class ReceiverInfoThread implements Runnable {
            @Override
            public void run() {
                String info=null;
                while (isReceiver)
                {
                    try {
                        info=in.readLine();
                        Message msg=handler.obtainMessage(RECEIVER_INFO,info);
                        handler.sendMessage(msg);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public void sendClick(View v)
        {
            final String content=editText_info.getText().toString();
            if (TextUtils.isEmpty(content))
            {
                Toast.makeText(ServerBluetoothActivity.this,"不能发送空消息",Toast.LENGTH_LONG).show();
                return;
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    out.println(content);
                    out.flush();
                    handler.sendEmptyMessage(SET_EDITTEXT_NULL);
                }
            }).start();
        }
        private void setInfo(String info)
        {
            StringBuffer sb=new StringBuffer();
            sb.append(textView_content.getText());
            sb.append(info);
            textView_content.setText(sb);
        }

}

ClientBluetoothActivity.java

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.util.UUID;

public class ClientBluetoothActivity extends Activity {
    private static final int CONN_SUCCESS=0x1;
    private static final int CONN_FAIL=0x2;
    private static final int RECEIVER_INFO=0x3;
    private static final int SET_EDITTEXT_NULL=0x4;
    private static Button button_send;
    private static TextView textView_content;
    private static EditText editText_info;

    BluetoothAdapter bluetooth=null;//本地蓝牙设备
    BluetoothDevice device=null;//远程蓝牙设备
    BluetoothSocket socket=null;//蓝牙设备Socket客户端

    //输入输出流
    PrintStream out;
    BufferedReader in;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client_bluetooth);
        setTitle("蓝牙客户端");
        textView_content= (TextView) findViewById(R.id.textView_content);
        editText_info= (EditText) findViewById(R.id.editText_info);
        button_send= (Button) findViewById(R.id.button_send);
        init();
    }
    //创建蓝牙客户端端的Socket
    private void init() {
        textView_content.setText("客户端已启动,正在等待连接...\n");
        new Thread(new Runnable() {
            @Override
            public void run() {
               //1.得到本地蓝牙设备的默认适配器
                bluetooth=BluetoothAdapter.getDefaultAdapter();
                //2.通过本地蓝牙设备得到远程蓝牙设备
                device=bluetooth.getRemoteDevice("22:22:4E:6E:59:86");
                //3.根据UUID创建并返回一个BoluetoothSocket
                try {
                    socket=device.createRfcommSocketToServiceRecord(UUID.fromString("00000000-2527-eef3-ffff-ffffe3160865"));
                    if (socket!=null)
                    {
                        // 连接
                        socket.connect();
                        //处理客户端输出流
                        out=new PrintStream(socket.getOutputStream());
                        in=new BufferedReader(new InputStreamReader(socket.getInputStream()));

                    }
                    handler.sendEmptyMessage(CONN_SUCCESS);
                } catch (IOException e) {
                    e.printStackTrace();
                    Message msg=handler.obtainMessage(CONN_FAIL,e.getLocalizedMessage());
                    handler.sendMessage(msg);

                }

            }
        }).start();
    }

    //防止内存泄漏 正确的使用方法
    private final MyHandler handler = new MyHandler(this);

    public  class MyHandler extends Handler {
        //软引用
        WeakReference<ClientBluetoothActivity> weakReference;

        public MyHandler(ClientBluetoothActivity activity) {
            weakReference = new WeakReference<ClientBluetoothActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            ClientBluetoothActivity activity = weakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    case RECEIVER_INFO:
                        setInfo(msg.obj.toString() + "\n");
                        break;
                    case SET_EDITTEXT_NULL:
                        editText_info.setText("");
                        break;
                    case CONN_SUCCESS:
                        setInfo("连接成功!\n");
                        button_send.setEnabled(true);
                        System.out.println("name"+device.getName());
                        System.out.println("Uuids"+device.getUuids());
                        System.out.println("Address"+device.getAddress());
                        new Thread(new ReceiverInfoThread()).start();
                        break;
                    case CONN_FAIL:
                        setInfo("连接失败!\n");
                        setInfo(msg.obj.toString() + "\n");
                        break;
                    default:
                        break;
                }
            }
        }
    }


    private boolean isReceiver=true;
    //接收信息的线程
    class ReceiverInfoThread implements Runnable {
        @Override
        public void run() {
            String info=null;
            while (isReceiver)
            {
                try {
                    System.out.println("--ReceiverInfoThread start --");
                    info=in.readLine();
                    System.out.println("--ReceiverInfoThread read --");
                    Message msg=handler.obtainMessage(RECEIVER_INFO,info);
                    handler.sendMessage(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public void sendClick(View v)
    {
        final String content=editText_info.getText().toString();
        if (TextUtils.isEmpty(content))
        {
            Toast.makeText(ClientBluetoothActivity.this,"不能发送空消息",Toast.LENGTH_LONG).show();
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                out.println(content);
                out.flush();
                handler.sendEmptyMessage(SET_EDITTEXT_NULL);
            }
        }).start();
    }
    private void setInfo(String info)
    {
        StringBuffer sb=new StringBuffer();
        sb.append(textView_content.getText());
        sb.append(info);
        textView_content.setText(sb);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xiaofei.app.bluetooth.MainActivity">


    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="打开蓝牙设备"
        android:id="@+id/open"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="关闭蓝牙设备"
        android:id="@+id/close"
        android:layout_below="@+id/open"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索蓝牙设备"
        android:id="@+id/button_scan"
        android:layout_below="@+id/close"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="服务器端"
        android:id="@+id/button_server"
        android:layout_below="@+id/button_scan"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignRight="@+id/button_scan"
        android:layout_alignEnd="@+id/button_scan" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="客户端"
        android:id="@+id/button_client"
        android:layout_below="@+id/button_server"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignRight="@+id/button_server"
        android:layout_alignEnd="@+id/button_server" />
</RelativeLayout>

activity_client_bluetooth.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xiaofei.app.bluetooth.ServerBluetoothActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text=""
        android:id="@+id/textView_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/editText_info"
        android:layout_below="@+id/textView" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText_info"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_toLeftOf="@+id/button_send"
        android:layout_toStartOf="@+id/button_send" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send"
        android:id="@+id/button_send"
        android:onClick="sendClick"
        android:layout_alignBottom="@+id/editText_info"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="客户端"
        android:id="@+id/textView"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
</RelativeLayout>

activity_server_bluetooth.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xiaofei.app.bluetooth.ServerBluetoothActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text=""
        android:id="@+id/textView_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/editText_info"
        android:layout_below="@+id/textView" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText_info"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_toLeftOf="@+id/button_send"
        android:layout_toStartOf="@+id/button_send" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send"
        android:id="@+id/button_send"
        android:onClick="sendClick"
        android:layout_alignBottom="@+id/editText_info"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="服务器端"
        android:id="@+id/textView"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
</RelativeLayout>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蓝牙通讯 的相关文章

  • 弹出式菜单(下拉菜单)实现——PopupMenu -

    PopupMenu代表弹出式菜单 它会在指定组件上弹出PopupMenu 默认情况下 PopupMenu会显示在该组件的下方或上方 PopupMenu可增加多个菜单项 并可为菜单项增加子菜单 使用PopupMenu创建菜单的步骤非常简单 只
  • 游戏开发安卓知识杂谈系列:关于下载jdk

    想要下载jdk11 去oracle官网下载jdk 发现jdk13以下的版本需要账号登陆 但是去注册账号发现官网账号无法注册 找了半天 网上说Oracle自java SE 8的某个版本以后 需要进行付费才能下载 两个解决办法 找百度网盘或者第
  • Android Studio实现智能聊天机器人

    项目目录 一 需求分析 1 业务需求分析 2 模型需求分析 3 界面需求分析 二 开发环境 三 聊天功能业务实现 1 申请机器人身份标识 2 搭建聊天界面布局 3 搭建聊天条目布局 4 封装聊天信息实体类 5 编写聊天列表适配器 6 实现智
  • C语言 - static inline

    2019 07 16 今天在看DPDK负载均衡的实例代码中 通过函数跳转 看到官方API后 发现了static inline这个关键字 这个我只是在很早之前知道inline是内联的 可以不进行压栈 但是static毕竟是限制函数的作用域的啊
  • 安卓 Android 11、12 不使用第三方 Recovery TWRP 刷入 Magisk v22+ 支持联发科

    测试机型 小米 10 至尊纪念版 Mi 10 Ultra 今天把 MIUI 版本更新到了 12 1 1 发现安卓版本升到了 11 接下来我就正常想刷 wzsx150 大佬的 TWRP 发现刷上去挂载不了 data 不支持安卓 11 网上搜索
  • 如何安装和使用Android夜神模拟器

    夜神模拟器 是全新一代的安卓模拟器 能够让你在电脑上畅玩手机游戏 与传统安卓模拟器相比 基于Android7 1内核 同时向下兼容Android5 1内核以及X86 AMD 具备极高的兼容性和稳定性 加上超高帧率模式 能够在电脑上运行高性能
  • Android使用OKHttp访问网络获取Cookie和带Cookie的请求

    登录 取得Cookie public void login String username String userpwd FormBody body new FormBody Builder add email username add p
  • 上架发布应用市场资料填写规则限制

    应用名称填写时 名字长度有没有限制呢 1 名称 1 字数限制 iOS 30 Android 64 2 应用市场显示的名称 2 副标题 1 字数限制 iOS 30 2 应用市场显示的副标题 宣传文本填写时 可以编写多少个字 1 字数限制 iO
  • 高帧率手机 Flutter 列表慢慢拖动的时候会有明显的抖动

    高帧率手机上 Flutter列表慢慢拖动的时候会感觉到明显的抖动现象 比如 一加手机输入的运行频率为120hz 而显示屏的运行频率为90hz 滚动时 这种不匹配会导致性能下降 google团队通过以下的方法来解决此问题 void main
  • 解决org.gradle.api.tasks.TaskExecutionException: Execution failed for task ‘:framework:compileDebugJav

    目录 介绍 解决方法1 解决方法2 解决方法3 解决方法4 解决方法5 解决方法6 解决方法7 介绍 今天在拉公司项目的时候报了一个奇怪的错误 在这里分享给大家 让大家少走弯路 报了这个错误信息其实有很多种可能性我依依把解决方案写在下面并且
  • Android中Activity的开启Activity页面的跳转详解

    android开启和关闭activity 1 在android 中我们要开启和关闭activity按钮首先就要创建两个activity 2 然后在他们的布局文件中添加页面 3 然后使用java代码编写程序实现页面的开启和关闭 在MainAc
  • 与Android对接注册接口的session会话取值为null问题

    与Android对接注册接口的session会话取值为null问题 问题 最近在改造一个springboot项目时在后端写好登录接口后 Android调用登录成功后 调用其他接口时发现获取session为null 经过swagger一番测试
  • Android MediaPlayer播放本地音频

    reference Android 第一行代码 MediaPlayer类常用的方法 setDataSource 设置要播放的音频文件的路径 prepare 开始播放之前调用这个方法完成准备工作 start 开始或继续播放 pause 暂停播
  • 关于Android Studio使用intent跳转到新的Activity出现not an enclosing class报错的解决办法

    目前遇到not an enclosing class这个问题两次 分别是犯了不同的错误 1 第一个参数输入错误 第一个参数应该是当前活动的上下文 也就是当前Activity的参数 例如我的当前Activity是MainActivity 要跳
  • didChangeDependencies什么时候被调用

    参考 我先上一个Demo 这个Demo也就是网上面传的比较广的 我们就以这个来举例子说明网上的结论 父级结构中的层级发生变化时didChangeDependencies被调用 这个结论为什么是不完整 import package flutt
  • 制作一个“生日快乐”App,来自程序员的生日礼物~

    点击上方 码农的后花园 选择 星标 公众号 精选文章 第一时间送达 之前给大家制作了一个来自程序员的表白神器 本期带大家做一个 生日快乐 App 来自程序员的生日礼物 不要再说程序员不懂浪漫咯 往期精彩 Android App 开发的三种姿
  • flutter 文字拼接

    Container margin EdgeInsets only right 10 child Row mainAxisSize MainAxisSize min children ConstrainedBox constraints Bo
  • 送一个2022年最赚钱的方法!包含操作方法!

    在互联网上 可恶的人有很多 值得我们学习的人也有很多 有的人做起事来不讲武德 而有的人却是我们值得学习一生的榜样 在赚钱的路上 信息就是金钱 你掌握了信息的源头 就掌握的金矿 拥有足够的信息来源 那么你就有足够的金钱 假如你想在一个行业里快
  • App隐私监管新规实施 隐私合规检测要注意这几点?

    5月1日 国家四部委联合制定的 常见类型移动互联网应用程序必要个人信息范围规定 简称 规定 将正式实施 规定 明确移动互联网应用程序 App 运营者不得因用户不同意收集非必要个人信息 而拒绝用户使用App基本功能服务 要求各地各相关单位督促
  • 如何在出厂重置后从 Android 恢复丢失的数据、照片、联系人

    什么是恢复出厂设置 恢复出厂设置是将电子设备恢复到制造商在工厂设置的原始状态 也称为主重置或硬重置 恢复出厂设置有什么作用 这样做将删除用户在设备上添加的所有数据 设置和应用程序 当手机需要出售 需要擦除个人数据或者遇到设备故障 病毒攻击

随机推荐

  • c语言输入输出函数printf与scanf的用法格式

    c语言输入输出函数printf与scanf的用法格式 格式化规则例如 5 4f等类似问题的说明 Turbo C2 0 标准库提供了两个控制台格式化输入 输出函数printf 和scanf 这两个函数可以在标准输入输出设备上以各种不同的格式读
  • SAP LSMW日志信息如何导出到Excel里?

    SAP LSMW日志信息如何导出到Excel里 在SAP系统中 数据迁移LSMW运行的日志 是可以下载到本地Excel文件里的 方式如下所示 双击某个会话 点击打印机图标 就可以导出到Excel文件里了 输入文件名 指定文件保存的目录 完
  • 送书

    今天是周三 又到了给大家送书的时刻啦 这次给大家带来的是 OpenCV图像处理入门与实践 文末查看送书规则 简介 OpenCV 是一个开源的计算机视觉库 可以实现计算机视觉算法 本书从 OpenCV 用 Python 实现的基础语法讲起 逐
  • C51定时器和计数器 timer and counter

    代码 include
  • Seven Different Linux/BSD Firewalls Reviewed

    Seven Different Linux BSD Firewalls Reviewed Firewall November 14th 2007 Did you know more than 500 million computers in
  • 鲸鱼优化算法论文【matlab代码与仿真】

    一 算法流程 通过回声定位并相互传递探寻猎物信息 研究表明 鲸鱼大脑的某些区域与人类相似 有一种叫做梭形细胞的共同细胞 这些细胞负责人类的判断 情感和社会行为 这种细胞的数量是成年人的两倍 事实证明 鲸鱼可以像人类一样思考 学习 判断 交流
  • 从Kubernetes 1.14 发布,看技术社区演进方向

    Kubernetes 1 14 正式发布已经过去了一段时间 相信你已经从不同渠道看过了各种版本的解读 不过 相比于代码 Release 马上就要迎来5周岁生日的Kubernetes 项目接下来如何演进 其实也是一个让人着迷的话题 而作为一个
  • 在linux中,&和&&,

    对应刚接触linux命令的小伙伴们来说 这些符号一定是很困扰的下面我们一起来看这些符号区别和用法 表示任务在后台执行 如要在后台运行 如 root localhost local java jar test jar gt log txt 运
  • 大型 SaaS 平台产品架构设计

    当我们去搜索 架构 可以得到很多的架构图片 比如组织架构 业务架构 数据架构 技术架构 安全架构 产品架构 部署架构等 什么是架构 通常大家说架构一般指软件架构 架构是指软件的基础结构 创造这些基础结构的准则 以及对这些结构的描述 在这个定
  • IAR常见报错

    右键进入函数出错 project gt clean
  • 利用python进行数据分析之数据聚合和分组运算--小白笔记

    GroupBy机制 split apply combine 拆分 应用 合并 import pandas as pd import numpy as np df pd DataFrame key1 a a b b a key2 one tw
  • 找不到匹配的host key算法

    vim etc ssh sshd config
  • 《WebRTC系列》实战 Web 端支持 h265 硬解

    1 背景 Web 端实时预览 H 265 需求一直存在 但由于之前 Chrome 本身不支持 H 265 硬解 软解性能消耗大 仅能支持一路播放 该需求被搁置 去年 9 月份 Chrome 发布 M106 版本 默认开启 H 265 硬解
  • raw格式详解

    raw格式是camera sensor直接输出的格式 每个像素点表示一个颜色分量B G或R 注意 这句话不准确 红外相机的sensor和彩色相机的sensor有些不同 有的红外相机的sensor输出的raw data就是亮度值 即灰度值 输
  • Android Flutter开发环境搭建

    1 搭建 Flutter 开发环境 本栏亦在快速上手Android Flutter Flutter框架就不介绍了 框架这个东西怎么说呢 对于大部分人来说只是了解即可 如需了解的话 可以度娘资料很多 本节我们主要看下如何在Windwos下搭建
  • Kotlin协程实现原理:CoroutineScope,看完不懂你砍我!墙裂建议收藏。

    今天我们来聊聊Kotlin的协程Coroutine 文末有为大家准备的彩蛋 如果你还没有接触过协程 推荐你先阅读这篇入门级文章What 你还不知道Kotlin Coroutine 如果你已经接触过协程 相信你都有过以下几个疑问 协程到底是个
  • 一个码稿人自述:什么样的文档产品适合我?|深度吐槽

    关注ITValue 看企业级最新鲜 最价值报道 图片来源 Unsplash 钛媒体打工人 媒体相关从业经验4 5年 文档使用重度患者 今天以我曾经用过的 和现在主流的一些文档产品为例 来谈谈我的使用体验 以及什么样的文档适合我 一 我与文档
  • [编程工具]MarkDown编辑查看以及使用语法

    目录 0 前言 1 markDown语法 2 markDown 3 MD正确打开方式 4 结尾 结束啦感谢观看 5 参考连接 0 前言 本文介绍了markDown的编辑查看 使用浏览器查看以及Vscode中查看编辑MD 最后介绍了MD的常用
  • python解析佳明fit文件

    使用 fitparse 解析 佳明 fit 文件 以下示例测试环境为 python 3 8 fitparse 1 2 fitparse 安装 pip3 install fitparse 使用方式 import fitparse from d
  • 蓝牙通讯

    蓝牙通讯 简介 蓝牙API 所需权限 使用蓝牙的步骤 普通调用案例 通讯案例 简介 蓝牙 是一种支持设备短距离通信 一般10m内 且无阻隔媒介 的无线电技术 能在包括移动电话 PDA 无线耳机 笔记本电脑等众多设备之间进行无线信息交换 利用