• android中反射技术使用实例


    在计算机科学领域。反射是指一类应用,它们能够自描写叙述和自控制。也就是说,这类应用通过採用某种机制来实现对自己行为的描写叙述(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<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 catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } 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; }


    最后通过资源ID和skinContext能够訪问到指定包下的全部资源,比如要訪问layout
    /** 
         * 获取皮肤包中的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;  
        }  

    注:换皮肤思路详见: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变量


    <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>


    android:fastScrollEnabled="true"
    使用高速滑块

    效果图例如以下:



    总结:

          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)
    使用该方法
  • 相关阅读:
    抖音服务器带宽有多大,才能供上亿人同时刷?今天长见识了。。
    用了很多年的 CMS 垃圾收集器,终于换成了 G1,真香!!
    Spring Boot 项目脚本(启动、停止、重启、状态)
    正排倒排,并不是 MySQL 的排序的全部!
    自从在 IDEA 中用了热部署神器 JRebel 之后,开发效率提升了 10 倍!
    beego实现多端口监听
    区块链分类
    Hyperledger/Fabric
    register db `default`, default addr for network 'localhost:3306' unknown must have one register DataBase alias named `default`
    go vendor的正确打开方式
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10691916.html
Copyright © 2020-2023  润新知