Edited at

cocos2d-xのtouchイベント内でtoastを表示したいとき。

More than 5 years have passed since last update.


概要

メニューをタップ等したときに、例えば通信状態がよくない場合にエラーメッセージを出したいことがあると思いますが、JNI経由でToastを呼び出すと思わぬエラーが発生することがあります。

そういったときの対処方法のひとつを記載します。


環境

cocos2d-x(2.2.4)


原因

cocos2d-xのtouchイベントはGLThread内で処理されますが、Toastクラスは初期化時に内部でHandlerクラスの引数なしの初期化が行われており、この際に例外が送出されます。

例外が発生する該当箇所を見てみると、


Handler.java

public Handler(Callback callback, boolean async) {

if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}


GLThread内でLooper.prepareがコールされていないようです。


対処方法

ここでは、Toastクラスの初期化がUIスレッド(mainスレッド)内で行われれば問題が発生しなさそうだということで、次のように記述してみました。

 //jni経由でコールされるメソッド

Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
public void run(){
Toast toast = new Toast(

toast.show();
}
});

かなり省略した感じですけどニュアンスは伝わると思います。

結局のところToastに限らず、touchイベント内でHandlerクラスを生成するケースがあれば全て同じ処理をする必要があります。