23 กรกฎาคม 2556

[Android Code] การใช้งาน Bluetooth เพื่อรับส่งข้อมูล [บลูทูธกับไมโครคอนโทรลเลอร์ได้]


        บทความนี้เลิกใช้งานแล้วเพราะว่าเจ้าของบล็อกได้เขียนใหม่เป็นไลบรารีที่สามารถใช้งานได้ง่ายและสะดวกกว่า โดยสามารถอ่านได้ที่ [Android Code] การเชื่อมต่ออุปกรณ์ผ่านบลูทูธแบบง่ายๆโดยใช้ BluetoothSPP

********************************************************

บทความเรื่องบลูทูธ เจ้าของบล็อกเคยเขียนไปแล้วก็จริง
แต่ตอนนั้นเป็นบทความแรกที่เริ่มเขียน ซึ่งเจ้าของบล็อกรู้สึกว่า
ยังไม่โอเคพอ เพราะอิงเนื้อหาจาก Android Developer เป็นหลัก
ก็เลยนำมาปรับเปลี่ยนใหม่แล้วทำเป็นบทความใหม่ไปเลย


สำหรับเรื่องบลูทูธในบทความนี้เจ้าของบล็อกจะเน้นไปที่
การใช้งานกับอุปกรณ์จำพวกไมโครคอนโทรลเลอร์ซะมากกว่า
เพราะระหว่างอุปกรณ์แอนดรอยด์สองเครื่องมีความจำเป็นน้อยมาก
ส่วนมากจะนำไปใช้งานกับไมโครคอนโทรลเลอร์กันซะส่วนใหญ่
ตัวอย่างนี้จึงเหมาะกับนำไปใช้สื่อสารกับไมโครคอนโทรลเลอร์

บลูทูธจะประกอบไปด้วยการทำงานหลายแบบที่เรียกว่า Profile
ในตัวอย่างนี้ก็จะเป็นการใช้งาน Profile ของบลูทูธที่เรียกว่า
Serial Port Profile [SPP] เป็นการส่งข้อมูลผ่านบลูทูธแบบอนุกรม
ถ้านำไปใช้กับไมโครคอนโทรลเลอร์ก็สามารถใช้กับโมดูลบลูทูธ
ที่รองรับการรับส่งข้อมูลแบบอนุกรมได้ทันที [Serial Bluetooth]
โดยโมดูลดังกล่าวจะรับข้อมูลอนุกรมผ่านบลูทูธแล้วส่งออกมา
เป็น UART ทันที จึงทำให้ง่ายต่อการใช้งานกับไมโครคอนโทรลเลอร์

ตัวอย่างอุปกรณ์ Serial Bluetooth จาก Innovative Experiment


สำหรับคำสั่งในการใช้งานบลูทูธก็จะมีคลาสที่ทำหน้าที่จัดการ
ในส่วนของเซอร์วิสสำหรับเชื่อมต่อและรับส่งข้อมูลให้เรียบร้อยแล้ว
ที่เหลือที่ผู้ที่หลงเข้ามาอ่านต้องจัดการก็คือการเข้าใช้งานบลูทูธ
อย่างเช่นการเปิดบลูทูธ การแสกนหาอุปกรณ์ เลือกอุปกรณ์ที่เชื่อมต่อ
และการรับ-ส่งข้อมูลผ่านบลูทูธ (แค่เรียกใช้คำสั่งจากคลาสที่มีให้)

เริ่มแรกสุดให้ผู้ที่หลงเข้ามาอ่านขอใช้ Permission ของบลูทูธก่อนเลย
เนื่องจากบลูทูธเป็นการใช้งานอุปกรณ์ภาพนอกแอปพลิเคชัน
โดยประกาศ Permission ที่ AndroidManifest.xml ด้วยคำสั่งดังนี้
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" />

เริ่มจาก Main.java

สำหรับค่าคงที่ที่จะใช้งานก็จะเอาไว้เวลาตรวจสอบสถานะเฉยๆ ดังนี้
public static final int MESSAGE_STATE_CHANGE = 1; public static final int MESSAGE_READ = 2; public static final int MESSAGE_WRITE = 3; public static final int MESSAGE_DEVICE_NAME = 4; public static final int MESSAGE_TOAST = 5; public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2; private static final int REQUEST_ENABLE_BT = 3;

ในการใช้งานบลูทูธเริ่มแรกสุดก็คือเรียกใช้คลาสที่ทำหน้าที่
จัดการการทำงานของบลูทูธ ซึ่งก็คือคลาส Bluetooth Adapter
โดยจะประกาศไว้ใน onCreate ก่อนเลย เพื่อเรียกใช้งานบลูทูธ
BluetoothService bs = null; BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
ส่วนคลาส BluetoothService เป็นคลาสภายนอกที่เพิ่มเข้ามาทีหลัง
ที่เอาไว้จัดการกับการรับส่งข้อมูล การเชื่อมต่อกับอุปกรณ์อื่น
ซึ่งตอนนี้ยังไม่ทำอะไรประกาศเป็น null ไว้ก่อน 

