【问题标题】:Sensormanager on fragment (add if visible; remove if invisible)片段上的传感器管理器(如果可见则添加;如果不可见则删除)
【发布时间】:2013-09-27 09:40:34
【问题描述】:

我想在片段上有一个传感器管理器,它仅在片段处于活动状态时才处于活动状态。如果用户改变了片段,监听器应该被移除。

添加和删除监听器非常简单。当片段出现/消失时,我不知道片段端的任何侦听器/函数。还有一个问题是,在几乎所有函数上,this.getActivity() 返回一个空指针。

【问题讨论】:

  • 你能在这里展示你的代码吗?
  • @PiyushGupta 我发布了我的解决方案
  • 我已经添加了一些关于 null 值的 cmets,这确实是一个在大多数情况下都有效的肮脏技巧。我已经详细说明了正常的方式(onActivityCreated+isAdded)
  • @user1281750 非常感谢。片段现在对我来说更清晰了。

标签: java android android-activity fragment sensormanager


【解决方案1】:

这就是我的解决方案。我试图从我的 Fragment 中删除它。如果有任何错误/语法问题,请告诉我。

public class MyFragment extends Fragment implements SensorEventListener {
    private SensorManager mSensorManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSensorManager = (SensorManager) this.getActivity().getSystemService(Activity.SENSOR_SERVICE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.mylayout, container, false);

        return rootView;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0], y = event.values[1];
    }

    @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { }

    @Override
    public void setMenuVisibility(boolean menuVisible) {
        super.setMenuVisibility(menuVisible);

        // First starts (gets called before everything else)
        if(mSensorManager == null) {
            return;
        }

        if(menuVisible) {
            this.registerSensorListener();
        } else {
            this.unregisterSensorListener();
        }   
    }

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

        if(this.getUserVisibleHint()) {
            this.registerSensorListener();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        this.unregisterSensorListener();
    }

    private void registerSensorListener() {
        mSensorManager.registerListener(this, mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0), SensorManager.SENSOR_DELAY_FASTEST);
    }

    private void unregisterSensorListener() {
        mSensorManager.unregisterListener(this);
    }
}

【讨论】:

    【解决方案2】:

    在片段中保留 Activity 的引用以处理该空指针异常。

    这里是一个片段的例子。

    public class YourFragment extends Fragment {
    
        private Activity mActivity;
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            mActivity = activity;
        }
    
        @Override
        public void onResume() {
            super.onResume();
            // BIND sensor here with mActivity, 
            // could also be done in other fragment lifecycle events, 
            // depends on how you handle configChanges
    
        }
    
        @Override
        public void onPause() {
            super.onPause();
            // UNBIND sensor here from mActivity, 
            // could also be done in other fragment lifecycle events, 
            // depends on how you handle configChanges
        }
    
    }
    

    调试该代码确实确定您是否应该在那里或以其他方法处理绑定,例如片段的 onCreate。我没有为您的目的测试此代码。

    编辑: 这确实是一个肮脏的修复下面的评论,并且在某些情况下可以很容易地解决异常。我只是想展示如何使用片段生命周期方法来绑定和取消绑定与活动的引用的传感器。我目前正在学习片段很长一段时间,但仍然没有完全理解它们。我建议您查看Fragment 的来源和其他涉及的组件。这是唯一完整记录片段的地方,因此我认为参考文档不是那么解释性的。

    关于空值Activity的一些选项:

    • 如果您想完全确定 getActivity 不返回 null,您应该等待 onActivityCreated 被调用。这个方法告诉片段它的活动有 完成了自己的Activity.onCreate()。在此之后 getActivity() 将不会返回 null,直到 initState() 被 FragmentManager 调用。

       // Called by the fragment manager once this fragment has been removed,
       // so that we don't have any left-over state if the application decides
       // to re-use the instance.  This only clears state that the framework
       // internally manages, not things the application sets.
      
      void initState() {
          mIndex = -1;
          mWho = null;
          mAdded = false;
          mRemoving = false;
          mResumed = false;
          mFromLayout = false;
          mInLayout = false;
          mRestored = false;
          mBackStackNesting = 0;
          mFragmentManager = null;
          mActivity = null;
          mFragmentId = 0;
          mContainerId = 0;
          mTag = null;
          mHidden = false;
          mDetached = false;
          mRetaining = false;
          mLoaderManager = null;
          mLoadersStarted = false;
          mCheckedForLoaderManager = false;
      }
      
    • 在调用 getActivity 之前,您始终可以通过调用 isAdded() 方法检查活动是否不为空。正如您在下面看到的,此方法检查 mActivity 是否不为空。或者,您可以使用 Handler.postDelayed 创建一个递归函数,该函数尝试在间隔中返回一个非空活动(您应该添加一个最大尝试计数器)。但这也是一个肮脏的伎俩。

      //Return true if the fragment is currently added to its activity.
      
      final public boolean isAdded() {
          return mActivity != null && mAdded;
      }
      

    【讨论】:

    • 是将活动存储在片段类中的好方法还是这些肮脏的解决方案之一?
    • @Niklas 取决于。但这个想法是让 Activity 不知道 Fragment 做了什么。但是,Activity 必须知道 Fragments 的作用,只要您必须在 Fragment 之间“交谈”,这应该始终通过 Activity 完成,从 Fragments 实现侦听器
    • 是的,我通过接口进行交流。但是我找到了一个解决方案(见下文),我不需要存储 Activity 并且它仍然有效。
    猜你喜欢
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2014-03-23
    • 2016-12-01
    • 2012-11-21
    • 2011-12-14
    • 1970-01-01
    • 2021-11-19
    相关资源
    最近更新 更多