如何从React Native Android模块访问Activity?

时间:2015-09-21 20:50:39

标签: android react-native

我正试图跨越Android屏幕保持React Native的功能。我想我可以用一个简单的模块做到这一点,但是我不知道如何从所述模块访问当前的Android Activity。

我需要Activity引用,因此我可以在其上调用((Activity)getReactApplicationContext().getBaseContext())

我尝试通过像{{1}}这样的转换来获取活动,但这会抛出“无法转换为Android.app.Activity”错误

10 个答案:

答案 0 :(得分:34)

CustomReactPackage.java

public class CustomReactPackage implements ReactPackage {

    private Activity mActivity = null;

    public CustomReactPackage(Activity activity) {
        mActivity = activity;
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        // Add native modules here
        return modules;
    }

    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        List<ViewManager> modules = new ArrayList<>();
        // Add native UI components here
        modules.add(new LSPlayerManager(mActivity));
        return modules;
    }
}

LSPlayerManager是我的原生UI组件。我定义了一个构造函数,以便我可以传入活动:

public LSPlayerManager(Activity activity) {
    mActivity = activity;
}

最后在定义MainActivity.java的{​​{1}}中,我们可以将活动传递给我们的自定义React包:

ReactInstanceManager

REACT NATIVE更新0.29.0

这不再是您在本机模块中访问活动的方式。有关迁移说明,请参阅https://github.com/facebook/react-native/releases/tag/v0.29.0

答案 1 :(得分:18)

我猜ReactContextBaseJavaModulegetCurrentActivity()方法可能会被使用,就像下面的代码一样,它是从React-Native原始代码中复制的;

import android.app.Activity;
import com.facebook.react.bridge.ReactContextBaseJavaModule;

public class AwesomeModule extends ReactContextBaseJavaModule {

  public AwesomeModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

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

  private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
  private static final String ERROR_NO_ACTIVITY_MESSAGE = "Tried to do the something while not attached to an Activity";

  @ReactMethod
  public void doSomething(successCallback, errorCallback) {

    final Activity activity = getCurrentActivity();

    if (activity == null) {
      errorCallback(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
      return;
    }

  }

}

答案 2 :(得分:6)

Editted:

问题是getReactApplicationContext()返回Application的上下文而不是Activity。您不能将Application上下文类型转换为Activity。

这是一个简单的解决方法

通常,反应原生中只有一个活动(主要活动),我们可以在MainActivity中编写一个静态函数来返回活动

private static Activity mCurrentActivity = null;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCurrentActivity = this;
    ...
}
...
public static Activity getActivity(){
    Activity activity = new Activity();
    activity = mCurrentActivity;
    return activity;
}

然后从桥接模块中调用MainActivity.getActivity()

答案 3 :(得分:1)

通过UI线程上下文获取活动/窗口/装饰视图

在您的课程文件中,导入内容包括...

import android.view.WindowManager;
import android.view.Window;
import android.view.View;

在您的类构造函数中...

private static ReactApplicationContext reactContext;
MyModule(ReactApplicationContext context) {
  super(context);
  reactContext = context;
}

然后输入类方法...

@ReactMethod
public void doSomethingRequiringWindow() {
  // get access to current UI thread first
  reactContext.getCurrentActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
      Window window = reactContext
       .getCurrentActivity().getWindow();
      View decorView = reactContext
       .getCurrentActivity().getWindow().getDecorView();
      // you have access to main ui thread so you can effect
      // immediate behavior on window and decorView
    }
  });
}

答案 4 :(得分:0)

对于0.28及之前,您可以使用同一字段从ReactInstanceManagerImpl的{​​{1}},0.29 + private @Nullable Activity mCurrentActivity;获取活动。

答案 5 :(得分:0)

如何将活动从ReactApplication :: getPackages()传递给包?

我不明白。我找不到任何明确的例子

package com.bluetoothioexample;

import android.app.Application;
import android.util.Log;

import com.facebook.react.bridge.ReactContextBaseJavaModule;

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;

import com.subsite.bluetoothio.BluetoothIOPackage;
import com.oblador.vectoricons.VectorIconsPackage;

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 BluetoothIOPackage(this), //<- How pass the activity
                                        // from ReactApplication ?
          new VectorIconsPackage()
      );
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

答案:您没有将活动从MainApplication传递到包。

从ReactContextBaseJavaModule中调用getCurrentActivity()

答案 6 :(得分:0)

对于自定义UI组件,您可以在构造函数中获取上下文,稍后可以通过context.getCurrentActivity()

获取活动。

答案 7 :(得分:0)

