java 如何通过蓝牙 android studio 发送/接收消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45140098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to send/receive messages via bluetooth android studio
提问by Joshua Payapulli
I am trying to create an app that allows a string to be sent from one Android phone to another. The code for this is provided below. However, it isn't working as I keep getting exceptions from the try catch piece of code under the pairDevice() section. Does anyone know why I might be getting this?
我正在尝试创建一个应用程序,该应用程序允许将字符串从一部 Android 手机发送到另一部。下面提供了此代码。但是,它不起作用,因为我不断从 pairDevice() 部分下的 try catch 代码段中获取异常。有谁知道我为什么会得到这个?
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.ParcelUuid;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
InputStream inStream;
OutputStream outputStream;
private static final int REQUEST_ENABLE_BT = 1;
public void pairDevice() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
Object[] devices = pairedDevices.toArray();
BluetoothDevice device = (BluetoothDevice) devices[0];
ParcelUuid[] uuid = device.getUuids();
try {
BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(uuid[0].getUuid());
socket.connect();
Toast.makeText(this, "Socket connected", Toast.LENGTH_LONG).show();
outputStream = socket.getOutputStream();
inStream = socket.getInputStream();
} catch (IOException e) {
Toast.makeText(this, "Exception found", Toast.LENGTH_LONG).show();
}
}
}
public void SendMessage(View v) {
EditText outMessage = (EditText) findViewById(R.id.editText);
try {
if (outputStream != null)
outputStream.write(outMessage.toString().getBytes());
TextView displayMessage = (TextView) findViewById(R.id.textView);
Scanner s = new Scanner(inStream).useDelimiter("\A");
displayMessage.setText(s.hasNext() ? s.next() : "");
} catch (IOException e) {/*Do nothing*/}
Toast.makeText(this,"No output stream", Toast.LENGTH_LONG).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pairDevice();
}
}
}
回答by rayan
I have made few changes to your app:-
我对您的应用程序进行了一些更改:-
Firstly, I shifted the code responsible for creating the Bluetooth connection to ConnectThread
.
首先,我将负责创建蓝牙连接的代码转移到ConnectThread
.
2) Added AcceptThread
responsible for listening incoming connections and ConnectedThread
maintaining the BTConnection, Sending the data, and
receiving incoming data through input/output streams respectively.
3) Created 2 buttons to start ConnectThread and AcceptThread.
2) 新增AcceptThread
负责监听传入连接和ConnectedThread
维护BTConnection,分别通过输入/输出流发送数据和接收传入数据。3) 创建了 2 个按钮来启动 ConnectThread 和 AcceptThread。
NOTE: Make sure both the devices are paired and the device that you are trying to connect to is at the top of the list(or just remove all the paired devices from both the devices and only pair the devices that you want to connect). Also, you must start the AcceptThread before ConnectThread
注意:确保两个设备都已配对,并且您尝试连接的设备位于列表顶部(或者只是从两个设备中删除所有已配对的设备,只与您要连接的设备配对)。此外,您必须在 ConnectThread 之前启动 AcceptThread
MAINACTIVITY.JAVA
MAINACTIVITY.JAVA
public class MainActivity extends AppCompatActivity {
private static final UUID MY_UUID_INSECURE =
UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
private static final int REQUEST_ENABLE_BT = 1;
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private BluetoothDevice mmDevice;
private UUID deviceUUID;
ConnectedThread mConnectedThread;
private Handler handler;
String TAG = "MainActivity";
EditText send_data;
TextView view_data;
StringBuilder messages;
public void pairDevice(View v) {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
Log.e("MAinActivity", "" + pairedDevices.size() );
if (pairedDevices.size() > 0) {
Object[] devices = pairedDevices.toArray();
BluetoothDevice device = (BluetoothDevice) devices[0];
//ParcelUuid[] uuid = device.getUuids();
Log.e("MAinActivity", "" + device );
//Log.e("MAinActivity", "" + uuid)
ConnectThread connect = new ConnectThread(device,MY_UUID_INSECURE);
connect.start();
}
}
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
public ConnectThread(BluetoothDevice device, UUID uuid) {
Log.d(TAG, "ConnectThread: started.");
mmDevice = device;
deviceUUID = uuid;
}
public void run(){
BluetoothSocket tmp = null;
Log.i(TAG, "RUN mConnectThread ");
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
Log.d(TAG, "ConnectThread: Trying to create InsecureRfcommSocket using UUID: "
+MY_UUID_INSECURE );
tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
} catch (IOException e) {
Log.e(TAG, "ConnectThread: Could not create InsecureRfcommSocket " + e.getMessage());
}
mmSocket = tmp;
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
Log.d(TAG, "run: Closed Socket.");
} catch (IOException e1) {
Log.e(TAG, "mConnectThread: run: Unable to close connection in socket " + e1.getMessage());
}
Log.d(TAG, "run: ConnectThread: Could not connect to UUID: " + MY_UUID_INSECURE );
}
//will talk about this in the 3rd video
connected(mmSocket);
}
public void cancel() {
try {
Log.d(TAG, "cancel: Closing Client Socket.");
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "cancel: close() of mmSocket in Connectthread failed. " + e.getMessage());
}
}
}
private void connected(BluetoothSocket mmSocket) {
Log.d(TAG, "connected: Starting.");
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "ConnectedThread: Starting.");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = mmSocket.getInputStream();
tmpOut = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
final String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
runOnUiThread(new Runnable() {
@Override
public void run() {
view_data.setText(incomingMessage);
}
});
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
public void write(byte[] bytes) {
String text = new String(bytes, Charset.defaultCharset());
Log.d(TAG, "write: Writing to outputstream: " + text);
try {
mmOutStream.write(bytes);
} catch (IOException e) {
Log.e(TAG, "write: Error writing to output stream. " + e.getMessage() );
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
public void SendMessage(View v) {
byte[] bytes = send_data.getText().toString().getBytes(Charset.defaultCharset());
mConnectedThread.write(bytes);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
send_data =(EditText) findViewById(R.id.editText);
view_data = (TextView) findViewById(R.id.textView);
if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
public void Start_Server(View view) {
AcceptThread accept = new AcceptThread();
accept.start();
}
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread(){
BluetoothServerSocket tmp = null ;
// Create a new listening server socket
try{
tmp = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("appname", MY_UUID_INSECURE);
Log.d(TAG, "AcceptThread: Setting up Server using: " + MY_UUID_INSECURE);
}catch (IOException e){
Log.e(TAG, "AcceptThread: IOException: " + e.getMessage() );
}
mmServerSocket = tmp;
}
public void run(){
Log.d(TAG, "run: AcceptThread Running.");
BluetoothSocket socket = null;
try{
// This is a blocking call and will only return on a
// successful connection or an exception
Log.d(TAG, "run: RFCOM server socket start.....");
socket = mmServerSocket.accept();
Log.d(TAG, "run: RFCOM server socket accepted connection.");
}catch (IOException e){
Log.e(TAG, "AcceptThread: IOException: " + e.getMessage() );
}
//talk about this is in the 3rd
if(socket != null){
connected(socket);
}
Log.i(TAG, "END mAcceptThread ");
}
public void cancel() {
Log.d(TAG, "cancel: Canceling AcceptThread.");
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "cancel: Close of AcceptThread ServerSocket failed. " + e.getMessage() );
}
}
}
ACTIVITY_MAIN.XML
ACTIVITY_MAIN.XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpi5.bluethoothshot.MainActivity"
tools:layout_editor_absoluteY="81dp"
tools:layout_editor_absoluteX="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:id="@+id/textView"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="58dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="153dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:onClick="SendMessage"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="22dp"
app:layout_constraintTop_toBottomOf="@+id/editText"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Server"
android:onClick="Start_Server"
android:layout_marginEnd="53dp"
tools:layout_constraintRight_creator="1"
tools:layout_constraintBottom_creator="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginBottom="84dp" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ConnectionREq"
android:onClick="pairDevice"
android:layout_marginStart="34dp"
tools:layout_constraintTop_creator="1"
tools:layout_constraintBottom_creator="1"
app:layout_constraintBottom_toBottomOf="@+id/button2"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/button2"
android:layout_marginLeft="30dp"
app:layout_constraintVertical_bias="0.0" />
</android.support.constraint.ConstraintLayout>
回答by Stanislav Orlov
Exception description will defenitely help, but i'm 99% sure that system prevents you from executing socket connection code inside UI thread - so you need to create a new thread, move your socket creation and socket connection code to that thread and, finally, create a callback, that will indicate listeners that connection was performed or failed.
异常描述肯定会有所帮助,但我 99% 肯定系统会阻止您在 UI 线程内执行套接字连接代码 - 因此您需要创建一个新线程,将您的套接字创建和套接字连接代码移动到该线程,最后,创建一个回调,这将指示连接已执行或失败的侦听器。
Note that android will block most of your attempts to do network-related time-consuming operations inside UI threads, because it makes UI so sloooow ;-)
请注意,android 将阻止您在 UI 线程中执行与网络相关的耗时操作的大部分尝试,因为它使 UI 变得如此缓慢;-)
回答by rayan
TWO MAJOR PROBLEMS-
两个主要问题-
1) connect()
is a blocking call, you should always perform this connection procedure in a thread that is separate from the main activity (UI) thread. You are doing this on the main thread.
1) connect()
是阻塞调用,您应该始终在与主活动 (UI) 线程分开的线程中执行此连接过程。您正在主线程上执行此操作。
Note: You should always call cancelDiscovery() to ensure that the device is not performing device discovery before you call connect(). If discovery is in progress, then the connection attempt is significantly slowed, and it's more likely to fail.
注意:在调用connect() 之前,您应该始终调用cancelDiscovery() 以确保设备未执行设备发现。如果发现正在进行,那么连接尝试会显着减慢,并且更有可能失败。
2) If you are using the same code on the second device too(so that you could send or receive data) then I don't see any call to accept()
. accept()
listens for connection requests.
Again, accept()
call is a blocking call, it should not be executed in the main activity UI thread so that your application can still respond to other user interactions.
2)如果您也在第二台设备上使用相同的代码(以便您可以发送或接收数据),那么我看不到任何对accept()
. accept()
侦听连接请求。同样,accept()
call 是一个阻塞调用,它不应该在主活动 UI 线程中执行,以便您的应用程序仍然可以响应其他用户交互。
Simplified thread for the server component that accepts incoming connections:
接受传入连接的服务器组件的简化线程:
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code.
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) {
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
// Closes the connect socket and causes the thread to finish.
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
Android documentation - BLUETOOTH
Android 文档 -蓝牙