android中反射技术使用实例

在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。反射 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。

1.通过反射技术可以访问到其他包名下数据方法等,这些为一些APK换皮肤提供了方便

首先初始化skinContext


?
1
2
3
4
5
6
7
8
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
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
      * 取得对应包的所有资源的ID
      * 存在MAP中
      * @param packageName
      * @return
      */ 
     private Map<string,map<string, object= "" >> getSkinResourcesId(String packageName) 
    
         Map<string, object= "" > temp =  null
         Map<string,map<string, object= "" >> resMap = new HashMap<string,map<string,object>>(); 
         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<resclass.length;i++) {= "" classname= "resClass[i].getName();" 取得该类的资源= "" field= "" field[]= "resClass[i].getFields();" for ( int = "" j= "0;j" <= "" field.length;= "" j++)= "" resourcename= "field[j].getName();" try = "" resourceid= "field[j].getInt(resourceName);" }= "" catch = "" (illegalargumentexception= "" e)= "" todo= "" auto-generated= "" block= "" e.printstacktrace();= "" (illegalaccessexception= "" if (resourcename!= "null" &&= "" !resourcename.equals( "" ))= "" temp= "new" hashmap<string,= "" object= "" >(); 
                             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; 
         } </resclass.length;i++)></string,map<string,object></string,map<string,></string,></string,map<string,>

最后通过资源ID和skinContext可以访问到指定包下的所有资源,例如要访问layout
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
      * 获取皮肤包中的layout
      * 并转化为VIEW
      * @param layoutName
      * @return
      */ 
     private View getLayoutFromSkin(String layoutName) 
    
         View view; 
         if (resMap == null
             return null
         Map<string, object= "" > 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; 
     }  </string,>

注:换皮肤思路详见:http://blog.csdn.net/tangnengwu/article/details/22801107


2. 访问android 隐藏的API

Toast信息框的关闭是由系统管理的,因为hide方法是隐藏的开发者没有办法直接调用,这种情况下可以用发射机制获取这个方法,创建一个显示和隐藏都由开发者控制的Toast信息框。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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:
?
1
2
MyToast toast = new MyToast( this , "反射机制!" );
toast.show();
隐藏toast:

toast.hide();

注意在4.0以上的版本中,还需要对Toast 中的View进行处理,如代码中所示


3. 修改某些“不可改” 的系统资源

ListView组件没有提供修改快速滑块图像的API,因此不能直接修改,但可通过反射实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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();
         }
     }
 
}
?
1
Field  field = AbsListView. class .getDeclaredField( "mFastScroller" );
FastScroller.mThunbDrawable变量保存了快速滑块图像,但首先要获取AbsListView.mFastScroller变量


?
1
2
<com.example.reflection.mlistview android:id= "@+id/listView1" android:layout_width= "match_parent" android:layout_height= "wrap_content" android:fastscrollenabled= "true" android:scrollbars= "none" >
     </com.example.reflection.mlistview>


?
1
android:fastScrollEnabled= "true"
使用快速滑块

效果图如下:

\

往sim卡里面复制短信

访问API隐藏的方法:往sim卡里面复制短信的时候,需要用到方法copyMessageToIcc,但是在apk中是hide的,那么我们就需要用反射的方法来获取出这个方法了:// smsManager.copyMessageToIcc(null, pdu, 1);

public void insert() {
     SmsManager smsManager = SmsManager.getDefault();
 
    byte[] smsc = new byte[2];
    smsc[0] = 0x1;
    smsc[1] = 0x2;
    String clxs = "123";
    byte[] pdu = hexStringToBytes("200d91683119603514f90000313021023025230331d90c");

    Class<?> c;
    try {
        c = Class.forName("android.telephony.SmsManager");
        Method[] ms = c.getMethods();
        for (Method m : ms) {
            System.out.println(m.getName());
            Class<?>[] cx = m.getParameterTypes();
            for (Class<?> cx1 : cx)
                System.out.println(cx1.getName());
            System.out.println(m.getReturnType());
        }

        Method m = c.getMethod("copyMessageToIcc", new Class[] {
                byte[].class, byte[].class, int.class });
        Object s = m.invoke(SmsManager.getDefault(), null, pdu, 1);
    } catch (Exception e) {
        e.printStackTrace();
    }

    // smsManager.copyMessageToIcc(null, pdu, 1);
}


总结:

Java中的反射机制,被称为Reflection,它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 construct等

反射中一些参数函数的理解

