【问题标题】:Is there a way to have getSystemService() return a completely new instance every time in Android?有没有办法让 getSystemService() 在 Android 中每次都返回一个全新的实例?
【发布时间】:2016-02-09 00:23:45
【问题描述】:

在 Android Wear 中,使用 SensorManager 重复注册和取消注册 SensorEventListener 会导致 SensorManager 失败。我想知道是否有一种方法可以在每次加载片段时获取 SensorManager 的新实例。这样我就可以获得一个新的 SensorManager,注册我的侦听器,并在 Fragment 销毁时取消注册它们,然后取消引用该 SensorManager 并在下次加载 Fragment 时获取一个新的。

在我的片段中,我目前正在这样做:

@Override
public View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    // ... 
    mSensorMgr = (SensorManager) mMainWearActivity.getSystemService(Activity.SENSOR_SERVICE);
    // ...
}

private void startListening(){

    yGesture.setOnShakeListener(yListener);
    xGesture.setOnShakeListener(xListener);
    mSensorMgr.registerListener(yGesture, mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL);
    mSensorMgr.registerListener(xGesture, mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
public void onResume(){
    super.onResume();
    startListening();
}

@Override
public void onPause(){
    stopListening();
    super.onPause();
}

private void stopListening(){

    mSensorMgr.unregisterListener(yGesture);
    mSensorMgr.unregisterListener(xGesture);
    mSensorMgr = null;
}

我需要mSensorMgr = (SensorManager) mMainWearActivity.getSystemService(Activity.SENSOR_SERVICE); 来返回一个新实例,否则多次注册和注销监听器会使 SensorManager 失败。这可能吗?最好不必创建一个新的 Activity 并坚持使用片段。谢谢

编辑:

我已将使用 sensorManager 注册侦听器转移到 onResume(),但同样的问题仍然存在。这是 Android Wear 框架中的错误吗?

【问题讨论】:

  • 为什么你不做 startListening();在onResume() 中,如果您在onPause() 中执行 stopListening() ?
  • @Boris_Treukhov OnCreateView() 在 Fragment 生命周期中的 onResume() 之前调用,所以我只是在创建视图后调用它,而不是接下来的几个方法。没有区别。

标签: android android-sensors sensormanager


【解决方案1】:

一般来说,您总是希望使用正确配对的 Activity 或 Fragment 生命周期方法来注册和注销任何类型的侦听器。所以你会使用创建/销毁,或启动/停止,或恢复/暂停。

在您的特定情况下,您在 onCreateView 中注册,对于片段实例仅调用一次 ,但是,您的取消注册是在 onPause 期间发生的,这可能会被多次调用。一旦这个片段因任何原因暂停(并且有很多原因可能发生这种情况),您的听众将永远消失,直到创建片段的新实例。

因此,您可能需要考虑使用创建/销毁或启动/停止,具体取决于您尝试对片段中的侦听器执行的操作。如果你不明白这些生命周期方法,请学习here

【讨论】:

  • onCreateView() 是否只为片段调用一次,即使它被放在后台堆栈或被替换?我认为如果片段被替换,它的视图会被破坏,然后一旦它从后台堆栈中弹出,它的视图将使用 onCreateView() - > onViewCreated() 重新绘制?我需要在替换片段时取消注册侦听器,并在从 backStack 弹出片段时再次注册它们,那么我将使用什么方法呢?
  • 如果片段由于某种原因被销毁,所有视图都将变为不可见并留给垃圾回收。官方文档给出了可能发生的情况的可视化:developer.android.com/guide/components/fragments.html#Creating
【解决方案2】:

有没有办法让我获得 SensorManager 的新实例...?

没有。 getSystemService(Context.SENSOR_SERVICE) 返回的对象基本上是系统级服务的接口对象。设备上只有一个该服务的实例。

您可以通过创建带有选定标签“SensorManager”和调试级别的 Android Studio logcat 过滤器来深入了解 SensorManager 服务正在做什么。过滤器将启用如下输出:

D/SensorManager: registerListener :: 6, CM3323 RGB Sensor, 200000, 0,
D/SensorManager: unregisterListener ::

查看此输出可能会帮助您在注册和注销侦听器的方式中看到一些意想不到的东西。

onCreateView() 中注册您的听众并在onPause() 中取消注册不是一个好习惯。当片段的活动被暂停和恢复时,片段也被暂停和恢复,没有调用onCreateView()。这在documentation 中有解释。

您也可以尝试使用较慢的传感器更新速率。 SENSOR_DELAY_GAME 是 20 毫秒,可能比您的应用程序需要的快。 SENSOR_DELAY_UI 是 67 毫秒,SENSOR_DELAY_NORMAL 是 200 毫秒。

【讨论】:

  • 我从没想过要改变延迟。我将更改注册/取消注册的位置并尝试延迟以查看是否有帮助,谢谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 2018-10-16
  • 2023-04-01
  • 2020-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多