Android上的内存泄漏使用片段和ViewPager

时间:2016-02-03 00:50:09

标签: android android-fragments wear-os fragmentmanager

我有一个有一个主要活动的应用。此活动包含对fragmentManager的引用,以及我在应用程序中使用的所有片段。加载主活动后,它会显示一个"导航片段",此片段包含一个ViewPager,它本身使用片段显示菜单项(使用FragmentPagerAdapter完成)。当我选择菜单项(通过单击它或使用手势)时,当前导航片段将被菜单项片段替换为:

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();
}

当我从菜单项片段返回到导航片段时,使用:

fragmentManager.popBackStackImmediate();

我在分配的内存中获得大幅跳跃。选择菜单项并返回导航片段大约8-10次后,我的记忆开始填满,我的sensorListeners停止工作,所以我不能使用手势。我尝试尽可能多地重用片段,并保持每个片段的onCreateView()方法不受任何实例化的影响。

当我选择菜单项片段然后多次返回导航片段时,这就是我的内存监视器输出的内容:

loading and unloading fragments several times

有谁知道可能导致这种情况的原因?

这是我的导航片段' MainFragment':

public class MainFragment extends Fragment {

    private MainWearActivity mMainWearActivity;
    View view;

    private int currentPage;
    private ViewPager pager;
    private ViewPagerAdapter adapter;

    private WearYFlick mYFlick;
    private WearXFlick mXFlick;
    private Vibrator vibrator;
    private OnShakeListener yFlickListener;
    private OnShakeListener xFlickListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMainWearActivity = (MainWearActivity) getActivity();
        vibrator = mMainWearActivity.getVibrator();
        adapter = new ViewPagerAdapter((MainWearActivity)getActivity(),getChildFragmentManager());

        mYFlick = new WearYFlick();
        mXFlick = new WearXFlick();

        yFlickListener = new OnShakeListener() {
            @Override
            public void onShake() {
                yFlickDetected();
            }
        };

        xFlickListener = new OnShakeListener() {
            @Override
            public void onShake() {
                xFlickDetected();
            }
        };
    }

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

        // Scrolling menu
        pager = (ViewPager) view.findViewById(R.id.watchNavPager);
        pager.setAdapter(adapter);
        pager.addOnPageChangeListener(adapter);
        // Set current item to the middle page
        pager.setCurrentItem(Consts.FIRST_PAGE);
        currentPage = Consts.FIRST_PAGE;
        // Set number of pages
        pager.setOffscreenPageLimit(4);
        // Set no margin so other pages are hidden
        pager.setPageMargin(0);

        // Set the listeners and start listening
        mYFlick.setOnShakeListener(yFlickListener);
        mXFlick.setOnShakeListener(xFlickListener);

        return view;
    }

    @Override
    public void onPause() {
        Log.d("FRAG", "MainFragment onPause() called");
        stopListening();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d("FRAG", "MainFragment onResume() called");
        startListening();
    }

    private void startListening(){
        mMainWearActivity.registerListener(mYFlick, Consts.GYRO);
        mMainWearActivity.registerListener(mXFlick, Consts.GYRO);
    }

    private void stopListening(){
        mMainWearActivity.unregisterListener(mYFlick);
        mMainWearActivity.unregisterListener(mXFlick);
    }

    private void yFlickDetected(){
        vibrator.vibrate(Consts.vibPattern, -1);
        currentPage = pager.getCurrentItem();
        currentPage++;
        pager.setCurrentItem(currentPage, true);
    }

    private void xFlickDetected(){
        vibrator.vibrate(Consts.vibPattern, -1);
        // Select the current menu item
        switch (mMainWearActivity.getCurrentSelection()) {
            case Consts.MENU_ITEM:
                mMainWearActivity.replaceFragment(mMainWearActivity.getFragment(Consts.FRAG_ITEM), Consts.FRAG_ITEM);
                break;
        }
    }

    @Override
    public void onDestroyView() {
        pager = null;
        super.onDestroyView();
    }
}

这是我的菜单项片段:

public class VoiceFragment extends Fragment {

