요즘은 스마트폰과 블루투스 기기를 연결하는 상황이 흔하게 일어난다.
스마트폰은 기본적으로 블루투스 기능이 탑재되어 있으므로 블루투스 기능이 들어간 다른 디바이스와 연결하는 것을 구현해보고자 한다.
개발 환경
Android Studio : Arctic Fox 2020.3.1 버전
SDK/ API Level : Android 12/ 31 ( Arctic Fox 버전으로 업데이트해야 Android12/ API 31레벨을 사용할 수 있다)
Java : 1.8.xx
Android 12, 블루투스 권한 업데이트
기존에 블루투스 기능을 사용하기 위해서 선언되는 Permission은 다음과 같았다.
- BLUETOOTH
- BLUETOOTH_ADMIN
- ACCESS_FINE_LOCATION
그러나, Android 12가 출시되면서 블루투스 권한에 대한 업데이트가 이루어졌다.
블루투스 기능을 사용하기 위해 위치 접근 권한인 ACCESS_FINE_LOCATION을 설정해주었다면, 앞으로는 그러지 않아도 되도록 개선되었다.
안드로이드 공식 개발자 문서에서는 다음과 같이 블루투스 권한 변경에 대한 설명을 친절하게 해주고 있다.
사용 클래스
BluetoothAdapter
: 로컬 블루투스 장치를 추상화 한 클래스이다.
장치 검색 시작, 연결된 장치 목록 쿼리 등 Bluetooth의 기본적인 작업을 수행할 수 있게 해주는 역할을 한다.
BluetoothDevice
: 원격 블루투스를 추상화 해 놓은 클래스로써 블루투스 장치의 이름, 주소 등과 같은 정보를 얻고, 소켓 연결을 하는 데 사용한다.
BluetoothSocket
: 블루투스 연결과 통신에 실질적인 역할을 하는 클래스이다. 클라이언트 단에서 사용하는 소켓 클래스이다.
코드 분석
전역 변수
먼저, BluetoothAcitivity라는 새로운 화면을 생성해주고, 전역으로 다음과 같은 변수들을 선언해준다.
이 포스팅에서는 블루투스 연결과 관련된 클래스 변수를 잘 이해하고 파악하는 것이 중요하다.
선언된 변수 클래스 중, ConnectedBluetoothThread
에 대해서는 아래에 자세히 나와있다.
public class BluetoothActivity extends AppCompatActivity {
// UI 컴포넌트
TextView mTvBluetoothStatus;
TextView mTvReceiveData;
TextView mTvSendData;
Button mBtnBluetoothOn;
Button mBtnBluetoothOff;
Button mBtnConnect;
Button mBtnSendData;
Button mBtnSendBody;
// 블루투스 연결 관련 변수
BluetoothAdapter mBluetoothAdapter;
Set<BluetoothDevice> mPairedDevices;
List<String> mListPairedDevices;
Handler mBluetoothHandler;
ConnectedBluetoothThread mThreadConnectedBluetooth;
BluetoothDevice mBluetoothDevice;
BluetoothSocket mBluetoothSocket;
// 상수 및 통신UUID 선언
final static int BT_REQUEST_ENABLE = 1;
final static int BT_MESSAGE_READ = 2;
final static int BT_CONNECTING_STATUS = 3;
final static UUID BT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
OnCreat() 메서드
많이 봐와서 알겠지만 Activity 화면이 생성될 때의 처리 과정을 담는 곳이다.
xml로 작성된 UI컴포넌트와 자바파일을 연결해주는 작업이 여기서 이루어진다.
그 이외에도 이벤트 메서드나 핸들러를 선언해주는 작업도 보통 여기서 이루어진다.
이벤트 메서드는 람다식을 이용해서 코드라인을 최소화시켜봤다.
각 버튼 클릭마다 이벤트 메서드를 걸어주고, mBluetoothHandler
라는 핸들러를 선언한다.
핸들러는 handleMessage(Message msg)
를 통해 핸들러가 받아온 메시지가 BT_MESSAGE_READ
에 해당하는 값일 경우,
메시지를 String으로 변환해주고나서 변환된 String 값을 텍스트뷰에 출력해준다.
핸들러의 동작은 아래에서 스레드가 구현되는 부분에서 확인할 수 있다.
@SuppressLint("HandlerLeak")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
mTvBluetoothStatus = findViewById(R.id.tvBluetoothStatus);
mTvReceiveData = findViewById(R.id.tvReceiveData);
mTvSendData = findViewById(R.id.tvSendData);
mBtnBluetoothOn = findViewById(R.id.btnBluetoothOn);
mBtnBluetoothOff = findViewById(R.id.btnBluetoothOff);
mBtnConnect = findViewById(R.id.btnConnect);
mBtnSendData = findViewById(R.id.btnSendData);
mBtnSendBody = findViewById(R.id.btnSendBody);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBtnBluetoothOn.setOnClickListener(view -> bluetoothOn());
mBtnBluetoothOff.setOnClickListener(view -> bluetoothOff());
mBtnConnect.setOnClickListener(view -> listPairedDevices());
mBtnSendData.setOnClickListener(view -> {
if(mThreadConnectedBluetooth != null) {
mThreadConnectedBluetooth.write(mTvSendData.getText().toString());
mTvReceiveData.append("나 : " + mTvSendData.getText().toString() + "\n");
mTvSendData.setText("");
}
});
mBtnSendBody.setOnClickListener(view -> {
if(mThreadConnectedBluetooth != null){
mThreadConnectedBluetooth.write(dataSet);
mTvReceiveData.append("나 : " + dataSet + "\n");
}
});
mBluetoothHandler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == BT_MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
mTvReceiveData.append("상대방 : " + readMessage + "\n");
}
}
};
}
onDestroy()
화면이 사라지면 실행되는 메서드이다.
여기에 쓰인 mThreadConnectedBluetooth.cancel() 에 대한 설명은 아래에서 다룰 예정이다.
@Override
protected void onDestroy() {
super.onDestroy();
mThreadConnectedBluetooth.cancel();
}
bluetoothOn() / bluetoothOff()
각각 블루투스 기능을 활성화하고, 비활성화 하는 메서드이다.
BluetoothAdapter 객체인 mBluetoothAdapter
가 null값인 경우, 블루투스를 지원하지 않는 것으로 토스트메시지 출력 처리를 해두었다.
null값이 아닌 경우에는 isEnabled()
메서드를 통해 블루투스 사용 여부를 판단해서 알맞게 처리해주었다.
비활성화 메서드 또한 isEnabled()
메서드를 통해 블루투스 사용 여부를 판단해서 적절하게 처리해주었다.
// 블루투스 활성화 메서드
void bluetoothOn() {
if(mBluetoothAdapter == null) {
Toast.makeText(getApplicationContext(), "블루투스를 지원하지 않는 기기입니다.", Toast.LENGTH_LONG).show();
}
else {
if (mBluetoothAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "블루투스가 이미 활성화 되어 있습니다.", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("활성화");
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 활성화 되어 있지 않습니다.", Toast.LENGTH_LONG).show();
Intent intentBluetoothEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intentBluetoothEnable, BT_REQUEST_ENABLE);
}
}
}
// 블루투스 비활성화 메서드
void bluetoothOff() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
Toast.makeText(getApplicationContext(), "블루투스가 비활성화 되었습니다.", Toast.LENGTH_SHORT).show();
mTvBluetoothStatus.setText("비활성화");
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 이미 비활성화 되어 있습니다.", Toast.LENGTH_SHORT).show();
}
}
onActivityResult()
앞서 설명했듯이 블루투스를 사용하기 위해서는 권한 설정이 필요하다.
권한을 사용하는 Activity로 넘어오게 되면 해당 권한에 대한 허용을 위한 팝업메시지가 뜨게 되는데, 그 메시지 창에서 확인 여부를 전달해주는 메서드라고 생각하면 된다.
// 권한 설정 페이지에서의 결과를 전송하는 Result 메서드
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == BT_REQUEST_ENABLE) {
if (resultCode == RESULT_OK) { // 블루투스 활성화를 확인을 클릭하였다면
Toast.makeText(getApplicationContext(), "블루투스 활성화", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("활성화");
} else if (resultCode == RESULT_CANCELED) { // 블루투스 활성화를 취소를 클릭하였다면
Toast.makeText(getApplicationContext(), "취소", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("비활성화");
}
}
super.onActivityResult(requestCode, resultCode, data);
}
listPairedDevices()
현재 디바이스와 이미 페어링 되어있는 블루투스 기기를 보여주는 메서드이다.
mPairedDevices
는 BluetoothDevice타입을 가진 Set 객체이다.
여기에 로컬 블루투스 기기에 붙어있는 기기를 가져오는 getBondedDevices()
메서드를 통해 값을 반환받는다.size()
를 통해 객체의 크기를 확인하고, 0보다 클 경우에 AlertDialog를 통해 장치를 선택할 수 있는 리스트뷰 형태의 다이얼로그를 만들어준다.
List<String>타입으로 선언했던 mListPairedDevices
를 인스턴스화 시켜주고 for문을 통해 mPairedDevices
에 저장된 디바이스를 리스트에 추가해준다.
CharSequence 타입의 배열인 items
에 mListPairedDevices.size()
를 통해 페어링된 기기의 갯수만큼 배열을 만들어 저장한다.
다이얼로그를 만들기 위해 사용한 builder를 통해 해당 items
를 다이얼로그에 추가해주면서, 이벤트 메서드를 통해 클릭된 item에 한해서 connectSelectedDevice()
메서드가 작동하도록 세팅한다.
// 페어링 된 기기를 보여주는 메서드
void listPairedDevices() {
if (mBluetoothAdapter.isEnabled()) {
mPairedDevices = mBluetoothAdapter.getBondedDevices();
if (mPairedDevices.size() > 0) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("장치 선택");
mListPairedDevices = new ArrayList<String>();
for (BluetoothDevice device : mPairedDevices) {
mListPairedDevices.add(device.getName());
//mListPairedDevices.add(device.getName() + "\n" + device.getAddress());
}
final CharSequence[] items = mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
builder.setItems(items, (dialog, item) -> connectSelectedDevice(items[item].toString()));
AlertDialog alert = builder.create();
alert.show();
} else {
Toast.makeText(getApplicationContext(), "페어링된 장치가 없습니다.", Toast.LENGTH_LONG).show();
}
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 비활성화 되어 있습니다.", Toast.LENGTH_SHORT).show();
}
connectSelectedDevice(String selectedDeviceName)
위에서 선택된 item을 클릭했을 경우 실행되는 메서드로, 블루투스 기기를 연결하는 작업이 이루어진다.
mPairedDevice
에 저장된 디바이스를 계속 타면서 선택했던 디바이스 이름과 저장된 디바이스의 이름이 일치하는 경우를 찾는다. 일치하는 디바이스를 찾으면 원격 블루투스 기기인 mBluetoothDeivce
에 해당 디바이스에 대한 정보를 저장하고 break문을 통해 빠져나온다.
그런 뒤에 선택된 디바이스에 RFCOMM통신을 위한 소켓을 반환하여 mBluetoothSocket
에 저장한다.
얻어온 소켓을 통해 기기와 연결을 시도하고, 아래에서 설명 할 블루투스 통신 스레드인 mThreadConnectedBluetooth
를 작동시킨다.
// 블루투스 기기 연결을 위한 메서드
void connectSelectedDevice(String selectedDeviceName) {
for(BluetoothDevice tempDevice : mPairedDevices) {
if (selectedDeviceName.equals(tempDevice.getName())) {
mBluetoothDevice = tempDevice;
break;
}
}
try {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(BT_UUID);
mBluetoothSocket.connect();
mThreadConnectedBluetooth = new ConnectedBluetoothThread(mBluetoothSocket);
mThreadConnectedBluetooth.start();
mBluetoothHandler.obtainMessage(BT_CONNECTING_STATUS, 1, -1).sendToTarget();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "블루투스 연결 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
Log.e( "Error Reason", e.toString());
}
}
class : ConnectedBluetoothThread
블루투스 양방향 실시간 통신을 위해 별도로 생성한 스레드 클래스이다.
BluetoothSocket을 매개변수로 갖는 생성자를 선언해준다. 직전에 블루투스 기기에서 얻어온 소켓이 이 매개변수로 전달된다.
해당 소켓의 InputStream과 OutputStream을 통신에 사용할 Stream들과 연결해준다.
// 블루투스 연결 및 통신 스레드
private class ConnectedBluetoothThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
// 스레드 생성자
public ConnectedBluetoothThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "소켓 연결 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// run() 메서드
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.available();
if (bytes != 0) {
SystemClock.sleep(100);
bytes = mmInStream.available();
bytes = mmInStream.read(buffer, 0, bytes);
mBluetoothHandler.obtainMessage(BT_MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
} catch (IOException e) {
break;
}
}
}
public void write(String str) {
byte[] bytes = str.getBytes();
try {
mmOutStream.write(bytes);
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "데이터 전송 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "소켓 해제 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
}
}
전체 소스 코드
블루투스 기능 구현을 위한 BluetoothActivity의 전체 소스 코드이다.
package com.example.accuniq.Activity;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.room.Room;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.accuniq.DB.AppDatabase;
import com.example.accuniq.DTO.BodyComposition;
import com.example.accuniq.R;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class BluetoothActivity extends AppCompatActivity {
TextView mTvBluetoothStatus;
TextView mTvReceiveData;
TextView mTvSendData;
Button mBtnBluetoothOn;
Button mBtnBluetoothOff;
Button mBtnConnect;
Button mBtnSendData;
Button mBtnSendBody;
BluetoothAdapter mBluetoothAdapter;
Set<BluetoothDevice> mPairedDevices;
List<String> mListPairedDevices;
Handler mBluetoothHandler;
ConnectedBluetoothThread mThreadConnectedBluetooth;
BluetoothDevice mBluetoothDevice;
BluetoothSocket mBluetoothSocket;
final static int BT_REQUEST_ENABLE = 1;
final static int BT_MESSAGE_READ = 2;
final static int BT_CONNECTING_STATUS = 3;
final static UUID BT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
@SuppressLint("HandlerLeak")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
mTvBluetoothStatus = findViewById(R.id.tvBluetoothStatus);
mTvReceiveData = findViewById(R.id.tvReceiveData);
mTvSendData = findViewById(R.id.tvSendData);
mBtnBluetoothOn = findViewById(R.id.btnBluetoothOn);
mBtnBluetoothOff = findViewById(R.id.btnBluetoothOff);
mBtnConnect = findViewById(R.id.btnConnect);
mBtnSendData = findViewById(R.id.btnSendData);
mBtnSendBody = findViewById(R.id.btnSendBody);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBtnBluetoothOn.setOnClickListener(view -> bluetoothOn());
mBtnBluetoothOff.setOnClickListener(view -> bluetoothOff());
mBtnConnect.setOnClickListener(view -> listPairedDevices());
mBtnSendData.setOnClickListener(view -> {
if(mThreadConnectedBluetooth != null) {
mThreadConnectedBluetooth.write(mTvSendData.getText().toString());
mTvReceiveData.append("나 : " + mTvSendData.getText().toString() + "\n");
mTvSendData.setText("");
}
});
mBtnSendBody.setOnClickListener(view -> {
if(mThreadConnectedBluetooth != null){
mThreadConnectedBluetooth.write(dataSet);
mTvReceiveData.append("나 : " + dataSet + "\n");
}
});
mBluetoothHandler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == BT_MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
mTvReceiveData.append("상대방 : " + readMessage + "\n");
}
}
};
}
@Override
protected void onDestroy() {
super.onDestroy();
mThreadConnectedBluetooth.cancel();
}
// 블루투스 활성화 메서드
void bluetoothOn() {
if(mBluetoothAdapter == null) {
Toast.makeText(getApplicationContext(), "블루투스를 지원하지 않는 기기입니다.", Toast.LENGTH_LONG).show();
}
else {
if (mBluetoothAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "블루투스가 이미 활성화 되어 있습니다.", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("활성화");
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 활성화 되어 있지 않습니다.", Toast.LENGTH_LONG).show();
Intent intentBluetoothEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intentBluetoothEnable, BT_REQUEST_ENABLE);
}
}
}
// 블루투스 비활성화 메서드
void bluetoothOff() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
Toast.makeText(getApplicationContext(), "블루투스가 비활성화 되었습니다.", Toast.LENGTH_SHORT).show();
mTvBluetoothStatus.setText("비활성화");
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 이미 비활성화 되어 있습니다.", Toast.LENGTH_SHORT).show();
}
}
// 권한 설정 페이지에서의 결과를 전송하는 Result 메서드
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == BT_REQUEST_ENABLE) {
if (resultCode == RESULT_OK) { // 블루투스 활성화를 확인을 클릭하였다면
Toast.makeText(getApplicationContext(), "블루투스 활성화", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("활성화");
} else if (resultCode == RESULT_CANCELED) { // 블루투스 활성화를 취소를 클릭하였다면
Toast.makeText(getApplicationContext(), "취소", Toast.LENGTH_LONG).show();
mTvBluetoothStatus.setText("비활성화");
}
}
super.onActivityResult(requestCode, resultCode, data);
}
// 페어링 된 기기를 보여주는 메서드
void listPairedDevices() {
if (mBluetoothAdapter.isEnabled()) {
mPairedDevices = mBluetoothAdapter.getBondedDevices();
if (mPairedDevices.size() > 0) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("장치 선택");
mListPairedDevices = new ArrayList<String>();
for (BluetoothDevice device : mPairedDevices) {
mListPairedDevices.add(device.getName());
//mListPairedDevices.add(device.getName() + "\n" + device.getAddress());
}
final CharSequence[] items = mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
builder.setItems(items, (dialog, item) -> connectSelectedDevice(items[item].toString()));
AlertDialog alert = builder.create();
alert.show();
} else {
Toast.makeText(getApplicationContext(), "페어링된 장치가 없습니다.", Toast.LENGTH_LONG).show();
}
}
else {
Toast.makeText(getApplicationContext(), "블루투스가 비활성화 되어 있습니다.", Toast.LENGTH_SHORT).show();
}
}
// 블루투스 기기 연결을 위한 메서드
void connectSelectedDevice(String selectedDeviceName) {
for(BluetoothDevice tempDevice : mPairedDevices) {
if (selectedDeviceName.equals(tempDevice.getName())) {
mBluetoothDevice = tempDevice;
break;
}
}
try {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(BT_UUID);
mBluetoothSocket.connect();
mThreadConnectedBluetooth = new ConnectedBluetoothThread(mBluetoothSocket);
mThreadConnectedBluetooth.start();
mBluetoothHandler.obtainMessage(BT_CONNECTING_STATUS, 1, -1).sendToTarget();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "블루투스 연결 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
Log.e( "Error Reason", e.toString());
}
}
// 블루투스 연결 및 통신 스레드
private class ConnectedBluetoothThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
// 스레드 생성자
public ConnectedBluetoothThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "소켓 연결 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// run() 메서드
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.available();
if (bytes != 0) {
SystemClock.sleep(100);
bytes = mmInStream.available();
bytes = mmInStream.read(buffer, 0, bytes);
mBluetoothHandler.obtainMessage(BT_MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
} catch (IOException e) {
break;
}
}
}
public void write(String str) {
byte[] bytes = str.getBytes();
try {
mmOutStream.write(bytes);
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "데이터 전송 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "소켓 해제 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
}
}
}
}
✍ 포스팅을 마치며...
- 21년 4월 쯤, 졸업 작품을 제출하기 위해 블루투스 통신을 하는 앱을 만든 적이 있는데, 이와 비슷한 코드를 사용해서 만들었던 것이 기억난다. (복붙만 했던 내 자신 반성하자...)
- 블루투스 통신을 구현하면서 생각했던 것 보다 식견이 넓어지는 느낌을 받았다.
👀 Reference
Android developers : 기능 및 API 개요
BugWhale님의 블로그 : 안드로이드 블루투스 애플리케이션 만들기
'Programming > Java' 카테고리의 다른 글
[Java/ Android] NDK를 활용한 C/C++ 라이브러리 사용하기 (0) | 2021.12.21 |
---|