Cocos2d-x 调用 Android 代码的后续

本文详细介绍了在电信计费测试中遇到的问题,即直接调用UI元素导致程序死机,通过引入Handler机制实现异步通信,有效解决了死机问题,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我发现简单的调用没有任何问题。 但是只要是调用了UI元素,比如显示个消息框什么的,程序立即就挂了。后来发现还是得上Google(鄙视一下百度同学),在StackOverFlow上面找到了一篇这样的回答

The problem was that when calling back from JNI the application wasn't on UI Thread so the dialog was never shown. To fix it I used a Handler (on Activity):

[java]  view plain copy
  1. public final Handler dialogHandler = new Handler(){       
  2.     public void handleMessage(Message msg){  
  3.         showDialog(SOME_ID);  
  4.     }     
  5. };  
So instead of directly call  showDialog()  I do it by calling  dialogHandler.sendMessage() .

翻译过来,就是说,当前程序的主线程没有在UI上。所以对话框当然显示不出来。这个时候需要一个Handler和UI线程进行异步通信。具体的机制我也没太明白。但是好歹解决了问题。代码如下

[java]  view plain copy
  1. /**************************************************************************** 
  2. Copyright (c) 2010-2012 cocos2d-x.org 
  3.  
  4. http://www.cocos2d-x.org 
  5.  
  6. Permission is hereby granted, free of charge, to any person obtaining a copy 
  7. of this software and associated documentation files (the "Software"), to deal 
  8. in the Software without restriction, including without limitation the rights 
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  10. copies of the Software, and to permit persons to whom the Software is 
  11. furnished to do so, subject to the following conditions: 
  12.  
  13. The above copyright notice and this permission notice shall be included in 
  14. all copies or substantial portions of the Software. 
  15.  
  16. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  17. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  18. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  19. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  20. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  21. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
  22. THE SOFTWARE. 
  23. ****************************************************************************/  
  24. package com.chen;  
  25.   
  26. import java.lang.ref.WeakReference;  
  27.   
  28. import org.cocos2dx.lib.Cocos2dxActivity;  
  29. import org.cocos2dx.lib.Cocos2dxEditText;  
  30. import org.cocos2dx.lib.Cocos2dxGLSurfaceView;  
  31. import org.cocos2dx.lib.Cocos2dxRenderer;  
  32.   
  33. import android.app.ActivityManager;  
  34. import android.content.Context;  
  35. import android.content.pm.ConfigurationInfo;  
  36. import android.os.Bundle;  
  37. import android.os.Handler;  
  38. import android.os.Message;  
  39. import android.util.Log;  
  40. import android.view.ViewGroup;  
  41. import android.widget.FrameLayout;  
  42. import cn.game189.sms.SMS;  
  43. import cn.game189.sms.SMSListener;  
  44.   
  45. public class FuckAndroid extends Cocos2dxActivity implements SMSListener{  
  46.     // 用来获得Activity的Object类型的实例,供JNI调用  
  47.     public static FuckAndroid instance = null;  
  48.     public static FuckAndroid getInstance(){  
  49.         if (instance == null){  
  50.             instance = new FuckAndroid();  
  51.         }  
  52.         return instance;  
  53.     }  
  54.   
  55.     public static Handler handler = null;  
  56.       
  57.     protected void onCreate(Bundle savedInstanceState){  
  58.         super.onCreate(savedInstanceState);  
  59.           
  60.         handler = new PayHandler(this);  
  61.           
  62.         if (detectOpenGLES20()) {  
  63.             // get the packageName,it's used to set the resource path  
  64.             String packageName = getApplication().getPackageName();  
  65.             super.setPackageName(packageName);  
  66.               
  67.             // FrameLayout  
  68.             ViewGroup.LayoutParams framelayout_params =  
  69.                 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  70.                                            ViewGroup.LayoutParams.FILL_PARENT);  
  71.             FrameLayout framelayout = new FrameLayout(this);  
  72.             framelayout.setLayoutParams(framelayout_params);  
  73.   
  74.             // Cocos2dxEditText layout  
  75.             ViewGroup.LayoutParams edittext_layout_params =  
  76.                 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  77.                                            ViewGroup.LayoutParams.WRAP_CONTENT);  
  78.             Cocos2dxEditText edittext = new Cocos2dxEditText(this);  
  79.             edittext.setLayoutParams(edittext_layout_params);  
  80.   
  81.             // ...add to FrameLayout  
  82.             framelayout.addView(edittext);  
  83.   
  84.             // Cocos2dxGLSurfaceView  
  85.             mGLView = new Cocos2dxGLSurfaceView(this);  
  86.   
  87.             // ...add to FrameLayout  
  88.             framelayout.addView(mGLView);  
  89.   
  90.             mGLView.setEGLContextClientVersion(2);  
  91.             mGLView.setCocos2dxRenderer(new Cocos2dxRenderer());  
  92.             mGLView.setTextField(edittext);  
  93.   
  94.             // Set framelayout as the content view  
  95.             setContentView(framelayout);  
  96.         }  
  97.         else {  
  98.             Log.d("activity""don't support gles2.0");  
  99.             finish();  
  100.         }     
  101.     }  
  102.       
  103.      @Override  
  104.      protected void onPause() {  
  105.          super.onPause();  
  106.          mGLView.onPause();  
  107.      }  
  108.   
  109.      @Override  
  110.      protected void onResume() {  
  111.          super.onResume();  
  112.          mGLView.onResume();  
  113.      }  
  114.        
  115.      private boolean detectOpenGLES20()   
  116.      {  
  117.          ActivityManager am =  
  118.                 (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  
  119.          ConfigurationInfo info = am.getDeviceConfigurationInfo();  
  120.          return (info.reqGlEsVersion >= 0x20000);  
  121.      }  
  122.        
  123.      static {  
  124.          System.loadLibrary("game");  
  125.      }  
  126.        
  127.        
  128.     //////////////////////////////////////////////////////////////////////////  
  129.       
  130.     //  Handler 用来  
  131.       
  132.     //////////////////////////////////////////////////////////////////////////     
  133.   
  134.     public static final int HANDLER_CHECKFEE_A = 1;  
  135.     public static final int HANDLER_CHECKFEE_B = 2;  
  136.       
  137.     public static class PayHandler extends Handler{  
  138.         WeakReference<FuckAndroid> mActivity;  
  139.           
  140.         PayHandler(FuckAndroid activity){  
  141.             mActivity = new WeakReference<FuckAndroid>(activity);  
  142.         }  
  143.           
  144.         @Override  
  145.         public void handleMessage(Message msg){  
  146.             FuckAndroid theActivity = mActivity.get();  
  147.             switch(msg.what){  
  148.             case HANDLER_CHECKFEE_A:  
  149.                 theActivity.checkFeeA();  
  150.                 break;  
  151.             case HANDLER_CHECKFEE_B:  
  152.                 theActivity.checkFeeB();  
  153.                 break;  
  154.             }  
  155.         }  
  156.     };  
  157.        
  158.     public static void sendCheckFeeAMessage(){  
  159.         Message msg = new Message();  
  160.         msg.what = HANDLER_CHECKFEE_A;  
  161.           
  162.         handler.sendMessage(msg);  
  163.     }   
  164.       
  165.     public static void sendCheckFeeBMessage(){  
  166.         Message msg = new Message();  
  167.         msg.what = HANDLER_CHECKFEE_B;  
  168.           
  169.         handler.sendMessage(msg);  
  170.     }  
  171.        
  172.     //////////////////////////////////////////////////////////////////////////  
  173.       
  174.     //  电信的计费API范例  
  175.       
  176.     //////////////////////////////////////////////////////////////////////////     
  177.       
  178.       
  179.     //采用本Activity实现SMSListener接口,必须实现smsOK和smsFail接口  
  180.       
  181.     private String reLifeFeeName = "reLife";  
  182.       
  183.        
  184.        
  185.     /** 
  186.      * 使用本Activity直接实现SMSListener接口的方式 
  187.      */  
  188.     void checkFeeA() {  
  189.         String feeName = "mode_A";  
  190.           
  191.         /* 
  192.          * 验证计费点核心静态方法,自动完成全部短代过程 
  193.          * @param feeName 计费点标识符,不可包含#号,不同计费点此值必须不同 
  194.          * @param activity Activity 不能为null 
  195.          * @param listener SMSListener接口,处理发送成功和失败的操作,不能为null 
  196.          * @param feeCode 短代代码,请登录平台查询产品计费信息并完整复制对应的计费点!!费用按平台上此计费点的对应费用计! 
  197.          * @param tip 短代提示语 
  198.          * @param okInfo 短代发送成功的提示语 
  199.          * @param isRepeat  是否可重复计费(true为软计费点,false为硬计费点) 
  200.          * @return 返回是否已计过费 
  201.          */  
  202.         if (SMS.checkFee(feeName, thisthis"0111C001741102210071271102210070930115174000000000000000000000000000""开启\"xxx-A\",点击确定将会发送一条1元短信,不含信息费.""发送成功!已成功解锁!",false)) {  
  203.             //在这里处理该计费点已扣过费后的处理  
  204. //          Toast.makeText(this, "已计过费,直接进入关卡"+feeName, Toast.LENGTH_SHORT).show();  
  205.             Cocos2dxActivity.showMessageBox("已计费""已计过费,直接进入关卡"+feeName);  
  206.         }  
  207.     }  
  208.       
  209.     void checkFeeB() {  
  210.         String feeName = "mode_B";  
  211.         /* 
  212.          * 验证计费点核心静态方法,自动完成全部短代过程 
  213.          * @param feeName 计费点标识符,不可包含#号,不同计费点此值必须不同 
  214.          * @param activity Activity 不能为null 
  215.          * @param listener SMSListener接口,处理发送成功和失败的操作,不能为null 
  216.          * @param feeCode 短代代码,请登录平台查询产品计费信息并完整复制对应的计费点!!费用按平台上此计费点的对应费用计! 
  217.          * @param tip 短代提示语 
  218.          * @param okInfo 短代发送成功的提示语 
  219.          * @param isRepeat  是否可重复计费(true为软计费点,false为硬计费点) 
  220.          * @return 返回是否已计过费 
  221.          */  
  222.         if (SMS.checkFee(feeName, thisthis"0813C3400211022100862511022100811701MC099572000000000000000000000000""开启\"xxx-B\",点击确定将会发送一条2元短信,不含信息费.""发送成功!已成功解锁!",false)) {  
  223.             //在这里处理该计费点已扣过费后的处理  
  224. //          Toast.makeText(this, "已计过费,直接进入关卡"+feeName, Toast.LENGTH_SHORT).show();  
  225.             Cocos2dxActivity.showMessageBox("已计费""已计过费,直接进入关卡"+feeName);  
  226.         }  
  227.     }  
  228.       
  229.       
  230.     /** 
  231.      * 在弹出计费提供框后,用户点击确定并计费成功后的处理 
  232.      * @param feeName 对应当计费标识值 
  233.      * @see cn.game189.sms.SMSListener#smsOK(java.lang.String) 
  234.      */  
  235.     public void smsOK(String feeName) {  
  236.         //关卡打开后续代码  
  237.         Log.i("SMSListener""模式"+feeName+"已计费完成,关卡已打开.");  
  238.         if (feeName.equals("mode_A")) {  
  239.             //打开mode_A计费点后的操作  
  240. //          Toast.makeText(this, "关卡"+feeName+"开启后的操作", Toast.LENGTH_SHORT).show();  
  241.             Cocos2dxActivity.showMessageBox("计费成功""关卡"+feeName+"开启后的操作");  
  242.         }else if(feeName.equals("mode_B")){  
  243.             //打开mode_B计费点后的操作  
  244. //          Toast.makeText(this, "第二个关卡"+feeName+"开启后的操作", Toast.LENGTH_SHORT).show();  
  245.             Cocos2dxActivity.showMessageBox("计费成功""第二个关卡"+feeName+"开启后的操作");  
  246.         }else if(feeName.equals(this.reLifeFeeName)){  
  247.             //原地复活  
  248. //          Toast.makeText(this, "角色原地复活功能实现", Toast.LENGTH_SHORT).show();  
  249.             Cocos2dxActivity.showMessageBox("计费成功""角色原地复活功能实现");  
  250.         }  
  251.     }  
  252.   
  253.   
  254.   
  255.     /** 
  256.      * 短代发送失败,错误码含义如下: 
  257.      * <pre> 
  258.      * 0.初始值或取消发送 
  259.      * 1.已计过费 
  260.      * 2.发送短信成功 
  261.      * -1.发送失败 
  262.      * -2.无卡 
  263.      * -3.非电信卡 
  264.      * -4.获取终端码失败 
  265.      * -5.保存计费点失败 
  266.      * -6.获取存档数据有误 
  267.      * -7.获取存档时读终端码失败 
  268.      * -8.获取存档时feeName不匹配 
  269.      * -9.获取存档时终端码不匹配 
  270.      * -10.获取存档发生异常  
  271.      * -11.feeName不合法 
  272.      * </pre> 
  273.      * @param feeName 对应当前的SMS.STR_CHECK值 
  274.      * @param errorCode 错误码 
  275.      * @see cn.game189.sms.SMSListener#smsFail(int) 
  276.      */  
  277.     public void smsFail(String feeName,int errorCode) {  
  278.         Log.e("SMSListener""计费失败!计费点:"+feeName+" 错误码:"+errorCode);  
  279.         //其他错误处理操作,不给道具或不放行关卡  
  280.     }  
  281.   
  282.   
  283.   
  284.     public void smsCancel(String feeName, int errorCode) {  
  285.         Log.e("SMSListener""用户点击取消!计费点:"+feeName+" 错误码:"+errorCode);  
  286.           
  287.     }  
  288. }  

以上是我作的电信计费测试代码。如果通过Handler调用,而不是直接调用,就不会出现死机问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值