    private View view;
    private MainWearActivity mMainWearActivity;
    private Vibrator vibrator;
    private FragmentManager fManager;

    private WearYShake mYShake;
    private WearYFlick mYFlick;

    private TextView menuItemText;
    private ImageView mainImageView;
    private ColorStateList defaultTextColor;

    private OnShakeListener yFlickListener;
    private OnShakeListener yShakeListener;
    private View.OnClickListener imgClickListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMainWearActivity = (MainWearActivity) getActivity();
        vibrator = mMainWearActivity.getVibrator();
        fManager = mMainWearActivity.getFragManager();

        mYShake = new WearYShake();
        mYFlick = new WearYFlick();

        yFlickListener = new OnShakeListener() {
            @Override
            public void onShake() {
                yFlickDetected();
            }
        };

        yShakeListener = new OnShakeListener() {
            @Override
            public void onShake() {
                yShakeDetected();
            }
        };

        imgClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                yFlickDetected();
            }
        };
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_menu_item, container, false);
        menuItemText = (TextView) view.findViewById(R.id.menuItemFragTxt);
        mainImageView= (ImageView) view.findViewById(R.id.itemMainImg);

        mYFlick.setOnShakeListener(yFlickListener);
        mYShake.setOnShakeListener(yShakeListener);
        mainImageView.setOnClickListener(imgClickListener);

        return view;
    }

    private void promptSpeechInput(){
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, Consts.PROMPT_SPEECH);
        try {
            startActivityForResult(intent, Consts.REQ_CODE_SPEECH_INPUT);
        } catch (ActivityNotFoundException a) {
            Toast.makeText(getActivity(), Consts.VOICE_ERROR_MSG, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case Consts.REQ_CODE_SPEECH_INPUT: {
                if (resultCode == Activity.RESULT_OK && null != data) {

                    ArrayList<String> result = data
                            .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
                    menuItemText.setText(result.get(0));
                }
                break;
            }
        }
    }

    @Override
    public void onPause() {
        Log.d("FRAG", "ItemFragment onPause() called");
        stopListening();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d("FRAG", "ItemFragment onResume() called");
        startListening();
    }

    private void startListening(){
        mMainWearActivity.registerListener(mYFlick, Consts.GYRO);
        mMainWearActivity.registerListener(mYShake, Consts.ACCEL);
    }

    private void stopListening(){
        mMainWearActivity.unregisterListener(mYFlick);
        mMainWearActivity.unregisterListener(mYShake);
    }

    private void yFlickDetected(){
        vibrator.vibrate(Consts.vibPattern, -1);
        fManager.popBackStackImmediate();
    }

    private void yShakeDetected(){
        vibrator.vibrate(Consts.vibPattern, -1);
        promptSpeechInput();
    }
}

我的ViewPagerAdapter看起来像这样:

public class ViewPagerAdapter extends FragmentPagerAdapter implements
        ViewPager.OnPageChangeListener {

    private MainWearActivity context;
    private FragmentManager fm;

    public ViewPagerAdapter(MainWearActivity context, FragmentManager fm) {
        super(fm);
        this.fm = fm;
        this.context = context;
    }


    @Override
    public Fragment getItem(int position)
    {
        position = position % Consts.PAGES;

        switch(position){
            case Consts.ITEM1_POS:
                return new AdapterItem1Fragment();
            case Consts.ITEM2_POS:
                return new AdapterItem2Fragment();
            case Consts.ITEM3_POS:
                return new AdapterItem3Fragment();
            case Consts.ITEM4_POS:
                return new AdapterItem4Fragment();
            default:
                return null;
        }
    }

    @Override
    public int getCount()
    {
        return Consts.PAGES * Consts.LOOPS;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset,
                               int positionOffsetPixels) {}

    @Override
    public void onPageSelected(int position) {}

    @Override
    public void onPageScrollStateChanged(int state) {}
}

任何人都可以看到为什么在我的主导航片段和菜单项片段之间切换可能会导致内存分配如此大的跳跃并阻止我的传感器工作?感谢。

0 个答案:

没有答案