gpt4 book ai didi

java - 调用 C 函数时,Toast 不显示

转载 作者:行者123 更新时间:2023-11-30 15:07:52 27 4
gpt4 key购买 nike

我有一个可以通过启动器启动或在启动时运行的服务。问题是,当我使用 JNI 调用 C 函数时,所有 Toast 通知不再显示,而如果我仅调用 java 方法,则 Toast 通知仅显示美好的。是什么原因导致此问题以及如何解决它?

注意:如果 C 函数执行一些简单的操作(例如回调 java 并终止),则会显示 Toast 通知。然而,我的函数有一个用于处理中断的无限循环。

服务启动器

public class ServiceLauncher extends AppCompatActivity  {
@Override
public void onCreate(Bundle savedInstanceState) {
Toast.makeText(getBaseContext(), "onCreate", Toast.LENGTH_LONG).show();
super.onCreate(savedInstanceState);
startService(new Intent(this, MyService.class));
finish();
}
}

我的服务

public class MyService extends Service  {
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
Toast.makeText(this, "Terminated", Toast.LENGTH_LONG).show();
}

@Override
public int onStartCommand(Intent intent,int flags, int startid) {
Toast.makeText(this, "Running", Toast.LENGTH_LONG).show();
javaMethod(); /*toast displays if this is called*/
cMethodFromJNI(); /*toast does not display if this is called*/
return START_STICKY;
}
}

C代码结构

JNIEXPORT jint JNICALL
Java_className_cMethodFromJNI(JNIEnv *env, jclass type) {


jmethodID mid = (*env)->GetStaticMethodID(env, type, "javaMethod", "(I)V");

// open and read some fd (not shown)

for (;;) {
// wait on change in fd and act on it (not shown)
callJavaAgain(env,type,mid)
}
}
//close fd (not shown)
exit(0);
}

编辑:我已经按照下面的答案更改了代码。看起来情况和以前一模一样,也许我漏掉了一些东西。

修改了C代码结构

JNIEXPORT jint JNICALL

Java_className_cMethodFromJNI(JNIEnv * env, jclass type) {

/*cache JVM*/
int status = ( * env) - > GetJavaVM(env, & jvm);
if (status != 0) {
LOGD("failed to retrieve *env");
exit(1);
}
attachedThread();
}

void attachedThread() {
/* get a new environment and attach a new thread */
JNIEnv * newEnv;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6; // choose your JNI version
args.name = NULL; // if you want to give the java thread a name
args.group = NULL; // you can assign the java thread to a ThreadGroup
( * jvm) - > AttachCurrentThread(jvm, & newEnv, & args);
jclass cls = ( * newEnv) - > FindClass(newEnv, "fully/qualified/class/name");
jmethodID mid = ( * newEnv) - > GetStaticMethodID(newEnv, cls, "callJavaAgain", "(V)V");
// open and read some fd (not shown)

for (;;) {
// wait on change in fd and act on it (not shown)
intermediaryFunction(newEnv, cls, mid);
}
}
//close fd (not shown)
exit(0);
}

void intermediaryFunction(JNIEnv * newEnv, jclass cls, jmethodID mid) {
//do some stuff (not shown)
( * newEnv) - > CallStaticVoidMethod(newEnv, cls, mid);
}

最佳答案

好的,所以这个主题需要仔细注意。 Android docs讨论 JavaVM 和 JNIEnv 以及如何与它们交互。您需要做的是存储对 JavaVM 的全局引用,该引用可从 C 代码中的所有线程访问。 JVM 允许线程访问 JNIEnv,这可以让您访问类的方法等等。下一个关键问题是您需要存储一个 jobject“指针”,指向您从 C 代码(您可能已经知道)回调的 android 对象。确保在获取 JNIEnv 引用的线程上调用 JNIEnv->DetachThread。

再说一遍:

  • 获取 JavaVM 引用并将其存储在 C 代码中
  • 让 java 调用 c 代码来存储回调的 jobject 引用
  • 启动一个线程进行循环,获取该线程上 JNIEnv 的引用以调用 java
  • 在终止线程执行之前调用 DetachThread

另一个麻烦点是从 java 代码访问 c++ 对象,有一个巧妙的技巧,您可以让 c++ 代码创建 java 对象,并分配给 private long _cppPointer 创建的 Java 类的成员,然后将此对象添加到您已经指向的 Java 对象(例如 Activity 或其他东西)的某个集合中

祝你好运。

编辑:我终于想起来了another great source有关 JNI 工作的信息

关于java - 调用 C 函数时,Toast 不显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37887000/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com