【问题标题】:Can I override a hidden (but public) method and call its super method?我可以覆盖隐藏(但公共)的方法并调用它的超级方法吗?
【发布时间】:2012-04-08 07:34:00
【问题描述】:

我需要重写一个非公共 api 以解决 Android 的 WebView 的一个怪癖。

api是隐藏的,但它是公开的:

/**
 * ...
 *
 * @hide pending API council approval
 */
public boolean selectText() {
    ...
}

所以我可以通过简单地在我自己的 WebView 类中声明它来覆盖它,减去 @Override:

public boolean selectText() {
    ...
}

是否可以从我的覆盖中调用超级方法?通常我可以写:

public boolean selectText() {
    return super.selectText();
}

但是方法是隐藏的,所以super.selectText()不可用。如果我使用反射:

public boolean selectText() {
    return (Boolean) WebView.class.getMethod("selectText").invoke(this, (Object[]) null);
}

我得到一个无限循环,因为它调用了我的重写方法。

有没有办法重写这个方法并且能够调用超级方法?

谢谢!

【问题讨论】:

标签: java android reflection overriding


【解决方案1】:

有没有办法覆盖这个方法并且能够调用超级 方法?

不,很遗憾,正如How to call a superclass method using Java reflection 问题的答案中所述,您无法通过反射解决此问题。

【讨论】:

  • 我不同意 - 看我的回答
【解决方案2】:

实际上有几种方法可以做到这一点,但它们有点费力,所以可能应该作为最后的手段使用。使用有根设备,您可以从设备上的框架 jar 中提取符号并将它们放入 sdk/platforms/ 文件夹中的 android.jar 中。曾经有一个脚本来执行此操作;在换工作中失去了它。

记忆中的步骤(请注意,您可能会遇到麻烦,因为我不记得这些步骤......对于了解我想要了解的高级用户):

  • adb pull /system/framework/*(这些都是jar文件)。有可能 足以得到framework.jar。解压缩它们。
  • 我相信每一个都会给你一个 classes.dex 和一个清单。如果 你只是得到类文件,跳过下一步
  • dex2jar classes.dex 并解压缩 classes_dex2jar.jar 或任何 输出来自 dex2jar,它会给你一堆 .class 文件
  • 获取类文件并将它们添加到您的 android sdk android.jar 文件(sdk/platforms/android-#sdk#/android.jar)。

我建议把你的android-#sdk#文件夹复制到一个android-1#sdk#文件夹中,这样android-19就变成了android-119,然后把文件夹里的build.prop改成ro.build.version.sdk = 119,然后针对 sdk 119 构建。这样,您可以选择针对干净的 119 或黑客攻击的 119 构建。只是不要引用任何 com.android.internal.R 文件,因为这些 id 在我的经验。

您现在可以针对这些符号进行编译并正常访问它们。尽管如果他们改变了工作方式,请不要生气,而且他们没有义务保持与 3rd 方应用程序的兼容性。

之所以有效,是因为 hide 标记仅在 SDK 编译步骤中使用,并从位于您的 sdk 中的 android.jar 中删除这些符号。如果我们收集编译到设备上的所有符号并将它们粘贴到您的 sdk jar 中,就好像它们从未被剥离。

或者,您可以下载并构建完整的 android 树 (https://source.android.com/source/building.html),然后针对完整源代码构建您的应用,第一步基本上是通过获取已编译的符号并使用它们来解决问题。

【讨论】:

    【解决方案3】:
    1. 是的,你可以 :) - 问题的第一部分
    2. 不,你不能 - 第二个

    解决方案 1) - 最接近您想要实现的目标的最佳方法

    // to override method 
    // which IDE doesn't see - those that contains {@ hide} text in JavaDoc
    // simple create method with same signature
    // but remove annotation
    // as we don't know if method will be present or not in super class 
    //
    //@Override      
    public boolean callMethod(String arg) {
    
        //  can we do it ?
        // boolean result = super.callMethod(arg)
        // no  why ? 
        // You may think you could perhaps
        // use reflection and call specific superclass method 
        // on a subclass instance.
    
    
    /** 
     * If the underlying method is an instance method, it is 
     * invoked using dynamic method lookup as documented in The 
     * Java Language Specification, Second Edition, section 
     * 15.12.4.4; in particular, overriding based on the runtime
     * type of the target object will occur.
     */
    
    
       // but always you can see what super class is doing in its method 
       // and do the same by forward call in this method to newly created one
       // return modified  result 
      return doSomthingWhatSuperDo()
    }
    

    解决方案 2)

    对象(调用此方法的)是否属于您?并实现接口?

    如果是这样,代理呢?

    1. 扩展类
    2. 创建代理
    3. 使用代理
    4. 拦截方法调用
    5. 基于某些条件?调用自己的实现还是回退到原来的?

    【讨论】:

      猜你喜欢
      • 2015-08-26
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      • 2013-01-16
      • 2018-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多