跳到主要内容

Android 原生模块

信息

原生模块和原生组件是我们旧架构中使用的稳定技术。当新架构稳定后,它们将在未来被弃用。新架构使用 Turbo 原生模块Fabric 原生组件 来实现类似的效果。

欢迎来到 Android 原生模块。请先阅读 原生模块介绍,了解原生模块是什么。

创建一个日历原生模块

在下面的指南中,你将创建一个原生模块 CalendarModule,它将允许你从 JavaScript 访问 Android 的日历 API。最终,你将能够从 JavaScript 调用 CalendarModule.createCalendarEvent('晚餐派对', '我家');,从而调用一个 Java/Kotlin 方法来创建日历事件。

设置

首先,在 Android Studio 中打开你的 React Native 应用程序中的 Android 项目。你可以在 React Native 应用程序中找到你的 Android 项目,路径如下:

Image of opening up an Android project within a React Native app inside of Android Studio.
显示 Android 项目位置的图片

我们建议使用 Android Studio 编写你的原生代码。Android Studio 是一个专为 Android 开发构建的 IDE,使用它可以帮助你快速解决代码语法错误等小问题。

我们还建议启用 Gradle Daemon 以在迭代 Java/Kotlin 代码时加快构建速度。

创建自定义原生模块文件

第一步是在 android/app/src/main/java/com/your-app-name/ 文件夹中创建 (CalendarModule.javaCalendarModule.kt) Java/Kotlin 文件(Kotlin 和 Java 的文件夹相同)。这个 Java/Kotlin 文件将包含你的原生模块 Java/Kotlin 类。

Image of adding a class called CalendarModule.java within the Android Studio.
如何添加 CalendarModuleClass 的图片

然后添加以下内容

java
package com.your-apps-package-name; // replace your-apps-package-name with your app’s package name
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 CalendarModule extends ReactContextBaseJavaModule {
CalendarModule(ReactApplicationContext context) {
super(context);
}
}

如你所见,你的 CalendarModule 类扩展了 ReactContextBaseJavaModule 类。对于 Android,Java/Kotlin 原生模块被编写为扩展 ReactContextBaseJavaModule 并实现 JavaScript 所需功能的类。

值得注意的是,从技术上讲,Java/Kotlin 类只需要扩展 BaseJavaModule 类或实现 NativeModule 接口,即可被 React Native 视为原生模块。

但是我们建议你使用 ReactContextBaseJavaModule,如上所示。ReactContextBaseJavaModule 提供了对 ReactApplicationContext (RAC) 的访问,这对于需要与 Activity 生命周期方法挂钩的原生模块很有用。使用 ReactContextBaseJavaModule 也将使你的原生模块在未来更容易实现类型安全。对于未来版本中将提供的原生模块类型安全,React Native 会查看每个原生模块的 JavaScript 规范,并生成一个扩展 ReactContextBaseJavaModule 的抽象基类。

模块名称

Android 中所有的 Java/Kotlin 原生模块都需要实现 getName() 方法。此方法返回一个字符串,表示原生模块的名称。然后可以使用其名称在 JavaScript 中访问原生模块。例如,在下面的代码片段中,getName() 返回 "CalendarModule"

java
// add to CalendarModule.java
@Override
public String getName() {
return "CalendarModule";
}

然后可以在 JS 中这样访问原生模块

tsx
const {CalendarModule} = ReactNative.NativeModules;

将原生方法导出到 JavaScript

接下来,你需要向你的原生模块添加一个方法,该方法将创建日历事件,并可以在 JavaScript 中调用。所有旨在从 JavaScript 调用的原生模块方法都必须使用 @ReactMethod 注解。

CalendarModule 设置一个方法 createCalendarEvent(),可以通过 CalendarModule.createCalendarEvent() 在 JS 中调用。目前,该方法将接收一个名称和位置作为字符串。参数类型选项将很快介绍。

