最近做的项目里需要使用反射来获internal class里的方法和成员变量并进行一些操作。
Kotlin中不常使用反射,但是有场景确实需要用到,这里没有使用kotlin特有的反射API,使用的还是java里的反射API,经测试也可以正常使用。
场景一 获取internal activity class并跳转到该activity
val activity = classLoader.loadClass("xxx.xxx.activity")
val intent = Intent(this, activity)
startActivity(intent)
注意loadClass方法里的参数是指定Activity的全路径包名与类名。
场景二 调用类的带参数方法
val clazz = Class.forName("xxx.xxx.YourClass")
val method = clazz.getDeclaredMethod("yourMethod",String::class.java)
val obj = clazz.newInstance()
method.isAccessible = true
method.invoke(obj,"YourStringParameter")
这个场景复杂一点,首先通过Class.forName方法获取指定类class。
接着通过getDeclaredMethod(方法名,参数类型)获取到方法。
通过Class.newInstance()方法获取一个类的实例。(若类的构造方法需要传参数,则使用下一个场景讲的带参数的构造方法如何使用)
然后设置这个方法的访问权限为true,最后通过invoke(类的实例,需要传的参数)
注意,例子中所用的是一个方法名为yourMethod的方法,该方法需要传一个String类型的参数。
若方法传参不同则需要自行替换。
场景三 调用带参数的构造方法
val clazz = Class.forName("xxx.xxx.yourclass")
val construc = clazz.getDeclaredConstructor(ParameterClass::class.java)
val obj = construc.newInstance(ParameterClass)
这个场景还是使用Class.forName来获取指定的类。
之后通过getDeclaredConstructor(参数类型) 来获取带参数的构造方法。
注意,这里的参数可以String这样的基础类型,也可以是自定义的类型。
最后通过获取的构造方法的变量的newInstance(参数实例)方法来获取类的实例。
场景四 获取internal 类的LiveData类型的成员变量并执行observe操作
val clazz = Class.forName("xxx.xxx.yourclass")
val construc = clazz.getDeclaredConstructor(ParameterClass::class.java)
val obj = construc.newInstance(parameter)
val field = clazz.getDeclaredField("yourField")
field.isAccessible = true
val member = field.get(obj)
(member as LiveData<String>).observe(this) { stringData ->
// do you handling
}
这个场景首先还是获取到指定的类,之后通过该类的构造方法获取一个该类的实例obj。
之后通过Class的getDeclaredField(成员变量名称)方法来获取成员变量的field。
接着设置field的访问权限为true。
然后通过field.get(类实例)方法获取这个类实例里的成员变量member。
这个member是真正从类实例里获取到的成员变量,对它可以进行相关操作了。
这个场景里,member是一个String数据类型的LiveData,通过as关键字将member转化为LiveData,并调用observe方法。
补充
有时候会在反射时遇到No Such Method或者No Such Field的崩溃,这个时候需要检查自己获取时是否有方法调用错误或者参数传错等问题。
以下两个方法可以获取到类的所有声明方法以及声明成员变量,可以将这内容打印出来用于确认自己获取方法名字和成员变量名字是否正确。
clazz.declaredMethods
clazz.declaredFields