SAXParserを使って作ったandroidアプリをGALAXY Nexus上でテストしていたのだが、java.io.IOExceptionが発生してどうしても動かない。
SAXParserFactory factory= SAXParserFactory.newInstance();
SAXParser parser= factory.newSAXParser();
parser.parse("http://api.hoge.co.jp/RestSearchAPI/?mode=1", new HogeHandler());
〜
java.io.IOException発生
この様なコードでインターネットを介したWebサービス用の公開URLに対して同パーサでアクセスすると、何故かjava.io.IOExceptionがスローされるのである。
AndroidのWebブラウザを使って同様のURLにアクセスするとXMLが戻るので、サーバ及びサービス用のURLに問題は無いはすだ。
さっぱり分らないので、メソッドの呼び方を変えてみようと、parseメソッドを文字列ではなくInputSourceを使う形式のものに替えてみると、今度は例外が変わった。
〜
URL xmlUrl = new URL("http://api.hoge.co.jp/RestSearchAPI/?mode=1");
parser.parse(new InputSource(xmlUrl.openStream()), new HogeHandler());
〜
android.os.NetworkOnMainThreadException発生
この例外を見てやっと分った。
AndroidはGingerBreadで追加になった"StrictMode"※が3.0以降はデフォルトで有効になっており、メインスレッド(UIスレッド)でネットワーク処理を行うと同例外がスローされるのである。
NetworkOnMainThreadException | Android Developers
取りあえず例外を抑制するためにコードStrictModeを完全に無効にすることもできる。
//staticブロックなど、アプリケーション開始前に実行する。 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
がしかし、これはテストのためだけに使うべきであって、ネットワーク処理を行うコードはAsyncTask、Android4.0以降であればローダー(AsyncTaskLoader)を使ってUIスレッドをブロックしないように他のスレッドに分離しなくてはならない。
AsyncTaskLoader | Android Developers
問題なのはSAXParser.parseでandroid.os.NetworkOnMainThreadExceptionではなく抽象度の高いjava.io.IOExceptionがスローされていたことである。これによって原因の発見がかなり遅れた訳で、
教訓: スローされた例外は絶対に隠してはいけない!!
ということだろう。
それにしてもだ。少しAndroidを離れていただけで分らないことだらけ。
これはどこかで一度キャッチアップしないと駄目だろう。