java
@ReactMethod
public void createCalendarEvent(String name, String location) {
}

在方法中添加一个调试日志,以确认当你从应用程序调用它时它已被调用。下面是如何从 Android util 包中导入和使用 Log 类的示例

java
import android.util.Log;

@ReactMethod
public void createCalendarEvent(String name, String location) {
Log.d("CalendarModule", "Create event called with name: " + name
+ " and location: " + location);
}

完成原生模块的实现并将其挂接到 JavaScript 后,你可以按照 这些步骤 查看应用程序的日志。

同步方法

你可以将 isBlockingSynchronousMethod = true 传递给原生方法,将其标记为同步方法。

java
@ReactMethod(isBlockingSynchronousMethod = true)

目前,我们不建议这样做,因为同步调用方法可能会严重影响性能,并为你的原生模块引入与线程相关的错误。此外,请注意,如果你选择启用 isBlockingSynchronousMethod,你的应用程序将无法再使用 Google Chrome 调试器。这是因为同步方法要求 JS VM 与应用程序共享内存。对于 Google Chrome 调试器,React Native 在 Google Chrome 的 JS VM 中运行,并通过 WebSockets 与移动设备异步通信。

注册模块(Android 特有)

原生模块编写完成后,需要向 React Native 注册。为此,你需要将你的原生模块添加到 ReactPackage 中,并将 ReactPackage 注册到 React Native。在初始化期间,React Native 将遍历所有包,并为每个 ReactPackage 注册其中的每个原生模块。

React Native 调用 ReactPackage 上的 createNativeModules() 方法,以获取要注册的原生模块列表。对于 Android,如果模块未在 createNativeModules 中实例化并返回,它将无法从 JavaScript 中使用。

要将你的原生模块添加到 ReactPackage,首先在 android/app/src/main/java/com/your-app-name/ 文件夹中创建一个名为 (MyAppPackage.javaMyAppPackage.kt) 的新 Java/Kotlin 类,该类实现 ReactPackage

然后添加以下内容

java
package com.your-app-name; // replace your-app-name with your app’s name
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 MyAppPackage 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 CalendarModule(reactContext));

return modules;
}

}

此文件导入你创建的原生模块 CalendarModule。然后,它在 createNativeModules() 函数中实例化 CalendarModule 并将其作为 NativeModules 列表返回以供注册。如果你后续添加更多原生模块,你也可以实例化它们并将它们添加到此处返回的列表中。

值得注意的是,这种注册原生模块的方式会在应用程序启动时急切地初始化所有原生模块,这会增加应用程序的启动时间。你可以使用 TurboReactPackage 作为替代方案。TurboReactPackage 不是 createNativeModules 返回实例化原生模块对象的列表,而是实现了一个 getModule(String name, ReactApplicationContext rac) 方法,该方法在需要时创建原生模块对象。TurboReactPackage 目前实现起来有点复杂。除了实现 getModule() 方法外,你还必须实现 getReactModuleInfoProvider() 方法,该方法返回包可以实例化的所有原生模块的列表以及实例化它们的功能,例如 此处。再次强调,使用 TurboReactPackage 将使你的应用程序启动时间更快,但目前编写起来有点麻烦。因此,如果你选择使用 TurboReactPackage,请谨慎操作。

要注册 CalendarModule 包,你必须将 MyAppPackage 添加到 ReactNativeHost 的 getPackages() 方法返回的包列表中。打开你的 MainApplication.javaMainApplication.kt 文件,该文件位于以下路径:android/app/src/main/java/com/your-app-name/

找到 ReactNativeHost 的 getPackages() 方法,并将你的包添加到 getPackages() 返回的包列表中

java
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new MyAppPackage());
return packages;
}

你现在已经成功注册了你的 Android 原生模块!

测试你的构建

至此,你已经在 Android 中为你的原生模块设置了基本脚手架。通过在 JavaScript 中访问原生模块并调用其导出的方法来测试它。