โดยคำสั่ง getDefaultAdapter จะดึงบลูทูธของอุปกรณ์แอนดรอยด์นั้นๆทันที
แต่ใช่ว่าอุปกรณ์แอนดรอยด์ทุกตัวจะมีบลูทูธ อย่างเช่นแทบเลตจีนทั้งหลาย
ที่ตัดบลูทูธออกไป ดังนั้นคำสั่งดังกล่าวจึง Return ค่าออกมาเป็น null แทน

ผู้ที่หลงเข้ามาอ่านจึงต้องเช็คด้วยว่า ba มีค่าเป็น null หรือป่าว
ถ้ามีค่าเป็น null ถือว่าเครื่องนั้นไม่มีบลูทูธ ก็ควรสั่งให้หยุดทำงานทันที
เพราะถ้าเกิดเรียกใช้คำสั่งบลูทูธต่างๆ ก็จะเออเรอทันทีเพราะไม่มีบลูทูธ
BluetoothService bs = null; BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); if (ba== null) { Toast.makeText(ActivityName.this , "Bluetooth is not available" , Toast.LENGTH_SHORT).show(); finish(); }

จึงใช้ if เพื่อเช็คค่าจาก ba ถ้าเป็น null ก็จะให้แสดง Toast
ว่าไม่สามารถใช้งานบลูทูธได้ และปิดแอปพลิเคชันทันที

คำสั่งใน onCreate ก็จะมีแค่นี้แหละ ต่อมาก็จะเป็น onStart
public void onStart() { super.onStart(); if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { setupChat(); } }

โดยฟังก์ชันนี้จะทำงานต่อจาก onCreate ทันที ดังนั้นคำสั่งในนี้
จะเป็นคำสั่งปิดใช้บลูทูธ โดยจะเช็คว่าบลูทูธเปิดอยู่หรือไม่
ถ้ายังไม่ได้เปิดบลูทูธก็จะ Intent ไปยังหน้าขอเปิดใช้งานบลูทูธ
ซึ่งคำสั่งตรงนี้จะเป็นการ Intent แบบรอรับ Result ด้วย
จึงต้องไปดูต่อที่ฟังก์ชัน onActivityResult อีกทีหนึ่งด้วย

ในกรณีที่บลูทูธเปิดอยู่แล้วก็จะเข้าสู่ฟังก์ชัน setupChat
เพื่อทำการกำหนดค่าให้กับ Object ต่างๆที่จะใช้กับบลูทูธ
อย่างเช่น ปุ่มสำหรับส่งข้อความผ่านบลูทูธ เป็นต้น

public void setupChat() { // กำหนดค่าต่างๆ ที่จะใช้กับบลูทูธ เช่น Button สำหรับส่งข้อมูล เป็นต้น bs = new BluetoothService(ActivityName.this, handler); }
สำหรับฟังก์ชัน setupChat หลักๆก็จะเป็นคำสั่งกำหนดค่า
ให้กับคลาส BluetoothService ที่ได้กำหนดเป็น null ไว้ในตอนแรก
โดยคลาสดังกล่าวเวลาที่กำหนดค่าจะต้องมีการกำหนด Handler 
เพื่อให้คลาส BluetoothService เวลาที่รับข้อมูลบลูทูธเข้ามาแล้ว
สามารถส่งมาที่ Activity นี้ได้ (คำสั่ง obtainMessage ของ Handler)

public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_ENABLE_BT: if (resultCode == Activity.RESULT_OK) { setupChat(); } else { Toast.makeText(Main.this , "Bluetooth was not enabled. Leaving Bluetooth Chat" , Toast.LENGTH_SHORT).show(); finish(); } } }
ทีนี้มาดูที่ฟังก์ชัน onActivityResult ที่เคยพูดไปก่อนหน้านี้
เนื่องจากมีการ Intent เพื่อเรียกขอเปิดใช้งานบลูทูธ แบบมี Result
ดังนั้นจึงต้องมีการรอรับ Result แล้วตรวจสอบด้วยว่า
ตอนที่ Intent เพื่อขอเปิดบลูทูธ ผู้ใช้ได้กดเปิดบลูทูธหรือไม่
เพราะบางครั้งถึงจะ Intent ไปหน้าขอเปิดบลูทูธ แต่บางที
ผู้ใช้ก็ไม่ได้กดเลือกเปิดบลูทูธเสมอไป อาจจะกดยกเลิกก็ได้
ดังนั้นก็ต้องมาเช็คในฟังก์ชันนี้ว่าค่าที่ส่งมาเป็น RESULT_OK
หรือ RESULT_CANCELED ถ้าเป็น RESULT_OK ก็จะให้
เรียกฟังก์ชัน setupChat เพื่อกำหนดค่าให้กับ BluetoothService
และคำสั่งกำหนดค่าต่างๆที่จะใช้กับการรับส่งข้อมูลผ่านบลูทูธ

แต่ถ้าผู้ใช้กดยกเลิกหรือไม่เปิดใช้งานบลูทูธ ก็จะทำการปิดทันที
พร้อมกับแสดงข้อความแจ้งผ่าน Toast ว่าไม่สามารถใช้บลูทูธได้
(ซึ่่งจริงๆก็มาจากผู้ใช้ไม่กดเปิดใช้งานบลูทูธนั่นเอง)

