2015-01-17 35 views
5

我需要在Android UI框架中的各种视图类上代理方法,如TextView。特别是TextView#setText(int resId)。此方法不是接口的一部分。因此,Java Proxy将不起作用,因为它只适用于接口。我需要使用字节码操作。非最终类中的代理最终方法

我发现了一个名为dexmaker的库,看起来很有希望。我假设我需要执行运行时字节码操作,因为Android View类只能在设备上使用。 Dexmaker可以在具体类上代理公共方法。然后我注意到TextView#setText(int resId)是莫名其妙的finalTextView类本身是非最终的。

我想我可以fork dexmaker来支持非final类中的final方法。这可能吗?如果不是,我不想开始这个项目。这对我的图书馆来说将是一个巨大的胜利,因为开发人员不需要为其视图提供子类,接口或手动静态方法调用。我的图书馆需要知道什么时候在特定的视图上设置文本。代理是完美的设计模式。

+1

随机拍摄(因为没有提到):布局充电器允许[设置工厂类](http://developer.android.com/reference/android/view/LayoutInflater。 html#setFactory2(android.view.LayoutInflater.Factory2))这可能是你在之后。这用在[probe](https://github.com/lucasr/probe/)中,工厂使用dexmaker动态地创建代理来拦截调用。 –

+0

我的图书馆的一部分实际上使用布局充气器工厂技术。您是说您可以在通过dexmaker创建的视图对象上设置代理? – jophde

+0

非常感谢Stefan。探测器来源正是我需要的:)。如果我理解正确Probe创建全新的View类,所以dexmaker Proxybuild无法处理最终方法的限制不是问题?来自dexmaker ProxyBuilder文档:“此过程仅适用于具有公共和受保护级别可见性的类。” – jophde

回答

2

据我所知,这是不可能在Android上。

Dexmaker创建包含新类的dex文件。然后通过使用dex类加载器将这些类添加到应用程序中。然而,这样的dex文件不能用于替换类,只能添加用作代理的新子类。

从这个意义上讲,dexmaker与javassist相比更像cglib。

请注意,Android既不能提供与常规Jvm类似的检测功能,您可以通过代理对类进行重新定义来检测最终的类和方法。这不是由Android提供的:http://developer.android.com/reference/android/app/Instrumentation.html

2

“最终”的意图是该方法不能被覆盖。这有效地阻止了代理的扩展。但是,您仍然可以通过包装来处理代理,这是Spring处理它的方式。

这是将接口与实现分离的最佳实践的原因之一。

更具体地说......

// This snip is not supposed to be functional, only to demonstrate a concept 
interface TextViewInterface { 
    void setText (int resId); 
} 

class TextView implements TextViewInterface { 
    public final void setText (int resId) { 
    ... snip ... 
    } 
} 

class Proxy$TextView implements TextViewInterface 
extends View { // Added this for Android hierarchy 
    private TextView textView; 

    public void setText (int resId) { 
     textView.setText(resId); 
    } 
} 

这是否帮助?

+0

这通常会起作用,但对象需要进入Android View Tree Hierarchy,它只接受View或ViewGroup的子类,并且我确信地点中使用了实例。如果我从TextView扩展接口方法会干扰类方法? – jophde

+0

是的,如果我也扩展TextView,它不会编译。如果他们只使用接口... – jophde

+0

接口机制允许你包装类的方法。你可以扩展View(称之为MyTextViewProxy)并包装TextView,只要View可以被接受。我更新了上面的示例以显示扩展视图。 –