読者です 読者をやめる 読者になる 読者になる

clock-up-blog

go-mi-tech

Android実行時エラーのトラブルシューティング(初心者向け)

Android Java トラブルシューティング

Unfortunately, Your application has stopped.

f:id:kobake:20140730080155p:plain:w150
嫌ですね、異常終了。

Android開発で遭遇する実行時エラーで、よくあるやつを少しまとめました。

  • NoSuchMethodException
  • ActivityNotFoundException
  • NullPointerException
  • ClassCastException

等。
あと、最低限のデバッグ用設定等。


Java基礎はあったほうが良いけど…

Java知らないばかりにハマるパターンもあるけど、あまり厳しいこと言いたくもないのです。
何度も対症療法してれば嫌でも身に付きます、たぶん。

最低限のEclipse設定 (Android Studio 使ってる人は適宜読み替え)

行番号を表示させる

  • Window - Preferences
    • General - Editors - Text Editors
      • Show line numbers を ON

文字コードUTF-8にする

  • Window - Preferences
    • General - Workspace - Text file encoding
      • Other で UTF-8 を選択

LogCatビューを出しておく

  • Window - Show View - Other
    • LogCat を選択して OK。(同じのが2つくらい出ることもあるけど上のやつを選択すればOK)

編集中のファイルを Package Explorer で常に選択状態にする

Package Explorer 上部の「←→」みたいなボタン (Link with Editor) を ON にしておく。
これで今編集中のファイルが Package Explorer 上でも選択状態になります。
今編集しているファイルがどこのプロジェクトのものだか分かりやすくなり、混乱しなくなる。

実行時エラー対処:まずはログ見る

LogCat ビューで見れます。
実行時エラー(要するにアプリが異常終了)が起こった場合、まずすべきこと。
ソースコードを見るよりも何よりも先にまずログを見る。絶対に見る。

f:id:kobake:20140729182053p:plain

LogCat の右上のほうでログレベルを選択できるので、
エラー調査したいときには「error」を選択しておくと良いです。

エラー種別を特定する

注目する場所は「Caused by: ~」という行。
ここでエラー内容がなんとなく分かります。この図だと NullPointerException です。

「Caused by: ~」がいっぱいある場合には、
一番最後の「Caused by: ~」を見るのが良いです。だいたい。

エラー発生源を特定する

注目する場所は「Caused by: ~」という行に続く、複数の「at ~」という行。
この「at ~」の時系列は下から上になってることに注意。

Caused by: java.lang.NullPointerException (エラー詳細)
 ↑
at com.example.hogehoge.MainActivity.onCreate (MainActivity.java:23) (直接のエラー発生源)
 ↑
at android.app.Activity.performCreate (onCreate の呼び出し元)
 ↑
at android.app.Instrumentation.callActivityOnCreate (performCreate の呼び出し元)
 ↑
at android.app.ActivityThread.performLaunchActivity (callActivityOnCreate の呼び出し元)

今回は、NullPointerException が MainActivity.java の23行目で発生していることが分かります。

覚えておくと良いデバッグ機能:ステップ実行

詳細は割愛。ググりましょう。

大きな力になります。

理不尽に困ったときの処方箋:Project - Clean

SDK 周りとかコンパイルタイミング周りとかなんとかよくわからない原因により、ときどきコンパイル結果のバイナリがぶっ壊れます。そんなときはどれだけエラーログ眺めようがソースコード眺めようが不毛なので、

とりあえずダメ元で「Project メニューの Clean」を実行してみましょう。

f:id:kobake:20140730002121p:plain

諸々コンパイルされ直されて、これだけで問題が解消されることも。

(ノ ゚Д゚)ノ ==== ┻━━┻

ツールを疑うことも時には必要なのです。

それではエラーを見ていきましょう

以下より実例。よくあるエラー。

ボタンクリック時に NoSuchMethodException発生

以下の可能性。

  • On Click プロパティに設定したメソッド名と実際のメソッド名が食い違ってる
  • メソッドの型が違う。public void buttonMethod(View view){} です。「public」「void」「View」の部分、ちゃんと確認しましょう。
// よくある間違い:定義の仕方は問題ないけど、On Click プロパティに設定した名前と食い違ってる。
public void buttttonMethod(View btn){
  …
}

// よくある間違い:public が抜けてる。
void buttonMethod(View btn){
  …
}

