java - 如何在回调函数中发送广播
问题描述
我创建了一个 android 项目,项目是一个服务,没有 UI。Java 层(函数名为 onReceive)将接收到 startservice 的广播。并且将调用本机 c 函数(函数名称为 startService)。C 函数会创建一个线程,在这个线程中,它将调用 Java 中的函数(函数名称分别为 SendLaResult(native) 和 SendLaResult(java))。而java函数会发送广播到另一个APP。这是一个大流量。以下代码是示例。
1.开始工作
public void onReceive(final Context context, final Intent intent) {
...
new Thread() {
public void run() {
try {
String str="test";
startService(str);
Log.i(TAG, "startService end!!!");
}
catch(Exception e) {
e.printStackTrace();
}
}
}.start();
...
}
2. native-lib.cpp,java中调用函数。
void SendResult( LaResult laResult)
{
bool isAttached = false;
if(!isAttached) {
int getEnvStat = g_JavaVM->GetEnv((void **)&g_env, JNI_VERSION_1_6);
if(getEnvStat < 0) {
jint status = g_JavaVM->AttachCurrentThread(&g_env, NULL);
if(status >= 0) {
isAttached = true;
}
}
}
if(g_env == NULL) {
LOGE("g_env is NULL!!!");
}
jshort conf = laResult.conf ;
jshort nls = laResult.nls ;
jshort egoln = laResult.egoln ;
g_laresult_constructor = g_env->GetMethodID(g_callback_laresult,"<init>","(SSSI[S)V");
if(g_laresult_constructor == NULL) {
LOGE("GetMethodID laresult error!!!");
}
jobject jparams = g_env->NewObject(g_callback_laresult, g_laresult_constructor, conf, nls, egoln);
if(jparams == NULL) {
char * str=strerror(errno);
LOGE("NewObject jparams error %s !!!" ,str);
}
g_mid_sendlaresult = g_env->GetMethodID(g_callback_laservice, "SendLaResult", "(Lcom/xxx/xxx/xxxx/LaResult;)V");
if(g_mid_sendlaresult == NULL) {
LOGE("GetMethodID g_mid_sendlaresult error!!!");
}
jobject serviceobject = g_env->AllocObject(g_callback_laservice);
if(serviceobject == NULL) {
LOGE("AllocObject serviceobject error!!!");
}
g_env->CallVoidMethod(serviceobject, g_mid_sendlaresult, jparams);
g_env->DeleteLocalRef(jparams);
if(isAttached ) {
g_JavaVM->DetachCurrentThread();
}
return;
}
3.LaService.java,发送广播到另一个APK
public void SendLaResult(LaResult laresult) {
Intent intent = new Intent();
intent.setAction( "com.xxx.xxx.xxx.LA_RESULT" );
intent.putExtra( "conf", laresult.conf);
Log.d( "confidence", Integer.toString(laneresult.confidence) );
intent.putExtra( "nls", laresult.nls);
Log.d( "nLanes", Integer.toString(laneresult.nLanes) );
intent.putExtra( "egoln", laresult.egoln);
sendBroadcast( intent );
}
4.调用sendBroadcast时,出现如下crash。
--------- beginning of crash
01-02 18:05:11.505 13501-13537/com.xxx.xxx.xxxxx
E/AndroidRuntime: FATAL EXCEPTION: Thread-9
Process: com.xxx.xxx.xxxx, PID: 13501
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.sendBroadcast(android.content.Intent)' on a null object reference
at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:431)
at com.xxx.xxx.xxxxx.xxxxxx.SendLaResult(LaService.java:94)
我发现sendBroadcast是异步的,最终被系统调用,立即返回。所以我删除了函数 SendResult 中的以下源代码。
g_JavaVM->DetachCurrentThread();
不会发生崩溃,但是会出现以下错误日志,请参阅函数 SendResult 中的源代码。
01-02 18:15:03.696 13707-13743/com.xxx.xxx.xxxx
E/native-lib: NewObject jparams error Success !!!
如何解决第一个问题(sendBroadcast 崩溃)或如何解决发送问题(NewObject return null) 请给一些建议。
解决方案
我解决了这个问题。不要在函数 SendLaResult 中发送广播,将每个 LaResult 存储到列表中,在 Oncreate 中创建另一个线程,在此线程中发送列表中的每个项目。
推荐阅读
- docker - 为什么 docker hub 上的某些存储库没有 dockerfile?
- javascript - 如何用玩笑模拟 es6 构造函数
- php - 为什么输入不去本地主机?
- amazon-web-services - 每个 AZ 中没有目标的 AWS 网络负载均衡器
- php - 如何计算 PHP 数组中的真值和假值?
- c# - 批量删除是在 Azure 存储中执行目录删除的更好方法吗?
- python - 如何在 Pygal 中制作子图?
- opencv - 在 Mac 上使用 opencv 在 Python 中制作带有图像的视频
- angular - 有没有办法在 Ionic 中使用 Angular 路由器插座?
- angular - 为什么 Angular 中需要 DoCheck 生命周期钩子?