MainActivity如下:

  1. package cn.testreflect;

  2.   import java.lang.reflect.Constructor;
  3.   import java.lang.reflect.Field;
  4.   import java.lang.reflect.Method;
  5.   import android.os.Bundle;
  6.   import android.app.Activity;
  7.   /**
  8.   * Demo描述:
  9.   * Android中Java反射技术的使用示例
  10.   * 在Java中描述字节码文件(xxx.class)的类叫Class
  11.   * 反射的过程可视为剖析Class的过程
  12.   */
  13.   public class MainActivity extends Activity {
  14.   @Override
  15.   protected void onCreate(Bundle savedInstanceState) {
  16.   super.onCreate(savedInstanceState);
  17.   setContentView(R.layout.main);
  18.   init();
  19.   }
  20.   private void init(){
  21.   try {
  22.   /**
  23.   * 1 反射出无参的构造方法并得到对象
  24.   * 注意:
  25.   * 1 在Class.forName()中应该传入含有包名的类全名
  26.   * 2 newInstance()方法的本质是调用类的无参Public构造方法
  27.   */
  28.   String className1="cn.testreflect.Worker";
  29.   Class clazz1=Class.forName(className1);
  30.   Object object1=clazz1.newInstance();
  31.   System.out.println("object1.toString()="+object1.toString());
  32.   /**
  33.   * 2 反射出带参数的构造方法并得到对象
  34.   */
  35.   String className2="cn.testreflect.Worker";
  36.   Class clazz2=Class.forName(className2);
  37.   Constructor constructor1=clazz2.getConstructor(int.class,String.class);
  38.   Object object2=constructor1.newInstance(18,"小明");
  39.   System.out.println("object2.toString()="+object2.toString());
  40.   /**
  41.   * 3 获取类的私有字段
  42.   * 注意:
  43.   * 获取共有字段应调用clazz3.getField(name)方法
  44.   */
  45.   String className3="cn.testreflect.Worker";
  46.   Class clazz3=Class.forName(className3);
  47.   Field ageField1=clazz3.getDeclaredField("age");
  48.   System.out.println("ageField1="+ageField1);
  49.   /**
  50.   * 4 获取和更改某个对象的私有字段
  51.   * 即模拟get()和set()方法
  52.   */
  53.   String className4="cn.testreflect.Worker";
  54.   Class clazz4=Class.forName(className4);
  55.   Field ageField2=clazz4.getDeclaredField("age");
  56.   Object object4=constructor1.newInstance(18,"小明");
  57.   //取消访问私有字段的合法性检查
  58.   ageField2.setAccessible(true);
  59.   //获取对象的私有字段
  60.   Object ageObject4=ageField2.get(object4);
  61.   System.out.println("ageObject4="+ageObject4);
  62.   //再更改对象的私有字段的值
  63.   ageField2.set(object4, 9527);
  64.   //重新获得
  65.   Object ageObject5=ageField2.get(object4);
  66.   System.out.println("ageObject5="+ageObject5);
  67.   /**
  68.   * 5 调用对象的带参数的方法
  69.   */
  70.   String className5="cn.testreflect.Worker";
  71.   Class clazz5=Class.forName(className5);
  72.   Method method=clazz5.getMethod("printMessage",
  73. String.class,int.class,int.class);
  74.   Object object5=clazz5.newInstance();
  75.   method.invoke(object5, "周星星",50,9527);
  76.   } catch (Exception e) {
  77.   System.out.println(e.toString());
  78.   }
  79.   }
  80.   }
复制代码
  Worker如下:
  1. package cn.testreflect;

  2.   public class Worker {
  3.   private int age;
  4.   private String name;
  5.   public Worker() {
  6.   super();
  7.   System.out.println("---> public Worker(){ }");
  8.   }
  9.   public Worker(int age, String name) {
  10.   super();
  11.   this.age = age;
  12.   this.name = name;
  13.   System.out.println("---> public Worker(int age, String name){ }");
  14.   }
  15.   public int getAge() {
  16.   return age;
  17.   }
  18.   public void setAge(int age) {
  19.   this.age = age;
  20.   }
  21.   public String getName() {
  22.   return name;
  23.   }
  24.   public void setName(String name) {
  25.   this.name = name;
  26.   }
  27.   @Override
  28.   public String toString() {
  29.   return "Worker [age=" + age + ", name=" + name + "]";
  30.   }
  31.   public void printMessage(String name,int age,int salary){
  32.   System.out.println("name="+name+",age="+age+",salary="+salary);
  33.   }
  34.   }
复制代码
  main.xml如下:
  1.   xmlns:tools="http://schemas.android.com/tools"
  2.   android:layout_width="match_parent"
  3.   android:layout_height="match_parent"
  4.   >  android:layout_width="wrap_content"
  5.   android:layout_height="wrap_content"
  6.   android:text="Android中Java反射技术的使用"
  7.   android:layout_centerInParent="true"/>
