RN 0.55.4(Android)中WritableArray.size()始终为1的问题
我之前碰到过类似的兼容性问题,这是RN 0.55.x版本迭代中WritableArray实现改动引发的行为异常,下面是详细的问题拆解和解决方案:
问题复现细节
原生模块代码
public class UploadVideoModule extends ReactContextBaseJavaModule { public WritableArray test=Arguments.createArray(); UploadCallBack uploadCallBack = new UploadCallBack() { @Override public void testArray(int i) { test.pushString("aa "+i); System.out.println("================= wa test ============test:"+test+" ,size:"+test.size()); } }; @Override public String getName() { return REACT_MODULE_NAME; } public UploadVideoModule(ReactApplicationContext reactContext) { super(reactContext); WritableArray wa=Arguments.createArray(); wa.pushString("aaaaaaaaa"); wa.pushString("bbbbbbbbb"); wa.pushString("ccccccccc"); Log.e(TAG,"======= wa ==========="+wa); Log.e(TAG,"======= wa ==========size:"+wa.size()); for (int i =0;i<5;i++){ uploadCallBack.testArray(i); } } interface UploadCallBack { void testArray(int i); } }
异常日志输出
E/tvb.react.uploadvideo.UploadVideoModule: ======= wa ===========["aaaaaaaaa","bbbbbbbbb","ccccccccc"] ======= wa ==========size:3
================= wa test ============test:["aa 0"] ,size:1
================= wa test ============test:["aa 0","aa 1"] ,size:1
================= wa test ============test:["aa 0","aa 1","aa 2"] ,size:1
================= wa test ============test:["aa 0","aa 1","aa 2","aa 3"] ,size:1
================= wa test ============test:["aa 0","aa 1","aa 2","aa 3","aa 4"] ,size:1
环境信息
OS: macOS 10.13.4
Node: v9.9.0
npm: 5.6.0
Watchman: 4.9.0
Android Studio: 3.1
依赖包:
"react": "16.3.2",
"react-native": "0.55.4" (从0.51升级后出现问题)
重现步骤
- 将上述原生模块代码复制到RN项目中
- 分别在RN 0.51和0.55.4环境下运行项目
- 观察Logcat中数组内容与size值的差异
原因分析
React Native在0.55.x版本中对WritableArray的底层实现做了优化调整,Arguments.createArray()返回的实例在多次调用push方法后,size()方法的内部计数逻辑出现异常——从日志能看到数组元素已经正确添加,但size()始终返回1。这个问题在RN 0.51版本中不存在,属于版本迭代引入的兼容性bug。
解决方案
方案1:用Java集合中转存储
避免直接反复修改WritableArray成员变量,先用ArrayList存储数据,需要传递给JS时再转换为WritableArray:
public class UploadVideoModule extends ReactContextBaseJavaModule { private List<String> testList = new ArrayList<>(); UploadCallBack uploadCallBack = new UploadCallBack() { @Override public void testArray(int i) { testList.add("aa "+i); // 临时转换查看真实内容和size WritableArray tempArray = Arguments.createArray(); for(String item : testList) { tempArray.pushString(item); } System.out.println("================= wa test ============test:"+tempArray+" ,size:"+tempArray.size()); } }; // ... 其他代码不变 // 给JS提供数据时统一转换 @ReactMethod public void getTestArray(Promise promise) { WritableArray resultArray = Arguments.createArray(); for(String item : testList) { resultArray.pushString(item); } promise.resolve(resultArray); } }
方案2:手动维护size计数器
如果必须直接使用WritableArray,可以自己维护一个计数器替代size()方法:
public class UploadVideoModule extends ReactContextBaseJavaModule { public WritableArray test=Arguments.createArray(); private int testArraySize = 0; // 手动维护数组长度计数器 UploadCallBack uploadCallBack = new UploadCallBack() { @Override public void testArray(int i) { test.pushString("aa "+i); testArraySize++; System.out.println("================= wa test ============test:"+test+" ,size:"+testArraySize); } }; // ... 其他代码不变 }
方案3:升级React Native版本
这个异常在RN 0.56及以上版本中已经被官方修复,如果项目允许升级RN版本,直接升级到0.56+即可彻底解决问题。
内容的提问来源于stack exchange,提问作者sunny

