2015-01-17 20 views
5

Ho bisogno di metodi proxy su varie classi di vista nel framework dell'interfaccia utente Android come TextView. In particolare TextView#setText(int resId). Questo metodo non fa parte di un'interfaccia. Pertanto, Java Proxy non funzionerà poiché funziona solo per le interfacce. Ho bisogno di usare la manipolazione bytecode.Metodo finale proxy in Classe non finale

Ho trovato una libreria chiamata dexmaker che sembrava promettente. Sto assumendo che ho bisogno di fare la manipolazione del codice byte di runtime in quanto le classi di Visualizzazione Android sono effettivamente disponibili sul dispositivo. Dexmaker può proxy metodi pubblici su classi concrete. Poi ho notato che TextView#setText(int resId) è inspiegabilmente final. La classe TextView non è definitiva.

Penso che potrei fare in modo che dexmaker supporti i metodi finali nelle classi non finali. È possibile? Non voglio iniziare questo progetto se non lo è. Sarebbe una grande vittoria per la mia libreria anche se gli sviluppatori non avrebbero bisogno di sottoclassi, interfacce o chiamate di metodi statici manuali per le loro viste. La mia biblioteca deve sapere quando il testo è impostato su una vista particolare. Un proxy è il modello di design perfetto per questo.

+1

Colpo casuale (poiché non è menzionato): Un influsso di layout consente di [impostare una classe di fabbrica] (http://developer.android.com/reference/android/view/LayoutInflater. html # setFactory2 (android.view.LayoutInflater.Factory2)) potrebbe essere quello che stai cercando. Questo è usato in [probe] (https://github.com/lucasr/probe/) dove la fabbrica crea dinamicamente dei proxy usando dexmaker per intercettare le chiamate. –

+0

Parte della mia biblioteca utilizza effettivamente la tecnica di fabbrica del gonfiaggio del layout. Stai dicendo che puoi configurare un proxy lì sugli oggetti vista creati tramite dexmaker? – jophde

+0

Grazie mille Stefan. La fonte Probe è esattamente ciò di cui avevo bisogno :). Se ho capito correttamente Probe crea classi View completamente nuove, quindi la limitazione del Proxybuild di dexmaker di non essere in grado di gestire i metodi finali non è un problema? Da Dexmaker ProxyBuilder doc: "Questo processo funziona solo per le classi con livello di visibilità pubblico e protetto." – jophde

risposta

2

Per quanto ne so, questo non è possibile su Android.

Dexmaker crea file dex che contengono nuove classi. Queste classi vengono quindi aggiunte a un'applicazione utilizzando i programmi di caricamento di classe dex. Tuttavia, tali file dex non possono essere utilizzati per sostituire le classi, ma solo per aggiungere nuove sottoclassi che fungono da proxy.

In questo senso, dexmaker è un po 'più cgibroso che javassista.

Si noti che Android non fornisce funzionalità di strumentazione simili a quelle di una normale Jvm in cui è possibile utilizzare strumenti e classi finali per ridefinizione della classe tramite un agente. Questo non è fornito da Android: http://developer.android.com/reference/android/app/Instrumentation.html

2

L'intento di "final" è che il metodo non può essere sovrascritto. Ciò blocca effettivamente il proxy per estensione. Tuttavia, è sempre possibile eseguire il proxy eseguendo il wrapping, così come lo gestisce Spring.

Questo è uno dei motivi per cui è consigliabile separare l'interfaccia dall'implementazione.

In termini più concreti ...

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

fa questo aiuto?

+0

Normalmente funzionerebbe, ma gli oggetti devono entrare nella gerarchia ad albero della vista di Android che accetta solo sottoclassi di View o ViewGroup e sono sicuro che l'istanza di è usata in luoghi. Se estendo da TextView il metodo dell'interfaccia interferirà con il metodo di classe? – jophde

+0

Sì, non verrà compilato se estenderò TextView. Se solo usassero le interfacce ... – jophde

+0

Il meccanismo dell'interfaccia ti permette di avvolgere il metodo di classe. È possibile estendere Visualizza (chiamarlo MyTextViewProxy) e inserire TextView, a condizione che l'estensione della visualizzazione sia accettabile. Ho aggiornato l'esempio sopra per mostrare l'estensione View. –