ทีนี้ก็มาต่อกันที่ Handler ตอนที่กำหนดค่าให้กับคลาส BluetoothService
ที่อยู่ในฟังก์ชันจะเห็นว่ามีการกำหนดคลาส Handler ให้ด้วย
public final Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_STATE_CHANGE: Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { case BluetoothService.STATE_CONNECTED: // ทำการเชื่อมต่อเรียบร้อยแล้ว break; case BluetoothService.STATE_CONNECTING: // กำลังเชื่อมต่ออยู่ break; case BluetoothService.STATE_LISTEN: // กำลังค้นหาอุปกรณ์ break; case BluetoothService.STATE_NONE: // อยู่ในสถานะยังไม่เชื่อมต่อ break; } break; case MESSAGE_WRITE: // เวลาส่งข้อมูลไปยังเป้าหมาย break; case MESSAGE_READ:; // เวลามีข้อมูลส่งเข้ามา break; case MESSAGE_DEVICE_NAME: // ชื่อของอุปกรณ์เป้าหมายหลังจากเชื่อมต่อแล้ว break; case MESSAGE_TOAST: // มีข้อความที่ BluetoothServer ต้องการแสดงผ่าน Toast break; } } };
สำหรับคำสั่งของคลาส Handler จะมีฟังก์ชัน handlerMessage
ซึ่งรอรับข้อมูลที่ส่งมาจาก BluetoothService [คำสั่ง obtainMessage]
โดยเวลาที่ BluetoothService ส่งข้อมูลมาจะมีการระบุด้วยว่า
ข้อมูลที่ส่งมาเป็นของอะไร อย่างเช่น ส่งมาว่าบลูทูธเชื่อมต่อแล้ว
กำลังเชื่อมต่ออยู่  มีข้อมูลส่งเข้ามา ส่งข้อมูลไปยังเป้าหมาย เป็นต้น
เวลาเกิดเหตุการณ์ (Event) เหล่านี้ ก็จะเรียกฟังก์ชัน handlerMessage ทุกครั้ง
ดังนั้นเวลาบลูทูธเชื่อมต่อแล้วต้องการให้ทำอะไร ก็ให้ใส่คำสั่งในนี้
ในส่วนของเงื่อนไขกรณีที่ STATE_CONNECTED เป็นต้น
และในกรณีที่มีข้อมูลส่งเข้ามาก็จะเป็นเงื่อนไข MESSAGE_READ
ดังนั้นถ้าอยากให้รับข้อมูลมาแล้วแสดงขึ้นจอก็ให้ใส่คำสั่งภายในนี้

เวลาที่จะเชื่อมต่อกับอุปกรณ์อื่นๆ ก็จะใช้วิธี Intent ไปอีกหน้าหนึ่ง
แล้วให้เลือกอุปกรณ์ที่จะเชื่อมต่อ จากหน้านั้น
แล้วจึงกลับมาเชื่อมต่อที่หน้า Main.java ดังเดิม
ก็จะต้องมีปุ่มเพื่อกดเข้าไปหน้าเชื่อมต่อบลูทูธ ใช้คำสั่งดังนี้

Button btnPair = (Button)findViewById(R.id.btnPair); btnPair.setOnClickListener(new OnClickListener() { public void onClick(View v) { Intent serverIntent = new Intent(Main.this , SelectDevice.class); startActivityForResult(serverIntent , REQUEST_CONNECT_DEVICE_SECURE); } });

สำหรับคำสั่งต่างๆที่อยู่ใน Activity หลัก ขอหยุดไว้ชั่วคราวก่อนนะ
อาจจะลืมไปว่าตอนนี้ยังไม่มีคำสั่งสำหรับเชื่อมต่อบลูทูธเลย
ว่าจะค้นหารายชื่ออุปกรณ์ที่เปิดบลูทูธอยู่ยังไง และเชื่อมต่อยังไง
โดยจะไปทำในอีก Activity หนึ่งแทน ที่เอาไว้ค้นหาอุปกรณ์และเชื่อมต่อ
ซึ่งในบทความนี้จะขอตั้งชื่อ Activity นี้ว่า SelectDevice.java
.

มาที่ SelectDevice.java กันก่อน

สำหรับ SelectDevice มีหน้าที่ค้นหาอุปกรณ์และทำการเชื่อมต่อ
คำสั่งก็จะมีคำสั่งค้นหาอุปกรณ์กับคำสั่งแสดงรายชื่ออุปกรณ์บน ListView
ส่วนคำสั่งเชื่อมต่อนั้นจะยังไม่มี จะใช้ Intent แบบส่ง Result กลับไป Main.java
เพื่อให้ไปทำการเชื่อมต่อกับอุปกรณ์ที่ต้องการที่ Activity ของ Main.java แทน

ก่อนอื่นก็จะเริ่มจากคำสั่งใน onCreate ก่อน ก็จะกำหนดคลาสต่างๆในนี้เลย
รวมไปถึงดึงรายชื่ออุปกรณ์ที่เคยเชื่อมต่อบลูทูธมาก่อน มาแสดงใน ListView
อย่างเช่น ประกาศและกำหนด Button ที่จะใช้สำหรับเป็นปุ่มค้นหาอุปกรณ์อื่นๆ
BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); Button btnScan = (Button) findViewById(R.id.btnScan); btnScan.setOnClickListener(new OnClickListener() { public void onClick(View v) { if(ba.isDiscovering()) { ba.cancelDiscovery(); } else { doDiscovery(); } } });
กำหนดให้เมื่อกดปุ่มจะทำการค้นหาอุปกรณ์ที่เปิดบลูทูธไว้
โดยเรียกไปที่ฟังก์ชัน doDiscovery เพื่อทำการค้นหา
แต่ถ้ากดปุ่มแล้วบลูทูธกำลังค้นหาอยู่แล้ว ก็จะเป็นการหยุดค้นหา

