Java 如何在Android中通过反射实例化侦听器
我必须为安卓1.6(API 4)开发一个应用程序,它应该能够在安卓2.2或更高版本的手机上使用OnAudioFocusChangeListener(自安卓2.2-API 8开始提供) 谁能告诉我如何通过反射实例化侦听器? 我已经通过反射运行了静态和非静态方法,但我不知道如何处理侦听器 这是要反映的侦听器:Java 如何在Android中通过反射实例化侦听器,java,android,Java,Android,我必须为安卓1.6(API 4)开发一个应用程序,它应该能够在安卓2.2或更高版本的手机上使用OnAudioFocusChangeListener(自安卓2.2-API 8开始提供) 谁能告诉我如何通过反射实例化侦听器? 我已经通过反射运行了静态和非静态方法,但我不知道如何处理侦听器 这是要反映的侦听器: AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); On
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);
}
这是一个代码示例,其中包含我通过反射运行的方法:
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);
IMHO反射会降低类的可读性。此外,反射比正常的字段或类访问要慢一些 作为替代方案,请参见此处描述的包装类方法:
创建接口及其两个实现,一个用于API 8+,另一个用于早期版本。在API8类中,您可以使用API8类,包括
OnAudioFocusChangeListener
。然后根据操作系统的版本实例化版本,您可以通过查看。最后,我使用代理类解决了这个问题。这是密码
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());
}
}
}
这是一个很好的例子,我不完全确定是否可以使用包装器,因为我需要将
OnAudioFocusChangeListener
对象作为参数传递给请求AudioFocus
和放弃AudioFocus
对象的方法。我想,如果传递一个AudioFocusChangeListener包装,它就不起作用了。您可以将它作为包装类中的一个内部类。这会有用的。我也会忽略反射——这是代码的味道——特别是当有更好的方法解决它的时候。使用wrapper方法更好。wrapper方法的缺点是需要将目标sdk版本设置为更高的版本。这意味着您需要小心,高级API中可用的所有类都不会被具有较低API的设备执行。由于eclipse(据我所知)无法突出显示哪些代码仅在较高的API上可用,并且需要“阻止”到较低的API,因此很容易忘记为较低的API重新编码。因此,我的建议是使用反射,以防在更高的API中只需要使用一个或两个可用的类。但您仍然可以制作包含所有版本相关代码的包装器,每个版本(或一组版本)一个包装器,然后在Eclipse中简单地切换目标版本,就可以在一个地方看到错误。这将使捕获与版本相关的错误变得更容易。
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;
}
}