我正在编写具有Java和本机部分的Android应用程序。 Java部分将消息发送到本机部分并接收回答。 本机部分完全在单独的线程上工作,当它返回答案时,我想在主线程上处理答案。 这是我扩展的Application类的一部分:
@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类的包装器。 包装由SWIG生成。
我尝试在GDB中调试它,GDB甚至向我展示了堆栈跟踪,它以本机Message.toStr方法结束。 但gdb拒绝打印变量,在当前上下文中说“无符号” * “。
请帮我解决这个问题。
I'm writing Android application that has Java and native part. Java part sends messages to native part and receives answers back. Native part does all work on separate thread and when it returns answer I want to handle answers on main thread. Here is part of my extended Application class:
@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 } }); }Native code calls OnMessage method on it's thread and trying to pass it to UI thread through Handler. And when I try to use any method of msg inside UI thread my program fails with SEGSEGV.
Significant fact is that Message class is the wrapper for C++ Message class. Wrapper was generated by SWIG.
I tried to debug it in GDB, and GDB even shows me stack trace, which ends in native Message.toStr method. But gdb refuses to print variables, saying "No symbol "*" in current context".
Please, help me to resolve this issue.
最满意答案
我认为你没有正确使用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
Finally I solved problem by myself. The problem was, that when we make call from C++ to Java, SWIG proxy method passed pointer to it's argument to Java side. Something like:
void SwigDirector_NativeLayerDelegate::OnMessage(Message msg, Long answer_to) { ... *((Message **)&jmsg) = &msg; ... jenv->CallStaticVoidMethod(..., jmsg, ...); ... }On Java side another proxy method recieved pointer, wrapped it with Java representation of Message class and passed it to Java method 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. }After OnMessage finished, native Message object was destructed in SwigDirector_NativeLayerDelegate::OnMessage and Java Message object kept pointer to destructed native object.
Solution
I've wrote custom typemaps for my Message object:
%typemap(directorin,descriptor="L$packagepath/$javaclassname;") Message %{*((Message**)&$input) = new Message($1);%} %typemap(javadirectorin,descriptor="L$packagepath/$javaclassname;") Message %{new Message($1, true)%}Now SwigDirector_NativeLayerDelegate::OnMessage creates copy of msg and Java object owns it:
// 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); }更多推荐
发布评论