欢迎转载,但请注明出处!谢谢。http://www.cnblogs.com/weizhxa/p/5792775.html

  最近公司在做一个蓝牙串口通讯的App,有一个固定的蓝牙设备,需要实现手机连接相互交换数据。以前没怎么做过蓝牙开发,故查看Android App Guide的蓝牙篇,发现有个chat示例,故此做了点研究。在研究的基础上进行了此App的实现。

  1、App特点:

    1.1 App中同时存在服务器与客户端,任意手机可以作为服务器或者客户端;

    1.2 客户端可以进行蓝牙环境扫描;

    1.3 诸多异常处理……均未做,O(∩_∩)O。demo了,主要学习的是蓝牙技术嘛。

  2、实现过程中的总结:

    2.1 蓝牙串口通讯,谷歌给出了一个固定UUID: 00001101-0000-1000-8000-00805F9B34FB,大多数蓝牙串口设备使用此UUID作为连接用UUID,此UUID在BluetoothDevice的createRfcommSocketToServiceRecord方法中有提到。具体可以看api doc。

  3、具体实现代码:

    3.1 客户端服务器选择页:MainActivity。此页仅进行客户端与服务器端选择使用。

      3.1.1 Activity:

      

 package org.fiu.bluetoothdemos;

 import org.fiu.bluetoothchatdemos.R;

 import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} /**
* 建立服务器
*
* @param view
*/
public void btn_server(View view) {
startActivity(new Intent(this, ServerActivity.class));
} /**
* 建立客户端
*
* @param view
*/
public void btn_client(View view) {
startActivity(new Intent(this, ClientActivity.class));
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

      3.1.2 layout:

 <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"
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="org.fiu.bluetoothdemos.MainActivity" > <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btn_server"
android:text="开启服务器" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btn_client"
android:text="开启客户端" /> </LinearLayout>

    3.2 服务器端代码:

      3.2.1 服务器页面:点击进入服务器页面后,直接使用上面所说UUID进行服务器建立,等待客户端连接工作。拥有一个消息显示框和发送EditText,可以与客户端进行交互。内部拥有一个BluetoothServer管理类,这个类主要管理了服务器的蓝牙操作。

      

 package org.fiu.bluetoothdemos;

 import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask; import org.fiu.bluetoothchatdemos.R; import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView; /**
* 服务器
*
* @author c
*
*/
public class ServerActivity extends Activity {
private EditText et_msg;
private BluetoothServer server;
private List<String> msgs = new ArrayList<String>();
private TimerTask task = new TimerTask() { @Override
public void run() {
synchronized (msgs) {
msgs = server.getMsgs();
}
runOnUiThread(new Runnable() {
public void run() {
msgAdapter.notifyDataSetChanged();
}
});
} };
private MyAdapter msgAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat); et_msg = (EditText) findViewById(R.id.et_msg);
server = new BluetoothServer(this);
server.start(); ListView lv_msg = (ListView) findViewById(R.id.lv_msg);
msgAdapter = new MyAdapter();
lv_msg.setAdapter(msgAdapter); Timer timer = new Timer();
timer.schedule(task, 0, 1000);
} public class MyAdapter extends BaseAdapter { @Override
public int getCount() {
// TODO Auto-generated method stub
return msgs.size();
} @Override
public Object getItem(int position) {
return msgs.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = null;
if (convertView != null) {
tv = (TextView) convertView;
} else {
tv = new TextView(ServerActivity.this);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(params);
}
tv.setTag(msgs.get(position));
tv.setText(msgs.get(position));
return tv;
} } /**
* 发送
*
* @param view
*/
public void btn_send(View view) {
String msg = et_msg.getText().toString().trim();
send(msg);
} /**
* 发送消息到客户端
*
* @param msg
*/
private void send(String msg) {
server.send(msg);
synchronized (msgs) {
msgs.add("服务器发送:" + msg);
}
}
}

      3.2.2 服务器页面layout

      

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:orientation="horizontal" > <EditText
android:id="@+id/et_msg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:hint="chatMessage" /> <Button
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btn_send"
android:text="send" />
</LinearLayout> <ListView
android:id="@+id/lv_msg"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView> </LinearLayout>

      3.2.3 服务器蓝牙管理类

      

 package org.fiu.bluetoothdemos;

 import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast; /**
* 蓝牙服务器
*
* @author weizh
*
*/
public class BluetoothServer {
/**
* 消息集合
*/
private List<String> listMsg = new ArrayList<String>();
/**
* 是否工作中
*/
private boolean isWorking = false;
/**
* bluetooth name
*/
private String name = "FIUBluetoothServer";
/**
* spp well-known UUID
*/
public static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final String TAG = "BluetoothServer";
/**
* 蓝牙服务器socket
*/
private BluetoothServerSocket bluetoothServerSocket;
/**
* 客户端socket
*/
private BluetoothSocket mClientSocket; Context context; public BluetoothServer(Context context) {
this.context = context;
} /**
* 开启服务器
*/
public void start() {
listen();
} /**
* 开始监听
*/
private void listen() {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
// 判断是否有蓝牙设备
if (!BluetoothUtils.checkBluetoothExists()) {
throw new RuntimeException("bluetooth module not exists.");
}
// 打开设备
if (!BluetoothUtils.openBluetoothDevice()) {
return;
}
try {
if (bluetoothServerSocket == null) {
bluetoothServerSocket = BluetoothAdapter
.getDefaultAdapter()
.listenUsingRfcommWithServiceRecord(name,
MY_UUID);
}
isWorking = true;
while (isWorking) {
mClientSocket = bluetoothServerSocket.accept();
Log.i(TAG, "客户端已连接:"
+ mClientSocket.getRemoteDevice().getName());
myHandler.sendEmptyMessage(0x01);
new ClientWorkingThread(mClientSocket).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start(); } private Handler myHandler = new Handler() { @Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(context,
"客户端已连接:" + mClientSocket.getRemoteDevice().getName(), 0)
.show();
} }; /**
* 停止
*/
public void stop() {
isWorking = false;
if (bluetoothServerSocket != null) {
try {
bluetoothServerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
bluetoothServerSocket = null;
}
}
if (mClientSocket != null) {
try {
mClientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
mClientSocket = null;
}
}
} /**
* 客户端socket工作类
*
* @author weizh
*
*/
private class ClientWorkingThread extends Thread {
/**
* 客户端socket
*/
private BluetoothSocket mClientSocket; public ClientWorkingThread(BluetoothSocket clientSocket) {
this.mClientSocket = clientSocket;
} @Override
public void run() {
try {
InputStream inputStream = mClientSocket.getInputStream();// 输入流
// 从输入流中取出数据,插入消息条中
byte[] buffer = new byte[1024];
while (isWorking) {
int read = inputStream.read(buffer);
if (read != -1) {
// 有内容
// 判断是否取得的消息填充满了buffer,未到字符串结尾符;如果不是,证明读取到了一条信息,并且信息是完整的,这个完整的前提是不能粘包,不粘包可以使用flush进行处理。
StringBuilder sb = new StringBuilder();
if (read < buffer.length) {
String msg = new String(buffer, 0, read);
sb.append(msg);
} else {
byte[] tempBytes = new byte[1024 * 4];
while (read == buffer.length
&& buffer[read - 1] != 0x7f) {
read = inputStream.read(buffer);
}
String msg = new String(buffer, 0, read);
sb.append(msg);
}
Log.i(TAG, "服务器收到:" + sb.toString());
synchronized (listMsg) {
listMsg.add("客户端发送:" + sb.toString());
}
}
// try {
// Thread.sleep(300);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 工作完毕,关闭socket
try {
mClientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
} /**
* 返回listMsg
*
* @return
*/
public List<String> getMsgs() {
synchronized (listMsg) {
return listMsg;
}
} /**
* 发送消息
*
* @param msg
*/
public void send(String msg) {
if (mClientSocket != null) {
try {
mClientSocket.getOutputStream().write(msg.getBytes());
mClientSocket.getOutputStream().flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

     3.3 客户端页面:客户端除了具有消息框和发送消息框外,加载后首先可以进行蓝牙环境扫描,并且和选择。demo中偷了懒,没在选择后停止蓝牙扫描工作等诸多小细节……

      3.3.1 客户端页面代码:

 package org.fiu.bluetoothdemos;

 import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask; import org.fiu.bluetoothchatdemos.R;
import org.fiu.bluetoothdemos.ServerActivity.MyAdapter; import android.app.Activity;
import android.app.AlertDialog;
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.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.AbsoluteLayout;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView; /**
* 客户端
*
* @author c
*
*/
public class ClientActivity extends Activity {
/**
* 被发现的设备
*/
private List<BluetoothDevice> discoverDevices = new ArrayList<BluetoothDevice>();
/**
* 蓝牙客户端
*/
private BluetoothClient bluetoothClient;
/**
* tag
*/
public final String TAG = "ClientActivity";
/**
* 搜索对话框
*/
private AlertDialog dlgSearch;
/**
* adapter
*/
private BaseAdapter adapter;
private EditText et_msg;
private List<String> msgs = new ArrayList<String>();
private TimerTask task = new TimerTask() { @Override
public void run() {
synchronized (msgs) {
msgs = bluetoothClient.getMsgs();
}
runOnUiThread(new Runnable() {
public void run() {
msgAdapter.notifyDataSetChanged();
}
});
} };
private MyAdapter msgAdapter;
/**
* 设备搜索广播
*/
private BroadcastReceiver receiver = new BroadcastReceiver() { @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case BluetoothDevice.ACTION_FOUND:
// 发现设备,添加到列表,刷新列表
discoverDevices.add((BluetoothDevice) intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
if (adapter != null) {
adapter.notifyDataSetChanged();
}
break;
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
// 开始搜索
Log.i(TAG, "开始搜索设备");
discoverDevices.clear();
// 弹出对话框
if (dlgSearch == null) {
dlgSearch = new AlertDialog.Builder(ClientActivity.this)
.create();
// 自定义对话框
View view = LayoutInflater.from(ClientActivity.this)
.inflate(R.layout.dialog_search, null);
ListView lv_devices = (ListView) view
.findViewById(R.id.lv_devices);
adapter = new DevicesAdapter(ClientActivity.this);
lv_devices.setAdapter(adapter);
lv_devices
.setOnItemClickListener(new OnItemClickListener() { @Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
// 项点击时,进行连接
BluetoothDevice device = (BluetoothDevice) view
.getTag();
bluetoothClient.connect(device);
dlgSearch.dismiss();
dlgSearch = null; }
});
dlgSearch.setView(view);
dlgSearch.setCancelable(true);// 可以按back键取消
dlgSearch.setCanceledOnTouchOutside(false);// 不可以按空白地方取消
}
dlgSearch.show();
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
// 结束搜索
Log.i(TAG, "结束搜索设备");
break; default:
break;
}
} }; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat); bluetoothClient = new BluetoothClient(); et_msg = (EditText) findViewById(R.id.et_msg); ListView lv_msg = (ListView) findViewById(R.id.lv_msg);
msgAdapter = new MyAdapter();
lv_msg.setAdapter(msgAdapter); Timer timer = new Timer();
timer.schedule(task, 0, 1000); // 搜索蓝牙设备
bluetoothClient.start();
} public class MyAdapter extends BaseAdapter { @Override
public int getCount() {
// TODO Auto-generated method stub
return msgs.size();
} @Override
public Object getItem(int position) {
return msgs.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = null;
if (convertView != null) {
tv = (TextView) convertView;
} else {
tv = new TextView(ClientActivity.this);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(params);
}
tv.setTag(msgs.get(position));
tv.setText(msgs.get(position));
return tv;
} } @Override
protected void onResume() {
super.onResume();
registerReceiver();
} private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
} @Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
} /**
* 设备adapter
*
* @author c
*
*/
private class DevicesAdapter extends BaseAdapter { private Context context; public DevicesAdapter(Context context) {
this.context = context;
} @Override
public int getCount() {
return discoverDevices.size();
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return discoverDevices.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(final int position, View convertView,
ViewGroup parent) {
TextView tv = null;
if (convertView != null) {
tv = (TextView) convertView;
} else {
tv = new TextView(context);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(params);
}
tv.setTag(discoverDevices.get(position));
tv.setText(discoverDevices.get(position).getName());
tv.setFocusable(false);
tv.setFocusableInTouchMode(false);
// tv.setOnClickListener(new OnClickListener() {
//
// @Override
// public void onClick(View v) {
// // 项点击时,进行连接
// bluetoothClient.connect(discoverDevices.get(position));
// dlgSearch.dismiss();
// dlgSearch = null;
// }
// });
return tv;
} } /**
* 发送
*
* @param view
*/
public void btn_send(View view) {
String msg = et_msg.getText().toString().trim();
send(msg);
} /**
* 发送消息到客户端
*
* @param msg
*/
private void send(String msg) {
bluetoothClient.send(msg);
synchronized (msgs) {
msgs.add("客户端发送:" + msg);
}
}
}

      3.3.2 客户端页面layout  

    

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:orientation="horizontal" > <EditText
android:id="@+id/et_msg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:hint="chatMessage" /> <Button
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btn_send"
android:text="send" />
</LinearLayout> <ListView
android:id="@+id/lv_msg"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView> </LinearLayout>

      3.3.3 客户端蓝牙管理类

    

 package org.fiu.bluetoothdemos;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log; /**
* 蓝牙服务器
*
* @author weizh
*
*/
public class BluetoothClient {
private static final String TAG = "BluetoothClient";
/**
* 消息集合
*/
private List<String> listMsg = new ArrayList<String>();
/**
* 是否工作中
*/
private boolean isWorking = false;
/**
* spp well-known UUID
*/
public final UUID uuid = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
/**
* 客户端socket
*/
private BluetoothSocket mClientSocket; public BluetoothClient() { } /**
* 开启服务器
*/
public void start() {
startDiscovery();
} /**
* 开始检查设备
*/
private void startDiscovery() {
if (!BluetoothUtils.checkBluetoothExists()) {
throw new RuntimeException("bluetooth module not exists.");
}
// 打开设备
if (!BluetoothUtils.openBluetoothDevice()) {
return;
}
// 开始扫描设备
BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
defaultAdapter.startDiscovery();
} OutputStream outputStream;
private InputStream inputStream; /**
* 停止
*/
public void stop() {
isWorking = false;
if (mClientSocket != null) {
try {
mClientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
mClientSocket = null;
}
}
} /**
* 客户端socket工作类
*
* @author weizh
*
*/
private class ClientWorkingThread extends Thread { public ClientWorkingThread() {
} @SuppressLint("NewApi")
@Override
public void run() {
try {
// 从输入流中取出数据,插入消息条中
byte[] buffer = new byte[1024];
while (isWorking) {
int read = inputStream.read(buffer);
if (read != -1) {
// 有内容
// 判断是否取得的消息填充满了buffer,未到字符串结尾符;如果不是,证明读取到了一条信息,并且信息是完整的,这个完整的前提是不能粘包,不粘包可以使用flush进行处理。
StringBuilder sb = new StringBuilder();
if (read < buffer.length) {
String msg = new String(buffer, 0, read);
sb.append(msg);
} else {
byte[] tempBytes = new byte[1024 * 4];
while (read == buffer.length
&& buffer[read - 1] != 0x7f) {
read = inputStream.read(buffer);
}
String msg = new String(buffer, 0, read);
sb.append(msg);
}
Log.i(TAG, "客户端收到:" + sb.toString());
synchronized (listMsg) {
listMsg.add("服务器发送:" + sb.toString());
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 工作完毕,关闭socket
try {
mClientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
} /**
* 返回listMsg
*
* @return
*/
public List<String> getMsgs() {
synchronized (listMsg) {
return listMsg;
}
} /**
* 发送消息
*
* @param msg
*/
public void send(final String msg) {
new Thread(new Runnable() { @Override
public void run() {
if (mClientSocket != null) {
try {
if (outputStream != null) {
byte[] bytes = msg.getBytes();
outputStream.write(bytes);
outputStream.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start(); } /**
* 进行连接
*
* @param device
*/
@SuppressLint("NewApi")
public void connect(final BluetoothDevice device) {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
try {
mClientSocket = device
.createRfcommSocketToServiceRecord(BluetoothServer.MY_UUID);
mClientSocket.connect();
isWorking = true;
try {
outputStream = mClientSocket.getOutputStream();
inputStream = mClientSocket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
new ClientWorkingThread().start(); } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i(TAG, "连接失败");
}
}
}).start();
} }

      3.4 其它用到的布局和类

        3.4.1 dialog_search

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="horizontal" > <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="正在搜索……" /> <ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true" />
</RelativeLayout> <View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginBottom="2dp"
android:layout_marginTop="2dp"
android:background="@android:color/darker_gray" /> <ListView
android:id="@+id/lv_devices"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp" >
</ListView> </LinearLayout>

3.5 BluetoothUtils.java:蓝牙帮助类

 package org.fiu.bluetoothdemos;

 import java.util.Locale;
import java.util.Set; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; /**
* 蓝牙帮助模块
*
* @author c
*
*/
public class BluetoothUtils {
/**
* 检查蓝牙模块是否存在
*
* @return
*/
public static boolean checkBluetoothExists() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter
.getDefaultAdapter();
if (bluetoothAdapter != null) {
return true;
}
return false;
} /**
* 打开蓝牙模块
*
* @return
*/
public static boolean openBluetoothDevice() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter
.getDefaultAdapter();
if (!bluetoothAdapter.isEnabled()) {
if (bluetoothAdapter.enable()) {
return true;
}
} else {
return true;
}
return false;
} /**
* 开启蓝牙模块扫描
*
* @return
*/
public static void startDiscovery() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter
.getDefaultAdapter();
if (!bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.startDiscovery();
}
} /**
* Convert hex string to byte[] 把为字符串转化为字节数组
*
* @param hexString
* the hex string
* @return byte[]
*/
public static byte[] hexStringToBytes(String hexString) {
hexString = hexString.replaceAll(" ", "");
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase(Locale.getDefault());
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
} /**
* Convert char to byte
*
* @param c
* char
* @return byte
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
} /**
* 获取已配对的蓝牙设备集合
*
* @return
*/
public static Set<BluetoothDevice> getBondedDevices() {
return BluetoothAdapter.getDefaultAdapter().getBondedDevices();
} /**
* 检测当前device是否已经bonded过
*
* @param device
* @return
*/
public static boolean isBonded(BluetoothDevice device) {
if (checkBluetoothExists()) {
// 连接之前先确定是否已经bond过,配对过
Set<BluetoothDevice> bondedDevices = BluetoothAdapter
.getDefaultAdapter().getBondedDevices();
if (bondedDevices != null) {
for (BluetoothDevice bluetoothDevice : bondedDevices) {
if (bluetoothDevice.getAddress()
.equals(device.getAddress())) {
// 该device已经bond过
return true;
}
}
}
}
return false;
}
}

3.6 AndroidManifest.xml:别忘了添加蓝牙权限

    

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fiu.bluetoothchatdemos"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="org.fiu.bluetoothdemos.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.fiu.bluetoothdemos.ServerActivity" />
<activity android:name="org.fiu.bluetoothdemos.ClientActivity" />
</application> </manifest>

    好了,此文章及至这里,如果有问题,欢迎留言。

    整包资源:http://download.csdn.net/detail/weizhhf/9736822

    

Android端简易蓝牙聊天通讯App(原创)的更多相关文章

  1. 【视频】零基础学Android开发:蓝牙聊天室APP(四)

    零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...

  2. 【视频】零基础学Android开发:蓝牙聊天室APP(二)

    零基础学Android开发:蓝牙聊天室APP第二讲 2.1 课程内容应用场景 2.2 Android UI设计 2.3 组件布局:LinearLayout和RelativeLayout 2.4 Tex ...

  3. 【视频】零基础学Android开发:蓝牙聊天室APP(三)

    零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件具体解释 3.2 GridView控件具体解释 3.3 SimpleAdapter适配器具体解 ...

  4. 【视频】零基础学Android开发:蓝牙聊天室APP(一)

    零基础学Android开发:蓝牙聊天室APP第一讲 1. Android介绍与环境搭建:史上最高效Android入门学习 1.1 Google的大小战略 1.2 物联网与云计算 1.3 智能XX设备 ...

  5. Android一对多蓝牙连接示例APP

    一对多蓝牙连接示例,基于Google BluetoothChat修改,实现一对多聊天(一个服务端.多个客户端),类似聊天室. 主要功能: 客户端的发出的消息所有终端都能收到(由服务端转发) 客户端之间 ...

  6. 基于Android Classic Bluetooth的蓝牙聊天软件

    代码地址如下:http://www.demodashi.com/demo/12133.html BluetoothChat 基于Android Classic Bluetooth的蓝牙聊天软件,目前仅 ...

  7. Android蓝牙串口通讯【转】

    本文转载自:http://blog.sina.com.cn/s/blog_631e3f2601012ixi.html Android蓝牙串口通讯 闲着无聊玩起了Android蓝牙模块与单片机蓝牙模块的 ...

  8. 基于Android 平台简易即时通讯的研究与设计[转]

    摘要:论文简单介绍Android 平台的特性,主要阐述了基于Android 平台简易即时通讯(IM)的作用和功能以及实现方法.(复杂的通讯如引入视频音频等可以考虑AnyChat SDK~)关键词:An ...

  9. Android - 传统蓝牙通信聊天

    Android -传统蓝牙通信聊天 技术:java+Android4.4+jdk1.8 运行环境:Android4.4.Android7.0 概述 Android 传统蓝牙的使用,包括开关蓝牙.搜索设 ...

随机推荐

  1. HTTP 错误 500.21 - Internal Server Error 解决方案

    不久前重新安装了Windows7,在安装了VS2010 开发平台之后,将网站发布到IIS,访问发生如下错误: HTTP 错误 500.21 - Internal Server Error处理程序“Ni ...

  2. 简单的 MessageBox

    有时候我们只是想实现一个消息框,给用户一些文字提醒,就像javascript的alert那样.没必要因此动用那些庞大的GUI库,下面是几种轻快的实现方法. 1. ctypes import ctype ...

  3. c#生成二维码

            String link ="www.baidu.com";//这里一般是一个链接 封装后的方法,直接调用就可以了  public void CreateQRCode ...

  4. .net导入excel数据到数据库中

    在开发过程中我们经常面临着需要将数据导出或者导入到系统中,例如一些生产管理系统,项目管理系统等等都会有这样的需求: 将excel数据到系统中思路:获取excel中每一行的数据,然后存入集合中,批量添加 ...

  5. MongoDB数据库未授权访问漏洞及加固

    1.漏洞危害 开启MongoDB服务时不添加任何参数时,默认是没有权限验证的,登录的用户可以通过默认端口无需密码对数据库任意操作(增删改高危动作)而且可以远程访问数据库. 2.漏洞成因 在刚安装完毕的 ...

  6. CentOS6.3 重启后/etc/resolv.conf 被还原解决办法(转)

    今天一台服务器上不了网,设置了nameserver,重启后/etc/resolv.conf文件就被自动还原了,最后发现是被Network Manager修改了.解决方法:停止Network Manag ...

  7. Mybatis批量操作

    首先,mysql需要数据库连接配置&allowMultiQueries=true jdbc:mysql://127.0.0.1:3306/mybank?useUnicode=true& ...

  8. Fabric远程自动化使用说明

    背景: 关于Fabric的介绍,可以看官网说明.简单来说主要功能就是一个基于Python的服务器批量管理库/工具,Fabric 使用 ssh(通过 paramiko 库)在多个服务器上批量执行任务.上 ...

  9. 【webGL】插件的使用的,实现一个鼠标动画的盒子

    准备工作: 1.stat.js stat.js是Three.js的作者Mr. Doob的另一个有用的JavaScript库.很多情况下,我们希望知道实时的FPS信息,从而更好地监测动画效果.这时候,s ...

  10. C#设计模式之原型模式

    原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象. 分析: 孙悟空:根据自己的形状复制(克隆)出多个身外身 软件开发:通过复制一个原型对象得到多个与原型对象一模一样的新对 ...