สำหรับฟังก์ชัน doDiscovery ที่เอาไว้ค้นหาอุปกรณ์
ก็จะให้เคลียร์รายชื่อใน List View ก่อนเป็นอย่างแรก
แล้วดึงรายชื่อที่เคยเชื่อมต่อก่อนหน้ามาแสดงเหมือนเดิม
และเช็คว่ากำลังค้นหาอยู่หรือไม่ ถ้าใช่ก็ยกเลิกก่อน
แล้วจึงทำการค้นหาอุปกรณ์อื่นๆใหม่อีกครั้ง
private void doDiscovery() { aa.clear(); for (BluetoothDevice device : ba.getBondedDevices()) { aa.add(device.getName() + "\n" + device.getAddress()); } if (ba.isDiscovering()) { ba.cancelDiscovery(); } ba.startDiscovery(); }

ต่อมาก็ประกาศคลาสต่างๆสำหรับ List View
โดย List View ตัวนี้จะเอาไปใช้สำหรับแสดงชื่ออุปกรณ์ที่ค้นหาเจอ
และจะทำการดึงรายชื่อที่เคยเชื่อมต่อไว้แล้วมาแสดงด้วย
และมีการสร้าง OnItemClickListener สำหรับ List View ไว้ด้วย
เพื่อให้ผู้ใช้กดเลือกอุปกรณ์ที่ต้องการเชื่อมต่อบน List View ได้เลย
BluetoothAdapter ba= BluetoothAdapter.getDefaultAdapter(); ArrayAdapter<String> aa = new ArrayAdapter<String>(this, R.layout.device_name); ListView lv= (ListView) findViewById(R.id.listView); lv.setAdapter(aa); lv.setOnItemClickListener(listener); Set<BluetoothDevice> pairedDevices = ba.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { aa.add(device.getName() + "\n" + device.getAddress()); } } else { aa.add("No devices have been paired"); }

ต่อมาก็ประกาศคลาส IntentFilter ที่จะกรอง Result 
ที่เป็นของ ACTION_FOUND กับ ACTION_DISCOVERY_FINISHED
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter);
สำหรับ ACTION_FOUND คือกรณีที่เวลาบลูทูธค้นหาอุปกรณ์เจอ
และ ACTION_DISCOVERY_FINISHED สำหรับกรณีที่ค้นหาเสร็จแล้ว
โดยจะให้เวลาที่ Intent Filter รับข้อมูลที่เป็น ACTION_FOUND 
กับ ACTION_DISCOVERY_FINISHED เรียกไปที่ mReceiver
ซึ่งเป็นคลาส BroadcastReceiver คอยรับเวลามีข้อมูลเข้ามา
ดังนั้นเวลาที่บลูทูธค้นหาอุปกรณ์อื่นๆเจอ mReceiver ก็จะทำงานทันที
คล้ายๆกับฟังก์ชัน onActivityResult หรือ Handler นั่นแหละ

สำหรับคลาส BroadcastReceiver ก็จะมีฟังก์ชัน onReceive
ที่จะทำงานก็ตามเมื่อเกิดเหตุการณ์ ACTION_FOUND
กับ ACTION_DISCOVERY_FINISHED ตามที่ได้กำหนดไว้
ในคำสั่ง registerReceiver ก็จะให้ทำคำสั่งตามแต่ละเงื่อนไขไปเลย
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); lif (device.getBondState() != BluetoothDevice.BOND_BONDED) { aa(device.getName() + " *\n" + device.getAddress()); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { if (aa.getCount() == 0) { aa("No devices found"); } } } };
ถ้าเข้าเงื่อนไข ACTION_FOUND หรือค้นหาเจออุปกรณ์ใดๆ
ก็อ่านชื่ออุปกรณ์และแอดเดรสของอุปกรณ์ มาแสดงบน List View
และถ้าเข้าเงื่อนไข ACTION_DISCOVERY_FINISHED
หรือค้นหาเสร็จแล้ว ก็จะเช็คว่ามีรายชื่ออุปกรณ์ใน List View หรือไม่
ถ้าไม่มีเลยก็จะให้แสดงข้อความว่าค้นหาอุปกรณ์ไม่เจอแทน

ทีนี้มาต่อกันที่ Listener ของ List View ที่ประกาศไว้ก่อนหน้านี้
ก็จะให้ยกเลิกการค้นหาก่อน (เผื่อว่ากำลังค้นหาอยู่แล้วกดเชื่อมต่อ)
จากนั้นก็จะเก็บชื่ออุปกรณ์และแอดเดรสเป็นตัวแปร String
แล้วทำการส่งแต่แอดเดรสอย่างเดียวกลับไปที่ Main.java
(อย่าลืมว่า SelectDevice.java มาจากการ Intent ของ Main.java)
private OnItemClickListener listener = new OnItemClickListener() { public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) { ba.cancelDiscovery(); String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); Intent intent = new Intent(); intent.putExtra(EXTRA_DEVICE_ADDRESS, address); setResult(Activity.RESULT_OK, intent); finish(); } };

