fix(android-animations): reuse animatorSet to prevent high memory usage (#6930)

This commit is contained in:
Alexander Djenkov
2019-02-21 10:49:35 +02:00
committed by GitHub
parent 09fa0856b8
commit 7236d32a24
3 changed files with 43 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ import {
} from "../styling/style-properties";
import { layout } from "../../utils/utils";
import { device } from "../../platform";
import lazy from "../../utils/lazy";
export * from "./animation-common";
@@ -92,6 +93,7 @@ export class Animation extends AnimationBase {
private _propertyResetCallbacks: Array<Function>;
private _valueSource: "animation" | "keyframe";
private _target: View;
private _resetOnFinish: boolean = true;
constructor(animationDefinitions: Array<AnimationDefinitionInternal>, playSequentially?: boolean) {
super(animationDefinitions, playSequentially);
@@ -134,12 +136,18 @@ export class Animation extends AnimationBase {
});
}
public play(): AnimationPromise {
public play(resetOnFinish?: boolean): AnimationPromise {
if (resetOnFinish !== undefined) {
this._resetOnFinish = resetOnFinish;
}
if (this.isPlaying) {
return this._rejectAlreadyPlaying();
}
let animationFinishedPromise = super.play();
if (this._animatorSet) {
return this._play();
}
this._animators = new Array<android.animation.Animator>();
this._propertyUpdateCallbacks = new Array<Function>();
@@ -156,21 +164,8 @@ export class Animation extends AnimationBase {
this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
if (this._animators.length > 0) {
if (this._playSequentially) {
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
}
else {
this._animatorSet.playTogether(this._nativeAnimatorsArray);
}
}
if (traceEnabled()) {
traceWrite("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), traceCategories.Animation);
}
this._animatorSet.setupStartValues();
this._animatorSet.start();
return animationFinishedPromise;
return this._play();
}
public cancel(): void {
@@ -188,6 +183,33 @@ export class Animation extends AnimationBase {
return _resolveAnimationCurve(curve);
}
private _play(): AnimationPromise {
const animationFinishedPromise = super.play();
if (device.sdkVersion <= "23") {
this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
}
if (this._animators.length > 0) {
if (this._playSequentially) {
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
}
else {
this._animatorSet.playTogether(this._nativeAnimatorsArray);
}
}
if (traceEnabled()) {
traceWrite("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), traceCategories.Animation);
}
this._animatorSet.setupStartValues();
this._animatorSet.start();
return animationFinishedPromise;
}
private _onAndroidAnimationEnd() { // tslint:disable-line
if (!this.isPlaying) {
// It has been cancelled
@@ -197,7 +219,7 @@ export class Animation extends AnimationBase {
this._propertyUpdateCallbacks.forEach(v => v());
this._resolveAnimationFinishedPromise();
if (this._target) {
if (this._resetOnFinish && this._target) {
this._target._removeAnimation(this);
}
}

View File

@@ -126,7 +126,7 @@ export type AnimationPromise = Promise<void> & Cancelable;
*/
export class Animation {
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
public play: () => AnimationPromise;
public play: (resetOnFinish?: boolean) => AnimationPromise;
public cancel: () => void;
public isPlaying: boolean;
public _resolveAnimationCurve(curve: any): any;

View File

@@ -243,8 +243,10 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
this._nativeAnimations.push(animation);
}
const isLastIteration = iterations - 1 <= 0;
// Catch the animation cancel to prevent unhandled promise rejection warnings
animation.play().then(() => {
animation.play(isLastIteration).then(() => {
this.animate(view, index + 1, iterations);
}, (error: any) => {
traceWrite(typeof error === "string" ? error : error.message, traceCategories.Animation, traceType.warn);