继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

初识React Native(二)—实现Android上的原生模块

喵喔喔
关注TA
已关注
手记 388
粉丝 101
获赞 605
有时候我们的项目
有时候我们的项目需要:
  1. 访问Android平台上的API时, 但是我们的React Native可能还没有相应的模块包装;

  2. 再或者我们需要复用一些Java代码的时候, 而不是用JavaScript重新实现时;

  3. 又或者我们需要实现一些高性能的, 多线程的(因为JavaScript只跑在一个线程上)的代码, 譬如: 操作数据库, 加载图片等等的时候;

这时候我们可以采用封装的方式, 将这些高级特性(平台上的API)封装成一个模块, 这样可以提高我们的工作效率, 减少许多代码量;
接下来我们来实现Android上的Toast模块, 为什么实现这个模块? 因为这个模块较为简单, 而且我们开发项目时也经常用到; 假设我们的希望从JavaScript发起一个Toast消息(React Native中内置了一个名为ToastAndroid的模块);

实现步骤:

1. 首先我们创建一个原生模块, 将这个模块命名为:ToastModule, 一个原生模块是集成了 ReactContextBaseJavaModule 的Java类, 它可以实现一些JavaScript所需的功能; 在这里我们的目标是在JavaScript的代码里, 当我们点击一个Button的时候, 会弹出一个类似Android里的Toast通知:
代码如下:
public class ToastModule extends ReactContextBaseJavaModule {

    private static final String DURATION_SHORT_KEY = "SHORT";    private static final String DURATION_LONG_KEY = "LONG";    public ToastModule(ReactApplicationContext reactContext) {        super(reactContext);
    }    @Nullable
    @Override
    public Map<String, Object> getConstants() {        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);        return constants;
    }    @ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }    @Override
    public String getName() {        return "ToastExample";
    }
}
> 注意: ReactContextBaseJavaModule 要求派生类实现 getName() 方法, 这个方法用来返回一个字符串(这个字符串很重要, 在后面的JavaScript代码里自定义原生模块的时候, 使用的就是该字符串, 在JavaScript端用来标记这个模块 ) ;
@Override
    public String getName() {        //如果模块有RCT前缀,那么这个前缀会被自动清除, 所以返回的字符串如果为RCTToastExample, 
        //那么在JavaScript端依然通过React.NativeModules.ToastExample访问到这个模块;
        return "ToastExample";
    }
接下来, 有一个可选的方法getContants()方法, 用来返回需要导出给JavaScript使用的常量(这个方法不一定需要实现, 但是定义一些可以被JavaScript同步访问到的预定义的值时还是非常有用的)
@Nullable
    @Override
    public Map<String, Object> getConstants() {        final Map<String, Object> constants = new HashMap<>();
        constants.put("SHORT", Toast.LENGTH_SHORT);
        constants.put("LONG", Toast.LENGTH_LONG);        return constants;
    }
在我们自定义的原生模块中, 最后一步就是要导出一个方法给JavaScript使用, 这时候Java方法需要使用到@ReactMethod这个注解, 这个方法的返回值必须为null; 因为React Native的跨语言访问是异步进行的, 所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件;
@ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }
2.注册模块
> 我们想要使用这个模块, 那么我们首先需要做的事情就是注册这个模块, 这时候我们需要在应用的Package类的 createNativeModules 方法中添加这个模块, 如果我们没注册这个模块, 那么我们无法在JavaScript中访问到这个模块:
public class AnExampleReactPackage implements ReactPackage {

    //这个方法为注册我们自定义的模块;
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ToastModule(reactContext));        return modules;
    }    //这个方法为注册我们的自定义的组件(以后的原生组件会讲到);
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {        return Collections.emptyList();
    }

}
然后这个package需要在MainApplication.java文件中的getPackages()方法中提供, 这个时候我的demo中, 我自己创建了一个新的MyApplication, 继承了Application, 并且实现了ReactApplication, 只不过我们创建完这个Application后 ,我们需要在Android Manifest中的application节点中设置name: MyApplication, 不了解的可以先去看我第一篇文章《初识React Native(一)—集成到原生Android项目》 :
public class MyApplication extends Application implements ReactApplication {

    private final ReactNativeHost reactNativeHost = new ReactNativeHost(this) {        @Override
        public boolean getUseDeveloperSupport() {            return BuildConfig.DEBUG;
        }        @Override
        protected List<ReactPackage> getPackages() {            return Arrays.<ReactPackage>asList(new MainReactPackage(), 
                    new AnExampleReactPackage());
        }
    };
    ...
}
3.运行我们的原生模块:
> 我们通常可以把原生模块封装成一个JavaScript模块, 这样我们从JavaScript端访问起来更加方便, 但是这不是必须的, 但是我依然封装成了JavaScript模块, 我的封装原生模块的ToastModule.js文件:
import { NativeModules } from 'react-native';export default NativeModules.ToastExample;
最后就是在我们React Native界面上使用这个模块了, 在这我生成一个Button, 当我们点击这个Button的时候, 就会弹出这个Toast通知:
...import ToastExample from './ToastModule';......export default class HelloReactNative extends React.Component {
    _onPressButton() {
        console.log("you tapped the button !");
        ToastExample.show('clicked me', ToastExample.SHORT);
    }
    render() {        return (
                <View style={styles.container}>                    ...
                    <TouchableNativeFeedback onPress={this._onPressButton}>
                        <Text style={styles.button}>Button</Text>
                    </TouchableNativeFeedback>                    ...
                </View>
        )
    }
}

原文链接:http://www.apkbus.com/blog-847095-77212.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP