コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

ICSでcom.sun.jdi.InvocationException例外が発生する

XPERIA mini ProをGB(v2.3.4)からICS(v4.0.4)にアップデイトしたところ、順調に動作していたSaridaが突然落ちるようになってしまいました。
原因を調べてみると、下記のサーバソケットを生成しているところで、com.sun.jdi.InvocationException例外が発生していました。

ServerSocket ss = new ServerSocket(60082, 1);

例外が発生している様子。この例外が発生するとhostnameがnullになります。

そして、下記のような接続待ちのコードでアプリが強制終了します。

Socket socket = ss.accept();

原因は例外処理が追加されたことのようです

この例外発生の原因はHC(v3.0)以降、NetworkOnMainThreadExceptionという例外が新たに追加されたからのようです。見た目は「com.sun.jdi.InvocationException」が発生しているようですが、実はNetworkOnMainThreadExceptionが発生しているようです。

この例外が発生するのは、UIスレッドでスレッドを長時間止めるようなソケット命令が実行されたときのようです。例えば、上の例では、UIスレッドをServerSocketを生成したため、この例外が発生したようです。

対策1

NetworkOnMainThreadExceptionを発生させない対策としては、UIスレッドでスレッドを長時間止めるようなソケット命令を書かないことです。AsyncTaskクラスを使ってソケット命令を別スレッドとして書くことです。
UIスレッドに書かなければ例外は発生しません。参考程度にSaridaのServerSocket#acceptをAsyncTaskスレッドに書き直したものを書いておきます。

public class AcceptLuaVMasync  extends AsyncTask<Integer, Integer, Integer >{
 private SaridaSurfaceView prMainThred;
 public AcceptLuaVMasync(SaridaSurfaceView mainThred) {
   prMainThred = mainThred;
 }
 @Override
 protected void onPostExecute(Integer result){
   prMainThred.postAcceptLuaVMasync(result);
 }
 @Override
 protected Integer doInBackground(Integer... arg0) {
   try{
     SaridaActivity.puserversocket = new ServerSocket(SaridaActivity.puportnumber, 1);
     //LuaVMクラスに接続準備OKを伝える
     SaridaActivity.puReadyFlg = 1;
     //LuaVMの接続待ち
     SaridaActivity.puclientSocket = SaridaActivity.puserversocket.accept();
     InetAddress iadd = SaridaActivity.puclientSocket.getInetAddress();
     // 設定したIPアドレスからの接続かどうかチェックする
     if (iadd.toString().indexOf( SaridaActivity.puhostIP ) == -1) {
       SaridaActivity.puclientSocket.close();
       return(0);
     }
     SaridaActivity.pudata_in = new DataInputStream(SaridaActivity.puclientSocket.getInputStream());
     SaridaActivity.pudata_out = new DataOutputStream(SaridaActivity.puclientSocket.getOutputStream());
     //LuaVMと接続したら立つフラグ
     SaridaActivity.isAcceptFlg = true;
   }
   catch(IOException e) {
     System.out.println(e);
     return(0);
   }
   return(1);
 }
}

対策2

もし、ミニマムSDKバージョンがAPIレベル8でも大丈夫であれば、AndroidManifest.xmlのminSdkVersionを8にする。

<uses-sdk android:minSdkVersion="8" />

minSdkVersion="8"のときは、ICSでもJBでも例外は発生しません。きちんとhostnameに"0.0.0.0"がセットされます。

まとめ

AndroidのUIスレッドに、スレッドを長時間止めるようなソケット命令が書かれてあるとき、NetworkOnMainThreadExceptionが発生する。ただし、発生する条件には下記のようなパターンがある。

  • とした場合は、例外は発生しない。
  • とした場合は、Ver2.3.4以下では例外が発生しないが、Ver3.0以上では発生する。
  • とした場合は、必ず例外が発生する。

ADKを使うために、としたことで、この例外発生の影響が顕在化しました。最良の対策としてはUIスレッドにSocket命令を書かないことだと思います。

これでようやくICSのXPERIAでSaridaのデバッグができます。