บทความนี้เก่ามากแล้ว และหยุดพัฒนาต่อแล้ว
จากที่เจ้าของบล็อกได้เกริ่นถึงคลาส BluetoothSPP ที่เจ้าของบล็อกลองนั่งเขียนเองแล้ว ทีนี้มาพูดถึงวิธีการใช้งานเบื้องต้นกันบ้าง
สำหรับผู้ที่หลงเข้ามาอ่านคนใดที่ยังไม่ได้อ่านบทความแนะนำ อยากให้ลองเข้าไปอ่านคร่าวๆก่อนที่ [Android Code] เปลี่ยนเรื่องบลูทูธให้เป็นเรื่องง่ายด้วย BluetoothSPP Library
สำหรับตัวอย่างนี้จะเป็นตัวอย่างการใช้งานเบื้องต้นเท่านั้น โดยจะมีตัวอย่างการทำงานหลักๆดังนี้
• มีปุ่มกดเพื่อส่งข้อความตามที่กำหนดไว้ในคำสั่ง
• เมื่อมีข้อมูลถูกส่งเข้ามาจะแสดงข้อมูลผ่าน Toast บนหน้าจอ
• แสดง Toast เมื่อเชื่อมต่อกับอุปกรณ์ต่างๆได้ หรือไม่ได้ หรือหยุดการเชื่อมต่อ
• ปุ่มเลือกอุปกรณ์ที่เชื่อมต่อ เมื่อกำลังเชื่อมต่ออยู่พอกดอีกครั้งจะหยุดเชื่อมต่อ
ก่อนจะใช้งานก็อย่าลืมดาวน์โหลด BluetoothSPP มา Import ไว้ใน Eclipse กันเสียก่อน โดยดาวน์โหลดได้จาก
BluetoothSPP [GitHub]
BluetoothSPP [Google Drive]
BluetoothSPP [Sleeping For Less]
เมื่อดาวน์โหลดเสร็จแล้วก็นำมา Import ซะ แล้วสร้างโปรเจคของผู้ที่หลงเข้ามาอ่านขึ้นมา แล้วกำหนดให้ใช้งานไลบรารี BluetoothSPP ด้วย
แล้วกำหนดในไฟล์ project.properties เพิ่มเข้าไปว่า
manifestmerger.enabled=true
ซึ่งคำสั่งนี้จะทำให้ Android Manifest ของโปรเจคที่สร้างกับไลบรารีนั้นถูกรวมเข้าด้วยกัน
และต้องประกาศ Permission ไว้ใน Android Manifest ดังนี้
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
สำหรับหัวใจสำคัญหลักๆในการใช้งาน BluetoothSPP มีดังนี้
ประกาศและกำหนดค่าตัวแปรของ BluetoothSPP (ไม่งั้นก็ใช้งานไม่ได้น่ะสิ....)
BluetoothSPP bt = new BluetoothSPP(this);
หรือจะกำหนดแบบระบุชื่อ Activity ด้วยเลยก็ได้
BluetoothSPP bt = new BluetoothSPP(Main.this);
โดยให้ประกาศชื่อตัวแปรเป็น Global ส่วนกำหนดค่าก็เอาไว้ใน onCreate ของ Activity ที่ต้องการใช้งานบลูทูธ
public class Main extends Activity {
BluetoothSPP bt;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt = new BluetoothSPP(this);
}
}
เมื่อประกาศเสร็จแล้ว อย่างแรกสุดก็ควรจะเช็คก่อนว่าเครื่องรองรับบลูทูธหรือไม่ ถ้าไม่รองรับก็จะให้ปิดแอปพลิเคชันทันทีแล้วแสดงข้อความแจ้งผู้ใช้ผ่าน Toast
เพิ่มเติม - จริงๆแล้วแอปพลิเคชันเวลาอยู่บน Google Play แล้ว ถ้ามีการใช้งานบลูทูธด้วย เครื่องที่ไม่มีบลูทูธในตัวจะไม่สามารถดาวน์โหลดได้ แต่ก็ต้องมีการเช็คเผื่อไว้ในกรณีที่ผู้ใช้ถือวิสาสะแอบเอาไปติดตั้งแบบไฟล์ APK หรือเครื่องบางรุ่นที่เป็นเครื่องจีนแล้วเฟิร์มแวร์ห่วยๆที่ผู้ผลิตใส่ไว้ว่ารองรับบลูทูธทั้งๆที่เครื่องนั้นไม่มีบลูทูธ ทำให้โหลดแอพบลูทูธจาก Google Play ได้ แต่ใช้งานไม่ได้
if(!bt.isBluetoothAvailable()) {
Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
finish();
}
สำหรับ onCreate โดยหลักๆจะมีเบื้องต้นแค่นั้น (แต่เดี๋ยวมีเพิ่มอีกทีหลัง) ทีนี้มาต่อกันที่ onStart โดยจะให้เรียกใช้งาน Service ของคลาส BluetoothSPP หลังจากที่ประกาศใช้งานใน onCreate
public void onStart() {
super.onStart();
if(!bt.isBluetoothEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
} else {
bt.setupService();
bt.startService(BluetoothState.DEVICE_ANDROID);
setup();
}
}
จะทำการตรวจสอบก่อนว่าบลูทูธเปิดใช้งานอยู่หรือไม่ ถ้าไม่ก็จะให้ Intent เพื่อร้องขอเปิดใช้งานบลูทูธ
สำหรับ Intent อันนี้เมื่อผู้ใช้เลือก Deny หรือ Allow แล้วจะ Return กลับมาที่ฟังก์ชัน onActivityResult อีกที ซึ่งเดี๋ยวค่อยว่ากันทีหลัง
แต่ในกรณีที่บลูทูธเปิดใช้งานอยู่แล้ว ก็จะเช็คว่า Service พร้อมใช้งานหรือยัง ถ้าไม่พร้อมใช้งานก็จะทำการกำหนดค่าให้กับ Service แล้วเรียกใช้ฟังก์ชัน setup ซึ่งฟังก์ชันนี้จะให้สร้างขึ้นมาเอง เอาไว้กำหนดค่าต่างๆเมื่อบลูทูธพร้อมใช้งานแล้ว เช่น ให้ปุ่มส่งข้อความสามารถทำงานได้ เป็นต้น
เพิ่มเติม - ถ้าเอาไปกำหนดไว้ใน onCreate แล้ว Service ไม่พร้อมใช้งาน พร้อมกับผู้ใช้ไปกดปุ่มส่งข้อความ ผลก็คือแอพเด้งเพราะเออเรอนั่นเอง
จะสังเกตุเห็นว่าคำสั่ง startService มีการกำหนดค่าเป็น DEVICE_ANDROID ด้วย ทั้งนี้เพราะเป็นเรื่องของ UUID ที่ใช้เชื่อมต่อกับอุปกรณ์อื่นๆ ซึ่งมีให้กำหนดค่าสองแบบดังนี้
bt.startService(BluetoothState.DEVICE_ANDROID);
bt.startService(BluetoothState.DEVICE_OTHER);
DEVICE_ANDROID จะเป็นการใช้ UUID ที่ใช้เชื่อมต่ออุปกรณ์แอนดรอยด์ด้วยกัน
DEVICE_OTHER เป็นอุปกรณ์อื่นๆที่ไม่ใช่อุปกรณ์แอนดรอยด์ อย่างเช่น โมดูล BlueStick ของ INEX เพื่อเอาไปใช้สั่งงานกับอุปกรณ์ไมโครคอนโทรลเลอร์ผ่านบลูทูธ เป็นต้น
ดังนั้นจะเชื่อมต่อกับอะไรก็กำหนดค่าไว้ให้ดี หรือจะทำเป็นเมนูเลือกก็ได้ว่าจะเชื่อมต่อแบบไหน
ส่วนฟังก์ชัน setup ที่เรียกใช้งาน ในนี้ก็เอาไว้กำหนดค่าตามที่บอกนั่นแหละ
public void setup() {
}
ทีนี้มาต่อกันที่ onDestroy เวลาที่ Activity ถูกปิดลงจะต้องทำการใช้คำสั่งปิด Service ของคลาส BluetoothSPP ด้วย
public void onDestroy() {
super.onDestroy();
bt.stopService();
}
ต่อมาเป็นการไปยังหน้าเลือกอุปกรณ์ที่จะเชื่อมต่อด้วย ซึ่งอันนี้จะใช้วิธี Intent ไป Activity ที่เจ้าของบล็อกได้เขียนไว้ในคลาส BluetoothSPP แล้วนั่นเอง
Intent intent = new Intent(getApplicationContext(), DeviceList.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
ในกรณีที่อยากให้เปิดหน้านั้นๆขึ้นมาแล้วไปยังหน้าเลือกอุปกรณ์ทันที ก็ให้ใส่คำสั่งนี้ไว้ในท้ายสุดของฟังก์ชัน setup ได้เลย
public void setup() {
...
...
...
Intent intent = new Intent(Main.this, DeviceList.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
แต่ถ้าอยากให้กดปุ่มแล้วค่อยไปหน้าเชื่อมต่อก็เอาไปใส่ไว้ใน onClickListener ของปุ่มนั้นๆ
Button btnConnect = (Button)findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new OnClickListener(){
public void onClick(View v){
Intent intent = new Intent(Main.this, DeviceList.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
});
สุดท้ายคือ onActivityResult ที่พูดค้างไว้ตอน Intent นั่นเอง
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
if(resultCode == Activity.RESULT_OK)
bt.connect(data);
} else if(requestCode == BluetoothState.REQUEST_ENABLE_BT) {
if(resultCode == Activity.RESULT_OK) {
bt.setupService();
bt.startService(BluetoothState.DEVICE_ANDROID);
setup();
} else {
Toast.makeText(getApplicationContext(), "Bluetooth was not enabled."
, Toast.LENGTH_SHORT).show();
finish();
}
}
}
ใน onActivityResult นี้จะทำหน้าที่รอ Return กลับมาจากการ Intent ไปที่อื่น ซึ่งในตัวอย่างของเจ้าของบล็อกคือ Intent ไปเพื่อเปิดใช้งานบลูทูธในกรณีที่ยังไม่ได้เปิด (REQUEST_ENABLE_BT) และ Intent เพื่อไปยังหน้าเลือกอุปกรณ์เพื่อเชื่อมต่อ (REQUEST_CONNECT_DEVICE)
ถ้า Return กลับมาเป้นของ REQUEST_ENABLE_BT ก็จะเช็คว่าผลลัพธ์เป็น RESULT_OK หรือไม่ ถ้าใช่ก็จะหมายถึงผู้ใช้กดเปิดบลูทูธนั่นเอง ก็จะให้ทำการกำหนดค่า Service และสั่งให้เริ่มทำงานโดยกำหนดอุปกรณ์เป็น DEVICE_ANDROID (สามารถเปลี่ยนได้ตามที่พูดไว้ก่อนหน้านี้) แต่ถ้าผลลัพธ์ไม่ใช่ RESULT_OK ก็จะทำการปิดแอปพลิเคชันทันทีพร้อมกับแสดงข้อความแจ้งผู้ใช้ผ่าน Toast เพราะผู้ใช้กดยกเลิกการเปิดใช้งานบลูทูธนั่นเอง
ถ้า Return กลับมาเป็นของหน้า REQUEST_CONNECT_DEVICE ก็จะเช็คว่าผลลัพธ์เป็น RESULT_OK หรือป่าว ถ้าใช่ก็จะทำการเชื่อมต่อบลูทูธกับอุปกรณ์ที่เลือก
เท่านี้ก็เสร็จแล้วกับคำสั่งหลักๆ
แต่ว่านั่นก็ยังไม่พอ เพราะต้องมีคำสั่งเสริมเพื่อทำให้แอปพลิเคชันสมบูรณ์มากขึ้น เช่น
ในฟังก์ชัน setup ที่เจ้าของบล็อกพูดไว้ แต่ในนั้นกลับไม่ได้ใส่คำสั่งอะไรเลย ทั้งนี้ก็เพราะว่าขึ้นอยู่กับผู้ใช้นั่นเอง ว่าจะมีอะไรบ้างที่สั่งงานบลูทูธ
สมมติว่าเจ้าของบล็อกสร้างปุ่ม Button ขึ้นมาตัวนึง เอาไว้ส่งข้อความว่า Text ก็กำหนดในนี้เลย
public void setup() {
Button btnSend = (Button)findViewById(R.id.btnSend);
btnSend.setOnClickListener(new OnClickListener(){
public void onClick(View v){
bt.send("Text", true);
}
});
}
จะมีสิบปุ่มก็ได้ตามใจชอบ เวลากำหนดก็มากำหนดไว้ในฟังก์ชัน setup ละกัน
ต่อมาก็คือ Listener สำหรับ Event การเชื่อมต่อบลูทูธ เพื่อให้สามารถรู้สถานะการเชื่อมต่อบลูทูธได้ โดยจะมี 3 Event ด้วยกัน คือ
• onDeviceConnected เมื่อเชื่อมต่อกับอุปกรณ์นั้นๆได้
• onDeviceDisconnected เมื่อหยุดทำการเชื่อมต่อ
• onDeviceConnectionFailed เมื่อไม่สามารถเชื่อมต่อได้
โดยจะให้แสดงสถานะการเชื่อมต่อให้ผู้ใช้เห็นผ่าน Toast
bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
public void onDeviceConnected(String name, String address) {
Toast.makeText(getApplicationContext(), "Connected to " + name + "\n" + address
, Toast.LENGTH_SHORT).show();
}
public void onDeviceDisconnected() {
Toast.makeText(getApplicationContext(), "Connection lost", Toast.LENGTH_SHORT).show();
}
public void onDeviceConnectionFailed() {
Toast.makeText(getApplicationContext(), "Unable to connect", Toast.LENGTH_SHORT).show();
}
});
ถ้าแอปพลิเคชันที่สร้างมีการรับข้อมูลจากอุปกรณ์ที่เชื่อมต่อด้วย ก็ควรมีการประกาศใช้ Listener สำหรับ Event การรับข้อมูลทางบลูทูธ เพื่อให้สามารถรับข้อมูลที่ส่งเข้ามาได้ โดยจะมี 1 Event เท่านั้น คือ
• onDataReceived เมื่อมีข้อมูลส่งเข้ามา
โดยจะให้ทำการแสดงข้อความที่รับเข้ามาให้ผู้ใช้งานเห็นผ่าน Toast
bt.setOnDataReceivedListener(new OnDataReceivedListener() {
public void onDataReceived(byte[] data, String message) {
Toast.makeText(Main.this, message, Toast.LENGTH_SHORT).show();
}
});
สำหรับ Listener สามารถประกาศไว้ใน onCreate ได้เลย ต่อท้ายจากการประกาศใช้งานคลาส BluetoothSPP และตรวจสอบว่าเครื่องมีบลูทูธแล้ว แต่มีหนึ่งสิ่งที่สำคัญคือจะทำงานก็ต่อเมื่อรับข้อมูลที่มี LF(0x0A) กับ CR(0x0D) ต่อท้ายเท่านั้น ถ้าส่งมาแบบไม่มีตัวปิดก็จะไม่แสดง และเก็บไว้เรื่อยๆจนกว่าจะส่งตัวปิดมา เพื่อป้องกันความไม่ต่อเนื่องของข้อมูล
ดังนั้นใน Activity ของเจ้าของบล็อกก็จะมีคำสั่งทั้งหมดดังนี้
Main.java
package app.akexorcist.bluetoothsppsimple;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import app.akexorcist.bluetoothspp.BluetoothSPP;
import app.akexorcist.bluetoothspp.BluetoothSPP.BluetoothConnectionListener;
import app.akexorcist.bluetoothspp.BluetoothSPP.OnDataReceivedListener;
import app.akexorcist.bluetoothspp.BluetoothState;
import app.akexorcist.bluetoothspp.DeviceList;
public class Main extends Activity {
BluetoothSPP bt;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt = new BluetoothSPP(this);
if(!bt.isBluetoothAvailable()) {
Toast.makeText(getApplicationContext(), "Bluetooth is not available"
, Toast.LENGTH_SHORT).show();
finish();
}
bt.setOnDataReceivedListener(new OnDataReceivedListener() {
public void onDataReceived(byte[] data, String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
});
bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
public void onDeviceConnected(String name, String address) {
Toast.makeText(getApplicationContext(), "Connected to " + name + "\n" + address
, Toast.LENGTH_SHORT).show();
}
public void onDeviceDisconnected() {
Toast.makeText(getApplicationContext(), "Connection lost"
, Toast.LENGTH_SHORT).show();
}
public void onDeviceConnectionFailed() {
Toast.makeText(getApplicationContext(), "Unable to connect"
, Toast.LENGTH_SHORT).show();
}
});
Button btnConnect = (Button)findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new OnClickListener(){
public void onClick(View v){
if(bt.getServiceState() == BluetoothState.STATE_CONNECTED) {
bt.disconnected();
} else {
Intent intent = new Intent(getApplicationContext(), DeviceList.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
}
});
}
public void onDestroy() {
super.onDestroy();
bt.stopService();
}
public void onStart() {
super.onStart();
if(!bt.isBluetoothEnabled()) {
Intent intent= new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
} else {
if(!bt.isServiceAvailable()) {
bt.setupService();
bt.startService(BluetoothState.DEVICE_ANDROID);
setup();
}
}
}
public void setup() {
Button btnSend = (Button)findViewById(R.id.btnSend);
btnSend.setOnClickListener(new OnClickListener(){
public void onClick(View v){
bt.send("Text", true);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
if(resultCode == Activity.RESULT_OK)
bt.connect(data);
} else if(requestCode == BluetoothState.REQUEST_ENABLE_BT) {
if(resultCode == Activity.RESULT_OK) {
bt.setupService();
bt.startService(BluetoothState.DEVICE_ANDROID);
setup();
} else {
Toast.makeText(getApplicationContext()
, "Bluetooth was not enabled."
, Toast.LENGTH_SHORT).show();
finish();
}
}
}
}
สำหรับ Layout ที่เจ้าของบล็อกใช้ในตัวอย่างนี้ จะไม่มีอะไรมาก มีแค่ Button 2 อัน อันนึงกดเพื่อไปหน้าเลือกอุปกรณ์แอนดรอยด์ และอีกปุ่มสำหรับส่งข้อความไปทางบลูทูธ
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" >
<Button
android:id="@+id/btnSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Send" />
<Button
android:id="@+id/btnConnect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Connect" />
</RelativeLayout>
และ Android Manifest ของบทความนี้จะไม่ต้องกำหนดอะไร เพราะว่าได้ทำการรวม Android Manifest เข้ากับของไลบรารีแล้ว ทำให้ไม่ต้องประกาศอะไรเพิ่ม เนื่องจากในไลบรารีได้ประกาศไว้แล้ว
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.akexorcist.bluetoothsppsimple"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<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="app.akexorcist.bluetoothsppsimple.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>
</application>
</manifest>
เมื่อเสร็จแล้วก็ลองทดสอบแอปพลิเคชันได้เลย ให้ลองกดเชื่อมต่อกับอุปกรณ์อื่นๆดู จะหาอุปกรณ์แอนดรอยด์มาสองเครื่อง แล้วลงแอปพลิเคชันนี้ไว้ทั้งคู่ แล้วเปิดขึ้นมาทำการเชื่อมต่อกันก็ได้ จากนั้นก็ลองส่งข้อความดู ลองกดยกเลิกการเชื่อมต่อดู แล้วจะเห็นการทำงานต่างๆที่ได้เขียนไว้ในโปรแกรม
สำหรับผู้ที่หลงเข้ามาอ่านคนใดที่ต้องการไฟล์ตัวอย่างสามารถดาวน์โหลดได้จาก
BluetoothSPP Simple [Google Drive]
BluetoothSPP Simple [Github]
BluetoothSPP Simple [Sleeping For Less]
บทความที่เกี่ยวข้อง
• เปลี่ยนเรื่องบลูทูธให้เป็นเรื่องง่ายด้วย BluetoothSPP Library
• การใช้งาน Listener สำหรับบลูทูธใน BluetoothSPP
• การใช้งานการเชื่อมต่ออัตโนมัติในคลาส BluetoothSPP
• การสร้างหน้าเลือกอุปกรณ์ที่จะเชื่อมต่อสำหรับ BluetoothSPP