在你的应用程序中找到一个你想要调用原生模块的 createCalendarEvent() 方法的地方。下面是一个组件 NewModuleButton 的示例,你可以将其添加到你的应用程序中。你可以在 NewModuleButtononPress() 函数中调用原生模块。

tsx
import React from 'react';
import {NativeModules, Button} from 'react-native';

const NewModuleButton = () => {
const onPress = () => {
console.log('We will invoke the native module here!');
};

return (
<Button
title="Click to invoke your native module!"
color="#841584"
onPress={onPress}
/>
);
};

export default NewModuleButton;

为了从 JavaScript 访问你的原生模块,你需要首先从 React Native 导入 NativeModules

tsx
import {NativeModules} from 'react-native';

然后你可以从 NativeModules 中访问 CalendarModule 原生模块。

tsx
const {CalendarModule} = NativeModules;

现在你已经可以使用 CalendarModule 原生模块了,你可以调用你的原生方法 createCalendarEvent()。下面它被添加到 NewModuleButtononPress() 方法中

tsx
const onPress = () => {
CalendarModule.createCalendarEvent('testName', 'testLocation');
};

最后一步是重新构建 React Native 应用程序,以便你可以使用最新的原生代码(包含你的新原生模块!)。在你的命令行中,在 React Native 应用程序所在的位置,运行以下命令

shell
npm run android

迭代时构建

当你完成这些指南并迭代你的原生模块时,你需要对你的应用程序进行原生重建,以便从 JavaScript 访问你最近的更改。这是因为你正在编写的代码位于应用程序的原生部分。虽然 React Native 的 metro 打包器可以监视 JavaScript 中的更改并为你即时重建,但它不会对原生代码这样做。因此,如果你想测试你最新的原生更改,你需要使用上述命令进行重建。

回顾✨

你现在应该能够在应用程序中调用原生模块上的 createCalendarEvent() 方法。在我们的示例中,这是通过按下 NewModuleButton 实现的。你可以通过查看你在 createCalendarEvent() 方法中设置的日志来确认这一点。你可以按照 这些步骤 在你的应用程序中查看 ADB 日志。然后你应该能够搜索你的 Log.d 消息(在我们的示例中是 “Create event called with name: testName and location: testLocation”),并查看每次调用你的原生模块方法时记录的消息。

Image of logs.
Android Studio 中的 ADB 日志图片

至此,你已经创建了一个 Android 原生模块,并在你的 React Native 应用程序中从 JavaScript 调用了它的原生方法。你可以继续阅读,了解更多关于原生模块方法可用的参数类型以及如何设置回调和 Promise 的信息。

超越日历原生模块

更好的原生模块导出

像上面那样通过从 NativeModules 中拉取来导入你的原生模块有点笨拙。

为了避免你的原生模块使用者每次想访问你的原生模块时都需要这样做,你可以为模块创建一个 JavaScript 包装器。创建一个名为 CalendarModule.js 的新 JavaScript 文件,其内容如下

tsx
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:

* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
export default CalendarModule;

这个 JavaScript 文件也成为了你添加任何 JavaScript 端功能的好地方。例如,如果你使用 TypeScript 等类型系统,你可以在这里为你的原生模块添加类型注释。虽然 React Native 尚未支持原生到 JS 的类型安全,但你所有的 JS 代码都将是类型安全的。这样做也将使你更容易在未来切换到类型安全的原生模块。下面是为 CalendarModule 添加类型安全性的示例

tsx
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:
*
* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
interface CalendarInterface {
createCalendarEvent(name: string, location: string): void;
}
export default CalendarModule as CalendarInterface;

在你的其他 JavaScript 文件中,你可以这样访问原生模块并调用其方法

tsx
import CalendarModule from './CalendarModule';
CalendarModule.createCalendarEvent('foo', 'bar');

