diff --git a/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/Animation.java b/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/Animation.java index 97ae900f..0d17dbc5 100755 --- a/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/Animation.java +++ b/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/Animation.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; + import org.hapjs.component.Component; public class Animation { @@ -101,6 +102,12 @@ public void pause() { } } + public void resume() { + if (mAnimatorSet != null) { + mAnimatorSet.resume(); + } + } + public void finish() { if (mAnimatorSet != null) { mAnimatorSet.finish(); diff --git a/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/CSSAnimatorSet.java b/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/CSSAnimatorSet.java index 094d4803..6be20d22 100755 --- a/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/CSSAnimatorSet.java +++ b/core/runtime/android/runtime/src/main/java/org/hapjs/component/animation/CSSAnimatorSet.java @@ -31,6 +31,7 @@ import android.view.View; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; + import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Objects; @@ -235,6 +236,10 @@ public void setRepeatCount(int repeatCount) { } } + public int getRepeatCount() { + return mRepeatCount; + } + public void start() { if (mComponent == null) { return; @@ -271,6 +276,10 @@ public void pause() { mWrapped.pause(); } + public void resume() { + mWrapped.resume(); + } + public void reverse() { for (Animator animator : mWrapped.getChildAnimations()) { animator.end(); diff --git a/core/runtime/android/runtime/src/main/java/org/hapjs/component/feature/AnimationFeature.java b/core/runtime/android/runtime/src/main/java/org/hapjs/component/feature/AnimationFeature.java index 4b0b4ac7..d99bd0b1 100755 --- a/core/runtime/android/runtime/src/main/java/org/hapjs/component/feature/AnimationFeature.java +++ b/core/runtime/android/runtime/src/main/java/org/hapjs/component/feature/AnimationFeature.java @@ -7,12 +7,17 @@ import android.app.Activity; import android.util.Log; + import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; + import org.hapjs.bridge.CallbackContext; import org.hapjs.bridge.CallbackContextHolder; import org.hapjs.bridge.CallbackHybridFeature; import org.hapjs.bridge.FeatureExtension; +import org.hapjs.bridge.HybridManager; +import org.hapjs.bridge.LifecycleListener; import org.hapjs.bridge.Request; import org.hapjs.bridge.Response; import org.hapjs.bridge.annotation.ActionAnnotation; @@ -82,7 +87,42 @@ public class AnimationFeature extends CallbackHybridFeature { protected static final String EVENT_ON_ANIMATION_FINISH = "onfinish"; private static final String TAG = "AnimationFeature"; private static final String CONNECTOR = "-"; - private Map mAnimations = new ConcurrentHashMap<>(); + private final Map mAnimations = new ConcurrentHashMap<>(); + private final Map mPausingAnimations = new ConcurrentHashMap<>(); + private final Object mLock = new Object(); + private HybridManager mHybridManager; + private final LifecycleListener mLifecycleListener = new LifecycleListener() { + @Override + public void onResume() { + super.onResume(); + synchronized (mLock) { + Set> entries = mPausingAnimations.entrySet(); + for (Map.Entry entry : entries) { + entry.getValue().resume(); + } + mPausingAnimations.clear(); + } + } + + @Override + public void onPause() { + super.onPause(); + synchronized (mLock) { + Set> entries = mAnimations.entrySet(); + for (Map.Entry entry : entries) { + Animation animation = entry.getValue(); + //页面 onPause 时,要暂停所有 infinity 的动画,否则会在 Android 13 的设备上崩溃 + if (animation.getAnimatorSet() != null + && Integer.MAX_VALUE == animation.getAnimatorSet().getRepeatCount()) { + if (animation.getPlayState().equals("running")) { + mPausingAnimations.put(entry.getKey(), entry.getValue()); + animation.pause(); + } + } + } + } + } + }; @Override public String getName() { @@ -98,6 +138,10 @@ protected Response invokeInner(final Request request) throws Exception { Activity activity = request.getNativeInterface().getActivity(); switch (request.getAction()) { case ACTION_ENABLE: + if (mHybridManager == null) { + mHybridManager = request.getView().getHybridManager(); + setLifecycleListener(); + } enable(request, compId, animId); break; case ACTION_PLAY: @@ -114,6 +158,9 @@ public void run() { new Runnable() { @Override public void run() { + synchronized (mLock) { + mPausingAnimations.remove(key); + } pause(key); } }); @@ -177,6 +224,12 @@ public void run() { return Response.SUCCESS; } + private void setLifecycleListener() { + if (mHybridManager != null) { + mHybridManager.addLifecycleListener(mLifecycleListener); + } + } + private void enable(Request request, String compId, String animId) { int ref = Integer.parseInt(compId); RootView rootView = request.getNativeInterface().getRootView(); @@ -405,6 +458,14 @@ public boolean isBuiltInExtension() { return true; } + @Override + public void dispose(boolean force) { + super.dispose(force); + if (force && mHybridManager != null) { + mHybridManager.removeLifecycleListener(mLifecycleListener); + } + } + private class AnimationCallbackContext extends CallbackContext implements Animation.OnFinishListener, Animation.OnCancelListener {