我有一个Android应用程序,它同时使用React Native和JNI。 C ++(通过JUCE库的一个分支)用于生成其中一个视图。
React Native要求从重写的方法createViewInstance(context)
返回一个新的视图实例。每次更新包含此视图的React Native组件时,都会调用此方法。
这是我的(简化)实施:
protected JuceViewHolder createViewInstance(ThemedReactContext themedReactContext) {
JuceBridge juceBridge = JuceBridge.getInstance();
juceViewHolder = new JuceViewHolder(themedReactContext);
// JNI method: this will trigger JuceBridge.createNewView
MainActivity.createJuceWindow(juceViewHolder);
return juceViewHolder;
}
作为参考,createJuceWindow
定义为:
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, createJuceWindow, jobject, (JNIEnv* env, jclass, jobject view))
{
JuceView::getInstance().createJuceWindow(view);
}
调用:
void createJuceWindow(jobject view)
{
viewToAttachTo = GlobalRef(view); // [GlobalRef][1] manages NewGlobalRef
myComponent = std::unique_ptr<MyComponent> (new MyComponent);
myComponent->setVisible (true);
myComponent->setOpaque(true);
if (viewToAttachTo.get() == nullptr)
DBG ("createJuceWindow: viewToAttachTo null!!!");
myComponent->setBounds(Desktop::getInstance().getDisplays().getMainDisplay().userArea);
myComponent->addToDesktop (0, viewToAttachTo.get()); // This passes in the `jobject` held by GlobalRef
}
我已将JuceViewHolder
派生自ViewGroup,我通过JNI将其传递给C ++函数,以附加从(C ++){{3}生成的(Java)ComponentPeerView
构造函数
AndroidComponentPeer (Component& comp, const int windowStyleFlags, void* viewToAttachTo)
: ComponentPeer (comp, windowStyleFlags),
usingAndroidGraphics (false),
fullScreen (false),
sizeAllocated (0),
scale ((float) Desktop::getInstance().getDisplays().getMainDisplay().scale)
{
// NB: must not put this in the initialiser list, as it invokes a callback,
// which will fail if the peer is only half-constructed.
if (viewToAttachTo == nullptr) DBG ("viewToAttachTo null");
view = GlobalRef (android.bridge.callObjectMethod (JuceBridge.createNewView,
(jboolean) component.isOpaque(),
(jlong) this,
(jobject) viewToAttachTo));
if (view.get() == nullptr)
DBG ("view null!");
else
DBG ("got view.");
if (isFocused())
handleFocusGain();
}
通过createNewView
方法:(简化在这里)
public final ComponentPeerView createNewView (boolean opaque, long host, ViewGroup viewToAttachTo)
{
ComponentPeerView v = new ComponentPeerView (viewToAttachTo.getContext(), opaque, host);
viewToAttachTo.addView(v);
return v;
}
host
是指向C ++ AndroidComponentPeer
实例的指针。
这最初有效,但似乎如果我切换到另一个View或Activity和/或切换回C ++ View,我会遇到类似于以下内容的崩溃:
JNI ERROR (app bug): accessed deleted global reference 0x100566
art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: use of deleted global reference 0x100566
art/runtime/java_vm_ext.cc:410] from void com.juce.JuceBridge$ComponentPeerView.focusChanged(long, boolean)
我目前的假设是错误是由于void*
指针在某些时候由于垃圾收集器移动底层对象而变得过时,如AndroidComponentPeer
中所述。我从文章中得到的是jobject
应该用来代替指针。
然而,我使用的Component::addToDesktop
方法的方法签名使用void*
:
virtual void addToDesktop (int windowStyleFlags,
void* nativeWindowToAttachTo = nullptr);
(这是iOS中用于传递原始UIView
以附加Component
的方法)
我的假设有效吗?如果是这样,是否可以安全地将void*
指针转换为Java对象,将其存储为jobject
(通过NewGlobalRef),然后将其传递回Java?