这假设你导入 CalendarModule 的位置与 CalendarModule.js 处于相同的层次结构中。请根据需要更新相对导入。

参数类型

当在 JavaScript 中调用原生模块方法时,React Native 会将参数从 JS 对象转换为其 Java/Kotlin 对象的对应物。因此,例如,如果你的 Java 原生模块方法接受一个 double 类型,那么在 JS 中你需要使用一个数字来调用该方法。React Native 将为你处理转换。下面是原生模块方法支持的参数类型及其对应的 JavaScript 类型列表。

JavaKotlinJavaScript
BooleanBoolean?boolean
布尔值布尔值
DoubleDouble?number
double数字
StringString字符串
CallbackCallbackFunction
PromisePromisePromise
ReadableMapReadableMapObject
ReadableArrayReadableArrayArray

目前支持以下类型,但 TurboModules 将不再支持。请避免使用它们

  • Integer Java/Kotlin -> ?number
  • Float Java/Kotlin -> ?number
  • int Java -> number
  • float Java -> number

对于上面未列出的参数类型,你需要自行处理转换。例如,在 Android 中,Date 转换不是开箱即用的。你可以像这样在原生方法中自行处理到 Date 类型的转换

java
    String dateFormat = "yyyy-MM-dd";
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
Calendar eStartDate = Calendar.getInstance();
try {
eStartDate.setTime(sdf.parse(startDate));
}

导出常量

原生模块可以通过实现原生方法 getConstants() 来导出常量,该方法在 JS 中可用。下面你将实现 getConstants() 并返回一个包含你可以在 JavaScript 中访问的 DEFAULT_EVENT_NAME 常量的 Map。

java
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("DEFAULT_EVENT_NAME", "New Event");
return constants;
}

然后可以通过在 JS 中调用原生模块上的 getConstants 来访问常量

tsx
const {DEFAULT_EVENT_NAME} = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);

从技术上讲,可以直接从原生模块对象访问 getConstants() 中导出的常量。但这将不再被 TurboModules 支持,因此我们鼓励社区切换到上述方法,以避免后续不必要的迁移。

目前常量只在初始化时导出,所以如果你在运行时更改 getConstants 的值,它不会影响 JavaScript 环境。这将在 TurboModules 中改变。使用 TurboModules,getConstants() 将成为一个常规的原生模块方法,每次调用都会命中原生端。

回调

原生模块还支持一种独特的参数:回调。回调用于将数据从 Java/Kotlin 传递到 JavaScript,用于异步方法。它们还可以用于从原生端异步执行 JavaScript。

要使用回调创建原生模块方法,首先导入 Callback 接口,然后向你的原生模块方法添加一个类型为 Callback 的新参数。回调参数有一些细微差别,这些细微差别将很快通过 TurboModules 解决。首先,你的函数参数中只能有两个回调——一个成功回调和一个失败回调。此外,原生模块方法调用的最后一个参数,如果它是一个函数,则被视为成功回调,而倒数第二个参数,如果它是一个函数,则被视为失败回调。

java
import com.facebook.react.bridge.Callback;

@ReactMethod
public void createCalendarEvent(String name, String location, Callback callBack) {
}

你可以在 Java/Kotlin 方法中调用回调,提供任何你想要传递给 JavaScript 的数据。请注意,你只能将可序列化的数据从原生代码传递到 JavaScript。如果你需要传回原生对象,可以使用 WriteableMaps;如果你需要使用集合,可以使用 WritableArrays。同样重要的是要强调,回调不会在原生函数完成之后立即调用。下面是将先前调用中创建的事件 ID 传递给回调的示例。

java
  @ReactMethod
public void createCalendarEvent(String name, String location, Callback callBack) {
Integer eventId = ...
callBack.invoke(eventId);
}

然后可以使用 JavaScript 访问此方法

