web-dev-qa-db-ja.com

後方互換性のあるAndroidコードを書く

最新のAPIレベル-16でのみ使用可能な一部の関数とクラスを使用するアプリを作成していますが、APIレベル15のデバイスでエラーなしで実行したいです。

いくつかの例を使用してみましょう。新しいクラス:_Android.widget.Advanceable_、および新しい/名前が変更されたメソッド:View.setBackground()

私はこのようなことをすることができます:

_Advanceable myAdvanceable = ...;

if (Android.os.Build.VERSION.SDK_INT >= 16)
{
    myView.setBackground(...);
    myAdvanceable.advance();
}
else
{
    myView.setBackgroundDrawable(...); // The old function name.
    // Don't bother advancing advanceables.
}
_

そして、minSdkを15に設定し、ビルドターゲットを16に設定すると(つまり、[プロジェクトプロパティ]-> [Android]で)、エラーなしで実際にコンパイルされます。少なくとも時々。 Eclipseはエラーについて少し確率論的であり、「setBackground()はAPIレベル> = 16でのみ使用可能」などと表示される場合がありますが、プロジェクトをきれいにすればそれらのエラーは魔法のように消えます。

だから私の質問は、これを行うことはできますか? APIレベル15デバイスで実行した場合、コードはクラッシュしませんか?実際に16コードに到達した場合にのみクラッシュしますか?なぜEclipseは私がそれを構築するのを止めないのですか?

編集1

答えてくれてありがとう、私は質問が本当にあるべきだと思います:新しいAPIの使用についてリントが警告しないのはなぜですか?

マニフェストにこれがあり、APIレベル16の関数を使用していますが、それでも警告は表示されません。

_<uses-sdk Android:minSdkVersion="15"
    Android:targetSdkVersion="16"/>
_

また、Advanceableなど、クラス全体がAPIレベルでいつ新しいのかについてもまだわかりません。特に、それらをメンバー変数として使用する場合。

編集2

答えは「Eclipseは地獄のようにバグがある」と判明しましたが、Nicoの答えも非常に役に立ちました。

53
Timmmm

インラインApiエラーはADTにとって新しいものであり、Eclipseはコードを分析し、それらのエラー/警告をインラインに配置するためにLint(およびおそらく他の何かを推測します)を実行します。最適化またはベストプラクティスに関する警告またはヒントがある場合、XMLレイアウトにも同じことが当てはまります。アノテーションを使用して、クラスまたは特定のメソッドでこれらのエラーを抑制することができます。

@TargetApi(16)
@ SuppressLint( "NewApi")

ここに配置したサンプルコードには問題があります。APIレベルチェックのほかに、APIで動作しないコードにAdvanceableのインスタンスがあるため、APIレベルのチェックは新しいメソッドを呼び出すときにのみ役立ちますが、 IFブロック外の新しいAPIクラスを参照します。

私が受け入れられると思ったアプローチの1つは、抽象クラスと2つの実装を作成し、正しい実装をインスタンス化するために、静的メソッドでファクトリクラスを使用することです。

たとえば、いくつかの新しいAPIクラスとメソッドを内部で使用するビューを作成するには、次が必要です。

1-抽象クラスを作成します。

public abstract class CustomView {
    public abstract void doSomething();
}
  • すべてのAPIと互換性のある共通の実装
  • ここで抽象メソッドを定義して実装を分割します

2-レガシー実装

public class CustomLegacyView extends CustomView {
    public void doSomething(){
        //implement api < 16
    }
}
  • aPI <16の抽象メソッドを実装する

3-API 16の実装

@TargetApi(16)
public class CustomL16View extends CustomView {

    Advanceable myAdvanceable;

    public void doSomething(){
        //implement api >= 16
    }
}
  • アノテーション@TargetApi(16)を使用します
  • aPI> = 16の抽象メソッドを実装する
  • ここでレベル16クラスを参照できます(ただし、CustomViewではできません)

4-工場クラス

public class ViewFactory {

    public static CustomView getCustomView(Context context) {

        if (Android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return new CustomL16View(context);
        }else{
            return new CustomLegacyView(context);
        }

    }
}
74
Nico

新しいビルドターゲットを使用し、適切な状況で新しいAPIが呼び出されることを保証するのが一般的な方法です。 GoogleはADT 17以降、条件付きでロードされたコードのローカルオーバーライドを指定するために@TargetApi()アノテーションを追加しました。

詳細については、 Lint APIチェック を参照してください。

3
biegleux