react / react/react-native

(Android) getCurrentActivity() sometimes returns null inside ReactContextBaseJavaModule.getConstants()

Đang mở
#37,518 23 bình luận 10 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Issue: Author Provided Repro Needs: Attention Needs: Repro Newer Patch Available Platform: Android
Ngôn ngữ chính
C++
Star
127k
Fork
25.3k
Merge trung bình
1 ngày 23 giờ
Pull request đã merge (30 ngày)
4

Mô tả

Description

ReactContextBaseJavaModule has a method called getCurrentActivity(). When used inside ReactContextBaseJavaModule.getConstants() (actually, BaseJavaModule.getConstants()) - namely, during app launch (Javascript init), it sometimes returns the current activity, and sometimes null in what seems to be a random behavior.

React Native Version

0.70.7

Output of npx react-native info
System:
    OS: macOS 12.5.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 42.30 MB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 14.18.2 - ~/.nvm/versions/node/v14.18.2/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v14.18.2/bin/yarn
    npm: 6.14.18 - ~/.nvm/versions/node/v14.18.2/bin/npm
    Watchman: 2022.07.04.00 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.10.1
  SDKs:
    iOS SDK:
      Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
    Android SDK:
      Android NDK: 19.2.5345600
  IDEs:
    Android Studio: 2022.2 AI-222.4459.24.2221.9971841
    Xcode: 14.2/14C18 - /usr/bin/xcodebuild
  Languages:
    Java: 17.0.6 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.1.0 => 18.1.0
    react-native: 0.70.7 => 0.70.7
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found
Steps to reproduce

⚠️ This is a theoretical guide that I haven't tried applying manually, but it should work.

  1. Run react-native init
  2. Open the android source code of it using Android Studio.
  3. Create a fresh stub NativeModule that looks roughly like so:
public class StubNativeModule extends ReactContextBaseJavaModule {
    StubNativeModule(ReactApplicationContext context) {
        super(context);
    }

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

    @Override
    public Map<String, Object> getConstants() {
        Activity activity = getCurrentActivity();
        Log.e("StubNM", "Has activity?" + (activity != null));
        return null;
    }

    // Required due to an old RN bug
    @ReactMethod
    public void oldBugWorkaround() {}
}
  1. Register the stub native module in a native package and add to your ReactNativeHost.getPackages() method.
  2. In index.js (or app.js), add the following import at the top:
import { NativeModules } from "react-native";
const stubConsts = NativeModules.StubNativeModule.value;
  1. In command line, launch the app repeatedly (i.e. using react-native run-android), and follow the logs using logcat. You will end up seeing something like this, in consequent runs:
StubNM  E  Has activity? true
...
StubNM  E  Has activity? true
...
StubNM  E  Has activity? false
...
StubNM  E  Has activity? true
...
StubNM  E  Has activity? false

(and so on and so forth)

Snack, code example, screenshot, or link to a repository

For starters, this report is in fact the reason behind this bug, which has been reported by me to the react-native-launch-arguments repo.

As for the problem itself - it is rooted in the handling of mCurrentActivity, here:

public void onHostResume(@Nullable Activity activity) {
    mLifecycleState = LifecycleState.RESUMED;
    mCurrentActivity = new WeakReference(activity);
// ...
}

While mCurrentActivity is set in onHostResume(), which is a bit late compared to when the activity gets initially created, getConstants() can be called by RN's initialization sequence in very early stages. Add to that the fact the two occur in an asynchronous way (i.e. in different, async threads) - you get that the call to getCurrentActivity() is very likely to miss the completion of the initialization of ReactContext.mCurrentActivity. These circumstances induce the mentioned behavior, which is highly nondeterministic and "feels random".

Solutions

There are quite a few nonoverlapping alternatives to how this can be resolved:

  1. Have the RN context start holding the activity upon creation, rather than wait for it to be resumed. Accordingly, clean-up might have to move to the destroyed phase. This is the most straightforward way but likely also the one introducing the most risk.
  2. Dispatch the native-modules thread (more precisely, its initialization) upon activity resume.
  3. Perform the native-modules init inside the existing thread in a more synchronous way, waiting for the activity to be available before moving forward with initialization.
  4. Enable native-modules (or native-packages) to specify various constraints, one of which could be the activity's state; Then, break the current init loop onto several ones based on constraints fulfillment.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java, đặc biệt là onHostResume(), và theo dõi cách ReactContextBaseJavaModule.getConstants() và quá trình khởi tạo BaseJavaModule được gọi. Tái hiện tình trạng activity khả dụng không liên tục bằng ví dụ StubNativeModule và logcat. Công việc được xem là hoàn tất khi có một thiết kế vòng đời hoặc khởi tạo đã được thống nhất, giúp hành vi của getCurrentActivity() trong khi tải các hằng số trở nên xác định.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
android, java, react-native
Lĩnh vực
mobile-dev
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.