Muy buenas, me llamo Miguel y hoy les traigo otro nuevo tutorial.
Android proporciona clase Observable y una interfaz Observer para implementar patrón observable. Sin embargo, esta no es una solución elegante porque, ¿qué pasa si queremos hacer observable una clase de vista personalizada? La clase de vista personalizada extenderá la Vista, por lo que no puede extender la clase Observable.
Además, como dice Joshua Bloch en su libro Effective Java: deberíamos favorecer la composición sobre la herencia, y como tal, va en contra de un buen diseño de software extender una clase solo para un solo comportamiento.
La posible solución sería utilizar una interfaz observable e implementarla, en lugar de extender la Observable clase.
Así es como podemos usar una interfaz observable simple:
public interface Observable { interface Listener{ void callback(); } void registerListener(Listener listener); void unregisterListener(Listener listener); }
(Esto funciona, pero aún así, los métodos de devolución de llamada deben estar predefinidos en la interfaz Observable.Listener. Regresaremos a este punto en un minuto).
Aquí, la devolución de llamada se implementaría en dos pasos:
Observable
El objeto observable, digamos la clase customView, necesitaría implementar la interfaz Observable.
Observador
Crear un objeto Listener anónimo en línea o implementar la interfaz Observable.Listener:
class CustomView implements Observable.Listener{ @Override callback(){ // do something } }
El problema aquí es que necesitamos definir los métodos de devolución de llamada en la propia interfaz, en el caso anterior, el método es “void callback ()”. Por lo tanto, no podemos reutilizar esta Interfaz en el código base ya que no todos los Observable querrán llamar al Observer en este método.
Entonces, la pregunta es: ¿hay alguna manera en que podamos crear una interfaz Observable mediante la cual la interfaz Listener sea definida más tarde por la clase que implementa la interfaz Observable?
Respuesta: ¡si! ¡Es posible a través de Genéricos!
Considere el siguiente código:
public interface Observable<ListenerType> { void registerListener(ListenerType listener); void unregisterListener(ListenerType listener); }
Ahora, tenemos un ListenerType genérico (que no conocemos en el momento de escribir la interfaz).
¡Se deja al Observable implementar esta interfaz y así definir los métodos de devolución de llamada!
Así es como se verá la clase Observable ahora:
public class CustomView implements Observable<CustomView.Listener> { private Listener mListener; // Listener interface and callbacks are now defined inside the Observable object class public interface Listener { void notifyDrawComplete(); void notifyCircleShiftedByX(int x); } @Override public void registerListener(Listener listener) { mListener = listener; } @Override public void unregisterListener(Listener listener) { mListener = null; } }
Así es como se verá la clase Observer:
public class MainActivity extends AppCompatActivity implements CustomView.Listener { private CustomView mCustomView = new CustomView(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStart() { super.onStart(); // register in onStart mCustomView.registerListener(this); } @Override protected void onStop() { super.onStop(); // very important to unregister in onStop to avoid memory leak mCustomView.unregisterListener(this); } @Override public void notifyDrawComplete() { // do something.. } @Override public void notifyCircleShiftedByX(int x) { // do something.. } }
¡Podemos implementar el patrón Observable simplemente escribiendo una interfaz genérica! En lugar de una clase y una interfaz que proporciona Android y que dificulta la composición.
De esta manera, la interfaz de Observable no tiene que saber nada sobre el Observador o el Observable y, por lo tanto, puede escribirse de una manera muy genérica y usarse en toda la base de código.x|
Añadir comentario