android中反射技术使用实例

最后更新于:2022-04-01 20:09:20

在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.反射 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。 **1.通过反射技术可以访问到其他包名下数据方法等,这些为一些APK换皮肤提供了方便** 首先初始化skinContext ~~~ try { skinContext = this.createPackageContext("com.skin", CONTEXT_IGNORE_SECURITY|CONTEXT_INCLUDE_CODE); } catch (NameNotFoundException e) { // TODO Auto-generated catch block skinContext=null; e.printStackTrace(); } ~~~ 可以通过下面的方法访问到指定包名下的资源ID ~~~ /** * 取得对应包的所有资源的ID * 存在MAP中 * @param packageName * @return */ private Map> getSkinResourcesId(String packageName) { Map temp = null; Map> resMap =new HashMap>(); try { //取得皮肤包中的R文件 Class rClass = skinContext.getClassLoader().loadClass(packageName+".R"); //取得记录各种资源的ID的类 Class[] resClass =rClass.getClasses(); String className,resourceName; int resourceId=0; for(int i=0;i(); temp.put(resourceName, resourceId); Log.i("DDDDD", "className:"+className+" resourceName:"+resourceName+" " + "resourceId:"+Integer.toHexString(resourceId)); } } //由于内部类的关系className应该是com.skin.R$layout的形式 //截掉前面的包名和.R$以方便使用 className = className.substring(packageName.length()+3); resMap.put(className, temp); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return resMap; } ~~~ 最后通过资源ID和skinContext可以访问到指定包下的所有资源,例如要访问layout ~~~ /** * 获取皮肤包中的layout * 并转化为VIEW * @param layoutName * @return */ private View getLayoutFromSkin(String layoutName) { View view; if(resMap == null) return null; Map temp = resMap.get("layout"); int viewId = (Integer) temp.get(layoutName); if(viewId != 0) { //引用皮肤包资源转化View LayoutInflater inflater =LayoutInflater.from(skinContext); view = inflater.inflate(skinContext.getResources().getLayout(viewId), null); } else { view = null; } return view; } ~~~ 注:换皮肤思路详见:[http://blog.csdn.net/tangnengwu/article/details/22801107](http://blog.csdn.net/tangnengwu/article/details/22801107) **2. 访问android 隐藏的API** Toast信息框的关闭是由系统管理的,因为hide方法是隐藏的开发者没有办法直接调用,这种情况下可以用发射机制获取这个方法,创建一个显示和隐藏都由开发者控制的Toast信息框。 ~~~ package com.example.reflection; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import android.widget.Toast; public class MyToast { Context context=null; Object obj =null; public MyToast(Context context,String text) { this.context =context; Toast toast =Toast.makeText(context, text, 1); try { Field field = toast.getClass().getDeclaredField("mTN"); field.setAccessible(true); obj =field.get(toast); } catch (Exception e) { // TODO: handle exception Log.d("AAA", "MyToast Exception--->"+e.toString()); } } public void show() { try { //android4.0以上就要以下处理 // Field mNextViewField = obj.getClass().getDeclaredField("mNextView"); // mNextViewField.setAccessible(true); // LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // View v = inflate.inflate(R.layout.ui_toast, null); // mNextViewField.set(obj, v); Method method =obj.getClass().getDeclaredMethod("show", null); method.invoke(obj, null); } catch (Exception e) { // TODO Auto-generated catch block Log.d("AAA", "show Exception--->"+e.toString()); e.printStackTrace(); } } public void hide() { try { Method method =obj.getClass().getDeclaredMethod("hide", null); method.invoke(obj, null); } catch (Exception e) { // TODO Auto-generated catch block Log.d("AAA", "hide Exception--->"+e.toString()); e.printStackTrace(); } } } ~~~ 显示toast: ~~~ MyToast toast = new MyToast(this, "反射机制!"); toast.show(); ~~~ 隐藏toast: toast.hide(); **注意在4.0以上的版本中,还需要对Toast 中的View进行处理,如代码中所示** **3. 修改某些“不可改” 的系统资源** ListView组件没有提供修改快速滑块图像的API,因此不能直接修改,但可通过反射实现 ~~~ package com.example.reflection; import java.lang.reflect.Field; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.AbsListView; import android.widget.ListView; public class MListView extends ListView { public MListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub setNewDrawable(context); } private void setNewDrawable(Context context) { try { Field field = AbsListView.class.getDeclaredField("mFastScroller"); field.setAccessible(true); Object obj = field.get(this); field =field.getType().getDeclaredField("mThumbDrawable"); field.setAccessible(true); Drawable drawable = (Drawable)field.get(obj); drawable = context.getResources().getDrawable(R.drawable.ic_launcher); field.set(obj, drawable); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } ~~~ ~~~ Field field = AbsListView.class.getDeclaredField("mFastScroller"); ~~~ FastScroller.mThunbDrawable变量保存了快速滑块图像,但首先要获取AbsListView.mFastScroller变量 ~~~ ~~~ ~~~ android:fastScrollEnabled="true" ~~~ 使用快速滑块 效果图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-18_57b550bbdd97e.jpg) 总结:      Java中的反射机制,被称为Reflection,它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods。再次基础上我们可以利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。 有关反射技术的API: Class类: Class类代表着某个类的字节码,要使用反射,就需要取得对应的Class对象,然后就通过这个对象,就可解剖出类的成员变量,成员方法等等。 获取Class类对象 //通过Class的forName()方法,此方法最为常用   Class class1 = Class.forName(className);   //通过 .class   Class class2 = XXX.class;   //通过对象获得   Class class3 = new XXX().getClass();  Class类的常用方法: getConstructor() 获取构造函数 getMethod()  获取成员方法 getField() 获取成员变量 getDeclaredConstructor() 获取私有的构造函数 getDeclaredMethod()  获取私有的成员方法 getDeclaredField() 获取私有的成员变量 取得method对象之后 调用 ~~~ method.invoke(obj, null) ~~~ 使用该方法
';