简体   繁体   English

通过多个活动持有android蓝牙连接

[英]Holding android bluetooth connection through multiple activities

I am building an Android app that communicates with an Arduino board via bluetooth, I have the bluetooth code in a class of it's own called BlueComms. 我正在构建一个通过蓝牙与Arduino板通信的Android应用程序,我将蓝牙代码放在一个名为BlueComms的类中。 To connect to the device I use the following methord: 要连接到设备,我使用以下方法:

public boolean connectDevice() {
    CheckBt();
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    Log.d(TAG, "Connecting to ... " + device);
    mBluetoothAdapter.cancelDiscovery();
    try {
        btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
        btSocket.connect();
        outStream = btSocket.getOutputStream();
        Log.d(TAG, "Connection made.");
        return true;

    } catch (IOException e) {
        try {
            btSocket.close();
        } catch (IOException e2) {
            Log.d(TAG, "Unable to end the connection");
            return false;
        }
        Log.d(TAG, "Socket creation failed");
    }
    return false;

}
    private void CheckBt() {
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    if (!mBluetoothAdapter.isEnabled()) {
        System.out.println("Bt dsbld");
    }

    if (mBluetoothAdapter == null) {
        System.out.println("Bt null");
    }
}

This connects fine but as soon as I leave the activity I connected through it drops the connection, showing this through LogCat, 这很好连接,但是一旦我离开我通过它连接的活动就会丢弃连接,通过LogCat显示,

 D/dalvikvm(21623): GC_CONCURRENT freed 103K, 10% free 2776K/3056K, paused 5ms+2ms, total 35ms

I can no longer connect to the device, but if I call killBt() it throws a fatal error and if I try to send data I get a 'Socket creation failed' error. 我不能再连接到设备,但如果我调用killBt()它会抛出一个致命的错误,如果我尝试发送数据,我会收到'Socket creation failed'错误。 My send message code is as follows: 我的发送消息代码如下:

public void sendData(String data, int recvAct) {
    try {
        outStream = btSocket.getOutputStream();
    } catch (IOException e) {
        Log.d(TAG, "Bug BEFORE Sending stuff", e);
    }

    String message = data;
    byte[] msgBuffer = message.getBytes();

    try {
        outStream.write(msgBuffer);
    } catch (IOException e) {
        Log.d(TAG, "Bug while sending stuff", e);
    }
}

How should I go about preventing the connection from being paused by the activity I connect with when I switch a different activity, I am switching activities with this code: 当我切换不同的活动时,我应该如何防止连接被我连接的活动暂停,我正在使用以下代码切换活动:

Intent myIntent = new Intent(v.getContext(), Timelapse.class);
    startActivityForResult(myIntent, 0);

Many Thanks, Rozz 非常感谢,Rozz

Where did you store the instance of your BlueComms class? 你在哪里存储了BlueComms类的实例? If you put it in the first activity then the class instance would have been killed when that activity was destroyed as you left it and moved to the next activity (NB activities also get destroyed on screen rotation) 如果你将它放在第一个活动中,那么当你离开它并移动到下一个活动时该类活动被销毁时类实例就会被杀死(NB活动也会在屏幕旋转时被破坏)

So you need to find a way to keep the instance of BlueComms class alive for as long as you need it. 所以你需要找到一种方法来保持BlueComms类的实例,只要你需要它。 You could pass it between activities via public properties and store it in onRetainNonConfigurationInstance() during rotations. 您可以通过公共属性在活动之间传递它,并在轮换期间将其存储在onRetainNonConfigurationInstance()中。

An easier trick is to create a class that extends Application use it as the application delegate for your app and add public property to it to store the instance of BlueComms class within it. 更简单的技巧是创建一个扩展Application的类,将其用作应用程序的应用程序委托,并向其添加公共属性以在其中存储BlueComms类的实例。 That way the instance of BlueComms class would be alive for the lifetime of you app. 这样,BlueComms类的实例将在你的应用程序的生命周期中存活。

