java - 突然缺了很多关于 Android 4 的类(class)

标签 java android dalvik

我的应用程序多年来一直在 Android 4.0.3 及更高版本上正常运行。最近进行了一次小更新后,它突然开始在 Android 4.x 设备上崩溃。当我在 Android 4 上调试它时,它可以正常构建和安装,但控制台会出现很多以

开头的错误
W/dalvikvm: VFY: unable to find class referenced in signature (Landroid/media/midi/MidiDeviceInfo;)
I/dalvikvm: Failed resolving Lcom/arlomedia/myapp/App$4; interface 113 'Landroid/media/midi/MidiManager$OnDeviceOpenedListener;'
W/dalvikvm: Link of class 'Lcom/arlomedia/myapp/App$4;' failed
E/dalvikvm: Could not find class 'com.arlomedia.myapp.App$4', referenced from method com.arlomedia.myapp.App.addMidiPorts
W/dalvikvm: VFY: unable to resolve new-instance 447 (Lcom/arlomedia/myapp/App$4;) in Lcom/arlomedia/myapp/App;
D/dalvikvm: VFY: replacing opcode 0x22 at 0x0007

然后我的应用程序中的许多类都出现类似的错误。应用程序一直运行,直到需要使用这些缺失的类之一,然后崩溃。

我读过几篇与 Android 4 上的 64K 方法限制相关的类似问题的帖子,可以想象,在最近的更新中,我碰巧跨越了 64K 阈值。所以我尝试根据these instructions设置multidex ,但这没有什么区别,我不知道如何判断它是否有效。当我构建一个 APK 文件并检查其内容时,我只看到一个classes.dex 文件。这可能意味着我的 multidex 设置无法正常工作,或者我没有超过 64K 的方法,而我的问题是其他原因。

我的第二个理论是,使用 Android 6 中添加的 MidiDeviceInfo 类在 Android 4 上导致了问题。但是,我正在使用版本检查和 @TargetApi(24) 在 Android 4-5 上忽略 MIDI 代码的注释。而这个问题在 Android 5 上不会出现。但奇怪的是,这却是每次第一个弹出的错误。

这些理论之一听起来正确,还是听起来像其他问题?

顺便问一下,“无法找到签名中引用的类”到底是什么意思——方法签名?我确实有一些使用 MidiDeviceInfo 类型参数的方法,但我用 @TargetApi(24) 注释了所有这些方法,并且编译没有任何问题。

更新

感谢 homerman 的提示,我发现方法的数量不是问题。这让我回到了 MIDI 兼容性,但我正在查看与之前版本的差异,并且没有看到 MIDI 代码有任何变化。我还应该寻找什么?

更新2

自上一个版本以来,我找不到任何与差异相关的内容,因此我从 VCS 中检查了上一个版本并运行它,它运行良好。但我在该版本的 logcat 中注意到 MIDI 类有所有相同的错误。所以看来这些并不是真正的问题。我想这就是 Android 在遇到新类时所做的事情。我不断比较上一个好版本和当前版本之间的 logcat,然后我看到了差异:我最近向我的一个类添加了一个 OnScrollChangeListener。这产生了另一批缺失类错误,这些错误不在上一个应用程序版本中。当我删除这个新功能时,该应用程序再次在 Android 4 上正常运行。

所以问题是:我有一个这样的类定义:

public class DocumentViewer extends RelativeLayout implements View.OnScrollChangeListener {

    if (Build.VERSION.SDK_INT >= 23) {
        textView.setOnScrollChangeListener(this);
    }

    @Override
    public void onScrollChange(final View scrollView, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
        Log.d("onScrollChange", "scroll changed: " + scrollY);
    }

}

显然,类定义中 View.OnScrollChangeListener 的存在使一切变得困惑。有没有办法声明仅适用于支持的 Android 版本?

显然 Android 5 会优雅地忽略这个不受支持的引用,但 Android 4 不会。

最佳答案

View.OnScrollChangeListener 接口(interface)是在 API 级别 23 中添加的。这意味着您的类定义已经存在问题;如果这个类在 23 之前加载过,你就会崩溃。

解决方案是创建一个公共(public)父级(可能是一个接口(interface))和该父级的两个具体实现:一个用于 23 岁以下,一个用于 23 岁以上。然后使用工厂根据当前运行的设备获取适当的实现。

public interface DocumentViewer {
    // interface methods
}
public class DocumentViewPre23 extends RelativeLayout implements DocumentViewer {
    // interface methods
}
public class DocumentViewer23 extends RelativeLayout implements DocumentViewer, View.OnScrollChangeListener {
    // interface methods
}

然后你可以得到类似的东西

public static DocumentViewer getDocumentViewer() {
    if (Build.VERSION.SDK_INT >= 23) {
        return new DocumentViewer23();
    } else {
        return new DocumentViewerPre23();
    }
}

Android 支持库经常这样做,无论其值(value)如何。以下是 ActionBarDrawerToggle 中的示例,它根据 API 版本在两个实现之间切换:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
    mActivityImpl = new JellybeanMr2Delegate(activity);
} else {
    mActivityImpl = new IcsDelegate(activity);
}
public interface Delegate {
    ...
}
@RequiresApi(18)
private static class JellybeanMr2Delegate implements Delegate {
    ...
}
private static class IcsDelegate implements Delegate {
    ...
}

关于java - 突然缺了很多关于 Android 4 的类(class),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52547192/

相关文章:

java - 在后端使用 Jersey 上传大文件

java - SpringJUnit4ClassRunner 为每个测试初始化​​ beans?

Android - 使用 Intent 打开具有特定应用程序的文件

android - 在 Eclipse 中添加断点,导致 Dalvik 崩溃

java - 填充二维数组的最后 n 个元素

java - XOM 解析器堆内存不足

android - 如何使用 JobScheduler 从后台应用程序获取步数

Android:我怎样才能得到通话日期?

android - Android 2.3 上的弱全局引用不起作用 (JNI)

java - ClassNotFoundException 安卓