ReactNative学习笔记之调用原生模块(进阶)之Callback、Promise使用

前言

前文ReactNative学习笔记——调用原生模块(Android)简单说了下ReactNative调用Android原生模块的基本用法,下面讲解下调用原生模块经常会用到的CallbackPromise
很多时候我们可能不仅仅是调用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有两个特点
  1. Promise对象的状态不会受到外界操作的影响

    Promise有三种状态:Pending、Resolved和 Rejected,只有等异步操作结束,得到操作结果后,由Promise根据结果决定自身是什么状态。

  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果

    Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。

Promise的三种状态

  • pending:进行时,无法知道处理进度,只知道目前正在处理异步操作;
  • resolve:已完成,表示异步操作正确返回结果回调方法;
  • reject:已失败,表示处理中途抛出异常,或者处理结果不正确的回调方法。

关于Promise还有很多内容,这里不做详解,下面我们就用Promise机制来实现刚刚Callback实现的功能。

首先在Java中实现使用PromiseReactMethod方法:

...
    @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的缺点:

  1. 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
  3. 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

好了,今天的文章先到这

参考文献
【React Native】Promise的简单使用
ReactNative中文网——原生模块

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值