模块构成及依赖关系
在软件设计之初,为了降低各功能之间的耦合,提高软件的复用性,提出了分层的概念:
demo分为3层,分别是UI层、业务逻辑层、网络层(蓝牙传输),每层包含的类如下所示:
其中UI层包含MainActivity、DeviceAdapter类;
业务逻辑层包含ChatControl、BlueToothControl类;
网络层包含ConnectedThread、AcceptThread、ConnectThread类。
各个类的依赖关系如下所示:
由图可知,模块之间是自顶至下的顺序依赖关系,这样做的好处是,当有某一个功能所对应的模块需要改变时,只需修改其内部逻辑即可,而向上提供的接口无需改变,这样也就无需修改上层的结构。
layout布局
首先是layout布局,初始时,默认显示聊天面板,隐藏蓝牙列表:
<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=".MainActivity"> <ListView android:id="@+id/device_list" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"></ListView> <RelativeLayout android:id="@+id/chat_panel" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible"> <Button android:id="@+id/bt_send" android:layout_width="100dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:text="@string/send" /> <EditText android:id="@+id/chat_edit" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_toLeftOf="@+id/bt_send" /> <TextView android:id="@+id/chat_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/bt_send" /> </RelativeLayout></RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
UI层
UI层主要负责初始化并更新用户界面、设置广播接收器、展示蓝牙搜索列表、通知用户蓝牙状态等。下面是MainActivity的代码:
public class MainActivity extends Activity { public static final int REQUEST_CODE = 0; private List<BluetoothDevice> mDeviceList = new ArrayList<>(); private List<BluetoothDevice> mBondedDeviceList = new ArrayList<>(); private BlueToothController mController = new BlueToothController(); private ListView mListView; private DeviceAdapter mAdapter; private Toast mToast; private View mChatPanel; private Button mSendBt; private EditText mInputBox; private TextView mChatContent; private StringBuilder mChatText = new StringBuilder(); private Handler mUIHandler = new MyHandler(); private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { setProgressBarIndeterminateVisibility(true); mDeviceList.clear(); mAdapter.notifyDataSetChanged(); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); } else if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mDeviceList.add(device); mAdapter.notifyDataSetChanged(); } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { int scanMode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, 0); if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { setProgressBarIndeterminateVisibility(true); } else { setProgressBarIndeterminateVisibility(false); } } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (remoteDevice == null) { showToast("no device"); return; } int status = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0); if (status == BluetoothDevice.BOND_BONDED) { showToast("Bonded " + remoteDevice.getName()); } else if (status == BluetoothDevice.BOND_BONDING) { showToast("Bonding " + remoteDevice.getName()); } else if (status == BluetoothDevice.BOND_NONE) { showToast("Not bond " + remoteDevice.getName()); } } } }; private AdapterView.OnItemClickListener bindDeviceClick = new AdapterView.OnItemClickListener() { @TargetApi(Build.VERSION_CODES.KITKAT) @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { BluetoothDevice device = mDeviceList.get(i); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { device.createBond(); } } }; private AdapterView.OnItemClickListener bindedDeviceClick = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { BluetoothDevice device = mBondedDeviceList.get(i); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initActionBar(); setContentView(R.layout.activity_main); initUI(); registerBluetoothReceiver(); mController.turnOnBlueTooth(this, REQUEST_CODE); } private void registerBluetoothReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); registerReceiver(mReceiver, filter); } private void initUI() { mListView = (ListView) findViewById(R.id.device_list); mAdapter = new DeviceAdapter(mDeviceList, this); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(bindDeviceClick); mChatPanel = findViewById(R.id.chat_panel); mSendBt = (Button) findViewById(R.id.bt_send); mSendBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String ext = mInputBox.getText().toString(); ChatController.getInstance().sendMessage(ext); mChatText.append(ext).append("\n"); mChatContent.setText(mChatText.toString()); mInputBox.setText(""); } }); mInputBox = (EditText) findViewById(R.id.chat_edit); mChatContent = (TextView) findViewById(R.id.chat_content); } @Override protected void onDestroy() { super.onDestroy(); ChatController.getInstance().stopChat(); unregisterReceiver(mReceiver); } public void enterChatMode() { mListView.setVisibility(View.GONE); mChatPanel.setVisibility(View.VISIBLE); } public void exitChatMode() { mListView.setVisibility(View.VISIBLE); mChatPanel.setVisibility(View.GONE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { if (resultCode != RESULT_OK) { finish(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } private void showToast(String text) { if (mToast == null) { mToast = Toast.makeText(this, text, Toast.LENGTH_LONG); } else { mToast.setText(text); } mToast.show(); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.enable_visiblity) { mController.enableVisibly(this); } else if (id == R.id.find_device) { mAdapter.refresh(mDeviceList); mController.findDevice(); mListView.setOnItemClickListener(bindDeviceClick); } else if (id == R.id.bonded_device) { mBondedDeviceList = mController.getBondedDeviceList(); mAdapter.refresh(mBondedDeviceList); mListView.setOnItemClickListener(bindedDeviceClick); } else if (id == R.id.listening) { ChatController.getInstance().waitingForFriends(mController.getAdapter(), mUIHandler); } else if (id == R.id.stop_listening) { ChatController.getInstance().stopChat(); exitChatMode(); } else if (id == R.id.disconnect) { exitChatMode(); } return super.onOptionsItemSelected(item); } private void initActionBar() { requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); getActionBar().setDisplayUseLogoEnabled(false); setProgressBarIndeterminate(true); try { ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class .getDeclaredField("sHasPermanentMenuKey"); if (menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); } } catch (Exception e) { e.printStackTrace(); } } private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case Constant.MSG_START_LISTENING: setProgressBarIndeterminateVisibility(true); break; case Constant.MSG_FINISH_LISTENING: setProgressBarIndeterminateVisibility(false); exitChatMode(); break; case Constant.MSG_GOT_DATA: byte[] data = (byte[]) msg.obj; mChatText.append(ChatController.getInstance().decodeMessage(data)).append("\n"); mChatContent.setText(mChatText.toString()); break; case Constant.MSG_ERROR: exitChatMode(); showToast("error: " + String.valueOf(msg.obj)); break; case Constant.MSG_CONNECTED_TO_SERVER: enterChatMode(); showToast("Connected to Server"); break; case Constant.MSG_GOT_A_CLINET: enterChatMode(); showToast("Got a Client"); break; } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
以下是自定义的蓝牙列表项布局及内容
public class DeviceAdapter extends BaseAdapter { private List<BluetoothDevice> mData; private Context mContext; public DeviceAdapter(List<BluetoothDevice> data, Context context) { mData = data; mContext = context.getApplicationContext(); } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int i) { return mData.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View view, ViewGroup viewGroup) { View itemView = view; if( itemView == null) { itemView = LayoutInflater.from(mContext).inflate(android.R.layout.simple_list_item_2,viewGroup,false); } TextView line1 = (TextView) itemView.findViewById(android.R.id.text1); TextView line2 = (TextView) itemView.findViewById(android.R.id.text2); BluetoothDevice device = (BluetoothDevice) getItem(i); line1.setText(device.getName()); line2.setText(device.getAddress()); return itemView; } public void refresh(List<BluetoothDevice> data) { mData = data; notifyDataSetChanged(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
业务逻辑层
业务逻辑层主要负责蓝牙功能的处理(如打开或关闭蓝牙、设置蓝牙设备的可见性、搜索蓝牙设备等)和聊天逻辑处理:
public class BlueToothController { private BluetoothAdapter mAapter; public BlueToothController() { mAapter = BluetoothAdapter.getDefaultAdapter(); } public BluetoothAdapter getAdapter() { return mAapter; } /** * 打开蓝牙 * @param activity * @param requestCode */ public void turnOnBlueTooth(Activity activity, int requestCode) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); activity.startActivityForResult(intent, requestCode); } /** * 打开蓝牙可见性,系统会发出广播 * @param context */ public void enableVisibly(Context context) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); context.startActivity(discoverableIntent); } /** * 查找设备,系统会发出广播 */ public void findDevice() { assert (mAapter != null); mAapter.startDiscovery(); } /** * 获取绑定设备 * @return */ public List<BluetoothDevice> getBondedDeviceList() { return new ArrayList<>(mAapter.getBondedDevices()); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
public class ChatController { private ConnectThread mConnectThread; private AcceptThread mAcceptThread; /** * 网络协议的处理函数 */ private class ChatProtocol implements ProtocolHandler<String> { private static final String CHARSET_NAME = "utf-8"; @Override public byte[] encodePackage(String data) { if( data == null) { return new byte[0]; } else { try { return data.getBytes(CHARSET_NAME); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return new byte[0]; } } } @Override public String decodePackage(byte[] netData) { if( netData == null) { return ""; } try { return new String(netData, CHARSET_NAME); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return ""; } } } /** * 协议处理 */ private ChatProtocol mProtocol = new ChatProtocol(); /** * 与服务器连接进行聊天 * @param device * @param adapter * @param handler */ public void startChatWith(BluetoothDevice device, BluetoothAdapter adapter, Handler handler) { mConnectThread = new ConnectThread(device,adapter,handler); mConnectThread.start(); } /** * 等待客户端来连接 * @param adapter * @param handler */ public void waitingForFriends(BluetoothAdapter adapter, Handler handler) { mAcceptThread = new AcceptThread(adapter,handler); mAcceptThread.start(); } /** * 发出消息 * @param msg */ public void sendMessage(String msg) { byte[] data = mProtocol.encodePackage(msg); if(mConnectThread != null) { mConnectThread.sendData(data); } else if( mAcceptThread != null) { mAcceptThread.sendData(data); } } /** * 网络数据解码 * @param data * @return */ public String decodeMessage(byte[] data) { return mProtocol.decodePackage(data); } /** * 停止聊天 */ public void stopChat() { if(mConnectThread != null) { mConnectThread.cancel(); } else if( mAcceptThread != null) { mAcceptThread.cancel(); } } /** * 单例方式构造类对象 */ private static class ChatControlHolder { private static ChatController mInstance = new ChatController(); } public static ChatController getInstance() { return ChatControlHolder.mInstance; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
网络层
网络层主要负责消息的传递。
public class AcceptThread extends Thread { private static final String NAME = "BlueToothClass"; private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID); private final BluetoothServerSocket mmServerSocket; private final BluetoothAdapter mBluetoothAdapter; private final Handler mHandler; private ConnectedThread mConnectedThread; public AcceptThread(BluetoothAdapter adapter, Handler handler) { mBluetoothAdapter = adapter; mHandler = handler; BluetoothServerSocket tmp = null; try { tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; while (true) { try { mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING); socket = mmServerSocket.accept(); } catch (IOException e) { mHandler.sendMessage(mHandler.obtainMessage(Constant.MSG_ERROR, e)); break; } if (socket != null) { manageConnectedSocket(socket); try { mmServerSocket.close(); mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING); } catch (IOException e) { e.printStackTrace(); } break; } } } private void manageConnectedSocket(BluetoothSocket socket) { if( mConnectedThread != null) { mConnectedThread.cancel(); } mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET); mConnectedThread = new ConnectedThread(socket, mHandler); mConnectedThread.start(); } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { mmServerSocket.close(); mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING); } catch (IOException e) { } } public void sendData(byte[] data) { if( mConnectedThread!=null){ mConnectedThread.write(data); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
public class ConnectThread extends Thread { private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID); private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private BluetoothAdapter mBluetoothAdapter; private final Handler mHandler; private ConnectedThread mConnectedThread; public ConnectThread(BluetoothDevice device, BluetoothAdapter adapter, Handler handler) { BluetoothSocket tmp = null; mmDevice = device; mBluetoothAdapter = adapter; mHandler = handler; try { tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void run() { mBluetoothAdapter.cancelDiscovery(); try { mmSocket.connect(); } catch (Exception connectException) { mHandler.sendMessage(mHandler.obtainMessage(Constant.MSG_ERROR, connectException)); try { mmSocket.close(); } catch (IOException closeException) { } return; } manageConnectedSocket(mmSocket); } private void manageConnectedSocket(BluetoothSocket mmSocket) { mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER); mConnectedThread = new ConnectedThread(mmSocket, mHandler); mConnectedThread.start(); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } public void sendData(byte[] data) { if( mConnectedThread!=null){ mConnectedThread.write(data); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
public class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; private final Handler mHandler; public ConnectedThread(BluetoothSocket socket, Handler handler) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; mHandler = handler; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mmInStream.read(buffer); if( bytes >0) { Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA, buffer); mHandler.sendMessage(message); } Log.d("GOTMSG", "message size" + bytes); } catch (IOException e) { mHandler.sendMessage(mHandler.obtainMessage(Constant.MSG_ERROR, e)); break; } } } public void write(byte[] bytes) { try { mmOutStream.write(bytes); } catch (IOException e) { } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
存储常量的类:
public class Constant { public static final String CONNECTTION_UUID = "00001101-0000-1000-8000-00805F9B34FB"; /** * 开始监听 */ public static final int MSG_START_LISTENING = 1; /** * 结束监听 */ public static final int MSG_FINISH_LISTENING = 2; /** * 有客户端连接 */ public static final int MSG_GOT_A_CLINET = 3; /** * 连接到服务器 */ public static final int MSG_CONNECTED_TO_SERVER = 4; /** * 获取到数据 */ public static final int MSG_GOT_DATA = 5; /** * 出错 */ public static final int MSG_ERROR = -1;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
** * 处理网络协议,对数据进行封包或解包 * */public interface ProtocolHandler<T> { public byte[] encodePackage(T data); public T decodePackage(byte[] netData);}
1 0