MainActivity如下:
java代码
  1. package cn.testreflect;

  2.   import java.lang.reflect.Constructor;
  3.   import java.lang.reflect.Field;
  4.   import java.lang.reflect.Method;
  5.   import android.os.Bundle;
  6.   import android.app.Activity;
  7.   /**
  8.   * Demo描述:
  9.   * Android中Java反射技术的使用示例
  10.   * 在Java中描述字节码文件(xxx.class)的类叫Class
  11.   * 反射的过程可视为剖析Class的过程
  12.   */
  13.   public class MainActivity extends Activity {
  14.   @Override
  15.   protected void onCreate(Bundle savedInstanceState) {
  16.   super.onCreate(savedInstanceState);
  17.   setContentView(R.layout.main);
  18.   init();
  19.   }
  20.   private void init(){
  21.   try {
  22.   /**
  23.   * 1 反射出无参的构造方法并得到对象
  24.   * 注意:
  25.   * 1 在Class.forName()中应该传入含有包名的类全名
  26.   * 2 newInstance()方法的本质是调用类的无参Public构造方法
  27.   */
  28.   String className1="cn.testreflect.Worker";
  29.   Class clazz1=Class.forName(className1);
  30.   Object object1=clazz1.newInstance();
  31.   System.out.println("object1.toString()="+object1.toString());
  32.   /**
  33.   * 2 反射出带参数的构造方法并得到对象
  34.   */
  35.   String className2="cn.testreflect.Worker";
  36.   Class clazz2=Class.forName(className2);
  37.   Constructor constructor1=clazz2.getConstructor(int.class,String.class);
  38.   Object object2=constructor1.newInstance(18,"小明");
  39.   System.out.println("object2.toString()="+object2.toString());
  40.   /**
  41.   * 3 获取类的私有字段
  42.   * 注意:
  43.   * 获取共有字段应调用clazz3.getField(name)方法
  44.   */
  45.   String className3="cn.testreflect.Worker";
  46.   Class clazz3=Class.forName(className3);
  47.   Field ageField1=clazz3.getDeclaredField("age");
  48.   System.out.println("ageField1="+ageField1);
  49.   /**
  50.   * 4 获取和更改某个对象的私有字段
  51.   * 即模拟get()和set()方法
  52.   */
  53.   String className4="cn.testreflect.Worker";
  54.   Class clazz4=Class.forName(className4);
  55.   Field ageField2=clazz4.getDeclaredField("age");
  56.   Object object4=constructor1.newInstance(18,"小明");
  57.   //取消访问私有字段的合法性检查
  58.   ageField2.setAccessible(true);
  59.   //获取对象的私有字段
  60.   Object ageObject4=ageField2.get(object4);
  61.   System.out.println("ageObject4="+ageObject4);
  62.   //再更改对象的私有字段的值
  63.   ageField2.set(object4, 9527);
  64.   //重新获得
  65.   Object ageObject5=ageField2.get(object4);
  66.   System.out.println("ageObject5="+ageObject5);
  67.   /**
  68.   * 5 调用对象的带参数的方法
  69.   */
  70.   String className5="cn.testreflect.Worker";
  71.   Class clazz5=Class.forName(className5);
  72.   Method method=clazz5.getMethod("printMessage",
  73. String.class,int.class,int.class);
  74.   Object object5=clazz5.newInstance();
  75.   method.invoke(object5, "周星星",50,9527);
  76.   } catch (Exception e) {
  77.   System.out.println(e.toString());
  78.   }
  79.   }
  80.   }
复制代码
  Worker如下:
  1. package cn.testreflect;

  2.   public class Worker {
  3.   private int age;
  4.   private String name;
  5.   public Worker() {
  6.   super();
  7.   System.out.println("---> public Worker(){ }");
  8.   }
  9.   public Worker(int age, String name) {
  10.   super();
  11.   this.age = age;
  12.   this.name = name;
  13.   System.out.println("---> public Worker(int age, String name){ }");
  14.   }
  15.   public int getAge() {
  16.   return age;
  17.   }
  18.   public void setAge(int age) {
  19.   this.age = age;
  20.   }
  21.   public String getName() {
  22.   return name;
  23.   }
  24.   public void setName(String name) {
  25.   this.name = name;
  26.   }
  27.   @Override
  28.   public String toString() {
  29.   return "Worker [age=" + age + ", name=" + name + "]";
  30.   }
  31.   public void printMessage(String name,int age,int salary){
  32.   System.out.println("name="+name+",age="+age+",salary="+salary);
  33.   }
  34.   }
复制代码
  main.xml如下:
  1.   xmlns:tools="http://schemas.android.com/tools"
  2.   android:layout_width="match_parent"
  3.   android:layout_height="match_parent"
  4.   >  android:layout_width="wrap_content"
  5.   android:layout_height="wrap_content"
  6.   android:text="Android中Java反射技术的使用"
  7.   android:layout_centerInParent="true"/>
复制代码

原文链接:http://www.eyeandroid.com/thread-17067-1-1.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值