ポイント
- onCreate、onResume、onPause で必ず同じ処理を行う場合はそれらをスーパークラスにまとめたい。
- しかし、このスーパークラスはアクティビティとして呼び出さないようにしたい。
- そこで、クラス宣言を abstract で行う一方で、メソッドでは abstract を付けない通常の宣言を行う。
- abstract でクラス宣言したアクティビティを起動しようとすると java.lang.InstantiationException と RuntimeException を発生させることができる。
onCreate、onResume、onPause で必ず同じ処理を行う場合とは?
たとえば NFC を使う場合ですの♪NFC の読み込み、書き込みを行うアクティビティでは、
- onCreate で NfcAdapter#getDefaultAdapter を呼び出す
- onResume で起動中のアクティビティが優先的に NFC を受け取れるよう設定
- onPause でアクティビティが優先的に NFC を受け取る設定を解除
を行うようにプログラムいたしました。次の参考書を元にしております。
NFC を扱うアクティビティは 2 〜 3 ございますので、たとえば NfcBaseActivity と名づけて onCreate、onResume、onPause の処理を書き、NFC を扱うアクティビティは NfcBaseActivity を継承するようにいたしました。
abstract でクラス宣言したアクティビティを起動すると発生する例外について
試しに、アクティビティのクラス宣言に abstract を付けて、どのようになるか確認いたしました。
結果、次のような実行時例外が発生しました。
05-04 08:04:39.170 11419-11419/com.example.sample E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.example.nfc, PID: 11419 java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.sample/com.example.sample.MainActivity}: java.lang.InstantiationException: can't instantiate class com.example.sample.MainActivity at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2124) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2248) at android.app.ActivityThread.access$800(ActivityThread.java:138) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5050) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:805) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:621) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.InstantiationException: can't instantiate class com.example.sample.MainActivity at java.lang.Class.newInstanceImpl(Native Method) at java.lang.Class.newInstance(Class.java:1208) at android.app.Instrumentation.newActivity(Instrumentation.java:1061) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2115) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2248) at android.app.ActivityThread.access$800(ActivityThread.java:138) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5050) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:805) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:621) at dalvik.system.NativeStart.main(Native Method)
これで、abstact を付けたクラスは継承専用のクラスであることを説明なしに表現できることを確認できました♪
おわりに
クラス宣言に abstract を付けるべきこと、次の本を読むまで思い浮かべることができませんでしたの><。
abstract 修飾子については、もちろん存じておりました。ですけれども、どういう時に使うとどのように嬉しいのか、理解はできておりませんでしたの><。
次の本の12.3 抽象クラスを読んで、どのようなときに使うのか、理解できました♪
なぜ抽象クラスが存在するのか、どのようなときに使うのかが理解できますので、とてもよい本だと思います。文章のコピペ不可能、印刷可能、ファイルの複製可能、PDF の電子書籍版もございます。
また、次のページも参考になります。
- Android – BaseActivityに処理を求めるのは間違っているだろうか – Qiita
→ 共通処理を盛り込むスーパークラスを扱う時の注意点がグッド♪ - プログラミング – チームとして少ないミスで素早くアプリを継続的・持続的に作り続けるためのメソッド – Qiita の「共通する処理を委譲する」
→ 継承だけでなく、他の解決方法が示されており、未来を感じます。グッド♪
以上です。