Cómo instanciar un oyente por reflexión en Android

Tengo que desarrollar una aplicación para Android 1.6 (API 4), que debería ser capaz de usar OnAudioFocusChangeListener (disponible desde Android 2.2 – API 8) en los teléfonos con Android 2.2 o posterior.

¿Cualquier persona puede decirme cómo instantiate a un oyente por la reflexión? Ya he logrado ejecutar métodos estáticos y no estáticos por reflexión, pero no sé cómo hacer con los oyentes.

Este es el oyente para reflexionar:

AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); OnAudioFocusChangeListener audioListener = new OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { // code to execute } }; public void getAudioFocus() { audioManager.requestAudioFocus(audioListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } public void releaseAudioFocus() { audioManager.abandonAudioFocus(audioListener); } 

Este es un ejemplo de código con métodos que logré ejecutar por reflexión:

 Class BluetoothAdapter = Class.forName("android.bluetooth.BluetoothAdapter"); Method methodGetDefaultAdapter = BluetoothAdapter.getMethod("getDefaultAdapter"); // static method from the BluetoothAdapter class returning a BluetoothAdapter object Object bluetooth = methodGetDefaultAdapter.invoke(null); Method methodGetState = bluetooth.getClass().getMethod("getState"); // non-static method executed from the BluetoothAdapter object (which I called "bluetooth") returning an int int bluetoothState = (Integer) methodGetState.invoke(bluetooth); 

Al final lo solucioné usando una clase Proxy. Aquí está el código!

 private AudioManager theAudioManager; private Object myOnAudioFocusChangeListener = null; private static final int AUDIOMANAGER_AUDIOFOCUS_GAIN = 1; private static final int AUDIOMANAGER_AUDIOFOCUS_LOSS = -1; theAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); // instantiating the OnAudioFocusChangeListener by reflection (as it only exists from Android 2.2 onwards) // we use a Proxy class for implementing the listener public void setOnAudioFocusChangeListener() { Log.i(this, "setOnAudioFocusChangeListener()"); Class<?>[] innerClasses = theAudioManager.getClass().getDeclaredClasses(); for (Class<?> interfaze : innerClasses) { if (interfaze.getSimpleName().equalsIgnoreCase("OnAudioFocusChangeListener")) { Class<?>[] classArray = new Class<?>[1]; classArray[0] = interfaze; myOnAudioFocusChangeListener = Proxy.newProxyInstance(interfaze.getClassLoader(), classArray, new ProxyOnAudioFocusChangeListener()); } } } // called by onResume public void getAudioFocus() { if (myOnAudioFocusChangeListener != null) { Log.i(this, "getAudioFocus()"); try { Method[] methods = theAudioManager.getClass().getDeclaredMethods(); for (Method method : methods) { if (method.getName().equalsIgnoreCase("requestAudioFocus")) { method.invoke(theAudioManager, myOnAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AUDIOMANAGER_AUDIOFOCUS_GAIN); Log.i(this, "requestAudioFocus"); } } } catch (Exception e) { Log.e(this, e.getMessage()); } } } // called by onPause public void releaseAudioFocus() { if (myOnAudioFocusChangeListener != null) { Log.i(this, "releaseAudioFocus()"); try { Method[] methods = theAudioManager.getClass().getDeclaredMethods(); for (Method method : methods) { if (method.getName().equalsIgnoreCase("abandonAudioFocus")) method.invoke(theAudioManager, myOnAudioFocusChangeListener); } } catch (Exception e) { Log.e(this, e.getMessage()); } } } 

Clase PROXY OnAudioFocusChangeListener

 private class ProxyOnAudioFocusChangeListener implements InvocationHandler { // implements the method onAudioFocusChange from the OnAudioFocusChangeListener public void onAudioFocusChange(int focusChange) { Log.e(this, "onAudioFocusChange() focusChange = " + focusChange); if (focusChange == AUDIOMANAGER_AUDIOFOCUS_LOSS) { Log.i(this, "AUDIOMANAGER_AUDIOFOCUS_LOSS"); Message msg = mHandler.obtainMessage(ControllerHandler.SET_ON_PAUSE); mHandler.sendMessage(msg); } else if (focusChange == AUDIOMANAGER_AUDIOFOCUS_GAIN) { Log.i(this, "AUDIOMANAGER_AUDIOFOCUS_GAIN"); // no action is taken } } // implements the method invoke from the InvocationHandler interface // it intercepts the calls to the listener methods // in this case it redirects the onAudioFocusChange listener method to the OnAudioFocusChange proxy method public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { if (args != null) { if (method.getName().equals("onAudioFocusChange") && args[0] instanceof Integer) { onAudioFocusChange((Integer) args[0]); } } } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); } return result; } } 

La reflexión de IMHO hará sus clases menos legibles. También la reflexión es un poco más lento que el acceso normal de campo o clase.

Como alternativa, vea el enfoque de la clase wrapper descrito aquí: http://android-developers.blogspot.com/2009/04/backward-compatibility-for-android.html

Crear interfaz y dos implementaciones de la misma, una para API 8+ y la otra para las versiones anteriores. En su clase API8 puede utilizar clases API 8 incluyendo OnAudioFocusChangeListener . A continuación, instanciar la versión basada en la versión del sistema operativo, que puede comprobar a través de Build.VERSION.SDK_INT .

  • Crear una vista compuesta en Android
  • Reemplazar el nuevo método dexlib2 fallando
  • Configuración de JAVA_HOME en SDK de Android
  • ¿Es posible usar la API de Java 8 Stream en la API de Android <24?
  • Android: ¿abro un recurso de archivo cada vez que quiero iniciar sesión
  • La clase debe ser declarada abstracta o implementar un error de método abstracto
  • Android - ¿Está bien poner valores @IntDef dentro de @interface?
  • Cómo puedo saber cuándo / dónde invocar el método anulado de la superclase
  • Impedir el clic de Android ImageVIew?
  • Libgdx dibujar caracteres chinos
  • ¿Cómo enviar notificaciones a la aplicación de Android desde el servidor de Java mediante GCM?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.