// よくある間違い:引数の型が Button になってる。(正しくは View)
public void buttonMethod(Button btn){
  …
}

何故か画面のどこをタップしても On Click 的なものが発動する

エラーというかなんというか。挙動。
レイアウトのほうの On Click プロパティが設定されてしまっている。

おそらくあなたは設定したつもりが無いのでしょうが、SDK周り(ADT Toolsあたり)の問題により、意図しない場所のプロパティが変わっちゃうことがときどきあります。

ツールを疑うことも時には必要なのです。(二度目)

起動時の setContentView でエラー

リソースが壊れてる可能性。

  • Project - Clean しましょう。

これで直らなかったら、いろいろ調査方法はありますが、
初めのうちは時間浪費しかねないので初めから作り直したほうがマシ。

ActivityNotFoundException

アプリ起動時またはアクティビティ切り替え時に起こる。
これも Project - Clean すると直ることがある。

あとは、AndroidManifest.xml を確認する。
AndroidManifest.xml の Application タブの下のほうにある Application Nodes というところにアクティビティ一覧が定義されてます。
アクティビティのクラスやレイアウトファイルが作成されていても、
ここの一覧にアクティビティが記載されていなければダメ。

普通にメニューからアクティビティ作っていれば AndroidManifest.xml も自動で更新されてるはずなんだけど、他プロジェクトからソースコピーとか繰り返してると、こういう漏れが発生しやすいですね。

NullPointerException

通称ぬるぽJava的におそらくもっともメジャーな例外であろうと思うし、本来は改めて説明するまでもないのですが。
万が一Javaを詳しく知らずにAndroidアプリを作り始めてしまってる人に対してヒントを与えておくと、これが発生するのは、だいたい以下のパターン。

変数の未初期化

TextView textView;
…
(textViewに何も代入してない)
…
textView.setText("hoge"); // textView は何も参照していないので、当然エラーが起こる。

ウィジェット取得に失敗している。

// textView1 が見つからなかった場合、結果は null となる
TextView textView = (TextView)findViewById(R.id.textView1);
// textView が null なら、当然エラーが起こる。
textView.setText("hoge");

何故ウィジェット取得に失敗するのか

よくあるパターンが以下。

  • そもそも他のアクティビティのウィジェットのIDを参照している
  • Activity の onCreate 時にフラグメント上のウィジェットを探しに行ってる
  • リソースがぶっ壊れている (Project - Clean で直ったり)

ClassCastException

よくあるパターン。

// ここで ClassCastException 発生
TextView textView = (TextView)findViewById(R.id.hogehogeView1);

hogehogeView1 で取得されたウィジェットがそもそも TextView ではなかったのに
TextView にキャストしようとしてエラーになるケース。
ちゃんとレイアウトを確認し直して、IDとタイプが意図通りに付けられているか確認しましょう。

どうしてもわからなかったら、findViewById 実行とキャストを同時にやらずに
以下のように分割して分析すると良いです。

// このあたりにブレークポイント張って、viewの型を確認する。
View view = findViewById(R.id.hogehogeView1);
TextView textView = (TextView)view;

「キャスト」ってなんじゃらほい?って人には良い薬なのでこの際Javaを少し勉強しましょう。Google等で。

それ以外

ググる

プログラミング全般に言えることですが、保有する知識量よりも
高速にググれるスキルが大事です。

(´ー`).o0(高速にググるための知識量も必要なんですけどね。。)

周りに聞ける人がいるのが理想ではある

ググって英語情報しか見つからなくて心が折れそうなときは人に聞くのも良いです。

根性鍛えるよりも先に形のある成功体験を積むことが大事だと僕は考えています。
ひとりでストイックにがんばって情報収集するのも良いけど、人から助けられてでも何か仕上げるほうが、たぶんモチベーションは継続するし、良い成果物もできあがります。何かアプリ仕上げてストアで公開とかできると良いですね。

お世話になった人にはちゃんと形になるお礼をしましょう。肉おごるとか。

まとめ

  • LogCat は必ず出す。
  • ステップ実行はできたほうが良い。
  • 理不尽に困ったら Project - Clean。
  • NoSuchMethodException, ActivityNotFoundException, NullPointerException, ClassCastException あたりは割と定番なので頭に入れておくと良い。
  • ググる
  • 人にも聞く。お礼はする。

これを読んだあなたができる限り甘い道を歩けますように。

});