JNI behält einen globalen Verweis auf ein Objekt und greift mit anderen JNI-Methoden darauf zu. Ein C ++ Objekt über mehrere JNI-Aufrufe hinweg am Leben erhalten

8

Ich beginne gerade mit JNI und habe ein folgendes Problem.

Ich habe eine C ++ - Bibliothek, die eine einfache Klasse hat. Ich habe drei JNI-Methoden, die aus dem Java-Android-Projekt aufgerufen wurden, die diese Klasse instatieren, eine Methode für die instanziierte Klasse aufrufen bzw. sie zerstören. Ich behalte einen globalen Verweis auf dieses Objekt, also wäre es für mich in den anderen beiden JNI-Methoden verfügbar.

Ich vermute, dass ich das nicht tun kann. Wenn ich die App ausführe, erhalte ich einen Laufzeitfehler (verwendeter Verweis abgestanden), und ich vermute, dass dies daran liegt, dass die globale Referenz bei nachfolgenden Aufrufen anderer JNI-Methoden ungültig ist.

Ist der einzige Weg, um das zu erreichen, was ich möchte (das Objekt über mehrere JNI-Aufrufe hinweg leben lassen), den Zeiger auf die instanziierte Klasse zurück an Java zu übergeben, dort herumzuhalten und dann an den JNI zu übergeben Funktionen? Wenn ja, ist das in Ordnung, ich möchte sicherstellen, dass ich es nicht mit einer globalen Referenz tun kann, und ich verpasse nicht einfach etwas.

Ich habe die Dokumentation und die Kapitel über globale / lokale Referenzen in JNI gelesen, aber es scheint, dass das nur für Java-Klassen gilt, und nicht für meine eigenen, nativen C ++ - Klassen, oder liege ich falsch.

Hier ist der Code, wenn meine Beschreibung nicht klar ist (zusammenfassend, ich frage mich, ob dieser Mechanismus von persistenten Objekten überhaupt funktioniert):

Java:

%Vor%

}

JNI-Header:

%Vor%

JNI Körper:

%Vor%

C ++ Header:

%Vor%

C ++ Körper:

%Vor%

Danke

    
cierech 20.03.2012, 23:05
quelle

3 Antworten

4

Das Problem mit Ihrer Implementierung ist das Datenelement jstring . NewStringUTF() erstellt ein Java String -Objekt, das von einer JNI-Methode zurückgegeben werden soll. Es ist also eine Java-lokale Referenz. Sie speichern das jedoch in einem C ++ - Objekt und versuchen, es über JNI-Aufrufe hinweg zu verwenden.

Sie sollten besser zwischen C ++ - Objekten, Java und der dazwischen liegenden JNI-Schnittstelle unterscheiden. Mit anderen Worten, das C ++ sollte eine C ++ - Methode zum Speichern von Strings verwenden (wie std::string ). Die JNI-Implementierung von InvokeNativeFunction() sollte das in einen jstring als Rückgabewert konvertieren.

PS: Dort sind Fälle Fälle, in denen die C ++ - Implementierung Verweise auf Java-Objekte beibehalten muss (oder umgekehrt). Aber es macht den Code komplexer und anfällig für Speicherfehler, wenn nicht richtig gemacht. Sie sollten es also nur dort verwenden, wo es wirklich einen Mehrwert darstellt.

    
Kris Van Bael 21.03.2012, 00:38
quelle
0

Das kannst du nicht tun. Objektreferenzen, einschließlich Klassenreferenzen, sind nicht über JNI-Aufrufe hinweg gültig. Sie müssen den Abschnitt der JNI-Spezifikation zu lokalen und globalen Referenzen lesen.

    
EJP 21.03.2012 00:35
quelle
0

Ich konnte zu diesem Thema keine gute Antwort zu SO finden, also ist hier meine Lösung, um Objekte in C ++ lebendig zu halten, um sie aus mehreren JNI-Aufrufen zu referenzieren:

Java

Auf der Java-Seite erstelle ich eine Klasse mit einem long -Zeiger, um einen Verweis auf das C ++ - Objekt zu behalten. Das Wrapping der C ++ - Methoden in einer Java-Klasse ermöglicht es uns, die C ++ - Methoden in mehreren Aktivitäten zu verwenden. Beachten Sie, dass ich das C ++ - Objekt für den Konstruktor erstelle und das Objekt beim Bereinigen löscht. Dies ist sehr wichtig, um Speicherlecks zu vermeiden:

%Vor%

C ++

Auf der C ++ - Seite definiere ich Funktionen zum Erstellen, Ändern und Löschen des Objekts. Es ist wichtig zu erwähnen, dass wir new und delete verwenden müssen, um das Objekt im HEAP-Speicher zu speichern, damit es während des gesamten Lebenszyklus der Java-Klasseninstanzen am Leben bleibt. Ich speichere auch den Zeiger auf CppObject gerade in der JavaClass mit getFieldId , SetLongField und GetLongField :

%Vor%

HINWEISE:

  • Im Gegensatz zu Java hat C ++ keine Speicherbereinigung, und das Objekt wird im HEAP-Speicher gespeichert, bis Sie delete .
  • verwenden
  • Ich verwende GetFieldID , SetLongField und GetLongField , um den Objektreferenz von C ++ zu speichern, aber Sie könnten auch den Objektzeiger jlong aus Java speichern, wie in anderen Antworten besprochen.
  • In meinem letzten Code habe ich die Klasse JavaObject als Parcelable implementiert, um meine Klasse an mehrere Aktivitäten zu übergeben, indem ich Intent mit Extras verwende.
Jaime Ivan Cervantes 20.06.2017 18:23
quelle

Tags und Links