React native 与Android原生交互方式(一)

前言##

最近在做React Native开发的时候避免不了的需要原生模块和JS之间进行交互,其实RN和原生的通信大致分为两种情况;一种是Android主动向RN端发送事件和数据,另外一种是RN端被动向Android询问获取事件和数据,接下来的几篇文章将向大家分享原生模块向JS交互的几种方式。

1、发送事件的方式

2、callback方式

3、Promise方式

由于篇幅原因本文只对发送事件的方式进行详细介绍

发送事件的方式

使用了React Native的RCTDeviceEventEmitter,通过消息机制来实现,原生可以向JS传递事件而不需要直接的调用,就像我们android中的广播。
下面通就像大家暂时通过RCTDeviceEventEmitter来向JS传递事件。
原生模块中(Android端):
首先定义Module类:MyModule.java

public class MyModule extends ReactContextBaseJavaModule {
    private final String TAG = MyModule.class.getName();

    public MyModule(ReactApplicationContext reactContext) {
        super(reactContext);

        //给上下文对象赋值
        Test.mContext = reactContext;

    }

    //不能用return tag 来实现 不然不能调用方法...原因不理解
    @Override
    public String getName() {
        return "MyModule";
    }


    @ReactMethod
    public void callNativeBySend(){
        //调用Test类中的原生方法。
        Log.e("wangfang","called send");
        new Test().fun();
    }


}

发送事件的代码在Test类中,
Test.java代码段如下:


public class Test {

    public static ReactContext mContext;
    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(mContext,"EventName",et);


            }
        }).start();

    }
    //定义发送事件的函数
    public  void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params)
    {
        System.out.println("reactContext="+reactContext);

        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName,params);//原生调Rn
    }
}

从上述代码可以看到,原生向JS模块发送了一个名为“EventName”的事件,并携带了"et"作为参数,那大家肯定会问JS中如何接收事件并进行处理呢,别急。。。。
先把原生的代码说完,得把模块添加到包中
MyPackage代码如下:

public class MyPackage implements ReactPackage {
    @Override
    public List createNativeModules(ReactApplicationContext reactContext) {

        List modules = new ArrayList<>();
        modules.add(new MyModule(reactContext));

        return modules;
    }

    @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

接着RN依附的Activity代码如下:

public class RnAndroidCommuActivity extends ReactActivity{


    @Override
    public String getMainComponentName() {
        return "testNative";
    }
}

原生的Activity的代码:

public class NativeActivity extends Activity {
    private Button btnGoReact;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnGoReact = (Button)this.findViewById(R.id.btn_go_react);
        btnGoReact.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(NativeActivity.this,RnAndroidCommuActivity.class);
                intent.putExtra("result","native go to react");
                startActivity(intent);
            }
        });

    }

activity_main资源文件的代码:




    

还有清单文件 这里就不贴代码了,相信做过Android的项目都知道咋写吧。。。
RN端的代码:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  DeviceEventEmitter,
  NativeModules,
  View,
  TextInput
} from 'react-native';
import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  DeviceEventEmitter,
  NativeModules,
  View,
  TextInput
} from 'react-native';
export class RnAndroidCommunication extends React.Component{
  componentWillMount(){
    DeviceEventEmitter.addListener("EventName",()=>{
      this.showState();
      alert("send event success");
    });
  }

  constructor(props){
    super(props);
    this.state={
      content:"这是个预定的接受消息"
    }

  }

  render(){
    return (
      

        
            当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。
            前端一直在监听该事件,如果收到,则给出alert提示! send 方式
        
       
        
            {this.state.content}
        

      

    );

  }
  
  callNative(){
      console.log(" js called by send");

      NativeModules.MyModule.callNativeBySend();
  }
  showState(){
    this.setState({content:"已经收到了原生模块发送来的事件,send event 方式"});
  }

}
const myStyles = 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('testNative', () => RnAndroidCommunication);

在JS中通过 DeviceEventEmitter 注册监听了名为“”的事件,当原生模块发出名为“EventName”的事件后,绑定在该事件上的 EventName = () 会被回调。 然后通过就可获得事件所携带的数据,并执行回调函数,进行页面显示灯。
心得:如果在JS中有多处注册了 EventName 事件,那么当原生模块发出事件后,这些地方会同时收到该事件。不过大家也可以通过 DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult) 来移除对名为“EventName”事件的监听。

下一篇:React native 与Android原生交互方式(二)

你可能感兴趣的:(React native 与Android原生交互方式(一))