【问题标题】:MemoryLeak in onBackPressed with AnimationonBackPressed 中的内存泄漏与动画
【发布时间】:2015-04-15 09:42:59
【问题描述】:

我在一个开源应用程序中创建了一个相当复杂的结束动画。

如果调用 onBackPressed() 方法,应用程序将为视图设置动画并关闭。似乎有一个内存韭菜,因为它不会停止分配新的内存。如果我删除动画并只调用正常的 onBackPressed 我没有提到的行为。

这是我在 onBackPressed 方法中调用的代码:

//make global var :D
ViewPropertyAnimator hideFabAnimator;

@Override
public void onBackPressed() {
    mFabDownloadButton.animate()
            .translationX(0)
            .setDuration(ANIMATION_DURATION_MEDIUM)
            .start();

    //move the share fab below the normal fab (58 because this is the margin top + the half
    mFabShareButton.animate()
            .translationX(0)
            .setDuration(ANIMATION_DURATION_MEDIUM)
            .setListener(new CustomAnimatorListener() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    //create the fab animation and hide fabProgress animation, set an delay so those will hide after the shareFab is below the main fab
                    hideFabAnimator = Utils.hideViewByScaleXY(mFabButton)
                            .setDuration(ANIMATION_DURATION_MEDIUM);

                    Utils.hideViewByScaleXY(mFabDownloadButton)
                            .setDuration(ANIMATION_DURATION_MEDIUM)
                            .start();
                    Utils.hideViewByScaleXY(mFabShareButton)
                            .setDuration(ANIMATION_DURATION_MEDIUM)
                            .start();
                    Utils.hideViewByScaleXY(mFabProgress)
                            .setDuration(ANIMATION_DURATION_MEDIUM)
                            .start();


                    //add listener so we can react after the animation is finished
                    hideFabAnimator.setListener(new CustomAnimatorListener() {

                        @Override
                        public void onAnimationEnd(Animator animation) {
                            try {
                                ViewPropertyAnimator hideFabAnimator = Utils.hideViewByScaleY(mTitleContainer);
                                hideFabAnimator.setListener(new CustomAnimatorListener() {
                                    @Override
                                    public void onAnimationEnd(Animator animation) {
                                        super.onAnimationEnd(animation);
                                        coolBack()
                                    }
                                });
                            } catch (Exception ex) {
                                super.onAnimationEnd(animation);
                                coolBack()
                            }
                        }
                    });

                    hideFabAnimator.start();
                    super.onAnimationEnd(animation);
                }
            })
            .start();
}

/**
 *
 */
private void coolBack() {
    try {
        super.onBackPressed();
    } catch (Exception e) {
    }
}

你可以在这里找到相同的来源@github:https://github.com/mikepenz/wall-splash-android/blob/master/app/src/main/java/com/mikepenz/unsplash/activities/DetailActivity.java#L701

我已经尝试了很多不同的东西。但没有任何帮助。

谢谢。

【问题讨论】:

  • 尝试删除 super.onBackPressed().. 在动画结束时使用 finish()
  • 对不起。确实完全错过了这条线。是我尝试过的事情之一。等我更新我的问题。

标签: android performance android-activity memory-leaks out-of-memory


【解决方案1】:

所以我能够解决这个问题。似乎如果您使用没有 animationListener 的普通动画,它可能会发生(它会发生)动画无法完成并保持“完整”。因此,即使活动已经关闭,它似乎仍在后台处理某些内容。

所以我能够通过定义一个侦听器“链”来解决这个问题,并检查我的所有动画是否完成。

这是有效的代码:

@Override
public void onBackPressed() {
    mFabDownloadButton.animate()
            .translationX(0)
            .setDuration(ANIMATION_DURATION_MEDIUM)
            .setListener(animationFinishListener1)
            .start();


    //move the share fab below the normal fab (58 because this is the margin top + the half
    mFabShareButton.animate()
            .translationX(0)
            .setDuration(ANIMATION_DURATION_MEDIUM)
            .setListener(animationFinishListener1)
            .start();
}

private CustomAnimatorListener animationFinishListener1 = new CustomAnimatorListener() {
    private int animateFinish1 = 0;

    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        process();
    }

    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
        process();
    }

    private void process() {
        animateFinish1 = animateFinish1 + 1;
        if (animateFinish1 == 2) {
            //create the fab animation and hide fabProgress animation, set an delay so those will hide after the shareFab is below the main fab
            Utils.hideViewByScaleXY(mFabDownloadButton)
                    .setDuration(ANIMATION_DURATION_MEDIUM)
                    .setListener(animationFinishListener2)
                    .start();
            Utils.hideViewByScaleXY(mFabShareButton)
                    .setDuration(ANIMATION_DURATION_MEDIUM)
                    .setListener(animationFinishListener2)
                    .start();
            Utils.hideViewByScaleXY(mFabProgress)
                    .setDuration(ANIMATION_DURATION_MEDIUM)
                    .setListener(animationFinishListener2)
                    .start();
            Utils.hideViewByScaleXY(mFabButton)
                    .setDuration(ANIMATION_DURATION_MEDIUM)
                    .setListener(animationFinishListener2)
                    .start();
        }
    }
};

private CustomAnimatorListener animationFinishListener2 = new CustomAnimatorListener() {
    private int animateFinish2 = 0;

    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        process();
    }

    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
        process();
    }

    private void process() {
        animateFinish2 = animateFinish2 + 1;
        if (animateFinish2 == 4) {
            ViewPropertyAnimator hideFabAnimator = Utils.hideViewByScaleY(mTitleContainer);
            hideFabAnimator.setListener(new CustomAnimatorListener() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    coolBack();
                }
            });
        }
    }
};

/**
 *
 */
private void coolBack() {
    try {
        super.onBackPressed();
    } catch (Exception e) {
        // ew;
    }
}

所以我对我的动画进行计数,并且只有在第一“批”动画完成后才会转到下一个动画,之后我将继续进行第二“批”动画。等这些完成后,我会完成活动。

【讨论】:

    【解决方案2】:

    我有一个类似的动画泄漏。就我而言,我使用了

    scaleY.setRepeatCount(1);
    scaleY.setRepeatMode(ValueAnimator.REVERSE);
    

    对于 setRepeatCount,我之前使用过 INFINITY,它也从不结束动画,即使在调用显式 cancle() 或 end() 之后也不会。我只是将其更改为 1 (它不再是无限的,但我可以忍受它)。 刚刚添加了这个答案,以防有人也遇到这个问题。

    【讨论】:

      猜你喜欢
      • 2017-07-14
      • 2016-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-02
      • 2014-08-18
      • 2021-08-04
      • 1970-01-01
      相关资源
      最近更新 更多