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);
    //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="" 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

/** 
     * 获取皮肤包中的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信息框。

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

<pre name="code" class="html"><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、 construct使用该方法




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值