我是 Android 开发新手,目前我正在使用 STM32 板和 Android 手机之间的蓝牙串行通信,我参考了这些项目Simple Android Bluetooth Application with Arduino Example和蓝牙聊天示例。我的项目有单独的 connectedThread 类、一个 MainActivity 和 Bluetoothactivity 来处理数据和蓝牙连接。BluetoothActivity 可以连接到连接到 stm32 的 HC-06 并接收数据,但是一旦我在 Mainactivity 和 BluetoothActivity 之间切换,连接就会丢失,而且我无法连接到同一设备,我会收到“连接失败”的消息。我已经阅读了很多关于同一问题的问题,即在 BluetoothSocket 关闭活动之间切换时,一些解决方案暗示使用服务,但事情是我不知道如何使用服务或什么是服务。我希望应用程序即使在活动之间切换时也能保持连接请为此提出解决方案。
我的课程如下: MainActivity
public class MainActivity extends AppCompatActivity {
public static final String EXTRA_NAME = "com.example.firstmultiscreen.extra.NAME";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//Go to BluetoothActivity on Button Press
public void Test_window(View v){
Toast.makeText(this, "Opening Bluetooth Activity", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, BluetoothActivity.class);
startActivity(intent);
}
}
ConnectedThread a、b 和 c 变量用于数据包同步
public class ConnectedThread extends Thread {
private BluetoothSocket mmSocket;
private InputStream mmInStream;
private OutputStream mmOutStream;
private final Handler mHandler;
private static final String TAG = "MainActivity";
byte[] buffer_L1 = new byte[2148]; // buffer store for the stream
private static int a,b,c;
public ConnectedThread(BluetoothSocket socket, Handler handler) {
mmSocket = socket;
mHandler = handler;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void run() {
// Keep listening to the InputStream until an exception occurs
while (true)
{
try
{
a=mmInStream.read();
if(a==9)
{
b=mmInStream.read();
if(b==9)
{
c=mmInStream.read();
if(c==9)
{
mmInStream.read(buffer_L1,0,496);
mHandler.obtainMessage(BluetoothActivity.MESSAGE_READ, 248, -1, buffer_L1).sendToTarget();
try{
Thread.sleep(63);
}catch (Exception e){
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String input) {
byte[] bytes = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
private void resetConnection() {
// setState(STATE_NONE);
Log.d(TAG, "reset connection");
if (mmInStream != null) {
try {
mmInStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing inputstream - " + e.getMessage());
}
mmInStream = null;
}
if (mmOutStream != null) {
try {
mmOutStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing outputstream - " + e.getMessage());
}
mmOutStream = null;
}
if (mmSocket != null) {
try {
mmSocket.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing socket - " + e.getMessage());
}
mmSocket = null;
}
}
}
蓝牙活动
public class BluetoothActivity extends Activity implements PopupMenu.OnMenuItemClickListener {
byte[] Buffer = new byte[500];
private final String TAG = MainActivity.class.getSimpleName();
private static final UUID BT_MODULE_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // "random" unique identifier
// #defines for identifying shared types between calling functions
private final static int REQUEST_ENABLE_BT = 1; // used to identify adding bluetooth names
public final static int MESSAGE_READ = 2; // used in bluetooth handler to identify message update
private final static int CONNECTING_STATUS = 3; // used in bluetooth handler to identify message status
// GUI Components
private TextView mBluetoothStatus,mReadBuffer;
private BluetoothAdapter mBTAdapter;
private Set<BluetoothDevice> mPairedDevices;
private ArrayAdapter<String> mBTArrayAdapter;
private Handler mHandler; // Our main handler that will receive callback notifications
private com.example.cme.ConnectedThread mConnectedThread; // bluetooth background worker thread to send and receive data
private BluetoothSocket mBTSocket = null; // bi-directional client-to-client data path
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mBluetoothStatus = (TextView) findViewById(R.id.bluetooth_status);
mReadBuffer = (TextView) findViewById(R.id.read_buffer);
mBTArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
mBTAdapter = BluetoothAdapter.getDefaultAdapter(); // get a handle on the bluetooth radio
// Ask for location permission if not already allowed
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_READ)
{
String readMessage = null;
try
{
readMessage = new String((byte[]) msg.obj, "UTF-8");
Buffer = (byte[]) msg.obj;
mReadBuffer.setText(readMessage);
} catch (Exception e)
{
e.printStackTrace();
}
}
if (msg.what == CONNECTING_STATUS) {
if (msg.arg1 == 1)
mBluetoothStatus.setText("Connected to Device: " + msg.obj);
else
mBluetoothStatus.setText("Connection Failed");
}
}
};
if (mBTArrayAdapter == null) {
// Device does not support Bluetooth
mBluetoothStatus.setText("Status: Bluetooth not found");
Toast.makeText(getApplicationContext(), "Bluetooth device not found!", Toast.LENGTH_SHORT).show();
}
}
public void showMenu(View v) {
PopupMenu popup = new PopupMenu(this, v);
// This activity implements OnMenuItemClickListener
popup.setOnMenuItemClickListener(this);
popup.inflate(R.menu.example_menu);
popup.show();
}
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
bluetoothOn();
return true;
case R.id.item2:
bluetoothOff();
return true;
case R.id.item3:
//listPairedDevices1();
// Initializing a new alert dialog
if (mBTAdapter.isEnabled())
{
ListView listView = new ListView(this);
listView.setAdapter(mBTArrayAdapter); // assign model to view
listView.setOnItemClickListener(mDeviceClickListener);
listPairedDevices();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setView(listView);
final AlertDialog dialog = builder.create();
dialog.show();
} else {
Toast.makeText(this, "Bluetooth is off!!", Toast.LENGTH_SHORT).show();
}
return true;
case R.id.item4:
discover();
return true;
case R.id.item5:
//mConnectedThread.
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void bluetoothOn(){
if (!mBTAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
mBluetoothStatus.setText("Bluetooth enabled");
Toast.makeText(getApplicationContext(),"Bluetooth turned on",Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getApplicationContext(),"Bluetooth is already on", Toast.LENGTH_SHORT).show();
}
}
// Enter here after user selects "yes" or "no" to enabling radio
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent Data) {
// Check which request we're responding to
super.onActivityResult(requestCode, resultCode, Data);
if (requestCode == REQUEST_ENABLE_BT) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
mBluetoothStatus.setText("Enabled");
} else
mBluetoothStatus.setText("Disabled");
}
}
private void bluetoothOff(){
mBTAdapter.disable(); // turn off
mBluetoothStatus.setText("Bluetooth disabled");
Toast.makeText(getApplicationContext(),"Bluetooth turned Off", Toast.LENGTH_SHORT).show();
}
private void discover(){
// Check if the device is already discovering
if(mBTAdapter.isDiscovering()){
mBTAdapter.cancelDiscovery();
Toast.makeText(getApplicationContext(),"Discovery stopped",Toast.LENGTH_SHORT).show();
}
else{
if(mBTAdapter.isEnabled()) {
mBTArrayAdapter.clear(); // clear items
mBTAdapter.startDiscovery();
Toast.makeText(getApplicationContext(), "Discovery started", Toast.LENGTH_SHORT).show();
registerReceiver(blReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
else{
Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
}
}
}
final BroadcastReceiver blReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// add the name to the list
mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress());
mBTArrayAdapter.notifyDataSetChanged();
}
}
};
private void listPairedDevices(){
mBTArrayAdapter.clear();
mPairedDevices = mBTAdapter.getBondedDevices();
if(mBTAdapter.isEnabled()) {
// put it's one to the adapter
for (BluetoothDevice device : mPairedDevices)
mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress());
Toast.makeText(getApplicationContext(), "Show Paired Devices", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
}
private final AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(!mBTAdapter.isEnabled()) {
Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
return;
}
mBluetoothStatus.setText("Connecting...");
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) view).getText().toString();
final String address = info.substring(info.length() - 17);
final String name = info.substring(0,info.length() - 17);
// Spawn a new thread to avoid blocking the GUI one
new Thread()
{
@Override
public void run() {
boolean fail = false;
BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
try {
mBTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
mBTSocket.connect();
} catch (IOException e) {
try {
fail = true;
mBTSocket.close();
mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if(!fail) {
mConnectedThread = new com.example.cme.ConnectedThread(mBTSocket, mHandler);
mConnectedThread.start();
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
};
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", UUID.class);
return (BluetoothSocket) m.invoke(device, BT_MODULE_UUID);
} catch (Exception e) {
Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
return device.createRfcommSocketToServiceRecord(BT_MODULE_UUID);
}
}