ReactNative学习笔记之调用原生模块(进阶)之CallbackPromise使用
Posted mictoy_朱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReactNative学习笔记之调用原生模块(进阶)之CallbackPromise使用相关的知识,希望对你有一定的参考价值。
前言
前文ReactNative学习笔记——调用原生模块(Android)简单说了下ReactNative调用android原生模块的基本用法,下面讲解下调用原生模块经常会用到的Callback和Promise。
很多时候我们可能不仅仅是调用Native的方法,还要通过原生方法获取它的返回值,但是,前面说过,要导出一个方法给javascript使用,Java方法的返回类型必须为void,React Native的跨语言访问是异步进行的,我们无法像Java中常规方法一样直接通过return方式获取返回值。想要给JavaScript返回一个值的唯一方法是使用回调函数(Callback)或者发送事件(Promise)
1.使用回调函数Callback
这里首先讲解CallBack的使用方法,它就是提供了一个回调函数来把返回值回传给JavaScript。
比如,我们通过原生模块获取手机型号:
package com.getnativemodule;
import android.os.Build;
import com.facebook.react.bridge.Callback;
...
public class SplashScreenModule extends ReactContextBaseJavaModule
public SplashScreenModule(ReactApplicationContext reactContext)
super(reactContext);
...
/**
* 获取手机型号
*/
@ReactMethod
public void getSystemModel(Callback result)
String sysModel= Build.MODEL;
result.invoke(sysModel);
这里,我们将CallBack作为参数传入方法中,然后调用invoke()
方法,并将我们最终需要获取的返回值传入invoke方法的参数列表中(比如这里的sysModel),这样,我们就可以在RN的js中获取该返回值。
我们看下Callback的源码:
package com.facebook.react.bridge;
public interface Callback
/**
* Schedule javascript function execution represented by this @link Callback instance
*
* @param args arguments passed to javascript callback method via bridge
*/
public void invoke(Object... args);
就是一个接口,里面就一个invoke方法,可以说,这就是一个约定俗成的规则,没啥好研究的。
接下来,在RN中调用获取该返回值,写法如下:
...
import SplashScreen from "./jscode/SplashScreen";
export default class App extends Component<>
constructor(props)
super(props);
this.state=
systemModel:'',
...
componentDidMount()
...
SplashScreen.getSystemModel((sysModel)=>
this.setState(systemModel:sysModel);
);
render()
return (
<View style=styles.container>
...
<Text style=styles.welcome>
this.state.systemModel
</Text>
</View>
);
之前忘了把SplashScreen.js代码添加进来,现在补上(也就两行代码)
import NativeModules from 'react-native'
export default NativeModules.SplashScreen;
在前面一文我们知道,Callback
映射到JavaScript中是function
,在ES6中使用箭头函数就如上面写法,这里的sysModel
就是我们最终要获取的返回值。
我们运行查看效果:
当然,我们还可以传多个参数,比如,我们还要获取系统版本号,在Java中写法如下:
@ReactMethod
public void getSystemModel(Callback result)
String sysModel= Build.MODEL;
String sysVersion=Build.VERSION.RELEASE;//获取系统版本号
result.invoke(sysModel,sysVersion); //将值传入invoke
前面我们知道,invoke方法的参数是可变长度参数,所以你可以传任意多个参数值。
相应的,我们在JavaScript中修改代码如下:
...
import SplashScreen from "./jscode/SplashScreen";
export default class App extends Component<>
constructor(props)
super(props);
this.state=
systemModel:'',
systemVersion:'',
...
componentDidMount()
...
SplashScreen.getSystemModel((sysModel,sysVersion)=>//增加传参sysVersion
this.setState(systemModel:sysModel,systemVersion:sysVersion);
);
render()
return (
<View style=styles.container>
...
<Text style=styles.welcome>
this.state.systemModel
</Text>
<Text style=styles.welcome>
this.state.systemVersion
</Text>
</View>
);
运行查看效果:
由此我们知道,JavaScript中传入的参数就是对应Java中invoke
传入的参数。
2.使用Promise机制
原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的async/await语法则效果更佳。如果桥接原生方法的最后一个参数是一个Promise,则对应的JS方法就会返回一个Promise对象。
它同样可以实现Callback的功能,我们先简单介绍一下Promise。
Promise是ES6中提供给原生的一个对象,它可以传递异步操作的消息,代表了某个未来才会知道结果的事件。
Promise有两个特点
Promise对象的状态不会受到外界操作的影响
Promise有三种状态:Pending、Resolved和 Rejected,只有等异步操作结束,得到操作结果后,由Promise根据结果决定自身是什么状态。
一旦状态改变,就不会再变,任何时候都可以得到这个结果
Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。
Promise的三种状态
- pending:进行时,无法知道处理进度,只知道目前正在处理异步操作;
- resolve:已完成,表示异步操作正确返回结果回调方法;
- reject:已失败,表示处理中途抛出异常,或者处理结果不正确的回调方法。
关于Promise还有很多内容,这里不做详解,下面我们就用Promise机制来实现刚刚Callback实现的功能。
首先在Java中实现使用Promise
的ReactMethod
方法:
...
@ReactMethod
public void getSystemModelByPromise(Promise promise)
String sysModel= Build.MODEL;
promise.resolve(sysModel);
@ReactMethod
public void getSystemVersionByPromise(Promise promise)
String sysVersion=Build.VERSION.RELEASE;
promise.resolve(sysVersion);
对应在JavaScript中实现方法如下:
...
import SplashScreen from "./jscode/SplashScreen";
export default class App extends Component<>
constructor(props)
super(props);
this.state=
systemModel:'',
systemVersion:'',
...
async componentDidMount() //注意此时要声明为`async`表示该方法为异步方法
...
this.setState(
systemModel:await SplashScreen.getSystemModelByPromise(), //声明await表示等待异步操作结果
systemVersion:await SplashScreen.getSystemVersionByPromise()
);
render()
return (
<View style=styles.container>
...
<Text style=styles.welcome>
this.state.systemModel
</Text>
<Text style=styles.welcome>
this.state.systemVersion
</Text>
</View>
);
运行,同样可以得到我们想要的效果(效果图就不贴了)
通过上面可知,Promise异步操作结果一次只能传递一个值,而无法像Callback一样可以通过可变长度参数一次性传递多个值,必须写多个方法来获取。当然,我们也可以用封装的方式,将我们所需要的值封装成一个对象传给resolve方法。
当然,Promise的使用是为了简化Callback的层层回调,只是在这个例子中没有体现出来,可以说各有利弊。
Promise的缺点
这里也简单说下Promise的缺点:
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
好了,今天的文章先到这
参考文献
【React Native】Promise的简单使用
ReactNative中文网——原生模块
以上是关于ReactNative学习笔记之调用原生模块(进阶)之CallbackPromise使用的主要内容,如果未能解决你的问题,请参考以下文章
ReactNative进阶:ReactNative学习资料汇总