เมื่อทำการส่งแอดเดรสของบลูทูธตัวที่จะเชื่อมต่อกลับไปที่ Main.java
ก่อนที่จะกลับไปยังหน้าดังกล่าว ก็จะให้ยกเลิก BroadcastReceiver
และเผื่อกรณีที่กำลังค้นหาอยู่ ก็ให้ทำการยกเลิกค้นหาเผื่อไปด้วย
ซึ่งคำสั่งที่กล่าวมานี้จะอยู่ใน onDestroy ที่จะทำงานเมื่อ Activity ถูกปิด
protected void onDestroy() { super.onDestroy(); if (ba != null) { ba.cancelDiscovery(); } this.unregisterReceiver(mReceiver); }


กลับมาสู่ Main.java อีกครั้งพร้อมกับ Address ที่จะเชื่อมต่อ

เมื่อกลับมาจาก SelectDevice.java ที่ทำการส่งค่ากลับมาด้วย
ฟังก์ชัน onActivityResult ของ Main.java ก็จะทำงานทันที
เนื่องจาก Result ที่ส่งกลับมาคราวนี้เป็นแอดเดรสสำหรับเชื่อมต่อ
จึงต้องเพิ่มเงื่อนไขเข้าไปเพื่อเช็ค Result จาก SelectDevice.java ดังนี้
public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CONNECT_DEVICE_SECURE: if (resultCode == Activity.RESULT_OK) connectDevice(data, true); break; case REQUEST_ENABLE_BT: if (resultCode == Activity.RESULT_OK) { setupChat(); } else { Toast.makeText(Main.this , "Bluetooth was not enabled. Leaving Bluetooth Chat" , Toast.LENGTH_SHORT).show(); finish(); } } }
ก็จะเพิ่มเงื่อนไข REQUEST_CONNECT_DEVICE_SECURE เข้าไป
เมื่อ onActivityResult ทำงานด้วยเงื่อนไขนี้ ก็จะให้ทำการเชื่อมต่อบลูทูธ
โดยอิงอุปกรณ์ที่จะเชื่อมต่อจากแอดเดรสที่ได้เลือกไว้ใน SelectDevice.java
ซึ่งก็จะไปเรียกฟังก์ชัน connectDevice ที่เจ้าของบล็อกเตรียมไว้อีกทีหนึ่ง

public void connectDevice(Intent data, boolean secure) { String address = data.getExtras() .getString(SelectDevice.EXTRA_DEVICE_ADDRESS); BluetoothDevice device = ba.getRemoteDevice(address); bs.connect(device, secure); }


เมื่อเชื่อมต่อแล้ว ที่เหลือก็ไม่ยากแล้ว

ทีนี้ก็เหลือแค่ขั้นตอนการส่งข้อมูลแล้ว ส่วนการรับข้อมูล
เจ้าของบล็อกอธิบายไปแล้วใน Handler แต่สำหรับการส่งข้อมูล
ยังไม่ได้มีการอธิบายคำสั่ง ซึ่งคำสั่งส่งข้อมูลผ่านบลูทูธนั้นไม่ยากเลย
โดยเจ้าของบล็อกสร้างฟังก์ชันสำหรับส่งข้อมูลแยกเอาไว้
เวลาเรียกใช้งานจะได้ง่ายขึ้น โดยใช้ฟังก์ชันชื่อว่า sendMessage
public void sendMessage(String message) { if (mChatService.getState() != BluetoothService.STATE_CONNECTED) { Toast.makeText(Main.this, "Device is not connected" , Toast.LENGTH_SHORT).show(); return; } if (message.length() > 0) { byte[] send = message.getBytes(); mChatService.write(send); } }
ก็จะมีการเช็คสถานะว่าเชื่อต่อแล้วหรือไม่ ถ้ายังไม่เชื่อมต่อ
ก็ให้แสดงข้อความผ่าน Toast ว่ายังไม่ได้เชื่อมต่อ
แต่ถ้าเชื่อมต่อแล้ว และข้อมูลมีขนาดมากกว่า 0 ตัวขึ้นไป
ก็จะให้แปลงข้อมูล String เป็น Byte Array แล้วส่งไปยังเป้าหมาย

เวลาเรียกใช้งานก็เรียกด้วยคำสั่ง senMessage(String) ได้เลย
โดยกำหนด String ที่ต้องการจะส่งไปยังอุปกรณ์เป้าหมายด้วย
Button btnData = (Button)findViewById(R.id.btnData); btnData.setOnClickListener(new OnClickListener() { public void onClick(View v) { sendMessage("Hello"); } });
การใช้ Button ส่งค่าตายตัวแบบนี้จะเหมาะกับการนำไป
ควบคุมไมโครคอนโทรลเลอร์ผ่านบลูทูธ อย่างเช่น รถ
เพราะสามารถสร้างหลายๆปุ่มที่เก็บข้อมูลไว้ต่างกัน

แต่ถ้าต้องการให้สามารถผู้ใช้กำหนดข้อความที่จะส่งได้
ก็ให้ใช้ Edit Text สำหรับรับข้อความ และ Button เพื่อทำการส่ง ดังนี้
EditText editText = (EditText)findViewById(R.id.editText); Button button = (Button)findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { sendMessage(etMessage.getText().toString()); etMessage.setText(""); } });

