React Native之学习篇一

      有时候一个应用程序需要访问一个平台API,React Native还没有相应的模块。 也许你想重用一些现有的Java代码,而不必在JavaScript中重新实现它,或者编写一些高性能,多线程的代码,例如图像处理,数据库或任何数量的高级扩展。

    我们设计了React Native,因此您可以编写真实的本地代码,并可以访问平台的全部功能。 这是一个更高级的功能,我们并不期望它成为通常开发过程的一部分,但它是必不可少的。 如果React Native不支持您需要的本地功能,您应该可以自己构建它。

   如果您打算对Java代码进行更改,我们建议启用Gradle Daemon来加速构建。

   Toast模块

    下面构建Toast示例。 假设我们希望能够从JavaScript创建Toast消息。

    我们首先创建一个本地模块。 本地模块是一个Java类,通常扩展ReactContextBaseJavaModule类并实现JavaScript所需的功能。 我们的目标是能写ToastExample.show('Awesome',ToastExample.SHORT); 从JavaScript在屏幕上显示一个简短的Toast。

 

package com.facebook.react.modules.toast;

import android.widget.Toast;

import com.facebook.react.bridge.NativeModule;

import com.facebook.react.bridge.ReactApplicationContext;

import com.facebook.react.bridge.ReactContext;

import com.facebook.react.bridge.ReactContextBaseJavaModule;

import com.facebook.react.bridge.ReactMethod;

import java.util.Map;

import java.util.HashMap;

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);

  }

}

     ReactContextBaseJavaModule要求实现一个名为getName的方法。 此方法的目的是返回在JavaScript中代表此类的NativeModule的字符串名称。 所以在这里我们将调用这个ToastExample,以便我们可以通过JavaScript中的React.NativeModules.ToastExample来访问它。

@Override

public String getName() {

     return "ToastExample";

}

    一个名为getConstants的可选方法返回暴露给JavaScript的常量值。 它的实现不是必需的,但是对于需要从JavaScript同步到Java的关键预定义值非常有用。

  @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;

  }

    要将方法公开到JavaScript,必须使用@ReactMethod对Java方法进行注释。 桥接方法的返回类型总是无效的。 React Native桥是异步的,因此将结果传递给JavaScript的唯一方法是使用回调或发送事件(请参见下文)。

  @ReactMethod

  public void show(String message, int duration) {

    Toast.makeText(getReactApplicationContext(), message, duration).show();

  }

参数类型

    以@ReactMethod注解的方法支持以下参数类型,并直接映射到它们的JavaScript等效项

Boolean -> Bool

Integer -> Number

Double -> Number

Float -> Number

String -> String

Callback -> function

ReadableMap -> Object

ReadableArray -> Array

    阅读更多关于 ReadableMap 和ReadableArray

    注册模块

    Java中的最后一步是注册模块; 这发生在您的应用程序包的createNativeModules中。 如果一个模块没有被注册,它将不能从JavaScript获得。

package com.facebook.react.modules.toast;

import com.facebook.react.ReactPackage;

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;

public class AnExampleReactPackage implements ReactPackage {

  @Override

  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {

    return Collections.emptyList();

  }

  @Override

  public List<NativeModule> createNativeModules(

                              ReactApplicationContext reactContext) {

    List<NativeModule> modules = new ArrayList<>();

    modules.add(new ToastModule(reactContext));

    return modules;

  }

}

     该包需要在MainApplication.java文件的getPackages方法中提供。 该文件存在于react-native应用程序目录中的android文件夹下。 这个文件的路径是:android / app / src / main / java / com / your-app-name / MainApplication.java。

protected List<ReactPackage> getPackages() {

    return Arrays.<ReactPackage>asList(

            new MainReactPackage(),

            new AnExampleReactPackage()); // <-- Add this line with your package name.

}

为了更简单地从JavaScript访问您的新功能,通常会将本地模块包装到JavaScript模块中。 这不是必须的,但是可以节省您的库的用户每次都需要将其从NativeModules中提取出来。 这个JavaScript文件也成为您添加JavaScript端功能的好地方。

/**

 * This exposes the native ToastExample module as a JS module. This has a

 * function 'show' which takes the following parameters:

 *

 * 1. String message: A string with the text to toast

 * 2. int duration: The duration of the toast. May be ToastExample.SHORT or

 *    ToastExample.LONG

 */

import {NativeModules} from 'react-native';

module.exports = NativeModules.ToastExample;

现在,从您的其他JavaScript文件中,您可以调用像这样的方法:

import ToastExample from './ToastExample';

ToastExample.show('Awesome', ToastExample.SHORT);

Toasts之外

回调

本地模块也支持一种特殊的参数 - 回调。 在大多数情况下,它被用来将函数调用结果提供给JavaScript。

import com.facebook.react.bridge.Callback;

public class UIManagerModule extends ReactContextBaseJavaModule {

...

  @ReactMethod

  public void measureLayout(

      int tag,

      int ancestorTag,

      Callback errorCallback,

      Callback successCallback) {

    try {

      measureLayout(tag, ancestorTag, mMeasureBuffer);

      float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);

      float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);

      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);

      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);

      successCallback.invoke(relativeX, relativeY, width, height);

    } catch (IllegalViewOperationException e) {

      errorCallback.invoke(e.getMessage());

    }

  }

...

它的方法将被访问在JavaScript中使用:

UIManager.measureLayout(

  100,

  100,

  (msg) => {

    console.log(msg);

  },

  (x, y, width, height) => {

    console.log(x + ':' + y + ':' + width + ':' + height);

  }

);

本地模块应该只调用一次回调。 但是,它可以存储回调并稍后调用它。

突出显示在本地函数完成后不立即调用回调是非常重要的 - 请记住,桥接通信是异步的,这也与运行循环有关。

承诺(Promises)

原生模块也可以履行承诺,这可以简化您的代码,特别是在使用ES2016的异步/等待语法时。 当桥接本地方法的最后一个参数是Promise时,其相应的JS方法将返回一个JS Promise对象。

重构上面的代码来使用promise而不是回调看起来像这样:

import com.facebook.react.bridge.Promise;

public class UIManagerModule extends ReactContextBaseJavaModule {

...

  private static final String E_LAYOUT_ERROR = "E_LAYOUT_ERROR";

  @ReactMethod

  public void measureLayout(

      int tag,

      int ancestorTag,

      Promise promise) {

    try {

      measureLayout(tag, ancestorTag, mMeasureBuffer);

 

      WritableMap map = Arguments.createMap();

 

      map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0]));

      map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1]));

      map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2]));

      map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3]));

 

      promise.resolve(map);

    } catch (IllegalViewOperationException e) {

      promise.reject(E_LAYOUT_ERROR, e);

    }

  }

...

该方法的JavaScript对应方返回一个Promise。 这意味着您可以在异步函数中使用await关键字来调用它并等待其结果:

async function measureLayout() {

  try {

    var {relativeX, relativeY, width, height} = await UIManager.measureLayout(

      100,

      100

    );

    console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);

  } catch (e) {

    console.error(e);

  }

}

measureLayout();

线程(Threading)

原生模块不应该对它们被调用的线程有任何假设,因为当前的分配将来可能会发生变化。 如果需要阻塞调用,则应该将繁重的工作分派给内部管理的工作者线程,并从那里分配任何回调。

 

转载于:https://my.oschina.net/todaybamboo/blog/1608341

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值