0

我正在编写具有 Java 和本机部分的 Android 应用程序。Java 部分向本机部分发送消息并接收回复。本机部分都在单独的线程上工作,当它返回答案时,我想在主线程上处理答案。这是我的扩展应用程序类的一部分:

@Override
public void OnMessage(final Message msg, final long answerTo) {
    Log.i(TAG, msg.ToStr()); // OK
    handler.post(new Runnable() {
        @Override
        public void run() {
            Log.i(TAG, msg.ToStr()); // Fatal signal 11 (SIGSEGV)
                                     // at 0x74616862 (code=1), thread 13255
        }
    });
}

本机代码在其线程上调用 OnMessage 方法并尝试通过 Handler 将其传递给 UI 线程。当我尝试在 UI 线程中使用任何 msg 方法时,我的程序因 SEGSEGV 而失败。

重要的事实是 Message 类是 C++ Message 类的包装器。Wrapper 由SWIG生成。

我尝试在 GDB 中调试它,GDB 甚至向我显示堆栈跟踪,它以本机 Message.toStr 方法结束。但是 gdb 拒绝打印变量,说“在当前上下文中没有符号” * “”。

请帮我解决这个问题。

4

2 回答 2

0

我认为您没有正确使用 Handler 来执行您正在尝试做的事情(跨线程复制对象)。在此处查看博客文章:

http://techtej.blogspot.com/2011/02/android-passing-data-between-main.html

特别是向这样的处理程序发送消息:

Message msg = Message.obtain();
msg.obj =  // Some Arbitrary object
mHandler.sendMessage(msg);

我认为您这样做的方式不会执行线程之间数据复制的 Handler 魔术,因为它只是运行 Runnable。

编辑:我很想知道这是否是问题所在,所以即使不是,您能否在评论中回复并让我知道结果?

编辑 2:所以看起来您的对象可能被存储为 JNI 层中的本地引用。不幸的是,这对于您的目的还不够好,您可能需要将其设为全局参考。请注意,如果您确实将其设为全局引用,则必须在完成后自己在本机代码中将其删除。

http://developer.android.com/training/articles/perf-jni.html#local_and_global_references

于 2013-08-08T23:45:37.397 回答
0

最后我自己解决了问题。问题是,当我们从 C++ 调用 Java 时,SWIG 代理方法将指向它的参数的指针传递给 Java 端。就像是:

void SwigDirector_NativeLayerDelegate::OnMessage(Message msg, Long answer_to) {
  ...
  *((Message **)&jmsg) = &msg;
  ...
  jenv->CallStaticVoidMethod(..., jmsg, ...);
  ...
}

在 Java 端,另一个代理方法接收到指针,用 Message 类的 Java 表示包装它并将其传递给 Java 方法 OnMessage:

  public static void SwigDirector_NativeLayerDelegate_OnMessage(
     NativeLayerDelegate self, long msg, long answer_to) {
    self.OnMessage(new Message(msg, false), answer_to);
    // false parameter means that Message object isn't owner of 'msg' pointer, so it
    // shouldn't free it on finalize.
  }

OnMessage 完成后,原生 Message 对象被破坏SwigDirector_NativeLayerDelegate::OnMessage,Java Message 对象保持指向被破坏的原生对象的指针。

解决方案

我为我的 Message 对象编写了自定义类型映射:

%typemap(directorin,descriptor="L$packagepath/$javaclassname;") Message
  %{*((Message**)&$input) = new Message($1);%}
%typemap(javadirectorin,descriptor="L$packagepath/$javaclassname;") Message
  %{new Message($1, true)%}

现在 SwigDirector_NativeLayerDelegate::OnMessage 创建副本msg并且 Java 对象拥有它:

// Native
void SwigDirector_NativeLayerDelegate::OnMessage(Message msg, Long answer_to) {
  ...
  *((Message**)&jmsg) = new Message(msg);
  ...
  jenv->CallStaticVoidMethod(..., jmsg, ...);
  ...
}

// Java
public static void SwigDirector_NativeLayerDelegate_OnMessage(
     NativeLayerDelegate self, long msg, long answer_to) {
    self.OnMessage(new Message(msg, true), answer_to);
}
于 2013-08-11T01:14:58.393 回答