【问题标题】:SurfaceView inside of React Native app makes everything blankReact Native 应用程序中的 SurfaceView 使一切变为空白
【发布时间】:2021-12-20 05:49:52
【问题描述】:

我正在创建一个 React Native Android 应用程序,并且我想嵌入一个使用 Vulkan 呈现的控件。我通过创建一个名为 VkSurfaceViewSurfaceView 的子类并使用 JNI 调用在 Rust 中实现 Vulkan 代码来实现此控制。

我打开了显示所有视图边界的调试设置,以便清楚地看到视图仍然存在。

这是一个简单的 Android 布局(无 React Native)内的 Vulkan 控件(目前,它只呈现一个三角形):

这是我没有 Vulkan 控件的 React Native 布局(正方形代表我试图放置 Vulkan 控件的位置):

但是当我放置 Vulkan 控件时,其他一切都变暗了,即使布局检查器和调试覆盖显示其他视图仍然存在:

为什么会发生这种情况?如上所示,Vulkan 控件在纯 Android 布局中工作,所以我认为它一定会以某种方式与 React Native 进行不利的交互。但是,我发现像 thisthis 这样的例子可以在 React Native 中使用 SurfaceView/TextureView/VideoView 而不会引起问题。

编辑:即使我注释掉VkSurfaceView中的所有代码,黑屏问题仍然存在(但三角形显然消失了),所以我认为不会发生这种情况因为我的 Vulkan 代码有问题。

编辑 2: 如果我从 TextureView 派生而不是 SurfaceView 派生,它会起作用。但为什么?我怀疑这与here 解释的差异有关,但我仍然不明白为什么视图是否使用 OpenGL 合成很重要。

这是我的代码:

React Native index.js:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
import VkSurfaceView from './surface-view';

const HelloWorld = () => {
  return (
    <View style={[styles.container, {
      // Try setting `flexDirection` to `"row"`.
      flexDirection: "column"
    }]}>
      <Text style={styles.hello}>Hello, World</Text>
      <View style={{ width: 100, height: 100, alignSelf: 'center', backgroundColor: 'pink' }}>
        <VkSurfaceView style={{ width: 100, height: 100 }}/>
      </View>
    </View>
  );
};
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#ffffff'
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: 'green'
  }
});

AppRegistry.registerComponent(
  'MyReactNativeApp',
  () => HelloWorld
);

React Native surface-view.js:

import { requireNativeComponent } from 'react-native';

module.exports = requireNativeComponent('SPVkSurfaceView');

JavaSurfaceReactPackage.java:

public class SurfaceReactPackage implements ReactPackage {
    @NonNull
    @Override
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @NonNull
    @Override
    public List<ViewManager> createViewManagers(
            @NonNull ReactApplicationContext reactContext) {
        return Collections.singletonList(
                new ReactSurfaceManager(reactContext)
        );
    }
}

JavaReactSurfaceManager.java:

public class ReactSurfaceManager extends SimpleViewManager<VkSurfaceView> {
    public static final String REACT_CLASS = "SPVkSurfaceView";
    ReactApplicationContext mCallerContext;

    public ReactSurfaceManager(ReactApplicationContext reactContext) {
        mCallerContext = reactContext;
    }

    @NonNull
    @Override
    public VkSurfaceView createViewInstance(ThemedReactContext context) {
        return new VkSurfaceView(context);
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }
}

JavaMainActivity.java

public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // initialize native code library before using VkSurfaceView
        MyNativeLibary.init();

        // initialize React Native
        mReactRootView = new ReactRootView(this);
        List<ReactPackage> packages = new PackageList(getApplication()).getPackages();
        packages.add(new SurfaceReactPackage());

        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setCurrentActivity(this)
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("index")
                .addPackages(packages)
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        // The string here (e.g. "MyReactNativeApp") has to match
        // the string in AppRegistry.registerComponent() in index.js
        mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);

        setContentView(mReactRootView);
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy(this);
        }
        if (mReactRootView != null) {
            mReactRootView.unmountReactApplication();
        }
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        this.onBackPressed();
    }

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }
}

【问题讨论】:

    标签: android react-native surfaceview vulkan


    【解决方案1】:

    一种解决方案是使用TextureView 而不是SurfaceView。但是,这似乎不太好用,因为每隔几秒我就会遇到与帧缓冲相关的超时问题。我最终使用的解决方案是将SurfaceView 包裹在FrameLayout 中。

    【讨论】:

      猜你喜欢
      • 2017-09-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多