Android: Fix native animation crash

Summary:
An exception is thrown when the native animation code attempts to play an animation on a view that hasn't been created yet. This can happen because views are created in batches. If this particular view didn't make it into a batch yet, the view won't exist and an exception will be thrown when attempting to start an animation on it.

This change eats the exception rather than crashing. The impact is that the app may drop one or more frames of the animation.

**Notes**

I'm not familiar enough with the Android native animation code to know whether or not this is a good fix. My team is using this change in our app because dropping animation frames is better than crashing the app. [This is the code](c612c61544/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java (L874-L892)) that is creating the views in batches. Hopefully my PR at least provides some insight into the cause of the bug.

This may fix #9887
Closes https://github.com/facebook/react-native/pull/10907

Differential Revision: D4340129

Pulled By: lacker

fbshipit-source-id: 69160d9e71281a96a7445d764b4715a3e54c0357
This commit is contained in:
Adam Comella 2016-12-16 14:25:30 -08:00 committed by Facebook Github Bot
parent 25cd2c5d7b
commit 1c32385344
2 changed files with 16 additions and 1 deletions

View File

@ -6,10 +6,12 @@ android_library(
'*.java',
]),
deps = [
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
react_native_dep('third-party/android/support/v4:lib-support-v4'),
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
react_native_dep('third-party/java/jsr-305:jsr-305'),
react_native_target('java/com/facebook/react/bridge:bridge'),
react_native_target('java/com/facebook/react/common:common'),
react_native_target('java/com/facebook/react/module/annotations:annotations'),
react_native_target('java/com/facebook/react/modules/core:core'),
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),

View File

@ -12,6 +12,7 @@ package com.facebook.react.animated;
import android.util.SparseArray;
import com.facebook.infer.annotation.Assertions;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
@ -19,6 +20,8 @@ import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.Event;
@ -446,7 +449,17 @@ import javax.annotation.Nullable;
nextNode.update();
if (nextNode instanceof PropsAnimatedNode) {
// Send property updates to native view manager
((PropsAnimatedNode) nextNode).updateView(mUIImplementation);
try {
((PropsAnimatedNode) nextNode).updateView(mUIImplementation);
} catch (IllegalViewOperationException e) {
// An exception is thrown if the view hasn't been created yet. This can happen because views are
// created in batches. If this particular view didn't make it into a batch yet, the view won't
// exist and an exception will be thrown when attempting to start an animation on it.
//
// Eat the exception rather than crashing. The impact is that we may drop one or more frames of the
// animation.
FLog.e(ReactConstants.TAG, "Native animation workaround, frame lost as result of race condition", e);
}
}
if (nextNode instanceof ValueAnimatedNode) {
// Potentially send events to JS when the node's value is updated