У меня есть плагин C++ NDK (.so), который я хочу изменить макет Activity на Android. Этот плагин должен поддерживать push-уведомления и интерфейс слушателя.
Я знаю, что для этого мне нужно использовать интерфейс JNI, чтобы инициировать запросы к Java, а также получать события обратно от элементов пользовательского интерфейса. Однако где я застрял, так это то, как мой C++ имеет доступ к JVM или JEnv должным образом и за его пределами.
Предупреждение весь псудо-код. Мои вопросы и недоумение - в слове.
public class MyActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new TestRenderer().Start()
}
}
class TestRenderer {
// Messages to the plugin.
void native Start();
// Messages from the plugin.
void OnCreated() {
// Do something.
}
static {
System.loadLibrary("testrenderer");
}
}
Который затем вызовет JNI
JNIEXPORT void JNICALL Java_TestRenderer_Start(JNIEnv* env, jobject obj)
{
// Create my C++ class that does all the work!
TestRenderer renderer = new TestRenderer();
renderer.Start();
}
Однако, когда приходит время для моего C++ TestRenderer вызывать его собственную Java, здесь я рисую пробел относительно того, что здесь делать.
class TestRenderer
{
public:
...
void Start()
{
// Create a relative view.
CreateRelativeView();
}
private:
void CreateRelativeView()
{
// JNI create my java class and find method.
// Call method against against that Java class.
// What JVM, JEnv, or jobject should I use?
// AT THIS EXACT POINT I NEED ACCESS TO THE ACTIVITY CONTEXT.
// new CustomView(context); <--- ?????
}
// Also, how do I ensure I call OnCreated on the right Java object.
void OnCreated()
{
...
// Call method against Java TestRenderer on the right jobject.
}
};
Теперь о Java плагина
public class CustomView extends RelativeLayout {
public CustomView(Context context) {
super(context);
// Call back into native
OnCreated();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
// Call back into native
OnCreated();
}
// My listener call I would want invoked to go back through plugin to client.
public native OnCreated();
static {
// I assume back to the same plugin?
System.loadLibrary("testrenderer");
}
}
Я знаю, что это звучит запутанно, но если я смогу пройти через нативный на среднем уровне, это решит так много проблем с общим кодом на других платформах. Я чувствую, что это вполне возможно, но я рисую пустое место.
Заранее спасибо.
Я понимаю. Итак, исходя из того, что вы сказали, похоже, что лучшим подходом было бы сохранить Activity в каком-то одноэлементном значении, которое будет извлечено из GetEnv / AttachCurrentThread, которое использует кешированную JavaVM из JNI_OnLoad. Это также звучит так, как будто в идеале я хотел бы кэшировать этот созданный мной проект для поддержания срока службы CustomView, созданного из нативного ... Как мне узнать, какой CustomView соответствует какому TestRenderer? Я предполагаю, что я буду реализовывать JNI для «общедоступного встроенного OnCreated ();» а будет какой способ сравнить проекты?




JavaVM*безопасно кэшировать, поэтому вы можете взять тот, который вы получили вJNI_OnLoad, и сохранить его в глобальной переменной.JNIEnv*безопасен для кэширования нет, поэтому для получения действительногоJNIEnv*из произвольного потока требуется немного времени. См. этот ответ.