繁体   English   中英

在Android中制作高效的重复动画

[英]Make an efficient repeating animation in android

我刚接触Android,所以我一直尝试在主要活动中重复制作4张图片的动画(翻译和淡入淡出)背景。 我在对动画进行编程之前和同时学习了动画(尤其是Animators),所以我想我没有找到最优雅,更有效的方法。

我的主要问题是,在多次更改设备方向后,应用程序因内存不足错误而崩溃。 我想找到一种解决方法,当然,还可以使整个过程变得优雅而高效。

编辑:

我所做的基本上是使用AnimatorSet实例顺序播放一组翻译和过渡(它们本身是由翻译,翻译+淡出,翻译+淡入等组成的AnimatorSet )。 最后,我添加了一个侦听器,它将在每次结束时再次播放动画。

这是我的MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private AnimatorSet mAnimatorSet;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView backgroundOne = findViewById(R.id.background_main1);
        ImageView backgroundTwo = findViewById(R.id.background_main2);
        ImageView backgroundThree = findViewById(R.id.background_main3);
        ImageView backgroundFour = findViewById(R.id.background_main4);

        mAnimatorSet = BackgroundAnimator.set
                (backgroundOne, backgroundTwo, backgroundThree, backgroundFour);

        setImagesWidth(backgroundOne, backgroundTwo, backgroundThree, backgroundFour);


        mAnimatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                animation.start();
            }
        });

        mAnimatorSet.start();


    }

    private void setImagesWidth(ImageView... imageViews) {

        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        int width = size.x;
        int height = size.y;

        for (ImageView imageView : imageViews) {
            imageView.getLayoutParams().width = width + 800;
            imageView.getLayoutParams().height = height;
            imageView.requestLayout();
        }


    }

    public void onAddClick(View view) {

        startActivity(new Intent(this, AddItemActivity.class));
    }

    private static class BackgroundAnimator {

        private static AnimatorSet animatorSet;

        enum TranslateOptions {

            INITIAL,
            LEFT_TO_RIGHT,
            RIGHT_TO_LEFT
        }

        /**
         * set the animator
         */
        private static AnimatorSet set(ImageView viewOne, ImageView viewTwo,
                                       ImageView viewThree, ImageView viewFour) {


            ArrayList<Animator> list = new ArrayList<>();


            list.add(translate(viewOne, TranslateOptions.LEFT_TO_RIGHT));
            list.add(transitionLeftEnd(viewOne, viewTwo));
            list.add(translate(viewTwo, TranslateOptions.RIGHT_TO_LEFT));
            list.add(transitionRightEnd(viewTwo, viewThree));
            list.add(translate(viewThree, TranslateOptions.LEFT_TO_RIGHT));
            list.add(transitionLeftEnd(viewThree, viewFour));
            list.add(translate(viewFour, TranslateOptions.RIGHT_TO_LEFT));
            list.add(transitionRightEnd(viewFour, viewOne));


            animatorSet = new AnimatorSet();
            animatorSet.playSequentially(list);
            return animatorSet;

        }


        private static Animator translate(ImageView view, TranslateOptions option) {

            float startValue = 0, endValue = 0;

            switch (option) {

                case INITIAL:
                    startValue = -500;
                    endValue = 300;
                    break;

                case LEFT_TO_RIGHT: {
                    startValue = -300;
                    endValue = 300;
                    break;
                }
                case RIGHT_TO_LEFT: {
                    startValue = 300;
                    endValue = -300;
                    break;
                }

            }

            ObjectAnimator animator = ObjectAnimator.ofFloat
                    (view, "translationX", startValue, endValue);
            animator.setInterpolator(new LinearInterpolator());
            animator.setDuration(9000);

            return animator;
        }

        private static AnimatorSet transitionLeftEnd(ImageView viewOut, ImageView viewIn) {

            return transition(viewOut, viewIn, 300, 500);


        }


        private static AnimatorSet transitionRightEnd(ImageView viewOut, ImageView viewIn) {

            return transition(viewOut, viewIn, -300, -500);


        }

        private static AnimatorSet transition(ImageView viewOut, ImageView viewIn,
                                              float startValue, float endValue) {


            PropertyValuesHolder translateOut =
                    PropertyValuesHolder.ofFloat("translationX", startValue, endValue);
            PropertyValuesHolder fadeOut =
                    PropertyValuesHolder.ofFloat("alpha", 0);

            ObjectAnimator animatorOut = ObjectAnimator.ofPropertyValuesHolder(viewOut, translateOut, fadeOut);
            animatorOut.setInterpolator(new LinearInterpolator());
            animatorOut.setDuration(2250);

            PropertyValuesHolder translateIn =
                    PropertyValuesHolder.ofFloat
                            ("translationX", endValue, startValue);
            PropertyValuesHolder fadeIn =
                    PropertyValuesHolder.ofFloat("alpha", 1);

            ObjectAnimator animatorIn = ObjectAnimator.ofPropertyValuesHolder(viewIn, translateIn, fadeIn);
            animatorIn.setInterpolator(new LinearInterpolator());
            animatorIn.setDuration(2250);

            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.playTogether(animatorIn, animatorOut);


            return animatorSet;
        }
    }
}

这是logcat的错误报告:

java.lang.OutOfMemoryError: Failed to allocate a 6144012 byte allocation with 2875952 free bytes and 2MB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613)
        at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:446)
        at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
        at android.content.res.Resources.createFromResourceStream(Resources.java:2952)
        at android.content.res.Resources.loadDrawableForCookie(Resources.java:2684)
        at android.content.res.Resources.loadDrawable(Resources.java:2580)
        at android.content.res.MiuiResources.loadDrawable(MiuiResources.java:388)
        at android.content.res.Resources.getDrawable(Resources.java:824)
        at android.content.Context.getDrawable(Context.java:467)
        at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:463)
        at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:203)
        at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:191)
        at android.support.v7.content.res.AppCompatResources.getDrawable(AppCompatResources.java:102)
        at android.support.v7.widget.AppCompatImageHelper.loadFromAttributes(AppCompatImageHelper.java:59)
        at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:78)
        at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:68)
        at android.support.v7.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:182)
        at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106)
        at android.support.v7.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1266)
        at android.support.v7.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1316)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:750)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:708)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:839)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:802)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:519)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:427)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
        at com.tfreifeld.collectx.MainActivity.onCreate(MainActivity.java:30)
        at android.app.Activity.performCreate(Activity.java:6355)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2440)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2547)
        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4191)
        at android.app.ActivityThread.access$1200(ActivityThread.java:151)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1406)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5603)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:774)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)

您的内存泄漏是由动画引起的。 不仅您永远都不会停止/取消动画,而且还在每个动画上设置了一个侦听器以在完成动画时对其进行重放。

这些动画具有静态引用(无论正在播放什么),在取消它们之前将不会被GC处理(取消时,我也会删除动画侦听器)。 动画本身引用了视图,引用了Activity上下文,等等。

另外, BackgroundAnimationanimatorSet是静态的,并且将泄漏至少一个活动。

关于您有关动画的一般问题-您做错了几件事。 通过将AnimatorSet.Builder用于动画合成,而不是AnimatorSet本身,可能会更好。 另外,还有比使用ObjectAnimator简单得多的方法,例如AlphaAnimationTranslateAnimation 通常,代码中有一些重复,可以将其提取为方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM