08 February 2014

BluetoothSPP - การใช้งาน Listener

Updated on
        บทความนี้เก่ามากแล้ว และหยุดพัฒนาต่อแล้ว

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


        คราวนี้จะมาพูดถึงการใช้งาน Listener ที่อยู่ในคลาส BluetoothSPP กันบ้าง โดยคลาส BluetoothSPP เจ้าของบล็อกได้ใส่ Listener ต่างๆไว้จำนวนหนึ่งเพื่ออำนวยความสะดวกในการใช้งาน ซึ่งจะมีทั้งหมดดังนี้


BluetoothConnectionListener

        เป็น Listener ที่เอาไว้คอยตรวจจับการเชื่อมต่อบลูทูธ เพื่อให้ผู้นำไปใช้งานสามารถตรวจสอบจากตรงนี้ได้เลยว่า เชื่อมต่อบลูทูธได้แล้วหรือยัง? การเชื่อมต่อล้มเหลวหรือป่าว? มีการยกเลิกการเชื่อมต่อ? โดยจะมีเมธอดภายในอยู่ 3 เมธอดด้วยกัน คือ

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

        onDeviceDisconnected
        เมธอดนี้จะทำงานก็ต่อเมื่ออยู่ในขณะกำลังเชื่อมต่ออยู่ แล้วมีการยกเลิกการเชื่อมต่อ

        onDeviceConnectionFailed
        เมธอดนี้จะทำงานก็ต่อเมื่อกำลังทำการเชื่อมต่อแล้วการเชื่อมต่อล้มเหลว



OnDataReceivedListener

        เป็น Listener ที่เอาไว้คอยตรวจจับการรับข้อมูลที่ส่งเข้ามาทางบลูทูธ โดยจะมีเมธอดภายในแค่ตัวเดียว คือ

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

        โดยทั้งสองพารามิเตอร์นี้มีจุดประสงค์การใช้งานไม่เหมือนกัน ถ้านำไปใช้งานรับส่งข้อมูล Byte ที่ต้องนำไปใช้งานอีกทอดหนึ่ง ก็ควรใช้ข้อมูลแบบ Byte Array แต่ถ้าส่งข้อมูลเป็นแบบข้อความ ASCII ก็ควรใช้ข้อมูลแบบ String



• AutoConnectionListener

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

        onNewConnection 
        เมธอดนี้จะทำงานเมื่อการเชื่อมต่ออัตโนมัติกำลังทำการเชื่อมต่อกับอุปกรณ์ตัวถัดไป สมมติเช่น มีรายชื่ออุปกรณ์อยู่ในเครื่องทั้งหมด 3 ชื่อด้วยกัน เมื่อเริ่มเชื่อมต่อตัวแรก เมธอดนี้ก็จะทำงาน ถ้าเชื่อมต่อไม่สำเร็จก็จะไปเชื่อมต่อตัวถัดไปแทน เมธอดนี้ก็จะทำงานอีกครั้ง ไปเรื่อยๆตลอดการเชื่อมต่ออัตโนมัติจนกว่าจะเชื่อมต่อกับอุปกรณ์ตัวใดๆได้

        โดยจะมีพารามิเตอร์อยู่ด้วยกันสองตัวคือ String ที่เป็นชื่อและ Address ของอุปกรณ์ที่ทำการเชื่อมต่อ ซึ่งคล้ายๆกับ onDeviceConnected เลย (แต่อันนั้นเป็นกรณีที่เชื่อมต่อสำเร็จแล้ว)

        onAutoConnectionStarted
        เมธอดนี้ไม่มีอะไรมาก จะทำงานก็ต่อเมื่อการเชื่อมต่ออัตโนมัติเริ่มทำงานเท่านั้นแหละ ใส่ไว้เผื่อว่ามีผู้ที่หลงเข้ามาอ่านคนใดต้องการจะใช้งาน



BluetoothStateListener

        เป็น Listener ที่เอาไว้ตรวจจับสถานะการทำงานของ Service ของบลูทูธว่ากำลังอยู่ในสถานะใด เพราะว่าการทำงานของ Service ของบลูทูธใน BluetoothSPP จะมีสถานะต่างๆด้วยกันดังนี้

                None : Service ยังไม่ได้ทำอะไร
                Listener : อยู่ในสถานะรอการเชื่อมต่อ
                Connecting : กำลังทำการเชื่อมต่อ
                Connected : เชื่อมต่อกับอุปกรณ์ใดๆอยู่
                Null : Service ยังไม่ได้ถูกสร้างขึ้นมา

        สถานะเหล่านี้จะอยู่ในคลาส BluetoothState ที่เจ้าของบล็อกได้เขียนเอาไว้แล้ว ดังนั้นเวลาตรวจสอบว่าอยู่ในสถานะอะไรก็ให้เทียบกับตัวแปรที่อยู่ในคลาสนี้ได้เลย (เดี๋ยวดูตัวอย่างอีกทีนึง)

        โดยที่ BluetoothStateListener จะมีเมธอดอยู่ภายในเพียง 1 เมธอดเท่านั้น คือ

        onServiceStateChanged
        เมธอดนี้จะทำงานก็ต่อเมื่อ Service มีการเปลี่ยนสถานะการทำงาน โดยมีพารามิเตอร์เป็น Integer บอกให้รู้ว่าอยู่ในสถานะใด โดยต้องไปเทียบกับตัวแปรที่อยู่ในคลาส BluetoothState (วิธีใช้งานรอดูตัวอย่างในตอนท้าย)
             
   
        การประกาศใช้งาน Listener เหล่านี้ก็ประกาศแบบ Anonymous ได้เลย หรือจะ Implement หรือจะประกาศเป็น Object ก็แล้วแต่ แต่เจ้าของบล็อกแบบ Anonymous เพราะชอบกระชับโค๊ดให้สั้นๆ

