首页 > 代码库 > [工作积累] Android system dialog with native callback

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

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:

 1 public static native void nativeOnSystemDialogResult(long nativeFuncAddr); 2  3  4     class DialogRunnable implements Runnable { 5         public String mTitle; 6         public String mMessage; 7         public String mYes; 8         public String mNo; 9         public long mOnYesAddr;10         public long mOnNoAddr;11         public boolean mTwoButton;12 13         //////////////////////////////////////////////////////////////////////////14         ///title, message, localized Yes No15         DialogRunnable(String tittle, String message, String locYes, String locNo, long onYesAddr, long onNoAddr, boolean twoButton)16         {17             mTitle = tittle;18             mMessage = message;19             mYes = locYes;20             mNo = locNo;21             mOnYesAddr = onYesAddr;22             mOnNoAddr = onNoAddr;23             mTwoButton = twoButton;24         }25 26         //////////////////////////////////////////////////////////////////////////27         public void run() {28 29             if( mTwoButton ) {30                 Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )31                 .setTitle(mTitle)32                 .setMessage(mMessage)33                 .setPositiveButton( mYes, new DialogInterface.OnClickListener() {34                                                     public void onClick(DialogInterface dialog, int whichButton) {35                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );36                                                     }37                                                 })38                 .setNegativeButton( mNo, new DialogInterface.OnClickListener() {39                                                     public void onClick(DialogInterface dialog, int whichButton) {40                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnNoAddr );41                                                     }42                                                 })43                 .setCancelable(false)44                 .create();45                 dialog.show();46             }else {47                 Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )48                 .setTitle(mTitle)49                 .setMessage(mMessage)50                 .setPositiveButton( mNo, new DialogInterface.OnClickListener() {51                                                     public void onClick(DialogInterface dialog, int whichButton) {52                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );53                                                     }54                                                 })55                 .setCancelable(false)56                 .create();57                 dialog.show();58             }59         }60     }61 62 63     //////////////////////////////////////////////////////////////////////////64     //Cooperate with native code. DO NOT call on Java65     //////////////////////////////////////////////////////////////////////////66     public void showDialogYesNo(String title, String showText, String locYes, String locNo, long onYesAddr, long onNoAddr) {67         this.runOnUiThread( new DialogRunnable(title, showText, locYes, locNo, onYesAddr, onNoAddr, true) );68     }69     70     71     72     

 

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

1 JNIEXPORT void JNICALL Java_com_org_package_GameActivity_nativeOnSystemDialogResult(JNIEnv *env, jobject thiz, jlong functionAddr)2 {3     typedef void(*FUNCPTR)(void);4     FUNCPTR ptr = (FUNCPTR)(void*)function;5     if( ptr != null )6         ptr();7 }

 

 1 ////////////////////////////////////////////////////////////////////////// 2 //Note: onOK & onCancel can be NULL 3 void    Android_SystemDialog(const char* title, const char* message, const char* yes, const char* no, void(*onOK)(void), void(*onCancel)(void) ) 4 { 5     android_app* app = GetApp(); 6     JNIEnv* env = app->activity->env; 7     //note: we need to attach dalvik VM to current thread, as it is not main thread 8     JavaVM* vm = app->activity->vm; 9     if ( (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) < 0 )10         (*vm)->AttachCurrentThread(vm, &env, NULL);11 12     jclass ActivityClass = (*env)->GetObjectClass(env, app->activity->clazz);13     jmethodID java_method = (*env)->GetMethodID(env, ActivityClass, 14         (char8*)"showDialogYesNo", 15         (char8*)"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJ)V");16     assert( java_method != NULL );17 18     jstring jTitle = (*env)->NewStringUTF(env, title, strlen(title) );19     jstring jMsg = (*env)->NewStringUTF(env, message, strlen(message) );20     jstring jOK = (*env)->NewStringUTF(env, yes, strlen(yes) );21     jstring jCancel = (*env)->NewStringUTF(env, no, strlen(no) );22     //Note: jlong is 64 bit23     jlong jOnOK = (intptr_t)onOK;24     jlong jOnCancel = (intptr_t)onCancel;25     //invoke UI Dialog in another thread26     (*env)->CallVoidMethod(env, app->activity->clazz , java_method, jTitle, jMsg, jOK, jCancel, jOnOK, jOnCancel);27 28     (*env)->DeleteLocalRef(env, jTitle);29     (*env)->DeleteLocalRef(env, jMsg);30     (*env)->DeleteLocalRef(env, jOK);31     (*env)->DeleteLocalRef(env, jCancel);32     (*env)->DeleteLocalRef(env, ActivityClass);33 }

 

native usage sample:

 1 static void OnExit() 2 { 3     exit(0); 4 } 5  6 void Android_Confirm_Exit() 7 { 8     const char* title = "Quit"; 9     const char* message = "Unsaved progress will be lost.\nAre you sure you want to quit game?";10     const char* yes = "Ok";11     const char* no = "Cancel";12     Android_SystemDialog(title, message, yes, no, &OnExit, NULL);13 }

 

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