Android的建议如果该类实现一个新的接口方式安全地支持更新的API有错误。为什么? [英] Android recommended way of safely supporting newer apis has error if the class implements a newer interface. Why?

查看:133
本文介绍了Android的建议如果该类实现一个新的接口方式安全地支持更新的API有错误。为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了支持不同的API级别,我使用这里所描述的技术:的http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html

In order to support different Api Levels, I am using the technique described here: http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-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的类。

This approach "takes advantage of the laziness of ClassLoaders." For devices with the newer API level (in the example's case, Froyo), it can use the Froyo class which accesses APIs in the newer version. For older devices, they receive a class that only uses the older APIs.

这完美的作品。

不过,如果你让FroyoDetector实现一个接口,只有在一个较新的API水平,当时的newInstance()被调用的存在,它可以运行任何方法中的code,甚至之前,它会尝试加载界面类FroyoDetector工具,并把错误到日志说,FroyoDetector类不能被加载。

However, if you make FroyoDetector implement an interface, that only exists in a newer api level, when newInstance() is called, even before it runs any of the code within that method, it tries to load the interface class that FroyoDetector implements and puts an error into the logs saying that the FroyoDetector class could not be loaded.

所以我的问题是,为什么会出现这种情况?我是即时pression下,与该技术的较新的类不会被加载,直到它第一次被直接引用。不过,如果你添加一个接口给它,它似乎尝试加载它甚至不调用 =检测新FroyoDetector(上下文);

So my question is, why does this happen? I was under the impression that with this technique that the newer class wouldn't be loaded until it was directly referenced for the first time. However if you add an interface to it, it seems to try to load it even without calling the detector = new FroyoDetector(context); line.

下面是一些code重现该问题:

Here is some code to reproduce the issue:

这是一个应用程序与8的2.3设备上运行这个分转载了问题针对SDK 16。

This is in an app targeting sdk 16 with a min of 8. Running this on a 2.3 device reproduces the issue.

下面三种类型:

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起。

AnimatorListener is only available from 3.1 onwards.

现在如果你运行: 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;

它不会崩溃,它实际上将继续正常工作。

It won't crash, and it will actually go on to work correctly.

推荐答案

是的,我可以重现该问题。还挺奇怪,不过,因为你注意,它不会崩溃的事实意味着这更多的是Dalvik的是也许有点太LogCat中比什么都应该造成损害的应用健谈的情况。

Yes, I can reproduce the problem. Kinda surprising, though, as you note, the fact that it does not crash means that this is more a case of Dalvik being perhaps a bit too chatty in LogCat than anything that should cause harm to an app.

一个解决方法是将接口移动到一个内部类。在你的榜样,而不是 NewVersionLoader 实施 AnimatorListener 在一个内部类 NewVersionLoader 将实施 AnimationListener

One workaround is to move the interface to an inner class. In your example, instead of NewVersionLoader implementing AnimatorListener, an inner class in NewVersionLoader would implement AnimationListener:

@TargetApi(11)
public class NewVersionLoader extends VersionedLoader {
    private class Foo 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) {}

    }
}

不可否认,这可能不是取决于你的使用目的 VersionedLoader 的理想。然而,由于 VersionedLoader 本身不执行 AnimationListener 用户 VersionedLoader 将不会被调用 AnimationListener 方法,因此,事实上,你的逻辑是一个内部类,而不是实际的类不应该是一个巨大的问题AFAIK。

Admittedly, this may not be ideal depending on your intended use of VersionedLoader. However, since VersionedLoader itself does not implement AnimationListener, users of VersionedLoader will not be calling AnimationListener methods, so the fact that your logic is on an inner class rather than the actual class should not be a huge issue AFAIK.

这篇关于Android的建议如果该类实现一个新的接口方式安全地支持更新的API有错误。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