我对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)
答案 0 :(得分:0)
您的内存泄漏是由动画引起的。不仅您永远都不会停止/取消动画,而且还在每个动画上设置了一个侦听器,以在完成动画时对其进行重放。
那些动画具有静态引用(无论正在播放什么),在取消它们之前不会被GC处理(取消时,我也会删除动画侦听器)。动画本身具有对视图的引用,具有对Activity上下文等的引用。
此外,BackgroundAnimation
的{{1}}是静态的,将泄漏至少一个活动。
关于动画的一般问题-您做错了几件事。通过将animatorSet
用于动画合成,而不是AnimatorSet.Builder
本身,可能会更好。另外,还有比使用AnimatorSet
更简单的方法,例如AlphaAnimation和TranslateAnimation。通常,代码中有一些重复,可以将其提取为方法。