【问题标题】:Instance of abstract class with hidden constructor具有隐藏构造函数的抽象类实例
【发布时间】:2015-06-03 21:24:16
【问题描述】:

我需要创建一个带有隐藏构造函数的抽象类的实例,该类如下所示:

public abstract class TestClass {
    /**
    * @hide
    */
    public TestClass() {
    }
}

创建一个具体的类不起作用,因为构造函数是不可见的,并且通过反射 API 调用构造函数也不起作用,因为该类是抽象的。

我需要创建一个 android.print.PrintDocumentAdapter.LayoutResultCallback 的实例

【问题讨论】:

  • 抽象类的实例???没有这样的事..
  • “我需要创建一个 android.print.PrintDocumentAdapter.LayoutResultCallback 的实例”:为什么?您所要做的就是创建一个扩展PrintDocumentAdapter 的类,并确保覆盖onLayout(...) 以使用LayoutResultCallback
  • 我知道不能直接创建这个类的实例,因为它是抽象的,但是继承类也是不可能的,因为构造函数是隐藏的,这就是问题所在。
  • 我想使用来自WebView.createPrintDocumentAdapter(String documentName) 的现有PrintDocumentAdapter 将网页转换为PDF,我知道我可以使用PrintManager 来保存PDF,但这必须在没有用户交互的情况下工作,所以我想要所以我想自己调用 PrintDocumentAdapter 的 onStart、onLayout、onWrite。
  • @Andreas 您是否能够使用此方法从 WebView 成功创建 PDF?我正在尝试做同样的事情......

标签: java android reflection abstract-class


【解决方案1】:

本教程似乎解决了您的要求:https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/。我自己从来没有这样做过,所以我不能保证。

警告: API 中的方法被隐藏是有原因的。对开发人员来说最重要的是,由于所讨论的方法不属于任何公共 API,因此无法保证该方法会持续存在任何时间。

【讨论】:

  • 我认为在这种情况下使用类是安全的,因为类本身和方法都没有隐藏或在内部API中,只有构造函数是隐藏的。
  • 在这种情况下,您可能是正确的。但是,构造函数的签名(参数类型等)仍然可以在没有警告的情况下更改(甚至在不同版本的 Android 上可能会有所不同)。我并不是要阻止你做你想做的事情,而只是确保你了解在其他版本的 Android 上可能遇到的运行时错误的来源。
【解决方案2】:

我遇到了完全相同的问题(甚至对于完全相同的类),我有一个比其他答案中建议的用 framework.jar 替换 android.jar 更好的解决方案。

解决方案使用dexmaker library。 (您将需要 dexmaker.1.4.jar 和 dexmaker-dx.1.4.jar)。这是一个在运行时为 Dalvik VM(android 中使用的 VM)生成字节码的库。

这个库有一个名为ProxyBuilder 的类,它为抽象类生成一个代理。代理是一个扩展抽象类并通过将方法分派到您指定的java.lang.reflect.InvocationHandler 实例来实现方法的对象。

ProxyBuilderjava.lang.refect.Proxy 几乎相同,只是java.lang.refect.Proxy 仅适用于接口,而dexmaker 的ProxyBuilder 适用于抽象类,这是我们解决问题所需要的。

代码全部是:

public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback(InvocationHandler invocationHandler,
                                                                                File dexCacheDir) throws  IOException{
    return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
            .dexCache(dexCacheDir)
            .handler(invocationHandler)
            .build();
}

回调逻辑在您提供的invocationHandler 中实现。 cacheDir 是 dexmaker 可以存储一些文件的目录。

【讨论】:

  • 感谢您的解决方案,我会在几天内尝试:)
  • 这适用于 Android 5.x 吗?因为 Android 5.0 中 Dalvik 被 ART 取代
  • 是的。我在 Android 6 上对其进行了测试。似乎 ART 使用与 Dalvik 相同的字节码:“ART and Dalvik are compatible runtimes running Dex bytecode”。由于 dexmaker 生成 Dex 字节码,因此 dexmaker 也适用于 ART。
  • 在哪里可以找到这个 dexmaker-dx-1.4.jar?在项目的 github 站点上,只有 dexmaker-1.4.jar 的下载。第二个jar文件真的有必要吗?
  • 你可以在这里找到它:mvnrepository.com/artifact/com.crittercism.dexmaker。我确实需要。我不明白为什么它是这样打包的,为什么 Github 自述文件中没有关于它的信息,但它对我有用......
猜你喜欢
  • 1970-01-01
  • 2018-06-10
  • 2014-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 2013-01-02
相关资源
最近更新 更多