RN项目问题总结梳理

2024-05-06 14:18
文章标签 问题 总结 项目 梳理 rn

本文主要是介绍RN项目问题总结梳理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题1

问题描述:TextInput组件在页面底部时,弹出键盘时遮挡TextInput组件,用户无法正常输入内容
分析解决:弹出键盘浮在页面布局之上占用了一部分布局控件,可以监听键盘的弹出和隐藏事件,实现动态调整页面布局。

//页面装载时
componentWillMount() {//监听键盘弹出事件this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShowHandler.bind(this));//监听键盘隐藏事件this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHideHandler.bind(this));
}//页面移除时
componentWillUnmount() {//卸载键盘弹出事件监听if (this.keyboardDidShowListener != null) {this.keyboardDidShowListener.remove();}//卸载键盘隐藏事件监听if (this.keyboardDidHideListener != null) {this.keyboardDidHideListener.remove();}
}
//自定义键盘事件处理
//键盘弹出事件响应
keyboardDidShowHandler(event) {this.setState({keyboardShow: true});console.log(event.endCoordinates.height);
}//键盘隐藏事件响应
keyboardDidHideHandler(event) {this.setState({keyboardShow: false});
}//强制隐藏键盘
dissmissKeyboard() {Keyboard.dismiss();console.log("输入框当前焦点状态:" + this.refs.bottomInput.isFocused());
}

在render()方法中,通过keyboardShow实现动态布局

{this.state.keyboardShow ? null :<Image style={styles.devImg}source={require('../../../res/img/device/dev_solar_add.png')}/>
}
<Text style={this.state.keyboardShow ? [styles.textTipMain,  {marginBottom:autoHeight(19)}] :styles.textTipMain}>{getString('solar_connect_input_model')}</Text>

问题2

问题描述:在某些情景下需要监听当前页面的物理返回键,例如双击back退出应用,或者某一页按下back键返回特定页面
分析解决:RN中的页面是通过组件的方式实现的,各页面之间的通过路由的方式连接起来,单纯在当前页面监听hardwareBackPress事件,不止会监听到当前页面的物理返回键事件,也会监听到该页面所有上层页面的物理返回键事件。
网上有很多说的是通过路由长度navigator.getCurrentRoutes().length 判断当前所在页面,尝试多次无果,之后找到了新版本react-navigation的当前页面物理返回键监听的正确方式:

class ScreenWithCustomBackBehavior extends Component {componentDidMount() {BackHandler.addEventListener('hardwareBackPress',this.onBackButtonPressAndroid);}componentWillUnmount() {BackHandler.removeEventListener('hardwareBackPress',this.onBackButtonPressAndroid);}onBackButtonPressAndroid = () => {if (this.props.navigation.isFocused()) {if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {//最近2秒内按过back键,可以退出应用。return false;}this.lastBackPressed = Date.now();ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);return true;}}
}

有些版本在componentWillUnmount里执行removeEventListener并没有用,还是会监听到,所以这个时候可以换一种写法:

componentDidMount() {this.backHandler = BackHandler.addEventListener('hardwareBackPress',this.onBackButtonPressAndroid);
}componentWillUnmount() {this.backHandler&&this.backHandler.remove();
}

问题3

问题描述:RN里边多语言适配一般用react-native-i18n第三方多语言库,具体使用参考https://github.com/AlexanderZaytsev/react-native-i18n,App多语言通常有一个需求就是切换语言,如果没有杀死应用进程,切换系统语言之后,App仍然后展示切换之前的语言。
分析解决:切换系统语言之后,App仍然显示为切换之前的语言,很可能是当前语言设置没有生效或者是没有进行语言的重新获取。通过原生方式监听切换系统语言的广播并发送消息给RN,然后再RN应用入口处接收系统语言切换的消息,并设置当前语言为切换后的系统语言:

//原生系统语言切换广播监听
public class LocalReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
reactContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("local_changed",null);}}
}

RN入口接收消息