BluetoothSPP bt = new BluetoothSPP(this);
bt.setBluetoothStateListener(new BluetoothStateListener() {                
    public void onServiceStateChanged(int state) {
        if(state == BluetoothState.STATE_CONNECTED)
            Log.i("Check", "State : Connected");
        else if(state == BluetoothState.STATE_CONNECTING)
            Log.i("Check", "State : Connecting");
        else if(state == BluetoothState.STATE_LISTEN)
            Log.i("Check", "State : Listen");
        else if(state == BluetoothState.STATE_NONE)
            Log.i("Check", "State : None");
    }
});
        
bt.setOnDataReceivedListener(new OnDataReceivedListener() {
    public void onDataReceived(byte[] data, String message) {
        Log.i("Check", "Message : " + message);
    }
});
        
bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
    public void onDeviceConnected(String name, String address) {
        Log.i("Check", "Device Connected!!");
    }

    public void onDeviceDisconnected() {
        Log.i("Check", "Device Disconnected!!");
    }

    public void onDeviceConnectionFailed() {
        Log.i("Check", "Unable to Connected!!");
    }
});
        
bt.setAutoConnectionListener(new AutoConnectionListener() {
    public void onNewConnection(String name, String address) {
        Log.i("Check", "New Connection - " + name + " - " + address);
    }
            
    public void onAutoConnectionStarted() {
        Log.i("Check", "Auto connection started");
    }
});

        โดยเจ้าของบล็อกแนะนำให้ใช้คำสั่งไว้ใน onCreate เลย ต่อจากที่ประกาศ BluetoothSPP เป็นที่เรียบร้อยแล้ว

        ทีนี้ก็ขอยกตัวอย่างการใช้งาน Listener ทั้ง 4 ตัวนี้เลย โดยตอนทดสอบอาจจะไม่เห็นผลการทำงานมากนัก แต่จะยกตัวอย่างวิธีเรียกใช้งานในคำสั่งให้ดูเป็นหลัก ส่วนจะเอาอันไหนไปใช้ก็แล้วแต่งานของผู้ที่หลงเข้ามาอ่าน เพราะไม่จำเป็นต้องเรียกใช้ทั้งหมดนี้ก็ได้

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


Main.java
package app.akexorcist.bluetoothspplistener;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
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.BluetoothStateListener;
import app.akexorcist.bluetoothspp.BluetoothSPP.OnDataReceivedListener;
import app.akexorcist.bluetoothspp.BluetoothState;
import app.akexorcist.bluetoothspp.DeviceList;
import app.akexorcist.bluetoothspp.BluetoothSPP.AutoConnectionListener;
import app.akexorcist.bluetoothspp.BluetoothSPP.BluetoothConnectionListener;

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.setBluetoothStateListener(new BluetoothStateListener() {            
            public void onServiceStateChanged(int state) {
                if(state == BluetoothState.STATE_CONNECTED)
                    Log.i("Check", "State : Connected");
                else if(state == BluetoothState.STATE_CONNECTING)
                    Log.i("Check", "State : Connecting");
                else if(state == BluetoothState.STATE_LISTEN)
                    Log.i("Check", "State : Listen");
                else if(state == BluetoothState.STATE_NONE)
                    Log.i("Check", "State : None");
            }
        });
        
        bt.setOnDataReceivedListener(new OnDataReceivedListener() {
            public void onDataReceived(byte[] data, String message) {
                Log.i("Check", "Message : " + message);
            }
        });
        
        bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
            public void onDeviceConnected(String name, String address) {
                Log.i("Check", "Device Connected!!");
            }

            public void onDeviceDisconnected() {
                Log.i("Check", "Device Disconnected!!");
            }

            public void onDeviceConnectionFailed() {
                Log.i("Check", "Unable to Connected!!");
            }
        });
        
        bt.setAutoConnectionListener(new AutoConnectionListener() {
            public void onNewConnection(String name, String address) {
                Log.i("Check", "New Connection - " + name + " - " + address);
            }
            
            public void onAutoConnectionStarted() {
                Log.i("Check", "Auto connection started");
            }
        });
        
        Button btnConnect = (Button)findViewById(R.id.btnConnect);
        btnConnect.setOnClickListener(new OnClickListener(){
            public void onClick(View v){
                if(bt.getServiceState() == BluetoothState.STATE_CONNECTED) {
                    bt.disconnect();
                } else {
                    Intent intent = new Intent(Main.this, DeviceList.class);
                    startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE); 
                }
            }
        });
    }
    
    public void onDestroy() {
        super.onDestroy();
        bt.stopService();
    }
    
    public void onStart() {
        super.onStart();
        if(!bt.isBluetoothEnabled()) {
            bt.enable();
        } else {
            if(!bt.isServiceAvailable()) { 
                bt.setupService();
                bt.startService(BluetoothState.DEVICE_ANDROID);
                setup();
            }
        }
    }
    
    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();
            } else {
                Toast.makeText(getApplicationContext(), "Bluetooth was not enabled."
                        , Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }
    
    public void setup() { }
}


        ส่วน Layout ก็จะไม่มีอะไร มีแค่ปุ่มเอาไว้เลือกอุปกรณ์ที่จะเชื่อมต่อเท่านั้น

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/btnConnect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="Connect" />

</RelativeLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app.akexorcist.bluetoothspplistener"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="app.akexorcist.bluetoothspplistener.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>

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


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

                BluetoothSPP Listener [GitHub]

                BluetoothSPP Listener [Google Drive]

                BluetoothSPP Listener [Sleeping For Less]



บทความที่เกี่ยวข้อง

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