添加权限 注册Activity 区分label
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moliying.bluetooth">
<span style="color:#FF0000;"> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /></span>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<span style="font-size:14px;color:#FF0000;"><activity android:name=".ServerActivity" android:label="server" android:configChanges="keyboard|keyboardHidden|screenSize|orientation"/>
<activity android:name=".ClientActivity" android:label="client" android:configChanges="keyboard|keyboardHidden|screenSize|orientation"/></span>
</application>
</manifest>
四个布局文件
activity_main.xml
bluetooth_item.xml
activity_server.xml
activity_client.xml
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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.moliying.bluetooth.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="openClick"
android:text="查找蓝牙"
android:id="@+id/openBlueTooth"
android:layout_toStartOf="@+id/button_start_server" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView_blueTooth"
android:layout_below="@+id/openBlueTooth"
android:layout_alignParentStart="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"
android:onClick="startServerClick"
android:id="@+id/button_start_server"
android:layout_alignTop="@+id/openBlueTooth"
android:layout_alignParentEnd="true" />
</RelativeLayout>
bluetooth_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_horizontal_margin">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="name"
android:id="@+id/textView_name" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="address"
android:id="@+id/textView2_address" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="配对状态"
android:id="@+id/textView_bond" />
</LinearLayout>
activity_server.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.moliying.bluetooth.ServerActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
android:onClick="sendClick"
android:id="@+id/button_send"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText_info"
android:layout_above="@+id/button_send"
android:layout_alignParentStart="true"
android:layout_alignEnd="@+id/button_send" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView_info"
android:gravity="top"
android:textSize="16sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_above="@+id/editText_info" />
</RelativeLayout>
activity_client.xml 布局与 activity_server.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.moliying.bluetooth.ServerActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
android:onClick="sendClick"
android:id="@+id/button_send"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText_info"
android:layout_above="@+id/button_send"
android:layout_alignParentStart="true"
android:layout_alignEnd="@+id/button_send" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView_info"
android:gravity="top"
android:textSize="16sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_above="@+id/editText_info" />
</RelativeLayout>
三个Activity
MainActivity.java
ServerActivity.java
ClientActivity.java
MainActivity.java
package com.moliying.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
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.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private static final int REQUEST_ENABLE = 0x1;
private ListView listView_bluetooth;
private MyAdapter myAdapter;
private List<BluetoothDevice> deviceList = new ArrayList<>();
BluetoothAdapter bluetoothAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView_bluetooth = (ListView) findViewById(R.id.listView_blueTooth);
myAdapter = new MyAdapter(this,deviceList);
listView_bluetooth.setAdapter(myAdapter);
listView_bluetooth.setOnItemClickListener(this);
}
public void openClick(View v){
deviceList.clear();
//提示用户是否打开蓝牙
// Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
// startActivityForResult(intent,REQUEST_ENABLE);
//直接打开蓝牙
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothAdapter.enable();
if(bluetoothAdapter.isEnabled()){
bluetoothAdapter.startDiscovery(); //开始扫描设备
}
}
//启动为蓝牙服务器
public void startServerClick(View view){
Intent intent = new Intent(this,ServerActivity.class);
startActivity(intent);
}
private BlueToothReceiver receiver = new BlueToothReceiver();
@Override
protected void onStart() {
super.onStart();
//注册广播接收器
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver,filter);
}
@Override
protected void onStop() {
//取消注册
unregisterReceiver(receiver);
super.onStop();
}
@Override
protected void onDestroy() {
bluetoothAdapter.cancelDiscovery();
myAdapter = null;
deviceList = null;
super.onDestroy();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
bluetoothAdapter.cancelDiscovery();//取消查找
BluetoothDevice device = deviceList.get(position);
int state = device.getBondState();
switch (state){
case BluetoothDevice.BOND_NONE:
//发现了没有配对的设备
// device.createBond(); //该方法在API19后可以使用
try {
//API19以下版本可便用反射来调用配对的方法
Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
createBondMethod.invoke(device);
} catch (Exception e) {
e.printStackTrace();
}
break;
case BluetoothDevice.BOND_BONDED:
Intent intent = new Intent(this,ClientActivity.class);
intent.putExtra("device",device);
startActivity(intent);
break;
}
}
private static class MyAdapter extends BaseAdapter{
private Context context;
private List<BluetoothDevice> list;
public MyAdapter(Context context, List<BluetoothDevice> list) {
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh = null;
if(convertView==null){
convertView = LayoutInflater.from(context).inflate(R.layout.bluetooth_item,null);
vh = new ViewHolder();
vh.textView_name = (TextView) convertView.findViewById(R.id.textView_name);
vh.textView_address = (TextView) convertView.findViewById(R.id.textView2_address);
vh.textView_bond = (TextView) convertView.findViewById(R.id.textView_bond);
convertView.setTag(vh);
}else{
vh = (ViewHolder) convertView.getTag();
}
BluetoothDevice bd = list.get(position);
vh.textView_name.setText(bd.getName());
vh.textView_address.setText(bd.getAddress());
String bond = "";
switch (bd.getBondState()){
case BluetoothDevice.BOND_NONE:
bond = "未配对";
break;
case BluetoothDevice.BOND_BONDED:
bond = "已配对";
break;
default:
bond = "未知";
}
vh.textView_bond.setText(bond);
return convertView;
}
static class ViewHolder{
TextView textView_name;
TextView textView_address;
TextView textView_bond;
}
}
//发现蓝牙设备后用于接收设备
class BlueToothReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i("BlueToothReceiver", "onReceive: "+device.getName()+"-"+device.getAddress());
deviceList.add(device);
myAdapter.notifyDataSetChanged();
}
}
}
ServerActivity.java
package com.moliying.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerActivity extends AppCompatActivity {
private static final int START_SERVER = 0x1;
private static final int CLIENT_CONNECT = 0X2;
private static final int HANDLER_INFO = 0x3;
private static final int CLEAN_INFO = 0x4;
private TextView textView_info;
private EditText editText_info;
private Button button_send;
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
private ExecutorService es = Executors.newFixedThreadPool(3);
private PrintStream ps;
private BufferedReader in;
private String name;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_server);
textView_info = (TextView) findViewById(R.id.textView_info);
editText_info = (EditText) findViewById(R.id.editText_info);
button_send = (Button) findViewById(R.id.button_send);
startServer();
}
//启动服务
private void startServer() {
handler.sendEmptyMessage(START_SERVER);
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
es.execute(new Runnable() {
@Override
public void run() {
try {
serverSocket = adapter.listenUsingRfcommWithServiceRecord("server",uuid);
//等待连接,会阻塞
socket = serverSocket.accept();
ps = new PrintStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
name = socket.getRemoteDevice().getName();
handler.sendEmptyMessage(CLIENT_CONNECT);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
private boolean isReceive = false;
//接收消息的线程
class ReceiverThread implements Runnable{
public ReceiverThread() {
isReceive = true;
}
@Override
public void run() {
while (isReceive){
try {
String info = in.readLine();//阻塞
Message msg = handler.obtainMessage(HANDLER_INFO,info);
handler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
isReceive = false;
}
}
}
}
//发送消息的事件
public void sendClick(View view){
final String info = editText_info.getText().toString();
if (TextUtils.isEmpty(info)){
Toast.makeText(ServerActivity.this, "不能发送空消息", Toast.LENGTH_SHORT).show();
}
es.execute(new Runnable() {
@Override
public void run() {
ps.println(info);
ps.flush();
handler.sendEmptyMessage(CLEAN_INFO);
}
});
}
//统一处理消息,更新UI
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case HANDLER_INFO:
textView_info.append("【"+name+"】对我说:"+msg.obj.toString()+"\n");
break;
case CLEAN_INFO:
textView_info.append("我对【"+name+"】说:"+editText_info.getText().toString());
editText_info.setText("");
break;
case START_SERVER:
textView_info.append("服务器端已启动,正在等待连接...\n");
break;
case CLIENT_CONNECT:
textView_info.append("【"+name+"】连接成功\n");
es.execute(new ReceiverThread());//启动接收消息的线程
break;
}
}
};
@Override
protected void onDestroy() {
isReceive = false;
es.shutdown();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
super.onDestroy();
}
}
ClientActivity.java
package com.moliying.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ClientActivity extends AppCompatActivity {
private static final int CONN_SUCCESS = 0x1;
private static final int HANDLER_INFO = 0x2;
private static final int CLEAN_INFO = 0x3;
private TextView textView_info;
private EditText editText_info;
private Button button_send;
private BluetoothDevice device;
private BluetoothSocket socket;
private ExecutorService es = Executors.newFixedThreadPool(3);
private PrintStream ps;
private BufferedReader in;
private String name;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
textView_info = (TextView) findViewById(R.id.textView_info);
editText_info = (EditText) findViewById(R.id.editText_info);
button_send = (Button) findViewById(R.id.button_send);
connect();
}
//连接指定的设备
private void connect() {
device = getIntent().getParcelableExtra("device");
if(device!=null){
es.execute(new Runnable() {
@Override
public void run() {
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
try {
socket = device.createRfcommSocketToServiceRecord(uuid);
if(socket!=null) {
socket.connect();
ps = new PrintStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
name = socket.getRemoteDevice().getName();
handler.sendEmptyMessage(CONN_SUCCESS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
private boolean isReceive = false;
//接收消息的线程
class ReceiverThread implements Runnable{
public ReceiverThread() {
isReceive = true;
}
@Override
public void run() {
while (isReceive){
try {
String info = in.readLine();//阻塞
Message msg = handler.obtainMessage(HANDLER_INFO,info);
handler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
isReceive = false;
}
}
}
}
//发送消息的事件
public void sendClick(View view){
final String info = editText_info.getText().toString();
if (TextUtils.isEmpty(info)){
Toast.makeText(ClientActivity.this, "不能发送空消息", Toast.LENGTH_SHORT).show();
}
es.execute(new Runnable() {
@Override
public void run() {
ps.println(info);
ps.flush();
handler.sendEmptyMessage(CLEAN_INFO);
}
});
}
//更新UI的处理器
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case HANDLER_INFO:
textView_info.append("【"+name+"】对我说:"+msg.obj.toString()+"\n");
break;
case CLEAN_INFO:
textView_info.append("我对【"+name+"】说:"+editText_info.getText().toString()+"\n");
editText_info.setText("");
break;
case CONN_SUCCESS:
String name = device.getName();
textView_info.append("成功与【"+name+"】连接\n");
es.execute(new ReceiverThread());
break;
}
}
};
@Override
protected void onDestroy() {
isReceive = false;
es.shutdown();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
super.onDestroy();
}
}