componentWillMount() {console.log('---componentWillMount---');
this.subLocalChangedListener = DeviceEventEmitter.addListener("local_changed", () => {//每次进入应用前台检查语言if (ObjectUtil.isEmpty(I18n.locale)) {getLanguages().then(languages => {console.log('当前语言' + languages);if (languages.toString().match(I18nUtils.ZH)) {I18n.locale = I18nUtils.ZH;} else {I18n.locale = I18nUtils.EN;}}).catch((error) => {console.log("获取语言失败" + error);});}});
}componentWillUnmount() {console.log('---componentWillUnmount---');
this.susubLocalChangedListener .remove();
}

问题4

问题描述:手势滑动事件处理粒度太粗,导致部分手机上当前页面点击事件无法响应
分析解决:在处理首页预留空间滑动事件时,在onStartShouldSetPanResponder事件时就成为事件的响应者,导致该组件成为所有触摸事件(包括点击事件)的响应者,而该组件又不能很好的处理自己所需触摸事件之外的其他事件,默认是不做任何响应,这就导致了页面点击事件无响应。详细分析RN里边触摸事件的分发处理机制,逐步细化处理触摸事件的响应,不要在一开始就响应,当满足特定需求之后,例如滑动时滑动长度超过特定长度之后再处理,这样既不会影响其他组件的默认事件处理机制,也能够处理特定情况的手势事件。

componentWillMount() {this._panResponder = PanResponder.create({// 要求成为响应者:onStartShouldSetPanResponder: (evt, gestureState) => false,onStartShouldSetPanResponderCapture: (evt, gestureState) => false,onMoveShouldSetPanResponder: (evt, gestureState) => false,onMoveShouldSetPanResponderCapture: (evt, gestureState) => {if (Math.abs(gestureState.dx) < this.thresholdMin && Math.abs(gestureState.dy) < this.thresholdMin) {return false;}else{if ((this.show && gestureState.dy < 0) || (!this.show && gestureState.dy > 0)) {return true;} else {return false;}}},onPanResponderGrant: (evt, gestureState) => {// 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!console.log('onPanResponderGrant');// gestureState.{x,y} 现在会被设置为0},onPanResponderMove: (evt, gestureState) => {// 最近一次的移动距离为gestureState.move{X,Y}console.log('onPanResponderMove');// 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}if ((this.show && gestureState.dy < 0) || (!this.show && gestureState.dy > 0)) {}}},onPanResponderTerminationRequest: (evt, gestureState) => true,onPanResponderRelease: (evt, gestureState) => {// 用户放开了所有的触摸点,且此时视图已经成为了响应者。console.log('onPanResponderRelease');// 一般来说这意味着一个手势操作已经成功完},onPanResponderTerminate: (evt, gestureState) => {// 另一个组件已经成为了新的响应者,所以当前手势将被取消。console.log('onPanResponderTerminate');},onShouldBlockNativeResponder: (evt, gestureState) => {// 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者// 默认返回true。目前暂时只支持android。return true;},});
}

问题5

问题描述:FlatList列表加载圈莫名消失,场景:网络慢时导致首页获取不到设备列表,首页为空,不能下拉刷新。
分析解决:这个问题真的是莫名其妙,我第一感觉是怀疑逻辑处理不严谨,开始按照网络请求-正常-异常展示各种情况梳理,顺便整理了下逻辑,没有问题,就把它定义为莫名消失了。记得刚开始简单列表demo的时候就不存在这个问题,和demo对比,转换网络请求的方式,就差把demo代码全部替换过来了。正常逻辑怎么也想不到,把布局调整成最简单的了,终于在网络请求失败时加载圈也不会消失了,那么问题就是出在布局上,也不是布局有误,就是给FlatList的父布局设置了FlexBox布局的属性就出现这个问题了,如下:

container: {flex: 1,justifyContent: 'center',alignItems: 'center',alignSelf: 'center',
}

去掉这三个属性,如下,其他代码逻辑复原,问题解决了。

container: {flex: 1,
}

问题6

问题描述:高版本手机通知栏小图标处理,在部分5.0或7.0手机的消息通知栏不仅会显示消息图标,还会显示一个非常小的应用通知图标,和其他应用对比发现默认显示效果不明显
分析解决:在部分高版本手机上,如果没有设置应用通知图标,系统会默认用应用的icon缩略一个小的通知图标(图标有颜色的部分会填充为白色,导致显示不出来),除非自己指定通知小图标。
找UI出了一个透明背景的icon(因为有颜色的部分会填充为白色,影响图标原有显示效果),指定为通知小图标,这样通知小图标就能显示出正常效果。

问题7

问题描述:编译版本不一致,例如targetSdk,google-supprot,firebase等版本不统一导致编译不通过问题

报错1:Error:Execution failed for task ‘:app:transformClassesWithDexForDebug’.
com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException:
报错2:Program type already present: android.support.v4.app.INotificationSideChannel
报错3:com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details
报错4:unable to find attribute android:fontVariationSettings and android:ttcIndex
报错5:java.util.zip.ZipException: duplicate entry
报错6:Android dependency ‘com.google.android.gms:play-services-basement’ has different version for the compile (16.0.1) and runtime (16.1.0) classpath. You should manually set the same version via DependencyResolution

分析解决:针对以上系列问题,花费了两天半时间,一直在排查这一系列问题,网上搜出的解决方案五花八门,但是都没有完全解决。之后回归问题初始是由于版本冲突/重复依赖第三方包导致的重复依赖或者依赖冲突。从第三方包依赖冲突入手,最容易出现依赖冲突的就是com.android.support组和com.google.firebase组下的包,参考Stack Overflow论坛里解决com.android.support包依赖冲突的解决方法,在project的build.gradle里配置com.android.support的统一版本,同时配置com.google.firebase和com.google.android.gms的同一版本,终于编译通过了。

allprojects {repositories {...}maven {url 'https://maven.google.com/'name 'Google'}configurations.all {resolutionStrategy.eachDependency { DependencyResolveDetails details ->def requested = details.requestedif (requested.group == 'com.google.android.gms') {details.useVersion '12.0.1'}if (requested.group == 'com.google.firebase') {details.useVersion '12.0.1'}}}}subprojects {project.configurations.all {resolutionStrategy.eachDependency { details ->if (details.requested.group == 'com.android.support'&& !details.requested.name.contains('multidex') ) {details.useVersion "26.1.0"}}}}
}

问题8

问题描述:app启动后,先出现白色页面2.5S~3S再出现启动页
分析解决:白屏为js文件解析阶段,将此时的白屏用启动页替换,到真正启动页停留时间完毕,跳转到主页。冷启动时间比热启动时间长,所以白屏时间也相对较长。
参考:React Native Android启动屏,启动白屏,闪现白屏
也可以直接使用第三方库react-native-splash-screen,原理一样

问题9

问题描述:文字过长添加省略号,最大长度阈值需要区分中英文,但中文和英文可容纳字符个数不同,在中英文混合的情况下如何动态控制可显示文字的长度
分析解决:在指定长度的区域内显示文字,超过可容纳长度用省略号表示,中文和英文可容纳字符个数不同,一个中文占两个英文长度,以中文文字可显示标准为例,为了更好的显示效果,就需要动态转换可显示中文文字个数,例如“你hhh好kk啊”转换为中文标准长度就是5.5个,提供可显示中文长度的最大值,截取可显示文字即可。

static CutStr(str, len){if (str.replace(/[^\x00-\xff]/g, "**").length <= 2 * len) {return str;}let char_length = 0;for (let i = 0; i < str.length; i++){let son_str = str.charAt(i);encodeURI(son_str).length > 2 ? char_length += 1 : char_length += 0.5;if (char_length >= len){let sub_len = char_length == len ? i+1 : i;return str.substr(0, sub_len) + '...';break;}}
}

问题10

问题描述:网络稳定的情况下,不能确保mqtt消息的正常接收,mqtt消息心跳检测,重连机制
分析解决:在物联网应用里,消息传输通常使用mqtt协议,MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。确保消息的正常接收就需要保证客户端和服务器的连接,通过重连机制和心跳检测来确保连接的可靠性。

重连机制:客户端和服务器mqtt建立连接失败/断开连接了则开启重连模式;三秒后进行一次重连,重连时首先检查网络是否正常,其次判断mqtt连接是否已经建立,如果没有建立连接才进行连接请求;当连接建立成功时,关闭重连循环,并开始消息订阅。
心跳检测:在RN的Android系统下,后台任务可以通过HeadlessJS 来实现,react-native-background-job就是基于HeadlessJS 实现的用来处理后台程序的第三方库,这里使用第三方库react-native-background-job做辅助,在应用切换到后台时,通过循环处理后台任务来确保连接不被断开,当应用再次回到前台时取消后台任务的执行。

//注册后台任务
BackgroundJob.register({jobKey: GlobalConstant.REGULAR_JOB_KEY,job: () => console.log("Running in background")
});//前后台切换
handleAppStateChange(appState) {console.log('当前状态为:' + appState);if (appState === 'active') {//回到前台BackgroundJob.cancel({jobKey: GlobalConstant.REGULAR_JOB_KEY});}else if(appState == 'background'){//后台运行,触发执行BackgroundJob.schedule({jobKey: GlobalConstant.REGULAR_JOB_KEY,period: 2000,exact: true});}
}

问题11

问题描述:Android9.0网络请求都是失败
分析解决: Android9 开始,也会默认阻止 http 请求,督促开发者使用https请求。

方法一:APP网络请求更改为HTTPS(推荐);
方法二:targetSdkVersion 降到27及以下;
方法三:在 res 下新增一个 xml 目录,然后创建一个名为:network_security_config.xml 文件(名字自己取) ,内容如下,大概意思就是允许开启http请求

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>

在项目的AndroidManifest.xml文件下的application标签增加以下属性,应用以上配置。

<application...android:networkSecurityConfig="@xml/network_security_config"...>
</application>

问题12

问题描述:github下载代码报错

fatal: unable to access ‘https://github.com/youyanping/react-native-project.git/’: Failed to connect to 127.0.0.1 port 1080: Connection refused

分析解决

git config --global http.proxy 查询到当前设置了代理,所以我取消这个设置,
git config --global --unset http.proxy 再查询,已经没有了代理,然后再clone,成功了!

问题13

问题描述:四指触控的报错

enabled a touch event which was not counted in ‘tracedeTouchCount’

分析解决:网上人说是ReactNative 框架本身的bug,可以通过修改RN的源码解决,之后没改源码,打包成正式apk就不会有这个问题了。

这篇关于RN项目问题总结梳理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964584

相关文章

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Springboot项目构建时各种依赖详细介绍与依赖关系说明详解

《Springboot项目构建时各种依赖详细介绍与依赖关系说明详解》SpringBoot通过spring-boot-dependencies统一依赖版本管理,spring-boot-starter-w... 目录一、spring-boot-dependencies1.简介2. 内容概览3.核心内容结构4.

MySQ中出现幻读问题的解决过程

《MySQ中出现幻读问题的解决过程》文章解析MySQLInnoDB通过MVCC与间隙锁机制在可重复读隔离级别下解决幻读,确保事务一致性,同时指出性能影响及乐观锁等替代方案,帮助开发者优化数据库应用... 目录一、幻读的准确定义与核心特征幻读 vs 不可重复读二、mysql隔离级别深度解析各隔离级别的实现差异

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

在ASP.NET项目中如何使用C#生成二维码

《在ASP.NET项目中如何使用C#生成二维码》二维码(QRCode)已广泛应用于网址分享,支付链接等场景,本文将以ASP.NET为示例,演示如何实现输入文本/URL,生成二维码,在线显示与下载的完整... 目录创建前端页面(Index.cshtml)后端二维码生成逻辑(Index.cshtml.cs)总结

Linux部署中的文件大小写问题的解决方案

《Linux部署中的文件大小写问题的解决方案》在本地开发环境(Windows/macOS)一切正常,但部署到Linux服务器后出现模块加载错误,核心原因是Linux文件系统严格区分大小写,所以本文给大... 目录问题背景解决方案配置要求问题背景在本地开发环境(Windows/MACOS)一切正常,但部署到