Dowemo
0 0 0 0


Question:

Question:
How can I manage (Connect, Read, Write, Disconnect) a bluetooth connection that persists through configuration changes?

Prefer solutions that are compatible with device version 2.2 "Froyo" using ActionBarSherlock.

Problems...

  • Neither BluetoothDevice nor BluetoothSocket can be retained in onSaveState.

  • In order to keep my app responsive, the 12 second blocking call BluetoothSocket.connect() must be made on a separate thread. Starting a Runnable is the recommended way to thread long tasks, but it's a nightmare trying to recover on a configuration change. The official docs point to three different solutions.

    • Use getLastNonConfigurationInstance(), which is deprecated (seriously?!).

    • Set android:configChanges="keyboardHidden|orientation" like the BluetoothChat Sample. However, this does not account for all types of configuration changes.

    • Cancel & restart tasks like the Shelves Example. In this case, this could potentially waste another 12 seconds.

Update 1

  • Further research led me to asyncTaskLoader, but it seems like this can only update the UI on completion, and cannot provide updates.

  • The BluetoothHDP sample uses a service. Services seem focused on inter-process communication and the need to persist beyond the activity life-cycle. I don't need either of these features.

Update 2

As pointed out by Reuben, Fragment.setRetainInstance(bool) has replaced the deprecated getLastNonConfigurationInstance(). At this point, it seems like the best option is to make a persistent non-UI fragment using setRetainInstance(true).


Best Answer:


There's a bunch of solutions to this. If you're not using Fragments then the simplest option is to override onRetainNonConfigurationInstance(). Never mind that the API is deprecated, that's only because they want you to use Fragments (where, to be fair, Fragment.setRetainInstance() makes this whole issue the no-brainer it should always have been). This API won't be going anywhere for a long time.

What I'd do is override onRetainNonConfiguration() to return 'this', i.e. a reference to the dead Activity instance, and then copy over the object refs you need from onCreate(), i.e. :

Object obj = getLastNonConfigurationInstance();
if (obj != null) {
    MyActivity deadActivity = (MyActivity)obj;
    this.foo = deadActivity.foo;
    this.bar = deadActivity.bar;
    ...
}

Alternatively you could use a Service, but I personally dislike them. Useful for doing cross-process stuff, no doubt, but otherwise they're a solution in search of a problem.

Lastly, as a general point of order you can safely stuff 'global' data into your Application context. To do this you subclass android.app.Application and use the <application android:name="MyApp"> attribute in your manifest. It's useful to also keep a ref to the Application object in global static data here, so AsyncTasks and other context-less code can always get to the Application context without having to pass Context parameters around for no reason.

class MyApp extends Application {
...
    public static MyApp context;
    ...
    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
        ... set up global data here ...
    }
...
}



Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs