7

问题:
如何管理(连接、读取、写入、断开)通过配置更改持续存在的蓝牙连接?

首选与使用ActionBarSherlock的设备版本 2.2 "Froyo" 兼容的解决方案。

问题...

  • BluetoothDevice不能也BluetoothSocket不能保留在onSaveState.

  • 为了让我的应用程序保持响应,12 秒的阻塞调用BluetoothSocket.connect()必须在单独的线程上进行。启动 aRunnable是线程化长任务的推荐方法,但尝试在配置更改时恢复是一场噩梦。官方文档指出了三种不同的解决方案。

更新 1

  • 进一步的研究使我找到了asyncTaskLoader,但似乎这只能在完成时更新 UI,而不能提供更新。

  • BluetoothHDP 示例使用服务。服务似乎专注于进程间通信以及在活动生命周期之外持续存在的需要。我不需要这些功能中的任何一个。

更新 2

正如 Reuben 所指出的Fragment.setRetainInstance(bool)已经取代了已弃用的getLastNonConfigurationInstance()。在这一点上,似乎最好的选择是使用setRetainInstance(true).

4

4 回答 4

8

我将通过使用Service可以处理您的蓝牙连接的方法来解决此问题,并按照此答案中的说明使该服务与您的 Activity 对话。

然后,您可以使用 ASyncTask 简单地显示/隐藏对话框,并在轮换时取消/重新启动 ASyncTasks,Shelves Example正如您提到的那样。

服务并没有那么可怕,它可能是解决您问题的最佳工具。

于 2013-03-31T16:16:34.197 回答
4

切勿将 App 模型(逻辑或数据)放在 Visual/UI 组件中。如您所见,它们来来去去,并发生变化。

存放非 UI 相关内容的地方,例如数据收集、实时连接、线程等:

  • 应用程序类。包含所有其他组件的生命周期。几乎就像一个全球单身人士。您可以将其用于临时存储。

例子:

public class App extends Application {

  private static Beer sBeer;

  public static void brbHoldMyBeer(Beer b){
    sBeer = b;
  }

  public static Beer imBackWheresMyBeer(){
    return sBeer;
  }

}

此外,在 Application 类中拥有一个静态线程 Executor 服务,将有助于保留正在运行的任务。

  • 正在运行的后台服务。哪些活动、片段等可以绑定/取消绑定,并发布命令/请求。这是应用范围内运行的进程和数据的推荐位置。

  • 一个非视觉片段,带有setRetainInstance(true). 这里的非可视化意味着它是一个附加到 Activity 但不显示任何视图的虚拟片段。它只是用作 Activity 的可保留对象持有者。这建议用于活动范围的流程和数据。

于 2013-04-05T18:41:20.933 回答
2

您可以尝试使用可以处理所有内容并在必要时调用主要活动的单例模式。

所以这是获取 MySingleton 对象实例的一种静态方法,每次调用 getInstance 时都是同一个实例。您可以在其中“存储”所有蓝牙对象,它不会被破坏并且可以从每个活动中访问。

public class MySingleton { 
    private static MySingleton instance; 
    public static MySingleton getInstance() { 
        if (null == instance) { 
            instance = new MySingleton(); 
        } 
    return instance; 
} 

    private MySingleton() { 
    } 
}
于 2013-03-31T16:21:43.323 回答
1

有很多解决方案。如果您不使用 Fragments,那么最简单的选择是覆盖 onRetainNonConfigurationInstance()。不要介意 API 已被弃用,这只是因为他们希望您使用 Fragments(公平地说,Fragment.setRetainInstance() 使整个问题成为理所当然的事情)。这个 API 很长一段时间都不会去任何地方。

我要做的是覆盖 onRetainNonConfiguration() 以返回“this”,即对死 Activity 实例的引用,然后从 onCreate() 复制您需要的对象引用,即:

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

或者,您可以使用服务,但我个人不喜欢它们。毫无疑问,这对于做跨进程的东西很有用,但除此之外,它们是寻找问题的解决方案。

最后,作为一般顺序,您可以安全地将“全局”数据填充到您的应用程序上下文中。为此,您将 android.app.Application 子类化并在清单中使用 <application android:name="MyApp"> 属性。在此处在全局静态数据中保留对 Application 对象的引用也很有用,因此 AsyncTasks 和其他无上下文代码始终可以访问 Application 上下文,而无需无缘无故地传递 Context 参数。

class MyApp extends Application {
...

    public static MyApp context;
    ...

    @Override
    public void onCreate() {
        super.onCreate();

        context = this;

        ... set up global data here ...
    }
...
}
于 2013-03-31T16:32:21.910 回答