【问题标题】:Android NDK Callbacks to Java ActivityAndroid NDK 回调到 Java Activity
【发布时间】:2014-08-08 11:31:22
【问题描述】:

我正在移植我的一个应用程序,因此大部分工作都在应用程序的本机部分完成,而 Java 端纯粹是为了我的 UI。

我目前正在尝试实现的是一个 ProgressBar,它将显示本机线程操作的状态。 UI 由不同的活动组成,我打算显示这些活动的进度条。

问题是:我该怎么做?我有一些本机代码如下:

jclass clazz = emv->FindClass( "com/example/myapp/MainActivity" );

对于 clazz 返回 null。我意识到当时实际上没有显示 MainActivity 活动 - 它是我的 SettingsActivity 的一个实例,所以我尝试相应地更改上面的行,但它仍然返回 null。

难道不能从本机代码调用 FindClass() 来检索 Activity 类吗?

最终我认为我需要做的是调用如下方法:

  public void ProgressUpdateFromNative( int i )
  {
    runOnUiThread( new Runnable()
    {
      @Override
      public void run()
      {
        DisplayProgressUpdate();
      }
    } );
  }

..这是我的一个活动中的一种方法。

jmethodID ProgressUpdateFromNative = env->GetMethodID( clazz, "ProgressUpdateFromNative", "(I)V");
env->CallObjectMethod( g_pObj, ProgressUpdateFromNative, 1 ) ;

我已经从我的 onLoad() JNI 调用中检索了 JavaVM 指针,并调用了 JavaVM->AttachCurrentThread() 来检索上面使用的 env 指针。

有人可以告诉我我缺少什么 - 即 - 为什么我从 FindClass 返回 null 类,或者如果我所做的完全错误,则将我置于不同的轨道上。我也打算阅读 Handlers,但我认为我的理解还没有那么远。

注意:我确实意识到我可以从 Java UI 轮询一些本机变量,但我更喜欢回调/事件处理实现而不是轮询。

【问题讨论】:

  • 调用FindClass()的本机代码如何调用?
  • @Hans Kratz:我有一个 pthread 正在运行处理从 Java Activity 发送到本机线程的消息。本机线程在循环中连续运行并处理它从 Java UI 获得的任何消息。

标签: java android callback android-ndk native


【解决方案1】:

如果您的代码不是从 Java 方法调用的,它将使用 FindClass() 中的系统类加载器,它只知道 Android 系统类。

我建议使用在JNI_OnLoad 中获取对类的引用,通过NewGlobalRef 创建对该类的全局引用并将其传递给您的线程或将其存储在全局变量中。

有关此行为的更多信息:http://markmail.org/message/25rrwp4va443rjuk#query:+page:1+mid:2u5wlkjyugwp75qa+state:results

【讨论】:

  • 我认为你得到了正确的答案。只是浏览我的 NDK Cookbook,我注意到 FindClass() 正在 OnLoad() 函数中的 MainActivity 上被调用。我不知道 NewGlobalRef 是做什么的,但我会做一些阅读和搜索。
  • 在 JNI 中对 Java 对象(例如类)的引用通常只有在获取它们的帧是生命时才有效。为了延长生命周期,您需要创建对它的全局引用。请注意,这将防止您创建全局引用的对象被垃圾收集。这就是为什么在通过DeleteGlobalRef 对普通对象完成引用后删除引用很重要的原因。
  • @Hand Kratz:谢谢。因此,如果我要获得对 Activity 的全局引用,这将是一件非常糟糕的事情,不是吗?我的 MainActivity 将始终保持不变,但如果设备被旋转,那么它将被重新创建 - 所以我最终会保留 2 个 Activity 对象,对吗? - 即使只有一个活动是有效的和最新的。我之前想知道是否有可能在(重新)创建时以某种方式用我的本机代码“注册”一个活动?
  • 当然可以在activity的onResume()方法中通过JNI调用原生方法来设置当前activity。在您的本机代码中,您可以删除旧的全局引用(如果它不为空)并为新活动创建一个新的全局引用。但是:我建议从您的本机代码中回调一个静态方法并在 Java 中进行所有进一步的处理。这样你就可以避免 NewGlobalRef/DeleteGlobalRef 的东西,除了对你的 jclass 的引用。
猜你喜欢
  • 1970-01-01
  • 2016-12-26
  • 1970-01-01
  • 2013-10-22
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多