RN中文网关于原生模块(Android)的介绍可以看到,RN前端与原生模块之
间通信,主要有三种方法:
1)使用回调函数Callback,它提供了一个函数来把返回值传回给JavaScript。
2)使用Promise来实现。
3)原生模块向JavaScript发送事件。
关于使用回调,这是最简单的一种通信,这里可以看看官网的实现,今天要讲的是滴三种由原生模块向JavaScript发送事件。
(1)首先,你需要定义一个发送事件的方法。如下所示:
代码语言:js复制/*原生模块可以在没有被调用的情况下往JavaScript发送事件通知。
最简单的办法就是通过RCTDeviceEventEmitter,
这可以通过ReactContext来获得对应的引用,像这样:*/
public static void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap paramss)
{
System.out.println("reactContext=" reactContext);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, paramss);
}
其中方法名可以任意,但是参数不可改变。该方法可以放在你要复用的原生类中(即为原生类1)。
需要注意的是,由于版本问题,该函数中的参数reactContext有可能为null,此时会报NullPointException的错误。所以我们需要手动给reactContext赋值,见步骤2.
(2)我们在原生类1中,定义变量public static ReactContext MyContext;
然后在我们自定义的继承至ReactContextBaseJavaModule的类中给reactContext赋值。
如下所示:
代码语言:java复制public class MyModule extends ReactContextBaseJavaModule {
private BluetoothAdapter mBluetoothAdapter = null;
public MyModule(ReactApplicationContext reactContext) {
super(reactContext);
原生类1.MyContext=reactContext;
}
.......以下写被@ReactNative所标注的方法
............................
...................
}
此时,reactContext将不会是null。也就不会报错。
(3)在某个原生函数中向JavaScript发送事件。如下所示:
代码语言:java复制WritableMap event = Arguments.createMap();
sendEvent(MyContext, "EventName",event);
(4)在RN前端监听事件。首先导入DeviceEventEmitter,即import{ DeviceEventEmitter } from 'react-native'
然后使用componentWillMount建立监听。
代码如下:
代码语言:js复制componentWillMount(){
DeviceEventEmitter.addListener('EventName', function() {
alert("send success");
});
}
注意:该监听必须放在class里边,和render、const对齐。
下边展示一个完整Demo,Demo功能如下:
(1)JavaScript端在监听一个事件。
(2)点击前端某行文字,调用原生方法。
(3)在原生方法中,延迟3s后向前端发送对应事件。
(4)前端接收到事件后,给出alert提示。
代码如下:
ManiActivity.Java
代码语言:js复制package com.ywq;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "ywq";
}
}
ManiApplication.java
代码语言:js复制package com.ywq;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new MyPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}
MyModule.java
代码语言:java复制package com.ywq;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
/**
* Created by Administrator on 2016/10/30.
*/
public class MyModule extends ReactContextBaseJavaModule {
public MyModule(ReactApplicationContext reactContext) {
super(reactContext);
//给上下文对象赋值
Test.myContext=reactContext;
}
@Override
public String getName() {
return "MyModule";
}
@ReactMethod
public void NativeMethod()
{
//调用Test类中的原生方法。
new Test().fun();
}
}
MyPackage.java
代码语言:java复制package com.ywq;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Created by Administrator on 2016/10/30.
*/
public class MyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules=new ArrayList<>();
modules.add(new MyModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Test.java
代码语言:java复制package com.ywq;
import android.provider.Settings;
import android.support.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
/**
* Created by Administrator on 2016/10/30.
*/
public class Test {
//定义上下文对象
public static ReactContext myContext;
//定义发送事件的函数
public void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params)
{
System.out.println("reactContext=" reactContext);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName,params);
}
public void fun()
{
//在该方法中开启线程,并且延迟3秒,然后向JavaScript端发送事件。
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//发送事件,事件名为EventName
WritableMap et= Arguments.createMap();
sendEvent(myContext,"EventName",et);
}
}).start();
}
}
前端index.android.js代码如下:
代码语言:java复制/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
DeviceEventEmitter,
NativeModules,
View
} from 'react-native';
export default class ywq extends Component {
componentWillMount(){
//监听事件名为EventName的事件
DeviceEventEmitter.addListener('EventName', function() {
alert("send success");
});
}
constructor(props) {
super(props);
this.state = {
content: '这个是预定的接受信息',
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={this.callNative.bind(this)}
>
当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。
前端一直在监听该事件,如果收到,则给出alert提示!
</Text>
<Text style={styles.welcome} >
{this.state.content}
</Text>
</View>
);
}
callNative()
{
NativeModules.MyModule.NativeMethod();
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('ywq', () => ywq);
运行结果如下所示:
点击之前:
调用原生方法并且等待3s后:
再说一个值得注意的地方,一般我们在接收到原生模块主动发来的事件时,都会进行一些操作,如更新UI,而不仅仅是弹出alert 。
例如我们需要更新UI,代码如下:
代码语言:js复制/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
DeviceEventEmitter,
NativeModules,
View
} from 'react-native';
export default class ywq extends Component {
componentWillMount(){
//监听事件名为EventName的事件
DeviceEventEmitter.addListener('EventName', function() {
this.showState();
alert("send success");
});
}
constructor(props) {
super(props);
this.state = {
content: '这个是预定的接受信息',
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={this.callNative.bind(this)}
>
当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。
前端一直在监听该事件,如果收到,则给出alert提示!
</Text>
<Text style={styles.welcome} >
{this.state.content}
</Text>
</View>
);
}
callNative()
{
NativeModules.MyModule.NativeMethod();
}
showState()
{
this.setState({content:'已经收到了原生模块发送来的事件'})
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('ywq', () => ywq);
很明显:当收到事件时,改变一个文本框的内容,即更新UI。
运行结果如下,说明在此function中不能使用this,也就是我们并不能更新UI。
那我们能做到在接收到事件后更新UI等后续操作吗?
使用胖箭头函数(Fat arrow functions)
修改UI代码如下:
代码语言:java复制/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
DeviceEventEmitter,
NativeModules,
View
} from 'react-native';
export default class ywq extends Component {
componentWillMount(){
//监听事件名为EventName的事件
DeviceEventEmitter.addListener('EventName', ()=> {
this.showState();
alert("send success");
});
}
constructor(props) {
super(props);
this.state = {
content: '这个是预定的接受信息',
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={this.callNative.bind(this)}
>
当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。
前端一直在监听该事件,如果收到,则给出alert提示!
</Text>
<Text style={styles.welcome} >
{this.state.content}
</Text>
</View>
);
}
callNative()
{
NativeModules.MyModule.NativeMethod();
}
showState()
{
this.setState({content:'已经收到了原生模块发送来的事件'})
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('ywq', () => ywq);
运行之后,界面刷新了。