Extend Application 扩展应用程序

import android.app.Application;

public class cBaseApplication extends Application {

    public BlueComms myBlueComms;

    @Override
    public void onCreate() 
    {
        super.onCreate();
        myBlueComms = new BlueComms();
    }

}

Make your class the application delegate in the app manifest 使您的类成为应用程序清单中的应用程序委托

<application
    android:name="your.app.namespace.cBaseApplication"
    android:icon="@drawable/icon"
    android:label="@string/app_name" >

Access the base app from any of your Activities like this 从您的任何活动中访问基本应用程序

((cBaseApplication)this.getApplicationContext()).myBlueComms.SomeMethod();

What I have done is, Created a singleton class for BluetoothConnection. 我所做的是,为BluetoothConnection创建了一个单例类。 So socket creation happens only for one time. 因此套接字创建只发生一次。

When onCreate method of any activity is created, it first fetch instance of BluetoothConnection class. 当创建任何活动的onCreate方法时,它首先获取BluetoothConnection类的实例。

Handler is used to send messages from thread in BluetoothConnection class to the corresponding activity by settings Handler. Handler用于通过设置Handler将来自BluetoothConnection类中的线程的消息发送到相应的活动。

Like: 喜欢:

Class MyBTConnection{
  private static MyBTConnection connectionObj;

  private Handler mHandler;

  public MyBTConnection() { //constructor }

  public static MyBTConnection getInstance() {
    if(connectionObj == null) {
        connectionObj = new MyBTConnection();
    }
     return connectionObj;
    }
  }

  public void setHandler(Handler handler) {
     mHandler = handler;
  }


  ..... Code for Bluetooth Connection ....
  to send message : 
  mHandler.obtainMessage(what).sendToTarget();

}

// in first activity
class MainActivity extends Activity {
     private MyBTConnection connectionObj;

     public onCreate(....) {

         /*
          * Since this is first call for getInstance. A new object
          * of MyBTConnection will be created and a connection to
          * remote bluetooth device will be established.
          */
         connectionObj = MyBTConnection.getInstance();
         connectionObj.setHandler(mHandler);
     }

     private Handler mHandler = new Handler(){
          public void onReceive(...) {
               /// handle received messages here 
          }
     };

}

// in second activity
class SecondActivity extends Activity {

     private MyBTConnection connectionObj;

     public onCreate(....) {

         /*
          * Since this is second call for getInstance.
          * Object for MyBTConnection was already created in previous 
          * activity. So getInstance will return that previously
          * created object and in that object, connection to remote
          * bluetooth device is already established so you can                
          * continue your work here.
          */
         connectionObj = MyBTConnection.getInstance();
         connectionObj.setHandler(mHandler);
     }

     private Handler mHandler = new Handler(){
          public void onReceive(...) {
               /// handle received messages here 
          }
     };
}

I'm currently having exactly the same issue and I was thinking of opening/closing the Bluetooth socket each time an Activity asks for it. 我目前遇到完全相同的问题,每次活动要求时,我都在考虑打开/关闭蓝牙套接字。 Each Activity has it's own BlueComms instance. 每个Activity都有自己的BlueComms实例。

Because my application will became a bit complex and there will be Bluetooth threaded requests from different activities, I'm thinking that this way will become very difficult to use and troubleshoot. 因为我的应用程序会变得有点复杂,并且会有来自不同活动的蓝牙线程请求,我认为这种方式将变得非常难以使用和排除故障。

Another way I came across by reading here... https://developer.android.com/guide/components/services.html 我在这里阅读的另一种方式... https://developer.android.com/guide/components/services.html

A Service can be created on the background having a Bluetooth socket always on. 可以在始终打开蓝牙插槽的背景上创建服务。 All Bluetooth requests can be made using Intent towards this service. 可以使用Intent对此服务进行所有蓝牙请求。 This also creates some fair amount of complexity but feels a lot more tidy and organized. 这也会产生一些相当大的复杂性,但感觉更整洁有序。

