Все мои анимации для Android пропущены

#android #background #task #objectanimator

#Android #фон #задача #objectanimator

Вопрос:

У меня проблема с игрой, которую я создал на Android.

Моя игра работает с большим количеством ObjectAnimator, ValueAnimator и Thread.

Некоторые пользователи сталкиваются с проблемой, которая делает игру неиграбельной: все анимации пропущены.

Я могу воспроизвести эту ошибку, когда активирован режим выносливости (на моем Xperia Z3), но у некоторых пользователей эта ошибка возникает и с S7 Edge. Для информации, режим выносливости — это функция экономии заряда батареи, включенная во все телефоны Xperia.

Как я могу предотвратить эту ошибку?

Ответ №1:

У меня была аналогичная проблема с моими анимациями. Анимация стоит дорого для батареи, поэтому в режиме экономии заряда батареи анимации не выполняются, и приложение переводит состояние в конечное состояние. Одна из возможностей, которую я использовал и которая отображает анимации, заключается в замене ObjectAnimator и ValueAnimator пользовательскими реализациями. Ниже приведен пример пользовательского кругового представления, которое я анимирую для заполнения против часовой стрелки. Эта анимация происходит в режиме экономии заряда батареи.

В принципе, я узнаю, какова продолжительность анимации, затем я знаю процент рисования, который нужно выполнять каждую секунду, я рисую это, а затем очищаю холст, а затем рисую процент рисования в следующую секунду. Это происходит до тех пор, пока я не достигну конечного состояния, когда я не очищаю холст и сохраняю конечное состояние. Основная часть — это метод onDraw.

 public class AnimatedCircleView extends View {
  private Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();

  @IntDef({START, END, ANIMATING})
  @Retention(RetentionPolicy.SOURCE)
  public @interface State {
  }

  private static final int START = 0;
  private static final int END = 1;
  private static final int ANIMATING = 2;

  private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  private final RectF mRect = new RectF();

  @State private int mState = START;
  private long mAnimationStartTime = 0;
  private long mDuration = 0;
  private Listener mListener = null;

  public AnimatedCircleView(Context context) {
    super(context);
  }

  public AnimatedCircleView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public void startCircleAnimation(long durationMillis, Listener listener) {
    mDuration = durationMillis;
    mAnimationStartTime = System.currentTimeMillis();
    mState = ANIMATING;
    mListener = listener;
    invalidate();
  }

  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mRect.left = 0;
    mRect.right = w;
    mRect.top = 0;
    mRect.bottom = h;
  }

  @Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (mState == START) {
      // Draw nothing.
      return;
    }

    float percentToDraw;
    if (mState == ANIMATING) {
      float currentAnimationTime = System.currentTimeMillis() - mAnimationStartTime;//Get how much animation time is remaining
      float percentAnimationTime = currentAnimationTime / mDuration;//So now you how much percent you need to draw
      if (percentAnimationTime >= 1f) { //If percent is greater than 100%, you have reached the end
        percentToDraw = 1f;
        mState = END;
        if (mListener != null) mListener.onAnimationEnd();
      } else {
        percentToDraw = INTERPOLATOR.getInterpolation(percentAnimationTime);//Else apply the interpolator
      }
    } else {
      // END state
      percentToDraw = 1f;
    }
    float sweepValue = 360f * percentToDraw; //Multiply the final value of the filled circle with percentToDraw, so you know how much to draw.
    float sweepAngle = -sweepValue; //Draw anti clockwise
    canvas.drawArc(mRect, -90, sweepAngle, false, mPaint); //Draw on canvas

    if (mState == ANIMATING) {
      postInvalidateOnAnimation(); // Clear the drawing as animation is happening
    }
  }

  public interface Listener {
    void onAnimationEnd();
  }
}
  

Включите это пользовательское представление в свой xml следующим образом:

 <com.example.sunny.BatteryCircle.AnimatedCircleView
        android:id="@ id/cvAnimatedCircleView"
        android:layout_centerVertical="true"
        android:layout_width="45dp"
        android:layout_height="45dp" />
  

Теперь вы можете вызвать анимацию из действия следующим образом:

 AnimatedCircleView animatedCircleView = (AnimatedCircleView) findViewById(R.id.cvAnimatedCircleView);
        animatedCircleView.startCircleAnimation(2000, new AnimatedCircleView.Listener() {
            @Override public void onAnimationEnd() {
            }
        });