您的位置:首页 > 移动开发 > Android开发

[工作积累] Android system dialog with native callback

2015-01-23 10:16 375 查看
JNI: invoke java dialog with native callback:

store native function address in java, and invoke native another method to this function.

key points:

1.Store callback function pointer(address) in java: to support multiple calls, use data block for each call.

2.Use primitive long(64bit) in Java to store native callback pointer, for 64 bit native compatibility

3.intptr_t for pointer in native.

4.Show dialog in UI thread (Activity.runOnUiThread )

5.optional: Let the native code to handle localization (minimize Java code)

Java:

public static native void nativeOnSystemDialogResult(long nativeFuncAddr);

class DialogRunnable implements Runnable {
public String mTitle;
public String mMessage;
public String mYes;
public String mNo;
public long mOnYesAddr;
public long mOnNoAddr;
public boolean mTwoButton;

//////////////////////////////////////////////////////////////////////////
///title, message, localized Yes No
DialogRunnable(String tittle, String message, String locYes, String locNo, long onYesAddr, long onNoAddr, boolean twoButton)
{
mTitle = tittle;
mMessage = message;
mYes = locYes;
mNo = locNo;
mOnYesAddr = onYesAddr;
mOnNoAddr = onNoAddr;
mTwoButton = twoButton;
}

//////////////////////////////////////////////////////////////////////////
public void run() {

if( mTwoButton ) {
Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )
.setTitle(mTitle)
.setMessage(mMessage)
.setPositiveButton( mYes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );
}
})
.setNegativeButton( mNo, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
GameActivity.getInstance().nativeOnSystemDialogResult( mOnNoAddr );
}
})
.setCancelable(false)
.create();
dialog.show();
}else {
Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )
.setTitle(mTitle)
.setMessage(mMessage)
.setPositiveButton( mNo, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );
}
})
.setCancelable(false)
.create();
dialog.show();
}
}
}

//////////////////////////////////////////////////////////////////////////
//Cooperate with native code. DO NOT call on Java
//////////////////////////////////////////////////////////////////////////
public void showDialogYesNo(String title, String showText, String locYes, String locNo, long onYesAddr, long onNoAddr) {
this.runOnUiThread( new DialogRunnable(title, showText, locYes, locNo, onYesAddr, onNoAddr, true) );
}


C (for C++, JNI calls are simpler & different)

JNIEXPORT void JNICALL Java_com_org_package_GameActivity_nativeOnSystemDialogResult(JNIEnv *env, jobject thiz, jlong functionAddr)
{
typedef void(*FUNCPTR)(void);
FUNCPTR ptr = (FUNCPTR)(void*)function;
if( ptr != null )
ptr();
}


//////////////////////////////////////////////////////////////////////////
//Note: onOK & onCancel can be NULL
void    Android_SystemDialog(const char* title, const char* message, const char* yes, const char* no, void(*onOK)(void), void(*onCancel)(void) )
{
android_app* app = GetApp();
JNIEnv* env = app->activity->env;
//note: we need to attach dalvik VM to current thread, as it is not main thread
JavaVM* vm = app->activity->vm;
if ( (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) < 0 )
(*vm)->AttachCurrentThread(vm, &env, NULL);

jclass ActivityClass = (*env)->GetObjectClass(env, app->activity->clazz);
jmethodID java_method = (*env)->GetMethodID(env, ActivityClass,
(char8*)"showDialogYesNo",
(char8*)"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJ)V");
assert( java_method != NULL );

jstring jTitle = (*env)->NewStringUTF(env, title, strlen(title) );
jstring jMsg = (*env)->NewStringUTF(env, message, strlen(message) );
jstring jOK = (*env)->NewStringUTF(env, yes, strlen(yes) );
jstring jCancel = (*env)->NewStringUTF(env, no, strlen(no) );
//Note: jlong is 64 bit
jlong jOnOK = (intptr_t)onOK;
jlong jOnCancel = (intptr_t)onCancel;
//invoke UI Dialog in another thread
(*env)->CallVoidMethod(env, app->activity->clazz , java_method, jTitle, jMsg, jOK, jCancel, jOnOK, jOnCancel);

(*env)->DeleteLocalRef(env, jTitle);
(*env)->DeleteLocalRef(env, jMsg);
(*env)->DeleteLocalRef(env, jOK);
(*env)->DeleteLocalRef(env, jCancel);
(*env)->DeleteLocalRef(env, ActivityClass);
}


native usage sample:

static void OnExit()
{
exit(0);
}

void Android_Confirm_Exit()
{
const char* title = "Quit";
const char* message = "Unsaved progress will be lost.\nAre you sure you want to quit game?";
const char* yes = "Ok";
const char* no = "Cancel";
Android_SystemDialog(title, message, yes, no, &OnExit, NULL);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: