Android传感器侦听器未响应添加和从后台堆栈中删除的片段

时间:2016-02-01 15:30:58

标签: android android-fragments wear-os

我有一个Android掌上应用程序和一个Android磨损应用程序,它们都使用片段并使用传感器管理器和我自己制作的自定义监听器来监听摇动手势。

在每个应用程序上,我有一个主片段,其中包含一个菜单和一个传感器管理器,我的自定义侦听器已注册。当用户选择菜单项时,主片段被菜单项片段替换(菜单项片段具有它自己的具有不同自定义监听器的传感器管理器),并且当您从菜单项片段返回时,popBackStackImmediate调用()返回主片段。

这在手持式应用程序上完美运行,并且在磨损应用程序上也能正常工作一段时间;如果你打开菜单项片段,然后连续回到主片段,经过5或6次这样做,传感器听众变得迟钝,最终停止工作。有谁知道可能导致这种情况的原因?

这是我在每个片段中使用sensorManager注册和取消注册侦听器的方法:

主要片段

public class MainFragment extends Fragment {

    private MainWearActivity mMainWearActivity;
    View view;

    private SensorManager mSensorMgr;
    private ShakeListener shakeListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMainWearActivity = (MainWearActivity) getActivity();
    }

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

        mSensorMgr = (SensorManager) mMainWearActivity.getSystemService(Activity.SENSOR_SERVICE);
        shakeListener = new ShakeListener();

        shakeListener.setOnShakeListener(new OnShakeListener() {
            @Override
            public void onShake() {
                    MenuItemFragment mif = new MenuItemFragment();
                    mMainWearActivity.replaceFragment(mif, "menuFrag");
                }
            }
        });

        startListening();
        return view;
    }

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

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

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


    private void startListening(){
        mSensorMgr.registerListener(shakeListener, mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
    }

    private void stopListening(){
        mSensorMgr.unregisterListener(shakeListener);
    }
}

菜单项碎片

public class MenuItemFragment extends Fragment {

    private View view;
    private MainWearActivity mMainWearActivity;
    private SensorManager mSensorMgr;
    private FragmentManager fManager;
    private ShakeListener shakeListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMainWearActivity = (MainWearActivity) getActivity();
        fManager = getFragmentManager();
    }

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

        mSensorMgr = (SensorManager) mMainWearActivity.getSystemService(Activity.SENSOR_SERVICE);
        shakeListener = new ShakeListener();

        shakeListener.setOnShakeListener(new OnShakeListener() {
            @Override
            public void onShake() {
                fManager.popBackStackImmediate();
            }
        });

        startListening();
        return view;
    }

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

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

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

    private void startListening(){
        mSensorMgr.registerListener(shakeListener, mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
    }

    private void stopListening(){
        mSensorMgr.unregisterListener(shakeListener);
    }
}

替换片段的方法

public void replaceFragment(Fragment frag, String fragTag) {
    mFragmentTransaction = mFragmentManager.beginTransaction();
    mFragmentTransaction.replace(R.id.fragmentContainer, frag, fragTag);
    mFragmentTransaction.addToBackStack(null);
    mFragmentTransaction.commit();
}

就像我说的那样,这个设置在手持应用程序上工作正常,但在手表上传感器监听器在加载并从菜单项片段返回后出现故障。非常感谢任何帮助,谢谢。

修改

因此,根据建议,我已将我的片段移动到MainActivity类,以便可以重复使用它们。我也将replaceFragment方法改为:

public void replaceFragment(Fragment frag, String fragTag) {
    Fragment currentFrag = mFragmentManager.findFragmentById(R.id.fragmentContainer);
    mFragmentManager.beginTransaction()
            .remove(currentFrag)
            .add(R.id.fragmentContainer, frag, fragTag)
            .addToBackStack(null)
            .commit();
}

我已将Logs放在MainFragment和MenuItemFragments的onResume()和onPause()方法中,以检查它们是否被调用并且可以确认它们是否正确。

我还将SensorManager移动到MainActivity并使用它来注册/取消注册侦听器,这些侦听器本身已移动到每个片段的OnCreate()方法,以便每次创建视图时都不会创建新的侦听器。

毕竟,同样的问题仍然存在。在听众/传感器停止工作之前,我可以进入MenuItemFragment并返回MainFragment 8-10次。我还看了Android Studio中AndroidMonitor的内存选项卡,因为我要进入和离开片段,它似乎会稳定填满,直到分配的数量达到约5MB,然后传感器崩溃。

1 个答案:

答案 0 :(得分:0)

我的测试表明onResume()onPause()没有被FragmentTransaction.replace()调用,所以如果在弹出该事务时它们也没有被调用,我也不会感到惊讶从后面堆栈。您可以在自己的代码中通过向onResume()onPause()方法添加一些日志记录并观察它们何时被调用来确认这一点。

如果确实如此,我使用的解决方法是拨打FragmentTransaction.remove()add()而不是replace()。因此,您的replaceFragment方法主体将如下所示:

Fragment currentFrag = fragMgr.findFragmentById(R.id.fragmentContainer);
mFragmentManager.beginTransaction()
    .remove(currentFrag)
    .add(R.id.fragmentContainer, frag, fragTag)
    .addToBackStack(null)
    .commit();