Passing a Java object to C++ via JNI and then back to Java, via void*
<p>I have an Android app that employs both React Native and JNI. C++ (via a fork of the JUCE library) is used to generate one of the views. </p>

<p>React Native requires that a new instance of a view be returned from the overridden method <code>createViewInstance(context)</code>. This seems to get called each time a React Native component containing this view is updated.</p>

<p>Here is my (simplified) implementation:</p>

<pre><code>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;
</code></pre>

<p>}</p>

<p>For reference, <code>createJuceWindow</code> is defined as:</p>

<pre><code>JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, createJuceWindow, jobject, (JNIEnv* env, jclass, jobject view))
{
    JuceView::getInstance().createJuceWindow(view);
}
</code></pre>

<p>which calls:</p>

<pre><code>void createJuceWindow(jobject view)
{
    viewToAttachTo = GlobalRef(view); // [GlobalRef][1] manages NewGlobalRef
    myComponent = std::unique_ptr&lt;MyComponent&gt; (new MyComponent);
    myComponent-&gt;setVisible (true);
    myComponent-&gt;setOpaque(true);

    if (viewToAttachTo.get() == nullptr)
        DBG ("createJuceWindow: viewToAttachTo null!!!");

    myComponent-&gt;setBounds(Desktop::getInstance().getDisplays().getMainDisplay().userArea);
    myComponent-&gt;addToDesktop (0, viewToAttachTo.get()); // This passes in the `jobject` held by GlobalRef
}
</code></pre>

<p>I have separated the <a href="https://github.com/adamski/JUCE/blob/android-bridge-attachWindow/modules/juce_core/native/java/JuceViewHolder.java" rel="nofollow"><code>JuceViewHolder</code></a> derived from ViewGroup, and I am passing it to a C++ function via JNI in order to attach the (Java)<a href="https://github.com/adamski/JUCE/blob/android-bridge-attachWindow/modules/juce_core/native/java/JuceBridge.java#L385" rel="nofollow"><code>ComponentPeerView</code></a> generated from the (C++) <a href="https://github.com/adamski/JUCE/blob/android-bridge-attachWindow/modules/juce_gui_basics/native/juce_android_Windowing.cpp#L131" rel="nofollow"><code>AndroidComponentPeer</code></a> constructor</p>

<pre><code>AndroidComponentPeer (Component&amp; 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();
}
</code></pre>

<p>via the <code>createNewView</code> method: (simplified here)</p>

<pre><code>public final ComponentPeerView createNewView (boolean opaque, long host, ViewGroup viewToAttachTo)
{
    ComponentPeerView v = new ComponentPeerView (viewToAttachTo.getContext(), opaque, host);
    viewToAttachTo.addView(v);
    return v;
}
</code></pre>

<p><code>host</code> is a pointer to the C++ <code>AndroidComponentPeer</code> instance. </p>

<p>This works initially, however it seems that if I switch to another View or Activity and/or switch back to the C++ View, I get a crash similar to the following:</p>

<pre><code>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)
</code></pre>

<p>My current assumption is that the error is due to the <code>void*</code> pointer becoming obsolete at some point due to the garbage collector moving the underlying object, as described in <a href="http://android-developers.blogspot.co.uk/2011/11/jni-local-reference-changes-in-ics.html" rel="nofollow">this article</a>. What I got from the article is that <code>jobject</code> should be used in place of a pointer. </p>

<p>However the method signature of the <code>Component::addToDesktop</code> method that I have employed uses <code>void*</code>:</p>

<pre><code>virtual void addToDesktop (int windowStyleFlags,
                               void* nativeWindowToAttachTo = nullptr);
</code></pre>

<p>(This is the method used in iOS to pass a native <code>UIView</code> to attach a <code>Component</code> to)</p>

<p>Is my assumption valid? If so, is it possible to safely cast a <code>void*</code> pointer to a Java object, store it as a <code>jobject</code> (via NewGlobalRef) and then pass it back to Java? </p>