2008/04/28(月) [n年前の日記]
#2 [iappli] リジュームだかレジュームだかの処理でハマる
ユーザ操作によるサスペンド/レジュームが行われた時の不具合発生。iアプリ動作中に、電源キーを押して、「終了しますか? YES/NO」で「NO」を選んで選択キーを押す、と、iアプリ本編にまで「使ってる人が選択キーを押してるよー」的情報が入ってきてしまって画面が先に進んでしまう、てな不具合が。
解決すべく一日中アレコレ試してみたけど、うまくいかない。
解決すべく一日中アレコレ試してみたけど、うまくいかない。
◎ resume()の中を弄った。 :
まず、レジューム処理が行われる時は、IApplication の resume() が呼ばれるので、今まではその中に、
もしかすると、実処理をするクラス…クラスって呼び方でいいのか判んないんだけど、上のソレで言えば l_main が null で入ってくるときがあったりするのかなと気になったり。いや、アプリ起動時なんかはそういう状態が有り得るのだけど、もしかするとレジューム時もそうだったりするんかなと。
あるいは、微妙な時間差で「今、レジューム処理中なんで、メイン処理はなんもしないでね」的フラグが設定されてないうちに、メイン処理が始まってしまったりするのかもしれない、てな根拠のない想像を。ということで、
public void resume() { if (l_main != null) { l_main.mcResume(); } }てな感じに書いてたわけなんだけど。
もしかすると、実処理をするクラス…クラスって呼び方でいいのか判んないんだけど、上のソレで言えば l_main が null で入ってくるときがあったりするのかなと気になったり。いや、アプリ起動時なんかはそういう状態が有り得るのだけど、もしかするとレジューム時もそうだったりするんかなと。
あるいは、微妙な時間差で「今、レジューム処理中なんで、メイン処理はなんもしないでね」的フラグが設定されてないうちに、メイン処理が始まってしまったりするのかもしれない、てな根拠のない想像を。ということで、
public void resume() { // 実処理クラスが復帰して、リジューム用処理が呼び出せるようになるまで繰り返す while (l_main == null) { Thread.yield(); } l_main.resumeJobEnable = true; // とにかくフラグだけでも先に設定 l_main.mcResume(); // レジューム時の実処理 }という感じにしてみたり。
◎ レジューム処理の中でキーの状態を見ることにした。 :
レジューム処理の中で、キーがどれも押されてない状態になれば、メイン処理を始めてもええだろうと。
public void mcResume() { resumeJobEnable = true; // キー入力ワークをクリアしたり、待ち時間カウンタを設定したり。 initResumeWaitWork(); if (!pauseEnable && soundUseEnable) { // サウンド再生を再開する必要があるなら再開する(キューに要求を入れるだけ) replaySound(); } initResumeWaitWork(); // キー入力がなくなるまで待つ do { try { Thread.sleep(SLEEP_VALUE); } catch (InterruptedException e) { } setKeyWork(getKeypadState()); } while (repbtn != 0 || trgBtn != 0); resumeJobEnable = false; }これで、どのキーも押されてない状態にならないとココから抜けない、イコール、「今、レジューム処理中なんで、メイン処理は仕事すんなよ」フラグがOFFにならないはずで。メイン処理に戻ってきたときは、選択キーは押されてない状態、なのではないかと期待。
◎ メイン処理もある程度スキップするように手を入れた。 :
レジューム処理に入ったら、「この後、nフレーム程度、メイン処理は仕事をしないでね」的カウンタをセットして、メイン処理はそのカウンタが0より大きかったら -1 だけして何もしない、ということにしてみた。もしかすると、レジューム直後は負荷が高いというか、今まで実行していたアプリのアレコレをどこかに避難させていたけど、それれがまだ書き戻せてなかったりする時があったりなんかして、そういう状態でメイン処理を動かしてしまうと何かマズイのかも、とこれまた根拠のない想像を。
◎ processEvent()でイベントも見ることに。 :
「レジューム発生だよ」とイベントが発生するらしいので、それも見ることに。
public void processEvent(int a_type, int a_param) { if (processEventJobEnable) return; processEventJobEnable = true; if (a_type == Display.RESUME_VM_EVENT) { // リジューム時はワークをクリア initResumeWaitWork(); } if (a_type == Display.KEY_PRESSED_EVENT) { // キーが押された if (keyNoCheckEnableCount <= 0) keyBtnInterrupt |= (0x01 << a_param); } processEventJobEnable = false; }どうもここらへんの処理の順番としては、RESUME_VM_EVENT発生 → resume() という順番になるらしい。であれば、先に発生するほうで最低限キー入力ワークをクリアしておけば多少は改善するのかなと。
◎ で、ダメだった。 :
ある程度は改善されたのだけど、何度か試してると、選択キーが押されたかのようにiアプリが動作してしまう時が。うーん。
resume()は必ずしも、レジューム時に最初に呼ばれるわけではない、と関連ドキュメントには書いてあるわけで。ということは、
仮にこういう状態が起きているなら、対処できないよ…。アプリ側で、レジュームしたことを知る術がないわけだから、対応は無理なのでは。いや、正確には、「レジュームしたよ」と教えてはもらえるのだけど、事が終わってから知らされてもどうしようもない、という話だらうか。
resume()は必ずしも、レジューム時に最初に呼ばれるわけではない、と関連ドキュメントには書いてあるわけで。ということは、
- サスペンドからレジュームする。
- メイン処理が再開される。キーを読んで、キー入力ワークに値を入れる。選択キーが押されてるらしいので、次の画面へ移行開始。
- resume() が呼ばれて、こちらの意図したレジューム処理が始まる。キー入力ワークがクリアされ、キーが離されるまで待つ。
- キーが離されたのでメイン処理に戻る。のだけど、メイン処理はもう次の画面に移行してますがな。
仮にこういう状態が起きているなら、対処できないよ…。アプリ側で、レジュームしたことを知る術がないわけだから、対応は無理なのでは。いや、正確には、「レジュームしたよ」と教えてはもらえるのだけど、事が終わってから知らされてもどうしようもない、という話だらうか。
[ ツッコむ ]
以上です。