2015-01-17 6 views
5

TextView과 같은 Android UI 프레임 워크의 다양한 뷰 클래스에 대한 메소드를 프록시해야합니다. 특히 TextView#setText(int resId). 이 메소드는 인터페이스의 일부가 아닙니다. 따라서 Java Proxy은 인터페이스에서만 작동하기 때문에 작동하지 않습니다. 바이트 코드 조작을 사용해야합니다.프록시 최종 메소드 비 최종 클래스

유망한 것으로 보이는 dexmaker 라이브러리를 발견했습니다. 안드로이드 뷰 클래스는 실제로 디바이스에서만 사용할 수 있기 때문에 런타임 바이트 코드 조작을해야한다고 가정합니다. Dexmaker는 public 클래스에 대한 public 메소드를 프록시 할 수 있습니다. 그 때 나는 TextView#setText(int resId)가 설명 할 수 없게 final다는 것을주의했다. TextView 클래스 자체는 최종본이 아닙니다.

나는 최종 사용자가 아닌 클래스에서 최종 메소드를 지원하기 위해 dexmaker를 포크 할 수 있다고 생각합니다. 이것이 가능한가? 나는 그렇지 않다면이 프로젝트를 시작하고 싶지 않다. 개발자는 하위 클래스, 인터페이스 또는 수동 정적 메서드 호출을 필요로하지 않으므로 내 라이브러리에 큰 도움이됩니다. 내 라이브러리는 특정보기에서 텍스트가 설정된시기를 알아야합니다. 프록시는이를위한 완벽한 디자인 패턴입니다.

+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

스테판 감사합니다. 프로브 소스는 정확히 내가 필요한 것입니다 :). 내가 올바르게 이해했다면 Probe는 완전히 새로운 View 클래스를 생성하므로 dexmaker Proxybuild의 최종 메소드를 처리 할 수 ​​없다는 제한이 문제가되지 않습니까? dexmaker ProxyBuilder docs : "이 프로세스는 공개 및 보호 수준이 표시된 클래스에만 적용됩니다." – jophde

답변

2

내가 아는 한, 이것은 Android에서는 불가능합니다.

Dexmaker는 새로운 클래스를 포함하는 dex 파일을 생성합니다. 이러한 클래스는 dex 클래스 로더를 사용하여 응용 프로그램에 추가됩니다. 그러나 이러한 dex 파일을 사용하여 클래스를 대체하거나 프록시 역할을하는 새 서브 클래스를 추가 할 수는 없습니다.

dexmaker는 javassist보다 cglib과 비슷합니다.

안드로이드는 에이전트를 통한 클래스 재정의에 따라 최종 클래스와 메소드를 준비 할 수있는 일반 Jvm과 유사한 계측 기능을 제공하지 않습니다. 이것은 안드로이드에서 제공하지 않습니다 : http://developer.android.com/reference/android/app/Instrumentation.html

2

"최종"의 의도는 메서드를 재정의 할 수 없다는 것입니다. 이는 효과적으로 확장에 의한 프록시 차단을 중지시킵니다. 그러나 래핑 (wrapping), 즉 스프링이 처리하는 방식으로 여전히 프록시 할 수 있습니다.

이것이 인터페이스를 구현과 분리하는 가장 좋은 방법입니다.

보다 구체적인 측면에서

...

// 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

이것은 일반적으로 작동하지만 객체는 View 또는 ViewGroup의 하위 클래스 만 받아들이는 Android View Tree Hierarchy로 이동해야하며 인스턴스가 of place에 사용되었다고 확신합니다. TextView에서 확장하면 인터페이스 메서드가 클래스 메서드를 방해합니까? – jophde

+0

그래도 TextView를 확장하면 컴파일되지 않습니다. 그들은 인터페이스를 사용하는 경우 ... – jophde

+0

인터페이스 메커니즘을 사용하면 클래스 메서드를 래핑 할 수 있습니다. 뷰를 확장 (MyTextViewProxy라고 함)하고 TextView를 래핑 할 수 있습니다. 위의 예제를 확장하여 뷰를 표시했습니다. –