react-native-fast-image 由于source的uri非法而奔溃
react-native 的 Image 组件加载性能低,未能很好地实现缓存,存在加载闪烁的问题。react-native-fast-image是一个native库,可以解决这些问题,是 Image 组件的替代品。 FastImage 在iOS上是使用 SDWebImage(IOS),Android上是Glide(Android),这2个项目在github都是4K以上的star,使用的开发者很多。
问题描述
如果给FastImage 传的source对象包含非法的uri:
{ uri: 'INVALID_URL' }
比如:
<FastImage source={{uri: "/logo.png"}} />
在安卓上运行,将出现以下异常,但是在ios上却是正常的。
com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'source' of a view managed by: FastImageView
at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:98)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46)
at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:268)
at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:198)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.dispatchPendingNonBatchedOperations(UIViewOperationQueue.java:1036)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1007)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:984)
at android.view.Choreographer.doCallbacks(Choreographer.java:798)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:972)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:192)
at android.app.ActivityThread.main(ActivityThread.java:6906)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
... 21 more
Caused by: java.lang.IllegalArgumentException: Must not be null or empty
at com.bumptech.glide.util.Preconditions.checkNotEmpty(Preconditions.java:39)
at com.bumptech.glide.load.model.GlideUrl.<init>(GlideUrl.java:57)
at com.dylanvann.fastimage.FastImageSource.getGlideUrl(FastImageSource.java:110)
at com.dylanvann.fastimage.FastImageViewManager.setSrc(FastImageViewManager.java:75)
... 23 more
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46)
at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:268)
at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:198)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.dispatchPendingNonBatchedOperations(UIViewOperationQueue.java:1036)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1007)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:984)
at android.view.Choreographer.doCallbacks(Choreographer.java:798)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:972)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:192)
at android.app.ActivityThread.main(ActivityThread.java:6906)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
Caused by: java.lang.IllegalArgumentException: Must not be null or empty
at com.bumptech.glide.util.Preconditions.checkNotEmpty(Preconditions.java:39)
at com.bumptech.glide.load.model.GlideUrl.<init>(GlideUrl.java:57)
at com.dylanvann.fastimage.FastImageSource.getGlideUrl(FastImageSource.java:110)
at com.dylanvann.fastimage.FastImageViewManager.setSrc(FastImageViewManager.java:75)
... 23 more
java.lang.IllegalArgumentException: Must not be null or empty
at com.bumptech.glide.util.Preconditions.checkNotEmpty(Preconditions.java:39)
at com.bumptech.glide.load.model.GlideUrl.<init>(GlideUrl.java:57)
at com.dylanvann.fastimage.FastImageSource.getGlideUrl(FastImageSource.java:110)
at com.dylanvann.fastimage.FastImageViewManager.setSrc(FastImageViewManager.java:75)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131)
at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46)
at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:268)
at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:198)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.dispatchPendingNonBatchedOperations(UIViewOperationQueue.java:1036)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1007)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:984)
at android.view.Choreographer.doCallbacks(Choreographer.java:798)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:972)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:192)
at android.app.ActivityThread.main(ActivityThread.java:6906)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
解决方法
使用FastImage前,先验证uri,不是以 http/https 开头的,返回null。
const normalisedSource = source && typeof source.uri === 'string' && (source.uri.split('https://')[1] || source.uri.split('http://')[1]) ? source : null;
<FastImage source={normalisedSource} />