ちょっと話題の記事

[Android Tips] バージョン毎に読み込むクラスを変える

2014.05.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

バージョン毎に異なる処理を吸収する

最近では Android 4.x 系の端末もかなり普及し、4.x 系のみサポートするようなアプリ開発も増えてきているように感じています。しかしながら、 2.x 系をサポートして欲しいとう要件もゼロではありません。

各バージョンの対応でよくある問題がバージョン毎にアクセスする API が異なるという点です。4.0 以降で追加された API を 2.x 系では呼ばないようにする (または独自で実装する) などといった対応が必要です。こういった場合によく使うのがバージョン毎に読み込むクラスを変えるという方法です。ということで、今回はその手順を解説したいと思います。ちなみにこの方法は Google I/O 2012 で発表されており、 Lazy Loading というデザインパターンをベースに生み出された手法です。Support Package も同じ手法を採用しているそうです。

ということで、今更感を感じるかたも多いとは思いますが、個人的なまとめとして投稿させていただきます。

実装してみる

1. 設計

ざっくりとどのような設計になるか解説したいと思います。

まず他のクラスから呼び出すことになる Abstract クラスを作成します。このクラスには他のクラスから呼び出す予定のメソッドを定義しておきます。

次にこのクラスの実装クラスをサポートしたいバージョン毎に作成します。対応させたいバージョンの数だけ作成していき、Abstract クラスのメソッドを Override して、バージョン特有の処理を行います。

最後に、このクラスのインスタンスを生成するメソッドを定義し、バージョン毎にインスタンス化するクラスを変える処理を書きます。これで対象のクラスをインスタンス化したときにバージョン毎に異なるクラスがインスタンス化されるようになります。

2. Abstract クラスの作成

それでは実装してみましょう。今回は例として Calendar を取り扱うヘルパークラスを実装してみます。Calendar は ICS 以後とそれ以前では URI などが異なるので、まさにうってつけです。まずは Abstract クラスである CalendarHelper クラスを作成します。

CalendarHelper.java

public abstract class CalendarHelper {
   protected abstract Uri getContentURI();
}

とりあえず ContentURI を返すメソッド getContentURI() だけ書いています。この Abstract クラスを対応させたいバージョン用に Override して、Abstract メソッドを実装していく形になります。

3. バージョン毎のクラスの作成

次にバージョン毎のクラスの作成です。今回は ICS 以前/以後で処理を分けたいので、ICS 以前で読み込む CalendarHelperBase クラスと ICS 以後で読み込む CalendarHelperICS クラスを作ります。

CalendarHelperBase.java

public class CalendarHelperBase extends CalendarHelper {
   protected Uri getContentURI() {
       return Uri.parse("content://com.android.calendar");
   };
}

CalendarHelperICS.java

public class CalendarHelperICS extends CalendarHelper {
   protected Uri getContentURI() {
       return CalendarContract.CONTENT_URI;
   };
}

ICS 以前では ContentURI は公開されていないので自分で書く必要がありますが、ICS から API として公開されたので、CalendarHelperICS では CalendarContract.CONTENT_URI を返すようにしています。

4. インスタンス化するときにバージョン毎に分岐させる

最後に CalendarHelper をもう一度編集し、インスタンス化するメソッドを追加します。

public abstract class CalendarHelper {
    
    ...
    
    public static final CalendarHelper getInstance() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            return new CalendarHelperICS();
        } else {
            return new CalendarHelperBase();
        }
    }
    
    ...
  
}

Build.VERSION.SDK_INT で実行中のバージョンを取得し、Build.VERSION_CODES.ICE_CREAM_SANDWICH と比較して返すインスタンスを変えています。このクラスを使うときは CalendarHelper.getInstance() でインスタンスを取得し、メソッドを叩いていく感じになります。

まとめ

以上です。なんだか小難しそうですが、実際はかなりシンプルにまとまるので、バージョンごとに処理を分けたい場合にオススメの手法です。ぜひ使ってみてください。

参考