tsx
const onPress = () => {
CalendarModule.createCalendarEvent(
'Party',
'My House',
eventId => {
console.log(`Created a new event with id ${eventId}`);
},
);
};

另一个需要注意的重要细节是,原生模块方法只能调用一次回调,并且只能调用一次。这意味着你只能调用成功回调或失败回调,不能同时调用,并且每个回调最多只能调用一次。但是,原生模块可以存储回调并在以后调用它。

回调有两种错误处理方法。第一种是遵循 Node 的约定,将传递给回调的第一个参数视为错误对象。

java
  @ReactMethod
public void createCalendarEvent(String name, String location, Callback callBack) {
Integer eventId = ...
callBack.invoke(null, eventId);
}

在 JavaScript 中,你可以检查第一个参数,看是否有错误传递过来

tsx
const onPress = () => {
CalendarModule.createCalendarEvent(
'testName',
'testLocation',
(error, eventId) => {
if (error) {
console.error(`Error found! ${error}`);
}
console.log(`event id ${eventId} returned`);
},
);
};

另一种选择是使用 onSuccess 和 onFailure 回调

java
@ReactMethod
public void createCalendarEvent(String name, String location, Callback myFailureCallback, Callback mySuccessCallback) {
}

然后在 JavaScript 中,你可以为错误和成功响应添加单独的回调

tsx
const onPress = () => {
CalendarModule.createCalendarEvent(
'testName',
'testLocation',
error => {
console.error(`Error found! ${error}`);
},
eventId => {
console.log(`event id ${eventId} returned`);
},
);
};

Promises

原生模块还可以履行 Promise,这可以简化你的 JavaScript,尤其是在使用 ES2016 的 async/await 语法时。当原生模块 Java/Kotlin 方法的最后一个参数是 Promise 时,其对应的 JS 方法将返回一个 JS Promise 对象。

将上面的代码重构为使用 Promise 而不是回调,如下所示

java
import com.facebook.react.bridge.Promise;

@ReactMethod
public void createCalendarEvent(String name, String location, Promise promise) {
try {
Integer eventId = ...
promise.resolve(eventId);
} catch(Exception e) {
promise.reject("Create Event Error", e);
}
}

与回调类似,原生模块方法可以拒绝或解决 Promise(但不能同时),并且最多只能执行一次。这意味着你只能调用成功回调或失败回调,不能同时调用,并且每个回调最多只能调用一次。但是,原生模块可以存储回调并在以后调用它。

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

tsx
const onSubmit = async () => {
try {
const eventId = await CalendarModule.createCalendarEvent(
'Party',
'My House',
);
console.log(`Created a new event with id ${eventId}`);
} catch (e) {
console.error(e);
}
};

reject 方法接受以下参数的不同组合

java
String code, String message, WritableMap userInfo, Throwable throwable

欲了解更多详情,您可以在此处找到 Promise.java 接口。如果未提供 userInfo,ReactNative 将其设置为 null。对于其余参数,React Native 将使用默认值。message 参数提供了错误调用堆栈顶部显示的错误 message。下面是 Java/Kotlin 中以下 reject 调用在 JavaScript 中显示的错误消息示例。

Java/Kotlin reject 调用

java
promise.reject("Create Event error", "Error parsing date", e);

Promise 被拒绝时 React Native 应用中的错误消息

Image of error message in React Native app.
错误消息图片

向 JavaScript 发送事件

原生模块可以在不被直接调用的情况下向 JavaScript 发送事件。例如,你可能想向 JavaScript 发送一个提醒,告知 Android 原生日历应用中的日历事件即将发生。最简单的方法是使用 RCTDeviceEventEmitter,它可以从 ReactContext 中获取,如以下代码片段所示。

java
...
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
...
private void sendEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}

private int listenerCount = 0;

@ReactMethod
public void addListener(String eventName) {
if (listenerCount == 0) {
// Set up any upstream listeners or background tasks as necessary
}

listenerCount += 1;
}