I'm currently having this dilemma, either to use a thread for each activity or use a service. 我目前正处于这种困境,要么为每个活动使用线程,要么使用服务。 I don't know which way is actually better. 我不知道哪种方式更好。

When you are Selecting A device to connect and when you are click on the device list item for requesting a connection to the device use AsyncTask and put the connect method inside the AsyncTask like this :- 当您选择要连接的设备时,当您单击设备列表项以请求连接到设备时,请使用AsyncTask并将connect方法放在AsyncTask中,如下所示: -

 AsyncTask.execute(new Runnable() {
                    @Override
                    public void run() {

                        try {

                            bluetoothSocket = Globals.bluetoothDevice.createRfcommSocketToServiceRecord(Globals.DEFAULT_SPP_UUID);
                            bluetoothSocket.connect();

                            // After successful connect you can open InputStream
                       } catch (IOException e) {
                         e.printStackTrace();
                       }


**Here is the full code for the same problem that i have cracked :-**

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
          @Override
          public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

              lablelexconnected.setText("Connecting ...");
              bdDevice = arrayListBluetoothDevices.get(position);
              //bdClass = arrayListBluetoothDevices.get(position)
              //    Toast.makeText(getApplicationContext()," " + bdDevice.getAddress(),Toast.LENGTH_SHORT).show();
              Log.i("Log", "The dvice : " + bdDevice.toString());

              bdDevice = bluetoothAdapter.getRemoteDevice(bdDevice.getAddress());


              Globals.bluetoothDevice = bluetoothAdapter.getRemoteDevice(bdDevice.getAddress());
              System.out.println("Device in GPS Settings : " + bdDevice);
              //       startService(new Intent(getApplicationContext(),MyService.class));

             /* Intent i = new Intent(GpsSettings.this, MyService.class);
              startService(i);*/
              //  finish();


            //  connectDevice();


             AsyncTask.execute(new Runnable() {
                 @Override
                 public void run() {

                     try {

                         bluetoothSocket = Globals.bluetoothDevice.createRfcommSocketToServiceRecord(Globals.DEFAULT_SPP_UUID);
                         bluetoothSocket.connect();

                         // After successful connect you can open InputStream

                         InputStream in = null;
                         in = bluetoothSocket.getInputStream();
                         InputStreamReader isr = new InputStreamReader(in);
                         br = new BufferedReader(isr);

                         while (found == 0) {
                             String nmeaMessage = br.readLine();
                             Log.d("NMEA", nmeaMessage);
                             // parse NMEA messages
                             sentence = nmeaMessage;

                             System.out.println("Sentence : " + sentence);


                             if (sentence.startsWith("$GPRMC")) {
                                 String[] strValues = sentence.split(",");
                                 System.out.println("StrValues : " + strValues[3] + " " + strValues[5] + " " + strValues[8]);
                                 if (strValues[3].equals("") && strValues[5].equals("") && strValues[8].equals("")) {
                                     Toast.makeText(getApplicationContext(), "Location Not Found !!! ", Toast.LENGTH_SHORT).show();

                                 } else {

                                     latitude = Double.parseDouble(strValues[3]);
                                     if (strValues[4].charAt(0) == 'S') {
                                         latitude = -latitude;
                                     }
                                     longitude = Double.parseDouble(strValues[5]);
                                     if (strValues[6].charAt(0) == 'W') {
                                         longitude = -longitude;
                                     }
                                     course = Double.parseDouble(strValues[8]);

                                     //    Toast.makeText(getApplicationContext(), "latitude=" + latitude + " ; longitude=" + longitude + " ; course = " + course, Toast.LENGTH_SHORT).show();
                                     System.out.println("latitude=" + latitude + " ; longitude=" + longitude + " ; course = " + course);
                                 //    found = 1;

                                     NMEAToDecimalConverter(latitude, longitude);


                                 }
                             }


                         }


                     } catch (IOException e) {
                         e.printStackTrace();
                     }


                 }
             });


          }

      });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM