Bluetooth模块中Socket通信
要实现多个蓝牙设备之间的通信连接,必须实现服务器端与客户端的机制。
1.BluetoothAdapter
本地的蓝牙适配器,是所有蓝牙通信的入口点。使用BluetoothAdapter,搜索其他蓝牙设备,获得一个bonded的设备列 表,使用一个知名的(know)MAC地址实例化一个BluetoothDevice,并创建一个BluetoothServerSocket来监听其他设备的通信
设置蓝牙需要的权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.INTERNET"/>
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);//方法1 startActivityForResult(intent, REQUEST_SEARCH_BLUETOOTH); //mAdapter.enable(); //方法2
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 200); startActivityForResult(intent, REQUEST_DISCOVER_BLUETOOTH);
onAcitivityResult
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { switch (requestCode) { case REQUEST_SEARCH_BLUETOOTH: SingleToast.show(this, "enable ok, scan mode:" + mAdapter.getScanMode()); break; } mStartBtn.setEnabled(true); } else if (requestCode == REQUEST_DISCOVER_BLUETOOTH) { SingleToast.show(this, "discover ok, scan mode:" + mAdapter.getScanMode()); mStartBtn.setEnabled(true); } }蓝牙配对
/* * 連接設備,藍牙配對 */ protected void bondDevice() { Log.i(ConstantUtil.TAG, "客戶端準備連接->Trying to connect..."); if (mDevice.getBondState() == BluetoothDevice.BOND_NONE) { mDevice.createBond(); } }
蓝牙连接
1.客户端连接
public class ConnectThread extends Thread implements MessageSender{ private BluetoothSocket mClient; private BluetoothDevice mDevice; private BluetoothAdapter mAdapter; private InputStream mInStream; private Handler mHandler; private String message; public ConnectThread(BluetoothDevice device, Handler handler) { mDevice = device; mHandler = handler; try { //初始化一個連接到BluetoothDevice對象的BluetoothSocket對象。 mClient = device.createRfcommSocketToServiceRecord(UUID.fromString(ConstantUtil.UUID)); } catch (IOException e) { e.printStackTrace(); } } public ConnectThread(BluetoothActivity activity, BluetoothDevice device, String msg) { this(device, activity.getHandler()); message = msg; } public BluetoothSocket getBluetoothSocket() { return mClient; } public Handler getHandler() { return mHandler; } public BluetoothDevice getDevice() { return mDevice; } @Override public void run() { super.run(); if (mAdapter == null) { mAdapter = BluetoothAdapter.getDefaultAdapter(); } mAdapter.cancelDiscovery(); connectDevice(); while (isEstablish()) { try { handlerSocketReceived(mClient); } catch (IOException e) { e.printStackTrace(); break; } } } public boolean isEstablish() { return (mClient != null) && mClient.isConnected(); } private void printLog(String message) { ConstantUtil.printLog(mHandler, message); } public void cancel() { try { mClient.close(); mInStream.close(); } catch (IOException e) { e.printStackTrace(); } } private boolean connectDevice() { try { if (!mClient.isConnected()) { mClient.connect(); } } catch (IOException e) { printLog("客戶端失敗FAILED..."); Log.i(ConstantUtil.TAG, "客戶端失敗FAILED..." + e.toString()); try { mClient = createRfcommSocket(); mClient.connect(); return true; } catch (Exception ex) { printLog("客戶端仍然失敗FAILED..."); Log.i(ConstantUtil.TAG, "客戶端仍然失敗FAILED..." + e.toString()); try { if (!mClient.isConnected()) { mClient.close(); } return false; } catch (IOException io) { io.printStackTrace(); } } } return send(message, false); } private BluetoothSocket createRfcommSocket() throws Exception { BluetoothSocket socket; socket = (BluetoothSocket) mDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(mDevice, ConstantUtil.PORT); return socket; } /** * 初始化傳輸數據的縣城。 * @param msg send message * @return true if success,else false; * @throws IOException */ private boolean handlerSocketSend(String msg, boolean isReport) throws IOException { if (!mClient.isConnected()) { printLog("客戶端未連接,返回"); return false; } if (msg.isEmpty()) { msg = "This is client, the message is test from " + mAdapter.getName() + "."; } new ConnectedThread(this, msg, isReport).start(); if (!isReport) { mHandler.obtainMessage(ConstantUtil.REPLY_CONNECT_SERVER).sendToTarget(); } return true; } @Override public boolean send(String msg, boolean isReport) { try { return handlerSocketSend(msg, isReport); } catch (IOException e) { e.printStackTrace(); } return false; } private void handlerSocketReceived(BluetoothSocket socket) throws IOException { Log.i(ConstantUtil.TAG, "客戶端连接成功"); mInStream = socket.getInputStream(); byte[] buffer = new byte[1024]; if (mInStream == null) { printLog("服务器连接成功 stream null"); return; } int num = mInStream.read(buffer);//this will block until client data; String message = new String(buffer, "UTF-8"); printLog("服务器[名称]:" + socket.getRemoteDevice().getName() + ",[地址]" + socket.getRemoteDevice().getAddress()); printLog("服务器[" + num + "]:" + new String(buffer, "UTF-8") + "\n"); Log.i(ConstantUtil.TAG, "服务器连接接成功 :" + num + message); if (!message.contains(ConstantUtil.RECEIVED)) { handlerSocketSend(ConstantUtil.RECEIVED, true); } } }
2.服务端连接
public class AcceptThread extends Thread implements MessageSender { private BluetoothActivity mActivity; private BluetoothServerSocket mServerSocket; private BluetoothAdapter mAdapter; private InputStream mInStream; private OutputStream mOutputSream; private BluetoothSocket mSocket = null; private Handler mHandler; public AcceptThread(BluetoothActivity activity) { this(); mActivity = activity; mHandler = activity.getHandler(); } public AcceptThread() { mAdapter = BluetoothAdapter.getDefaultAdapter(); BluetoothServerSocket temp; try { // createRfcommSocket temp = mAdapter.listenUsingRfcommWithServiceRecord("zxz", UUID.fromString(ConstantUtil.UUID)); mServerSocket = temp; } catch (Exception e) { e.printStackTrace(); } } public BluetoothSocket getBluetoothSocket() { return mSocket; } public Handler getHandler() { return mHandler; } public boolean isEstablish() { return (mSocket != null) && mSocket.isConnected(); } @Override public void run() { super.run(); printLog("服务器启动..."); Log.i(ConstantUtil.TAG, "服务器启动..."); while (true) { try { // This is a blocking call and will only return on a // successful connection or an exception if (mSocket == null) { if (mServerSocket == null) continue; mSocket = mServerSocket.accept(); //Once the BluetoothSocket is acquired, to call mServerSocket.close() mServerSocket.close(); mActivity.startServer(); } } catch (IOException e) { printLog("服务器启动: " + mSocket + ":" + e.getMessage()); Log.i(ConstantUtil.TAG, "服务器启动: " + mSocket + ":" + e.getMessage()); try { mServerSocket = listenUsingRfcomm(); } catch (Exception ex) { e.printStackTrace(); break; } } if (isEstablish()) { try { handlerSocketConnect(mSocket); } catch (IOException e) { e.printStackTrace(); break; } } } } private void printLog(String message) { ConstantUtil.printLog(mHandler, message); } public void cancel() { try { if (mSocket != null) { mSocket.close(); mSocket = null; } if (mInStream != null) { mInStream.close(); mInStream = null; } if (mOutputSream != null) { mOutputSream.close(); mOutputSream = null; } } catch (IOException e) { e.printStackTrace(); } } @Override public boolean send(String msg, boolean isReport) { if (!isEstablish()) { printLog("客戶端未連接,返回"); return false; } if (msg.isEmpty()) { msg = "This is server, the message is test from " + mAdapter.getName() + "."; } new ConnectedThread(this, msg, isReport).start(); return true; } /** * 初始化傳輸數據的線程。 * */ private void handlerSocketConnect(BluetoothSocket socket) throws IOException { Log.i(ConstantUtil.TAG, "服务器连接成功"); mInStream = socket.getInputStream(); mOutputSream = socket.getOutputStream(); byte[] buffer = new byte[1024]; if (mInStream == null) { printLog("服务器连接成功 stream null"); return; } mHandler.obtainMessage(ConstantUtil.REPLY_CONNECT_SERVER).sendToTarget(); int num = mInStream.read(buffer);//this will block until client data; String message = new String(buffer, "UTF-8"); printLog("客戶端[名称]:" + socket.getRemoteDevice().getName() + ",[地址]" + socket.getRemoteDevice().getAddress()); printLog("客戶端[" + num + "]:" + message + "\n"); Log.i(ConstantUtil.TAG, "服务器连接接成功 :" + num + message); if (!message.contains(ConstantUtil.RECEIVED)) { send(ConstantUtil.RECEIVED, true); } } private BluetoothServerSocket listenUsingRfcomm() throws Exception { Method method = mAdapter.getClass().getMethod("listenUsingRfcommOn", int.class); BluetoothServerSocket serverSocket = (BluetoothServerSocket) method.invoke(mAdapter, ConstantUtil.PORT); if (serverSocket == null) { throw new IllegalStateException("BluetoothServerSocket return null"); } return serverSocket; } }
3. 发送数据线程
public class ConnectedThread extends Thread { private final BluetoothSocket mSocket; private BluetoothAdapter mAdapter; private OutputStream mOutputStream; private Handler mHandler; private String message; private boolean isClient; private boolean mIsReport; public ConnectedThread(ConnectThread conn, String msg, boolean isReport) { mSocket = conn.getBluetoothSocket(); mHandler = conn.getHandler(); message = msg; isClient = true; mIsReport = isReport; if (mAdapter == null) { mAdapter = BluetoothAdapter.getDefaultAdapter(); } try { mOutputStream = mSocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } public ConnectedThread(AcceptThread conn, String msg, boolean isReport) { mSocket = conn.getBluetoothSocket(); mHandler = conn.getHandler(); message = msg; isClient = false; mIsReport = isReport; if (mAdapter == null) { mAdapter = BluetoothAdapter.getDefaultAdapter(); } try { mOutputStream = mSocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { super.run(); try { handlerSocketConnect(message); } catch (IOException e) { e.printStackTrace(); cancel(); } } private void sendReport() throws IOException { write("Received."); } private boolean handlerSocketConnect(String msg) throws IOException { if (!mSocket.isConnected()) { printLog("未連接成功..."); return false; } if (mIsReport) { sendReport(); return true; } printLog((isClient ? "客戶端":"服务端") + "连接成功,发送:" + msg); if (msg.isEmpty()) { msg = "This is test message, the message is test from " + mAdapter.getName() + "."; } mOutputStream = mSocket.getOutputStream(); write(msg); return true; } public void write(String msg) throws IOException { mOutputStream.write(msg.getBytes()); mOutputStream.flush(); } public void cancel() { try { mSocket.close(); mOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } private void printLog(String message) { ConstantUtil.printLog(mHandler, message); } }
4. Acitivity
package com.example.zxz.asdemo.ui; import android.app.Activity; import android.app.ProgressDialog; 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.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import com.example.zxz.asdemo.R; import com.example.zxz.asdemo.data.AcceptThread; import com.example.zxz.asdemo.data.BluetoothDevicesAdapter; import com.example.zxz.asdemo.data.ConnectThread; import com.example.zxz.asdemo.util.ConstantUtil; import com.example.zxz.asdemo.util.SingleToast; import java.util.ArrayList; import java.util.List; /** * Created by zxz on 15-11-15. * Once the device is set up as server, it will act as server among devices. */ public class BluetoothActivity extends ActionBarActivity implements View.OnClickListener, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { private EditText mLogcat, mSendText; private Button mSendBtn; private BluetoothDevicesAdapter mDevicesAdapter; private final int REQUEST_SEARCH_BLUETOOTH = 1001; private final int REQUEST_DISCOVER_BLUETOOTH = 1002; private BluetoothAdapter mAdapter; private ProgressDialog mDialog; private List<AcceptThread> server = new ArrayList<>(); private List<ConnectThread> client = new ArrayList<>(); private boolean isAsServer; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); BluetoothDevice device; if (ConstantUtil.DEBUG) { SingleToast.show(BluetoothActivity.this, "onReceive " + action); } if (BluetoothDevice.ACTION_FOUND.equals(action) || BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { device = intent.getParcelableExtra( BluetoothDevice.EXTRA_DEVICE); if (device != null) { mDevicesAdapter.addDevice(device); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { if (mDialog.isShowing() && !mDevicesAdapter.isEmpty()) { SingleToast.show(BluetoothActivity.this, "Devices " + mDevicesAdapter. getCount() + " finished"); mDialog.dismiss(); } mDevicesAdapter.notifyDataSetChanged(); } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (device.getBondState()) { case BluetoothDevice.BOND_NONE: SingleToast.show(BluetoothActivity.this, "取消配對"); break; case BluetoothDevice.BOND_BONDED: SingleToast.show(BluetoothActivity.this, "完成配對"); mDevicesAdapter.notifyDataSetChanged(); mDialog.dismiss(); break; case BluetoothDevice.BOND_BONDING: mDialog.setTitle("藍牙配對"); mDialog.setMessage("正在配對"); mDialog.show(); break; } } else if (ConstantUtil.DEBUG) { SingleToast.setText(BluetoothActivity.this, "onReceive:" + action); } } }; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (mAdapter.isEnabled()) { menu.findItem(R.id.action_start).setTitle( getResources().getString(R.string.stop_bluetooth)); } menu.findItem(R.id.action_asserver).setEnabled(mAdapter.isEnabled()); menu.findItem(R.id.action_search).setEnabled(mAdapter.isEnabled()); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_start: if (!mAdapter.isEnabled()) { mAdapter.enable(); item.setTitle(getResources().getString(R.string.stop_bluetooth)); } else { mAdapter.disable(); mDevicesAdapter.removeAllDevice(); item.setTitle(getResources().getString(R.string.start_bluetooth)); } break; case R.id.action_discover: Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 200); startActivityForResult(intent, REQUEST_DISCOVER_BLUETOOTH); break; case R.id.action_search: mAdapter.cancelDiscovery(); mAdapter.startDiscovery(); mDialog.setTitle("藍牙設備"); mDialog.setMessage("搜索中..."); mDialog.show(); break; case R.id.action_asserver: if (!isAsServer) { if (getActionBar() != null) { getActionBar().setTitle(getResources().getString(R.string.server_BT) + ":" + mAdapter.getName()); } startServer(); item.setTitle(getResources().getString(R.string.close_server_bluetooth)); } else { closeServer(); item.setTitle(getResources().getString(R.string.server_bluetooth)); } break; case R.id.action_clear: mLogcat.setText(""); default: break; } return super.onOptionsItemSelected(item); } public Handler getHandler() { return mHandler; } private Handler mHandler = new Handler(Looper.myLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case ConstantUtil.MSG_UPDATE_MESSAGE: mLogcat.append(msg.getData().getCharSequence("data") + "\n"); break; case ConstantUtil.REPLY_CONNECT_SERVER: mSendBtn.setText(getResources().getString(R.string.send)); break; } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.setPriority(Integer.MAX_VALUE); registerReceiver(mReceiver, filter); ListView mListView = (ListView) findViewById(R.id.device_list); mLogcat = (EditText) findViewById(R.id.logcat); mSendText = (EditText) findViewById(R.id.send_message); mSendBtn = (Button) findViewById(R.id.send_bluetooth); mSendBtn.setOnClickListener(this); mDevicesAdapter = new BluetoothDevicesAdapter(this); mListView.setAdapter(mDevicesAdapter); mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(this); mDialog = new ProgressDialog(this); initDevice(); } private void initDevice() { mAdapter = BluetoothAdapter.getDefaultAdapter(); if (getActionBar() != null) { getActionBar().setTitle(mAdapter.getName()); } } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); mAdapter.cancelDiscovery(); unregisterReceiver(mReceiver); cancel(); } private void cancel() { if (server != null) { for (AcceptThread accept: server) { accept.cancel(); } } if (client != null) { for (ConnectThread connect: client) { connect.cancel(); } } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.send_bluetooth: if (mAdapter.isEnabled()) { if (isAsServer) {//TODO Log.i(ConstantUtil.TAG, "send as server reply."); for (AcceptThread accept : server) { accept.send(mSendText.getText().toString(), false); } mSendText.setText(""); } else { if (mDevicesAdapter.getBondDevices() == null || mDevicesAdapter.getBondDevices().size() == 0) { SingleToast.show(BluetoothActivity.this, "compare device first!"); return; } for (BluetoothDevice device: mDevicesAdapter.getBondDevices()) { if (checkClientExist(device)) { Log.i(ConstantUtil.TAG, "send as exist client."); for (ConnectThread conn : client) { conn.send(mSendText.getText().toString(), false); } } else { SingleToast.show(BluetoothActivity.this, "给" + mDevicesAdapter.getBondDevices().size() + "台设备发送"); sendMessageFromClient(mDevicesAdapter.getBondDevices(), mSendText.getText().toString()); } } mSendText.setText(""); } } else { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, REQUEST_SEARCH_BLUETOOTH); } break; default: break; } } @Override public void onItemClick(AdapterView<?> parent, View view, int pos, long id) { mAdapter.cancelDiscovery(); SingleToast.show(this, "Device: " + ((BluetoothDevice) mDevicesAdapter.getItem( pos)).getName() + "連接"); if (((BluetoothDevice) mDevicesAdapter.getItem(pos)).getBondState() != BluetoothDevice.BOND_BONDED) { bondDevice((BluetoothDevice) mDevicesAdapter.getItem(pos)); } } /** * Server */ public void startServer() { isAsServer = true; AcceptThread thread = new AcceptThread(this); server.add(thread); new Thread(thread).start(); } private void closeServer() { isAsServer = false; if (getActionBar() != null) { getActionBar().setTitle(mAdapter.getName()); } mLogcat.append(getResources().getString(R.string.close_server_bluetooth) + "\n"); for (AcceptThread accept:server) { if (accept != null) accept.cancel(); } server.clear(); } /** * * @param device device * @param message msg */ private void startClient(BluetoothDevice device, String message) { if (device != null) { ConnectThread conn = new ConnectThread(this, device, message); client.add(conn); new Thread(conn).start(); } } private boolean checkClientExist(BluetoothDevice device) { for (ConnectThread conn: client) { if (conn.getDevice() == device) { return true; } } return false; } public void sendMessageFromClient(List<BluetoothDevice> mDeviceList, String message) { if (mDeviceList != null) { for (BluetoothDevice device : mDeviceList) { startClient(device, message); } } } /* * 連接設備,藍牙配對 */ protected void bondDevice(BluetoothDevice device) { if (device.getBondState() == BluetoothDevice.BOND_NONE) { device.createBond(); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int pos, long id) { mAdapter.cancelDiscovery(); SingleToast.show(this, "Device: " + ((BluetoothDevice) mDevicesAdapter.getItem(pos)). getName() + ":" + getBondState((BluetoothDevice) mDevicesAdapter.getItem(pos))); if (((BluetoothDevice) mDevicesAdapter.getItem(pos)).getBondState() == BluetoothDevice.BOND_BONDED) { for (ParcelUuid uuid:((BluetoothDevice) mDevicesAdapter.getItem(pos)). getUuids()){ SingleToast.show(this,uuid.toString()); } } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { switch (requestCode) { case REQUEST_SEARCH_BLUETOOTH: SingleToast.show(this, "enable ok, scan mode:" + mAdapter.getScanMode()); break; } } else if (requestCode == REQUEST_DISCOVER_BLUETOOTH) { SingleToast.show(this, "discover ok, scan mode:" + mAdapter.getScanMode()); } } @Override public void onBackPressed() { super.onBackPressed(); mDialog.dismiss(); SingleToast.cancelShow(); mAdapter.cancelDiscovery(); } private String getBondState(BluetoothDevice device) { String state = ""; switch (device.getBondState()) { case BluetoothDevice.BOND_BONDED: state = getResources().getString(R.string.state_on); break; case BluetoothDevice.BOND_NONE: state = getResources().getString(R.string.state_off); break; default: break; } return state; } }
package com.example.zxz.asdemo.data; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; import com.example.zxz.asdemo.R; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Created by zxz on 15-11-16. * Adapter in the list */ public class BluetoothDevicesAdapter extends BaseAdapter { private LayoutInflater mInflater; private List<BluetoothDevice> mDevices, mBondDevices; private Context mContext; public List<BluetoothDevice> getBondDevices() { return mBondDevices; } public BluetoothDevicesAdapter(Context context) { this(context, new ArrayList<BluetoothDevice>()); } public BluetoothDevicesAdapter(Context context, List<BluetoothDevice> devices) { mInflater = LayoutInflater.from(context); mDevices = devices; mContext = context; } /** * 不重複添加 * @param device bonded device */ public void addDevice(BluetoothDevice device) { if (mDevices == null) mDevices = new ArrayList<>(); if (mBondDevices == null) mBondDevices = new ArrayList<>(); if (!mDevices.contains(device)) { mDevices.add(device); if (device.getBondState() == BluetoothDevice.BOND_BONDED && !mBondDevices.contains(device)) { mBondDevices.add(device); } } // else { // mDevices.remove(device); // mDevices.add(device); // } notifyDataSetChanged(); } public void removeAllDevice() { if (mDevices == null) return; Iterator<BluetoothDevice> iterator = mDevices.iterator(); mBondDevices = null; while (iterator.hasNext()) { iterator.next(); iterator.remove(); } notifyDataSetChanged(); } @Override public Object getItem(int position) { return mDevices.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_item, parent, false); holder.image = (ImageView) convertView.findViewById(R.id.image); holder.title = (TextView) convertView.findViewById(R.id.title); holder.description = (TextView) convertView.findViewById(R.id.description); holder.checkbox = (CheckBox) convertView.findViewById(R.id.checkbox); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked && (!mBondDevices.contains(mDevices.get(position)))){ mBondDevices.add(mDevices.get(position)); } else if (!isChecked && (mBondDevices.contains(mDevices.get(position)))) { mBondDevices.remove(mDevices.get(position)); } } }); if (mBondDevices.contains(mDevices.get(position))) { holder.checkbox.setChecked(true); } else { holder.checkbox.setChecked(false); } if (mDevices.get(position).getBondState() == BluetoothDevice.BOND_BONDED) { holder.image.setBackground(mContext.getDrawable( R.drawable.ic_settings_bluetooth_alpha)); } else { holder.image.setBackground(mContext.getDrawable( android.R.drawable.stat_sys_data_bluetooth)); } holder.title.setText(mDevices.get(position).getName()); holder.description.setText(mDevices.get(position).getAddress()); return convertView; } @Override public int getCount() { return mDevices.size(); } private class ViewHolder { private TextView title, description; private ImageView image; private CheckBox checkbox; } }
写得烂,不过可以实现一个客户端和多个server通信。未完待续