Сделать эффективную повторяющуюся анимацию в Android - PullRequest
0 голосов
/ 10 октября 2018

Я довольно новичок в Android, и я пытался сделать повторяющийся анимационный (перевод и кроссфейд) фон из 4 изображений в моей основной деятельности.Я узнал об анимации (и особенно об Аниматорах) до и параллельно с программированием анимации, поэтому я предполагаю, что не нашел самый элегантный, не говоря уже об эффективном, способ сделать это.

Моя главная проблема заключается в том, чтосбой приложения с ошибкой нехватки памяти после нескольких изменений ориентации устройства.Я хотел бы найти способ исправить это, но также сделать все это элегантно и эффективно использовать память.

РЕДАКТИРОВАТЬ:

То, что я сделал в основном, этоиспользование экземпляра 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)

1 Ответ

0 голосов
/ 11 октября 2018

Ваша утечка памяти вызвана анимацией.Мало того, что вы никогда не останавливаете / не отменяете анимации, вы настраиваете слушателя на каждую анимацию, чтобы воспроизводить ее, когда она закончится.

Эти анимации имеют статические ссылки (независимо от того, где они воспроизводятся) и не будут GC', пока вы не отмените их (я бы также удалил слушателей анимации при отмене).Сами анимации имеют ссылки на представления, которые имеют отношение к контексту Activity и т. Д. *

. Кроме того, BackgroundAnimation * animatorSet является статическим и будет пропускать по крайней мере одно действие.

Что касается вашего общего вопроса об анимации - вы делаете несколько вещей неправильно.Вам, вероятно, будет лучше, если использовать AnimatorSet.Builder для композиции анимации вместо AnimatorSet.Кроме того, есть гораздо более простые способы, чем использование ObjectAnimator, например AlphaAnimation и TranslateAnimation .И вообще, в коде есть некоторые повторения, которые можно извлечь в методы.

...