當前位置:首頁 » 安卓系統 » android線程返回

android線程返回

發布時間: 2023-09-05 15:38:54

㈠ 如何在android的jni線程中實現回調

JNI回調是指在c/c++代碼中調用java函數,當在c/c++的線程中執行回調函數時,會導致回調失敗。

其中一種在Android系統的解決方案是:

把c/c++中所有線程的創建,由pthread_create函數替換為由Java層的創建線程的函數AndroidRuntime::createJavaThread。

假設有c++函數:

[cpp] view plain
void *thread_entry(void *args)
{
while(1)
{
printf("thread running...\n");
sleep(1);
}

}

void init()
{
pthread_t thread;
pthread_create(&thread,NULL,thread_entry,(void *)NULL);
}

init()函數創建一個線程,需要在該線程中調用java類Test的回調函數Receive:

[cpp] view plain
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
}

首先在c++中定義回調函數指針:

[cpp] view plain
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef void (*ReceiveCallback)(unsigned char *buf, int len);

/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);

typedef struct{
ReceiveCallback recv_cb;
CreateThreadCallback create_thread_cb;
}Callback;

再修改c++中的init和thread_entry函數:

[cpp] view plain
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"

void *thread_entry(void *args)
{
char *str = "i'm happy now";
Callback cb = NULL;
int len;
if(args != NULL){
cb = (Callback *)args;
}

len = strlen(str);
while(1)
{
printf("thread running...\n");
//invoke callback method to java
if(cb != NULL && cb->recv_cb != NULL){
cb->recv_cb((unsigned char*)str, len);
}
sleep(1);
}

}

void init(Callback *cb)
{
pthread_t thread;
//pthread_create(&thread,NULL,thread_entry,(void *)NULL);
if(cb != NULL && cb->create_thread_cb != NULL)
{
cb->create_thread_cb("thread",thread_entry,(void *)cb);
}
}

然後在jni中實現回調函數,以及其他實現:

[cpp] view plain
//jni_test.c
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include "test.h"
#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android;

static jobject mCallbacksObj = NULL;
static jmethodID method_receive;

static void (JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}

static void receive_callback(unsigned char *buf, int len)
{
int i;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jcharArray array = env->NewCharArray(len);
jchar *pArray ;

if(array == NULL){
LOGE("receive_callback: NewCharArray error.");
return;
}

pArray = (jchar*)calloc(len, sizeof(jchar));
if(pArray == NULL){
LOGE("receive_callback: calloc error.");
return;
}

// buffer to jchar array
for(i = 0; i < len; i++)
{
*(pArray + i) = *(buf + i);
}
// buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->DeleteLocalRef(array);
free(pArray);
pArray = NULL;

(env, __FUNCTION__);
}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}

static Callback mCallbacks = {
receive_callback,
create_thread_callback
};

static void jni_class_init_native
(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
}

static int jni_init
(JNIEnv *env, jobject obj)
{

if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);

return init(&mCallbacks);
}

static const JNINativeMethod gMethods[] = {
{ "class_init_native", "()V", (void *)jni_class_init_native },
{ "native_init", "()I", (void *)jni_init },
};

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s/n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s/n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI("Radio JNI_OnLoad");
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed/n");
goto fail;
}

if(env == NULL){
goto fail;
}
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed/n");
goto fail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result;
}

jni的Android.mk文件中共享庫設置為:

[cpp] view plain
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最後再實現Java中的Test類:

[java] view plain
//com.tonny.Test.java

public class Test {

static{
try {
System.loadLibrary("test");
class_init_native();

} catch(UnsatisfiedLinkError ule){
System.err.println("WARNING: Could not load library libtest.so!");
}

}

public int initialize() {
return native_radio_init();
}

public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback" + msg;
Log.d("Test", msg);
}

protected static native void class_init_native();

protected native int native_init();

}

㈡ android 怎樣返回子線程裡面獲到的資料庫的值

直接定義個public static的全局變數,就可以了;可以保存在自定義的類、繼承自Application的類、
SharePreference等中的一個屬性;另一個activity從這裡面取數據,不用直接傳遞。

㈢ 如何在android的jni線程中實現回調

您好,很高興能幫助您
如果是C/C++回調,你只要參考linux的線程指南,在線程函數中傳入回調函數地址就行了。如果是要回調到Java層,稍微復雜點。
首先,你需要在onload的時候,找到回調函數所在的類,用全局變數保存:
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
LOGE("JNI_OnLoad start");
jint version;
g_vm = vm; // 全局變數保存
JNIEnv *env;
jobject cls;
version = vm->GetEnv((void **)&env, JNI_VERSION_1_2);

if (env)
{
g_clazz = env->FindClass(CLASS_CustomSurfaceView); // 全局變數保存
}

LOGE("JNI_OnLoad finish g_clazz = 0x%x", g_clazz);
return JNI_VERSION_1_2;
}

在JNI啟動線程的時候,需要把線程掛到JVM上,不然不能訪問Java。你有了g_vm, g_clazz, 以及env,就可以做回調操作了。
// 線程函數

void *threadFunc(void *data)
{
JNIEnv *env = MNull;
int ret = g_vm->AttachCurrentThread( (JNIEnv **) &env, MNull); // 掛到JVM
if (ret < 0)
{
LOGE("fail to attach");
return;
}
// TODO: 在這里做你的回調操作

g_vm->DetachCurrentThread(); // 從JVM卸載
return;
}

你的採納是我前進的動力,
記得好評和採納,答題不易,互相幫助,

㈣ Android等待線程返回結果

樓主,不知道我說的對不對,如果有問題,可以進一步交流
首先在onCreate使用匿名類做子線程是不行的,如果下載時間過長onCreate是主線程,阻塞時間過長會出現ANR(超時)錯誤
如果要在onCreate上開啟線程,需要使用Timer
我個人建議是在onCreate中開啟Timer在TimerTask的run方法裡面開啟匿名線程或者直接就在TimerTask的run方法裡面下載,下載完畢後,使用Handler接收消息再執行System.out.println(str);

熱點內容
司機會所訪問 發布:2025-02-01 15:54:11 瀏覽:778
家用電腦改成伺服器並讓外網訪問 發布:2025-02-01 15:30:23 瀏覽:354
javac工資 發布:2025-02-01 15:24:28 瀏覽:22
如何刪除伺服器登錄賬號 發布:2025-02-01 15:21:05 瀏覽:498
瑞薩編程器 發布:2025-02-01 15:19:18 瀏覽:85
上海ntp伺服器搭建 發布:2025-02-01 15:03:38 瀏覽:991
c游戲編程基礎 發布:2025-02-01 15:00:17 瀏覽:993
routejs怎麼動態配置 發布:2025-02-01 14:59:07 瀏覽:502
家用電腦安裝伺服器內存 發布:2025-02-01 14:38:50 瀏覽:257
增量調制編解碼實驗報告 發布:2025-02-01 14:30:30 瀏覽:787