@ReactMethod
public void removeListeners(Integer count) {
listenerCount -= count;
if (listenerCount == 0) {
// Remove upstream listeners, stop unnecessary background tasks
}
}
...
WritableMap params = Arguments.createMap();
params.putString("eventProperty", "someValue");
...
sendEvent(reactContext, "EventReminder", params);

JavaScript 模块可以通过在 NativeEventEmitter 类上使用 addListener 来注册接收事件。

tsx
import {NativeEventEmitter, NativeModules} from 'react-native';
...
useEffect(() => {
const eventEmitter = new NativeEventEmitter(NativeModules.ToastExample);
let eventListener = eventEmitter.addListener('EventReminder', event => {
console.log(event.eventProperty) // "someValue"
});

// Removes the listener once unmounted
return () => {
eventListener.remove();
};
}, []);

从 startActivityForResult 获取 Activity 结果

如果你想从使用 startActivityForResult 启动的 Activity 中获取结果,你需要监听 onActivityResult。为此,你必须扩展 BaseActivityEventListener 或实现 ActivityEventListener。前者更受推荐,因为它对 API 更改更具弹性。然后,你需要像这样在模块的构造函数中注册监听器

java
reactContext.addActivityEventListener(mActivityResultListener);

现在,你可以通过实现以下方法来监听 onActivityResult

java
@Override
public void onActivityResult(
final Activity activity,
final int requestCode,
final int resultCode,
final Intent intent) {
// Your logic here
}

我们来实现一个基本的图片选择器来演示这一点。图片选择器将向 JavaScript 公开 pickImage 方法,该方法在调用时将返回图片的路径。

kotlin
public class ImagePickerModule extends ReactContextBaseJavaModule {

private static final int IMAGE_PICKER_REQUEST = 1;
private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";

private Promise mPickerPromise;

private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {

@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
if (requestCode == IMAGE_PICKER_REQUEST) {
if (mPickerPromise != null) {
if (resultCode == Activity.RESULT_CANCELED) {
mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
} else if (resultCode == Activity.RESULT_OK) {
Uri uri = intent.getData();

if (uri == null) {
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
} else {
mPickerPromise.resolve(uri.toString());
}
}

mPickerPromise = null;
}
}
}
};

ImagePickerModule(ReactApplicationContext reactContext) {
super(reactContext);

// Add the listener for `onActivityResult`
reactContext.addActivityEventListener(mActivityEventListener);
}

@Override
public String getName() {
return "ImagePickerModule";
}

@ReactMethod
public void pickImage(final Promise promise) {
Activity currentActivity = getCurrentActivity();

if (currentActivity == null) {
promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
return;
}

// Store the promise to resolve/reject when picker returns data
mPickerPromise = promise;

try {
final Intent galleryIntent = new Intent(Intent.ACTION_PICK);

galleryIntent.setType("image/*");

final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");

currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST);
} catch (Exception e) {
mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
mPickerPromise = null;
}
}
}

监听生命周期事件

监听 Activity 的生命周期事件,如 onResumeonPause 等,与实现 ActivityEventListener 的方式非常相似。模块必须实现 LifecycleEventListener。然后,你需要在模块的构造函数中注册一个监听器,如下所示

java
reactContext.addLifecycleEventListener(this);

现在你可以通过实现以下方法来监听 Activity 的生命周期事件

java
@Override
public void onHostResume() {
// Activity `onResume`
}
@Override
public void onHostPause() {
// Activity `onPause`
}
@Override
public void onHostDestroy() {
// Activity `onDestroy`
}

线程

迄今为止,在 Android 上,所有原生模块的异步方法都在一个线程上执行。原生模块不应该对它们被调用的线程有任何假设,因为当前的分配未来可能会改变。如果需要阻塞调用,则应将繁重的工作分派到内部管理的 worker 线程,并从那里分发任何回调。