2015-01-17 15 views
5

Ich muss Methoden auf verschiedenen Ansichtsklassen im Android UI Framework wie TextView Proxy-Methoden. Insbesondere TextView#setText(int resId). Diese Methode ist nicht Teil einer Schnittstelle. Daher wird Java Proxy nicht funktionieren, da es nur für Schnittstellen funktioniert. Ich muss Bytecode-Manipulation verwenden.Endgültige Proxy-Methode in nicht abschließender Klasse

fand ich eine Bibliothek namens dexmaker, die vielversprechend schien. Ich gehe davon aus, dass ich Laufzeit-Byte-Code manipulieren muss, da die Android View-Klassen nur auf dem Gerät verfügbar sind. Dexmaker kann öffentliche Methoden auf konkrete Klassen anwenden. Dann habe ich bemerkt, dass TextView#setText(int resId) unerklärlicherweise final ist. Die Klasse TextView selbst ist nicht endgültig.

Ich glaube, ich dexmaker Gabel könnte endgültige Methoden in nicht-finalen Klassen zu unterstützen. Ist das möglich? Ich möchte dieses Projekt nicht starten, wenn es nicht ist. Es wäre jedoch ein großer Gewinn für meine Bibliothek, da Entwickler für ihre Ansichten keine Unterklassen, Schnittstellen oder manuelle statische Methodenaufrufe benötigen würden. Meine Bibliothek muss wissen, wann Text für eine bestimmte Ansicht festgelegt wurde. Ein Proxy ist das perfekte Designmuster dafür.

+1

Random Schuss (da es nicht erwähnt wird): Ein Layout Inflater ermöglicht [eine Factory-Klasse festlegen] (http://developer.android.com/reference/android/view/LayoutInflater. html # setFactory2 (android.view.LayoutInFlater.Factory2)) das könnte sein, wonach Sie suchen. Dies wird in [Probe] (https://github.com/lucasr/probe/) verwendet, wo die Factory mit dexmaker zum Abfangen von Anrufen dynamisch Proxys erstellt. –

+0

Ein Teil meiner Bibliothek verwendet tatsächlich die Layout-Inflatter-Factory-Technik. Sie sagen, Sie können dort auf den über dexmaker angelegten View-Objekten einen Proxy einrichten? – jophde

+0

Vielen Dank Stefan. Die Probequelle ist genau das, was ich brauchte :). Wenn ich das richtig verstanden habe, erstellt Probe völlig neue View-Klassen, so dass die Dexmaker-Beschränkung von Proxybuild, mit finalen Methoden nicht umgehen zu können, kein Problem ist. Von dexmaker ProxyBuilder docs: "Dieser Prozess funktioniert nur für Klassen mit öffentlicher und geschützter Sichtbarkeitsebene." – jophde

Antwort

2

Soweit ich weiß, ist dies auf Android nicht möglich.

Dexmaker erstellt Dex-Dateien, die neue Klassen enthalten. Diese Klassen werden dann mithilfe von dex-Klassenladeprogrammen zu einer Anwendung hinzugefügt. Solche Dex-Dateien können jedoch nicht zum Ersetzen von Klassen verwendet werden, sondern nur zum Hinzufügen neuer Unterklassen, die als Proxy dienen.

In diesem Sinne ist dexmaker eher wie cglib als Javassist.

Beachten Sie, dass Android keine ähnlichen Instrumentierungsfunktionen wie eine reguläre JVM bietet, in der Sie letzte Klassen und Methoden durch Klassenredefinition über einen Agenten instrumentieren können. Dies wird nicht von Android zur Verfügung gestellt: http://developer.android.com/reference/android/app/Instrumentation.html

2

Die Absicht von "final" ist, dass die Methode nicht überschrieben werden kann. Dadurch wird die Proxy-Vergabe durch die Erweiterung effektiv gestoppt. Sie können jedoch immer noch Proxy durch Umbrechen, so wie Spring es behandelt.

Das ist ein Grund, warum es eine bewährte Methode ist es, die Schnittstelle von der Implementierung zu trennen.

In Konkreter ...

// 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); 
    } 
} 

Does diese Hilfe?

+0

Das würde normalerweise funktionieren, aber die Objekte müssen in die Android View Tree Hierarchie gehen, die nur Unterklassen von View oder ViewGroup akzeptiert, und ich bin mir sicher, dass Instanz von an Orten verwendet wird. Wenn ich von TextView erweitere, wird die Interface-Methode die Klassenmethode stören? – jophde

+0

Ja, es wird nicht kompiliert, wenn ich TextView auch erweitere. Wenn sie nur Interfaces verwendet haben ... – jophde

+0

Der Interface-Mechanismus ermöglicht es Ihnen, die Klassenmethode zu umbrechen. Sie könnten View erweitern (nennen Sie es MyTextViewProxy) und TextView umbrechen, vorausgesetzt, dass alles, was View erweitert, akzeptabel ist. Ich habe das obige Beispiel aktualisiert, um die erweiterte Ansicht anzuzeigen. –

Verwandte Themen