และสุดท้ายก็คือ เมื่อผู้ใช้ปิดแอปพลิเคชัน
จะต้องยกเลิกคลาส BluetoothService ดังนี้
public void onDestroy() { super.onDestroy(); if (mChatService != null) mChatService.stop(); }


อาจจะดูสับสนกับโค๊ด ทั้งนี้ก็เพราะว่าเจ้าของบล็อกอธิบายทีละส่วน
ไม่ได้อธิบายโดยรวม เนื่องจากการรับส่งข้อมูลผ่านบลูทูธคำสั่งจะเยอะ
ซึ่งจริงๆแล้ว จะเห็นว่าคำสั่งเยอะแค่เฉพาะในส่วนของการเชื่อมต่อเท่านั้น
และผู้ที่หลงเข้ามาอ่านที่ต้องการโค๊ดตัวอย่าง จะมีการแก้ไขเล็กน้อย
เพื่อให้โค๊ดสมบูรณ์ เนื่องจากจะยกมาอธิบายทั้งหมดก็จะซับซ้อนเกินไป

ตัวอย่างในบทความนี้ก็จะให้มีปุ่ม Button 2 ปุ่ม สำหรับส่งข้อมูลสองแบบ
คือปุ่มแรกส่งข้อความว่า Hello และปุ่มที่สองส่งข้อความว่า 0123
และยังมี Edit Text กับ Button อีกชุดสำหรับให้กรอกข้อความที่ต้องการได้


main.xml
<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:focusable="true" android:focusableInTouchMode="true" tools:context=".Main" > <requestFocus /> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="70dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:background="#44000000" android:gravity="center_vertical" > <TextView android:id="@+id/tvStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="Status : Not Connect" android:textColor="#FFFFFF" android:textSize="18sp" android:textStyle="bold" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="right" android:orientation="vertical" > <Button android:id="@+id/btnPair" android:layout_width="60dp" android:layout_height="60dp" android:text="Pair" /> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/linearLayout1" android:layout_centerHorizontal="true" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:id="@+id/btnData1" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="20dp" android:text="&quot;Hello&quot;" /> <Button android:id="@+id/btnData2" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="20dp" android:text="&quot;0123&quot;" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" > <EditText android:id="@+id/etMessage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:minLines="1" android:singleLine="true" /> <Button android:id="@+id/btnSend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Send" /> </LinearLayout> </LinearLayout> <ListView android:id="@+id/listDataIncoming" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/linearLayout2" android:layout_centerHorizontal="true" android:layout_margin="30dp" > </ListView> </RelativeLayout>


select_device.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/btnScan" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="#55000000" android:text="Scan for devices" android:textColor="#FFFFFF" /> <ListView android:id="@+id/lvDevice" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/btnScan" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" > </ListView> </RelativeLayout>


