[工作积累] 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 No

15         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 Java

65     //////////////////////////////////////////////////////////////////////////

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 bit

23     jlong jOnOK = (intptr_t)onOK;

24     jlong jOnCancel = (intptr_t)onCancel;

25     //invoke UI Dialog in another thread

26     (*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 }

 

你可能感兴趣的:(callback)