さまざまなApiレベルをサポートするために、ここで説明する手法を使用しています:http://android-developers.blogspot.com/2010/07/how-to-have-your-担甲-and-eat-it-too。 html
記事の例は次のとおりです。
public static VersionedGestureDetector newInstance(Context context,
OnGestureListener listener) {
final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
VersionedGestureDetector detector = null;
if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
detector = new CupcakeDetector();
} else if (sdkVersion < Build.VERSION_CODES.FROYO) {
detector = new EclairDetector();
} else {
detector = new FroyoDetector(context);
}
detector.mListener = listener;
return detector;
}
このアプローチは、「ClassLoaderの怠惰を利用します」。新しいAPIレベルのデバイス(この例ではFroyo)の場合、新しいバージョンのAPIにアクセスするFroyoクラスを使用できます。古いデバイスの場合、古いAPIのみを使用するクラスを受け取ります。
これは完全に機能します。
ただし、FroyoDetectorに新しいAPIレベルにのみ存在するインターフェイスを実装させる場合、newInstance()が呼び出されると、そのメソッド内のコードを実行する前であっても、FroyoDetectorが実装して配置するインターフェイスクラスを読み込もうとします。 FroyoDetectorクラスをロードできなかったことを示すエラーがログに記録されます。
だから私の質問は、なぜこれが起こるのですか?この手法では、新しいクラスが初めて直接参照されるまでロードされないという印象を受けました。detector = new FroyoDetector(context);
ただし、インターフェイスを追加すると、回線を呼び出さなくてもロードしようとしているようです。
問題を再現するためのコードを次に示します。
これは、最小8のSDK16を対象とするアプリにあります。2.3デバイスでこれを実行すると、問題が再現されます。
これが3つのクラスです:
public class VersionedLoader {
public static VersionedLoader newInstance() {
if (Build.VERSION.SDK_INT < 12) {
return new OldVersionLoader();
} else {
return new NewVersionLoader();
}
}
}
-
public class OldVersionLoader extends VersionedLoader {
}
-
@TargetApi(11)
public class NewVersionLoader extends VersionedLoader implements AnimatorListener {
@Override
public void onAnimationStart(Animator animation) {}
@Override
public void onAnimationEnd(Animator animation) {}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
}
AnimatorListenerは、3.1以降でのみ使用できます。
今実行する場合:Object obj = VersionedLoader.newInstance();
このエラーはログに表示されます。
10-27 13:51:14.437: I/dalvikvm(7673): Failed resolving Lyour/package/name/NewVersionLoader; interface 7 'Landroid/animation/Animator$AnimatorListener;'
10-27 13:51:14.437: W/dalvikvm(7673): Link of class 'Lyour/package/name/NewVersionLoader;' failed
10-27 13:51:14.445: E/dalvikvm(7673): Could not find class 'your.package.name.NewVersionLoader', referenced from method your.package.name.VersionedLoader.newInstance
10-27 13:51:14.445: W/dalvikvm(7673): VFY: unable to resolve new-instance 1327 (Lyour/package/name/NewVersionLoader;) in Lyour/package/name/VersionedLoader;
10-27 13:51:14.445: D/dalvikvm(7673): VFY: replacing opcode 0x22 at 0x000c
10-27 13:51:14.445: D/dalvikvm(7673): VFY: dead code 0x000e-0011 in Lyour/package/name/VersionedLoader;.newInstance ()Lyour/package/name/VersionedLoader;
クラッシュすることはなく、実際には正しく機能します。