Main.java
package app.akexorcist.bluetoothsimple; import java.util.ArrayList; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Intent; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class Main extends Activity { private static final String TAG = "BluetoothSimple"; public static final int MESSAGE_STATE_CHANGE = 1; public static final int MESSAGE_READ = 2; public static final int MESSAGE_WRITE = 3; public static final int MESSAGE_DEVICE_NAME = 4; public static final int MESSAGE_TOAST = 5; public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2; private static final int REQUEST_ENABLE_BT = 3; TextView tvStatus; EditText etMessage; ListView listDataIncoming; Button btnPair, btnData1, btnData2, btnData3, btnData4, btnSend; ArrayList<String> arr_list; String mConnectedDeviceName = null; BluetoothAdapter mBluetoothAdapter = null; BluetoothService mChatService = null; boolean isConnected = false; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.e(TAG, "+++ ON CREATE +++"); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(Main.this, "Bluetooth is not available" , Toast.LENGTH_SHORT).show(); finish(); } } public void onStart() { super.onStart(); if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { if (mChatService == null) setupChat(); } } public synchronized void onResume() { super.onResume(); if (mChatService != null) { if (mChatService.getState() == BluetoothService.STATE_NONE) { mChatService.start(); } } } public void setupChat() { tvStatus = (TextView)findViewById(R.id.tvStatus); etMessage = (EditText)findViewById(R.id.etMessage); arr_list = new ArrayList<String>(); listDataIncoming = (ListView)findViewById(R.id.listDataIncoming); listDataIncoming.setAdapter(new ArrayAdapter(Main.this , android.R.layout.simple_list_item_1, arr_list)); btnSend = (Button)findViewById(R.id.btnSend); btnSend.setOnClickListener(new OnClickListener() { public void onClick(View v) { sendMessage(etMessage.getText().toString()); etMessage.setText(""); } }); btnData1 = (Button)findViewById(R.id.btnData1); btnData1.setOnClickListener(new OnClickListener() { public void onClick(View v) { sendMessage("Hello"); } }); btnData2 = (Button)findViewById(R.id.btnData2); btnData2.setOnClickListener(new OnClickListener() { public void onClick(View v) { sendMessage("0123"); } }); btnPair = (Button)findViewById(R.id.btnPair); btnPair.setOnClickListener(new OnClickListener() { public void onClick(View v) { if(!isConnected) { Intent serverIntent = new Intent(Main.this , SelectDevice.class); startActivityForResult(serverIntent , REQUEST_CONNECT_DEVICE_SECURE); } else { mChatService.stop(); mChatService = new BluetoothService(Main.this, mHandler); isConnected = false; } } }); mChatService = new BluetoothService(Main.this, mHandler); } public void onDestroy() { super.onDestroy(); if (mChatService != null) mChatService.stop(); } public void sendMessage(String message) { if (mChatService.getState() != BluetoothService.STATE_CONNECTED) { Toast.makeText(Main.this, "Device is not connected" , Toast.LENGTH_SHORT).show(); return; } if (message.length() > 0) { byte[] send = message.getBytes(); mChatService.write(send); } } public final void setStatus(String subTitle) { tvStatus.setText(subTitle); } public final Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_STATE_CHANGE: Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { case BluetoothService.STATE_CONNECTED: setStatus("Connected to " + mConnectedDeviceName); isConnected = true; break; case BluetoothService.STATE_CONNECTING: setStatus("Connecting..."); isConnected = false; break; case BluetoothService.STATE_LISTEN: case BluetoothService.STATE_NONE: setStatus("Not Connected"); break; } break; case MESSAGE_WRITE: byte[] writeBuf = (byte[]) msg.obj; String writeMessage = new String(writeBuf); break; case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; String readMessage = new String(readBuf, 0, msg.arg1); arr_list.add(readMessage); break; case MESSAGE_DEVICE_NAME: mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); Toast.makeText(getApplicationContext() , "Connected to " + mConnectedDeviceName , Toast.LENGTH_SHORT).show(); break; case MESSAGE_TOAST: Toast.makeText(getApplicationContext() , msg.getData().getString(TOAST) , Toast.LENGTH_SHORT).show(); break; } } }; public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CONNECT_DEVICE_SECURE: if (resultCode == Activity.RESULT_OK) connectDevice(data, true); break; case REQUEST_CONNECT_DEVICE_INSECURE: if (resultCode == Activity.RESULT_OK) connectDevice(data, false); break; case REQUEST_ENABLE_BT: if (resultCode == Activity.RESULT_OK) { setupChat(); } else { Toast.makeText(Main.this , "Bluetooth was not enabled. Leaving Bluetooth Chat" , Toast.LENGTH_SHORT).show(); finish(); } } } public void connectDevice(Intent data, boolean secure) { String address = data.getExtras() .getString(SelectDevice.EXTRA_DEVICE_ADDRESS); BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); mChatService.connect(device, secure); } }

คงไม่ต้องอธิบายอะไรกับโค๊ดแล้วล่ะ มันเยอะจัด = =


SelectDevice.java
package app.akexorcist.bluetoothsimple; import java.util.Set; import android.app.Activity; 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.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; public class SelectDevice extends Activity { private static final String TAG = "DeviceListActivity"; public static String EXTRA_DEVICE_ADDRESS = "device_address"; private BluetoothAdapter mBtAdapter; private ArrayAdapter<String> mDevicesArrayAdapter; private Button btnScan; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.select_device); setResult(Activity.RESULT_CANCELED); btnScan = (Button) findViewById(R.id.btnScan); btnScan.setOnClickListener(new OnClickListener() { public void onClick(View v) { if(mBtAdapter.isDiscovering()) { mBtAdapter.cancelDiscovery(); btnScan.setText("Scan for devices"); } else { doDiscovery(); btnScan.setText("Scanning..."); } } }); mDevicesArrayAdapter = new ArrayAdapter<String>(SelectDevice.this , android.R.layout.simple_list_item_1); ListView pairedListView = (ListView) findViewById(R.id.lvDevice); pairedListView.setAdapter(mDevicesArrayAdapter); pairedListView.setOnItemClickListener(mClickListener); mBtAdapter = BluetoothAdapter.getDefaultAdapter(); Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { mDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } else { mDevicesArrayAdapter.add("No devices have been paired"); } IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter); } protected void onDestroy() { super.onDestroy(); if (mBtAdapter != null) { mBtAdapter.cancelDiscovery(); } this.unregisterReceiver(mReceiver); } private void doDiscovery() { mDevicesArrayAdapter.clear(); for (BluetoothDevice device : mBtAdapter.getBondedDevices()) { mDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } if (mBtAdapter.isDiscovering()) { mBtAdapter.cancelDiscovery(); } mBtAdapter.startDiscovery(); } private OnItemClickListener mClickListener = new OnItemClickListener() { public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) { mBtAdapter.cancelDiscovery(); String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); Intent intent = new Intent(); intent.putExtra(EXTRA_DEVICE_ADDRESS, address); setResult(Activity.RESULT_OK, intent); finish(); } }; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { mDevicesArrayAdapter.add(device.getName() + " *\n" + device.getAddress()); } } else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){ if (mDevicesArrayAdapter.getCount() == 0) { mDevicesArrayAdapter.add("No devices found"); } btnScan.setText("Scan for devices"); btnScan.setEnabled(true); } } }; }


