前言
项目中有许多以前调用的API,Android studio提示已经过时,所以打算把过时的API替换掉,但是新的API是@hide的,需要反射来调用,于是便重温了一下反射机制。先上例子:wifi遗忘功能以前的实现方式是:
mWifiManager.removeNetwork(config.get(i).networkId);
mWifiManager.saveConfiguration();
但是新的实现方法是forget方法,由于forget方法是隐藏方法,所以利用反射机制调用:
public static void forgetNetwork(WifiManager manager, int networkId) {
if (manager == null) {
return;
}
try {
//如果不传入WiFimanager,我们可以利用Class类来获取
// Class wifiManagerClass = WifiManager.class;
//Method forget = wifiManagerClass.getDeclaredMethod("forget", int.class, Class.forName("android.net.wifi.WifiManager$ActionListener"));
Method forget = manager.getClass().getDeclaredMethod("forget", int.class, Class.forName("android.net.wifi.WifiManager$ActionListener"));
if (forget != null) {
forget.setAccessible(true);
forget.invoke(manager, networkId, null);
//forget.invoke(wifiManagerClass.newInstance(), networkId, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Android反射机制调用API步骤
Android反射机制调用API有三个步骤:
1.获取Class对象
lass wifiManagerClass = WifiManager.class;
2.获取方法
Method forget = wifiManagerClass.getDeclaredMethod("forget", int.class, Class.forName("android.net.wifi.WifiManager$ActionListener"));
3.方法调用
forget.invoke(manager, networkId, null);
获取方法有getMethod(String name, Class>[] parameterTypes, boolean recursivePublicMethods)和getDeclaredMethod(String name, Class>... parameterTypes).其中getMethod获取public方法,getDeclaredMethod方法获取private方法。
获取方法和方法调用源码注释
getDeclaredMethod源码注释如下:
/**
* Returns a {@code Method} object that reflects the specified
* declared method of the class or interface represented by this
* {@code Class} object. The {@code name} parameter is a
* {@code String} that specifies the simple name of the desired
* method, and the {@code parameterTypes} parameter is an array of
* {@code Class} objects that identify the method's formal parameter
* types, in declared order. If more than one method with the same
* parameter types is declared in a class, and one of these methods has a
* return type that is more specific than any of the others, that method is
* returned; otherwise one of the methods is chosen arbitrarily. If the
* name is "<init>"or "<clinit>" a {@code NoSuchMethodException}
* is raised.
*
* If this {@code Class} object represents an array type, then this
* method does not find the {@code clone()} method.
*
由源码注释可知,第一个参数为方法名,后面的都是方法的参数,如果一个方法重载了多次,则根据参数匹配度来判断是使用哪一个方法。
* @param name the name of the method
* @param parameterTypes the parameter array
* @return the {@code Method} object for the method of this class
* matching the specified name and parameters
* @throws NoSuchMethodException if a matching method is not found.
* @throws NullPointerException if {@code name} is {@code null}
* @throws SecurityException
* If a security manager, s, is present and any of the
* following conditions is met:
*
*
*
* - the caller's class loader is not the same as the
* class loader of this class and invocation of
* {@link SecurityManager#checkPermission
* s.checkPermission} method with
* {@code RuntimePermission("accessDeclaredMembers")}
* denies access to the declared method
*
*
- the caller's class loader is not the same as or an
* ancestor of the class loader for the current class and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to the package
* of this class
*
*
*
* @jls 8.2 Class Members
* @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
public Method getDeclaredMethod(String name, Class>... parameterTypes)
throws NoSuchMethodException, SecurityException {
return getMethod(name, parameterTypes, false);
}
方法的调用invoke源码注释如下:
/**
* Invokes the underlying method represented by this {@code Method}
* object, on the specified object with the specified parameters.
* Individual parameters are automatically unwrapped to match
* primitive formal parameters, and both primitive and reference
* parameters are subject to method invocation conversions as
* necessary.
*
* If the underlying method is static, then the specified {@code obj}
* argument is ignored. It may be null.
*
*
If the number of formal parameters required by the underlying method is
* 0, the supplied {@code args} array may be of length 0 or null.
*
*
If the underlying method is an instance method, it is invoked
* using dynamic method lookup as documented in The Java Language
* Specification, Second Edition, section 15.12.4.4; in particular,
* overriding based on the runtime type of the target object will occur.
*
*
If the underlying method is static, the class that declared
* the method is initialized if it has not already been initialized.
*
*
If the method completes normally, the value it returns is
* returned to the caller of invoke; if the value has a primitive
* type, it is first appropriately wrapped in an object. However,
* if the value has the type of an array of a primitive type, the
* elements of the array are not wrapped in objects; in
* other words, an array of primitive type is returned. If the
* underlying method return type is void, the invocation returns
* null.
*
由注释可知第一个参数为调用该方法的实例对象,其他参数为该方法的参数
* @param obj the object the underlying method is invoked from
* @param args the arguments used for the method call
* @return the result of dispatching the method represented by
* this object on {@code obj} with parameters
* {@code args}
*
* @exception IllegalAccessException if this {@code Method} object
* is enforcing Java language access control and the underlying
* method is inaccessible.
* @exception IllegalArgumentException if the method is an
* instance method and the specified object argument
* is not an instance of the class or interface
* declaring the underlying method (or of a subclass
* or implementor thereof); if the number of actual
* and formal parameters differ; if an unwrapping
* conversion for primitive arguments fails; or if,
* after possible unwrapping, a parameter value
* cannot be converted to the corresponding formal
* parameter type by a method invocation conversion.
* @exception InvocationTargetException if the underlying method
* throws an exception.
* @exception NullPointerException if the specified object is null
* and the method is an instance method.
* @exception ExceptionInInitializerError if the initialization
* provoked by this method fails.
*/
@FastNative
public native Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;