如果您想在 import xarray as xr import numpy as np # aggregation function def aggregate_xr_dataset(ds, n_types = 2): #prepare a resultant xr dataset regions = ds['regions'].values time_steps = ds['time'].values types = [f'type_{i}' for i in range(n_types)] data = np.zeros((len(time_steps), len(regions), n_types)) res_ts_var_da = xr.DataArray(data, [('time', time_steps), ('regions', regions), ('types', types)]) data = np.zeros((len(regions), len(types))) res_values_var_da = xr.DataArray(data, [('regions', regions), ('types', types)]) # Aggregation in every region... for region in regions: # Get ts and values of current region regional_ds = ds.sel(regions = region) regional_ts_da = regional_ds['ts_var'] regional_value_da = regional_ds['values_var'] # Preprocess - stack and transpose dimensions regional_ts_da = regional_ts_da.stack(x_y = ['x', 'y']) regional_ts_da = regional_ts_da.transpose(transpose_coords= True) regional_value_da = regional_value_da.stack(x_y = ['x', 'y']) regional_value_da = regional_value_da.transpose(transpose_coords= True) # Aggregation ## values res_values_var_da.loc[region, types[0]] = regional_value_da[dict(x_y=slice(None, 3))].sum() res_values_var_da.loc[region, types[1]] = regional_value_da[dict(x_y=slice(3, 9))].sum() ## ts res_ts_var_da.loc[:, region, types[0]] = regional_ts_da[dict(x_y=slice(None, 3))].sum() res_ts_var_da.loc[:, region, types[1]] = regional_ts_da[dict(x_y=slice(3, 9))].sum() # Create resulting dataset res_ds = xr.Dataset({"values": res_values_var_da, "ts": res_ts_var_da}) return res_ds # xarray dataset regions = ['reg_1','reg_2'] x_locations = np.arange(3) y_locations = np.arange(3) time = np.arange(3) ## time series data ts_var = np.array([ [[[1, 1, 1] for i in range(3)] for i in range(3)], [[[1, 1, 1] for i in range(3)] for i in range(3)] ]) ts_var_da = xr.DataArray(ts_var, coords=[regions, y_locations, x_locations, time], dims=['regions', 'y', 'x','time']) ## values data values_var = np.array([ [[1, 1, 1] for i in range(3)], [[1, 1, 1] for i in range(3)] ]) values_var_da = xr.DataArray(values_var, coords=[regions, y_locations, x_locations], dims=['regions', 'y', 'x']) ds = xr.Dataset({'ts_var': ts_var_da, 'values_var': values_var_da}) # Function call aggregate_xr_dataset(ds) 子类中获取前台活动的当前实例,请使用:

ReactContextBaseJavaModule

它来自使用 // class MyReactModule extends ReactContextBaseJavaModule Activity activity = getCurrentActivity();

ReactContextBaseJavaModule#getCurrentActivity <块引用>

注意reactContext.getCurrentActivity()包私有。所以你不能使用 ReactApplicationContext#getCurrentActivity

  • reactContext.getCurrentActivity() 的受保护。所以推导出它是可以实现的:
ReactContextBaseJavaModule
  • protected @Nullable final Activity getCurrentActivity() { return mReactApplicationContext.getCurrentActivity(); } 是包私有的(默认访问)。所以你无法得到它:
ReactApplicationContext
<块引用>

布诺斯

由于它是 /* package */ @Nullable Activity getCurrentActivity() { return mCurrentActivity; } ,请确保检查它的可用性:

@Nullable

答案 8 :(得分:-1)

https://github.com/facebook/react-native/blob/master/docs/NativeModulesAndroid.md开始并不是很清楚,但是您可以在react native分发中阅读ToastModule的源代码,看看他们是如何做到这一点github.com/facebook/react-native/blob /daba14264c9f0d29c0327440df25d81c2f58316c/ReactAndroid/src/main/java/com/facebook/react/modules/toast/ToastModule.java#L31-L33

我们的想法是,主要活动将作为反应器中的reactContext传递给调用来自ReactInstanceManager.builder()的模块调用github.com/facebook/react-native/blob/3b4845f93c296ed93c348733809845d587227823/local-cli/generator -android / templates / package / MainActivity.java#L28通过MainReactPackage实例化github.com/facebook/react-native/blob/daba14264c9f0d29c0327440df25d81c2f58316c/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java #L49

答案 9 :(得分:-1)

我需要修改过时的模块(react-android-360-video)并发现这有用......

android/app/src/main/java/com/webcdpmobiledemo/MainApplication.java中,我使用 new 格式添加了一个包:

...
import com.vrvideocomponent.VrVideoViewPackage;

public class MainApplication extends Application implements ReactApplication {

    ...

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
      ...

      @Override
      protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new VrVideoViewPackage()
        );
      }

      ...
    };

    ...
}

android/app/src/main/java/com/webcdpmobiledemo/MainActivity.java基本上是空的:

package com.yourproject;

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 "YourProject";
    }
}

然后,我修改了VrVideoViewPackage文件,该文件需要将reactContext传递给它调用的VrVideoViewManager

...

public class VrVideoViewPackage implements ReactPackage {
    ...

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>asList(
                new VrVideoViewManager(reactContext)
        );
    }

}

最后,在VrVideoViewManager中,可以像这样访问活动:

...

import android.app.Activity;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.bridge.ReactContext;

...

public class VrVideoViewManager extends SimpleViewManager<VrVideoView> {
    ...

    public VrVideoViewManager(ReactContext reactContext) {
        // Do not store mActivity, always getCurrentActivity when needed
        Activity mActivity = mContext.getCurrentActivity();
    }

    @Override
    protected VrVideoView createViewInstance(ThemedReactContext reactContext) {

        // You can also activity from ThemedReactContext
        Activity mActivity = reactContext.getCurrentActivity();

        VrVideoView vrView = new VrVideoView(mActivity);
        vrView.setEventListener(new ActivityEventListener(vrView));
        vrView.pauseVideo();
        return new VrVideoView(mActivity);
    }

    ...
}