BluetoothService.java
package app.akexorcist.bluetoothsimple; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; public class BluetoothService { private static final String TAG = "BluetoothChatService"; private static final boolean D = true; private static final String NAME_SECURE = "BluetoothChatSecure"; private static final String NAME_INSECURE = "BluetoothChatInsecure"; private static final UUID MY_UUID_SECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private static final UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private final BluetoothAdapter mAdapter; private final Handler mHandler; private AcceptThread mSecureAcceptThread; private AcceptThread mInsecureAcceptThread; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; private int mState; public static final int STATE_NONE = 0; public static final int STATE_LISTEN = 1; public static final int STATE_CONNECTING = 2; public static final int STATE_CONNECTED = 3; public BluetoothService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; } private synchronized void setState(int state) { if (D) Log.d(TAG, "setState() " + mState + " -> " + state); mState = state; mHandler.obtainMessage(Main.MESSAGE_STATE_CHANGE , state, -1).sendToTarget(); } public synchronized int getState() { return mState; } public synchronized void start() { if (D) Log.d(TAG, "start"); if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(STATE_LISTEN); if (mSecureAcceptThread == null) { mSecureAcceptThread = new AcceptThread(true); mSecureAcceptThread.start(); } if (mInsecureAcceptThread == null) { mInsecureAcceptThread = new AcceptThread(false); mInsecureAcceptThread.start(); } } public synchronized void connect(BluetoothDevice device, boolean secure) { if (D) Log.d(TAG, "connect to: " + device); if (mState == STATE_CONNECTING) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } mConnectThread = new ConnectThread(device, secure); mConnectThread.start(); setState(STATE_CONNECTING); } public synchronized void connected(BluetoothSocket socket , BluetoothDevice device, final String socketType) { if (D) Log.d(TAG, "connected, Socket Type:" + socketType); if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread = null; } if (mInsecureAcceptThread != null) { mInsecureAcceptThread.cancel(); mInsecureAcceptThread = null; } mConnectedThread = new ConnectedThread(socket, socketType); mConnectedThread.start(); Message msg = mHandler.obtainMessage(Main.MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(Main.DEVICE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } public synchronized void stop() { if (D) Log.d(TAG, "stop"); if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread = null; } if (mInsecureAcceptThread != null) { mInsecureAcceptThread.cancel(); mInsecureAcceptThread = null; } setState(STATE_NONE); } public void write(byte[] out) { ConnectedThread r; synchronized (this) { if (mState != STATE_CONNECTED) return; r = mConnectedThread; } r.write(out); } private void connectionFailed() { Message msg = mHandler.obtainMessage(Main.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(Main.TOAST, "Unable to connect device"); msg.setData(bundle); mHandler.sendMessage(msg); BluetoothService.this.start(); } private void connectionLost() { Message msg = mHandler.obtainMessage(Main.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(Main.TOAST, "Device connection was lost"); msg.setData(bundle); mHandler.sendMessage(msg); BluetoothService.this.start(); } private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; private String mSocketType; public AcceptThread(boolean secure) { BluetoothServerSocket tmp = null; mSocketType = secure ? "Secure":"Insecure"; try { if (secure) { tmp = mAdapter.listenUsingRfcommWithServiceRecord (NAME_SECURE, MY_UUID_SECURE); } else { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord (NAME_INSECURE, MY_UUID_INSECURE); } } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed"); } mmServerSocket = tmp; } public void run() { if (D) Log.d(TAG, "Socket Type: " + mSocketType + "BEGIN mAcceptThread" + this); setName("AcceptThread" + mSocketType); BluetoothSocket socket = null; while (mState != STATE_CONNECTED) { try { socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed"); break; } if (socket != null) { synchronized (BluetoothService.this) { switch (mState) { case STATE_LISTEN: case STATE_CONNECTING: connected(socket, socket.getRemoteDevice(), mSocketType); break; case STATE_NONE: case STATE_CONNECTED: try { socket.close(); } catch (IOException e) { Log.e(TAG, "Could not close unwanted socket", e); } break; } } } } if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType); } public void cancel() { if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed"); } } } private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device, boolean secure) { mmDevice = device; BluetoothSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; try { if (secure) { tmp = device.createRfcommSocketToServiceRecord( MY_UUID_SECURE); } else { tmp = device.createInsecureRfcommSocketToServiceRecord( MY_UUID_INSECURE); } } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "create() failed"); } mmSocket = tmp; } public void run() { Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); setName("ConnectThread" + mSocketType); mAdapter.cancelDiscovery(); try { mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2); } connectionFailed(); return; } synchronized (BluetoothService.this) { mConnectThread = null; } connected(mmSocket, mmDevice, mSocketType); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect " + mSocketType + " socket failed"); } } } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { Log.d(TAG, "create ConnectedThread: " + socketType); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mmInStream.read(buffer); mHandler.obtainMessage(Main.MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); connectionLost(); BluetoothService.this.start(); break; } } } public void write(byte[] buffer) { try { mmOutStream.write(buffer); mHandler.obtainMessage(Main.MESSAGE_WRITE, -1, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } }


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.akexorcist.bluetoothsimple" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="Main" 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="SelectDevice"></activity> </application> </manifest>


บทความนี้ยาวไปหน่อยเพราะตัวโค๊ดของบลูทูธนั่นแหละ
สำหรับผู้ที่หลงเข้ามาอ่านที่ต้องการไฟล์ตัวอย่างสามารถดาวน์โหลดได้จาก




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium