我发现简单的调用没有任何问题。 但是只要是调用了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):
- public final Handler dialogHandler = new Handler(){
- public void handleMessage(Message msg){
- showDialog(SOME_ID);
- }
- };
showDialog()
I do it by calling
dialogHandler.sendMessage()
.
翻译过来,就是说,当前程序的主线程没有在UI上。所以对话框当然显示不出来。这个时候需要一个Handler和UI线程进行异步通信。具体的机制我也没太明白。但是好歹解决了问题。代码如下
- /****************************************************************************
- Copyright (c) 2010-2012 cocos2d-x.org
- http://www.cocos2d-x.org
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- package com.chen;
- import java.lang.ref.WeakReference;
- import org.cocos2dx.lib.Cocos2dxActivity;
- import org.cocos2dx.lib.Cocos2dxEditText;
- import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
- import org.cocos2dx.lib.Cocos2dxRenderer;
- import android.app.ActivityManager;
- import android.content.Context;
- import android.content.pm.ConfigurationInfo;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.ViewGroup;
- import android.widget.FrameLayout;
- import cn.game189.sms.SMS;
- import cn.game189.sms.SMSListener;
- public class FuckAndroid extends Cocos2dxActivity implements SMSListener{
- // 用来获得Activity的Object类型的实例,供JNI调用
- public static FuckAndroid instance = null;
- public static FuckAndroid getInstance(){
- if (instance == null){
- instance = new FuckAndroid();
- }
- return instance;
- }
- public static Handler handler = null;
- protected void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- handler = new PayHandler(this);
- if (detectOpenGLES20()) {
- // get the packageName,it's used to set the resource path
- String packageName = getApplication().getPackageName();
- super.setPackageName(packageName);
- // FrameLayout
- ViewGroup.LayoutParams framelayout_params =
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT);
- FrameLayout framelayout = new FrameLayout(this);
- framelayout.setLayoutParams(framelayout_params);
- // Cocos2dxEditText layout
- ViewGroup.LayoutParams edittext_layout_params =
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- Cocos2dxEditText edittext = new Cocos2dxEditText(this);
- edittext.setLayoutParams(edittext_layout_params);
- // ...add to FrameLayout
- framelayout.addView(edittext);
- // Cocos2dxGLSurfaceView
- mGLView = new Cocos2dxGLSurfaceView(this);
- // ...add to FrameLayout
- framelayout.addView(mGLView);
- mGLView.setEGLContextClientVersion(2);
- mGLView.setCocos2dxRenderer(new Cocos2dxRenderer());
- mGLView.setTextField(edittext);
- // Set framelayout as the content view
- setContentView(framelayout);
- }
- else {
- Log.d("activity", "don't support gles2.0");
- finish();
- }
- }
- @Override
- protected void onPause() {
- super.onPause();
- mGLView.onPause();
- }
- @Override
- protected void onResume() {
- super.onResume();
- mGLView.onResume();
- }
- private boolean detectOpenGLES20()
- {
- ActivityManager am =
- (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- ConfigurationInfo info = am.getDeviceConfigurationInfo();
- return (info.reqGlEsVersion >= 0x20000);
- }
- static {
- System.loadLibrary("game");
- }
- //////////////////////////////////////////////////////////////////////////
- // Handler 用来
- //////////////////////////////////////////////////////////////////////////
- public static final int HANDLER_CHECKFEE_A = 1;
- public static final int HANDLER_CHECKFEE_B = 2;
- public static class PayHandler extends Handler{
- WeakReference<FuckAndroid> mActivity;
- PayHandler(FuckAndroid activity){
- mActivity = new WeakReference<FuckAndroid>(activity);
- }
- @Override
- public void handleMessage(Message msg){
- FuckAndroid theActivity = mActivity.get();
- switch(msg.what){
- case HANDLER_CHECKFEE_A:
- theActivity.checkFeeA();
- break;
- case HANDLER_CHECKFEE_B:
- theActivity.checkFeeB();
- break;
- }
- }
- };
- public static void sendCheckFeeAMessage(){
- Message msg = new Message();
- msg.what = HANDLER_CHECKFEE_A;
- handler.sendMessage(msg);
- }
- public static void sendCheckFeeBMessage(){
- Message msg = new Message();
- msg.what = HANDLER_CHECKFEE_B;
- handler.sendMessage(msg);
- }
- //////////////////////////////////////////////////////////////////////////
- // 电信的计费API范例
- //////////////////////////////////////////////////////////////////////////
- //采用本Activity实现SMSListener接口,必须实现smsOK和smsFail接口
- private String reLifeFeeName = "reLife";
- /**
- * 使用本Activity直接实现SMSListener接口的方式
- */
- void checkFeeA() {
- String feeName = "mode_A";
- /*
- * 验证计费点核心静态方法,自动完成全部短代过程
- * @param feeName 计费点标识符,不可包含#号,不同计费点此值必须不同
- * @param activity Activity 不能为null
- * @param listener SMSListener接口,处理发送成功和失败的操作,不能为null
- * @param feeCode 短代代码,请登录平台查询产品计费信息并完整复制对应的计费点!!费用按平台上此计费点的对应费用计!
- * @param tip 短代提示语
- * @param okInfo 短代发送成功的提示语
- * @param isRepeat 是否可重复计费(true为软计费点,false为硬计费点)
- * @return 返回是否已计过费
- */
- if (SMS.checkFee(feeName, this, this, "0111C001741102210071271102210070930115174000000000000000000000000000", "开启\"xxx-A\",点击确定将会发送一条1元短信,不含信息费.", "发送成功!已成功解锁!",false)) {
- //在这里处理该计费点已扣过费后的处理
- // Toast.makeText(this, "已计过费,直接进入关卡"+feeName, Toast.LENGTH_SHORT).show();
- Cocos2dxActivity.showMessageBox("已计费", "已计过费,直接进入关卡"+feeName);
- }
- }
- void checkFeeB() {
- String feeName = "mode_B";
- /*
- * 验证计费点核心静态方法,自动完成全部短代过程
- * @param feeName 计费点标识符,不可包含#号,不同计费点此值必须不同
- * @param activity Activity 不能为null
- * @param listener SMSListener接口,处理发送成功和失败的操作,不能为null
- * @param feeCode 短代代码,请登录平台查询产品计费信息并完整复制对应的计费点!!费用按平台上此计费点的对应费用计!
- * @param tip 短代提示语
- * @param okInfo 短代发送成功的提示语
- * @param isRepeat 是否可重复计费(true为软计费点,false为硬计费点)
- * @return 返回是否已计过费
- */
- if (SMS.checkFee(feeName, this, this, "0813C3400211022100862511022100811701MC099572000000000000000000000000", "开启\"xxx-B\",点击确定将会发送一条2元短信,不含信息费.", "发送成功!已成功解锁!",false)) {
- //在这里处理该计费点已扣过费后的处理
- // Toast.makeText(this, "已计过费,直接进入关卡"+feeName, Toast.LENGTH_SHORT).show();
- Cocos2dxActivity.showMessageBox("已计费", "已计过费,直接进入关卡"+feeName);
- }
- }
- /**
- * 在弹出计费提供框后,用户点击确定并计费成功后的处理
- * @param feeName 对应当计费标识值
- * @see cn.game189.sms.SMSListener#smsOK(java.lang.String)
- */
- public void smsOK(String feeName) {
- //关卡打开后续代码
- Log.i("SMSListener", "模式"+feeName+"已计费完成,关卡已打开.");
- if (feeName.equals("mode_A")) {
- //打开mode_A计费点后的操作
- // Toast.makeText(this, "关卡"+feeName+"开启后的操作", Toast.LENGTH_SHORT).show();
- Cocos2dxActivity.showMessageBox("计费成功", "关卡"+feeName+"开启后的操作");
- }else if(feeName.equals("mode_B")){
- //打开mode_B计费点后的操作
- // Toast.makeText(this, "第二个关卡"+feeName+"开启后的操作", Toast.LENGTH_SHORT).show();
- Cocos2dxActivity.showMessageBox("计费成功", "第二个关卡"+feeName+"开启后的操作");
- }else if(feeName.equals(this.reLifeFeeName)){
- //原地复活
- // Toast.makeText(this, "角色原地复活功能实现", Toast.LENGTH_SHORT).show();
- Cocos2dxActivity.showMessageBox("计费成功", "角色原地复活功能实现");
- }
- }
- /**
- * 短代发送失败,错误码含义如下:
- * <pre>
- * 0.初始值或取消发送
- * 1.已计过费
- * 2.发送短信成功
- * -1.发送失败
- * -2.无卡
- * -3.非电信卡
- * -4.获取终端码失败
- * -5.保存计费点失败
- * -6.获取存档数据有误
- * -7.获取存档时读终端码失败
- * -8.获取存档时feeName不匹配
- * -9.获取存档时终端码不匹配
- * -10.获取存档发生异常
- * -11.feeName不合法
- * </pre>
- * @param feeName 对应当前的SMS.STR_CHECK值
- * @param errorCode 错误码
- * @see cn.game189.sms.SMSListener#smsFail(int)
- */
- public void smsFail(String feeName,int errorCode) {
- Log.e("SMSListener", "计费失败!计费点:"+feeName+" 错误码:"+errorCode);
- //其他错误处理操作,不给道具或不放行关卡
- }
- public void smsCancel(String feeName, int errorCode) {
- Log.e("SMSListener", "用户点击取消!计费点:"+feeName+" 错误码:"+errorCode);
- }
- }
以上是我作的电信计费测试代码。如果通过Handler调用,而不是直接调用,就不会出现死机问题。