zoukankan      html  css  js  c++  java
  • DexClassLoader使用-(1)

    可以先参考java的java类加载器

    一、DexClassLoader

      一般情况下,我们使用import就可以了,为什么还要使用类装载器呢?

    import中所引用的类文件有两个特点:

    1.一定在存在于本地,当程序运行时需要这个类时,内部类装载器就会自动装载,程序员感知不到这个过程。

    2.编译时一定要在现场,否则会因找不到引用文件而不能正常编译。

      但是在有的情况下,要用的类不一定满足这些条件,如从运程下载一个类并在本地运行,例子如applet执行的java,另一种是要引用的class文件不方便在编译时直接参与 ,而只能在运行时动态调用。如在android中修改FrameWork中已经有的类,为了保持与原生的FrameWork最小化的修改,可以使用类装载器动态装载自己定义 的jar包。

    二、DexClassLoader的使用方法

      有两个apk。

    • 插件部分

    定义了类PluginClass。如下

    public class PluginClass {
        public PluginClass(){
            Log.d("PluginCLass", "PluginClass initiazed");
        }
    
        public int function1(int a,int b){
            return a +b;
        }
    }
    

    还定义了

    一个空的Activity,这个作用只是为了让宿主apk中可以找到package而已,所以只要有就可以了。

    <activity
                android:name=".BlankActivity"
                android:label="@string/title_activity_blank" >
                <intent-filter>
                    <action android:name="com.example.lsj.testapp.plugin.client"/>
                </intent-filter>
            </activity>
    

    我们将可以通过intent-filter得到相关的信息。

    • 宿主部分

    通过下面的ClassLoader可以装载插件中的类,再构造出Method对象 ,并构造出Method对象所使用的参数对象 ,然后才能调用 。

    ublic void useDexClassLoader(){
            Intent intent = new Intent("com.example.lsj.testapp.plugin.client", null);
            PackageManager pm = getPackageManager();
            final List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);
            ResolveInfo rinfo = plugins.get(0);
            ActivityInfo ainfo = rinfo.activityInfo;
    
            String div = System.getProperty("path.separator");
            String packageName = ainfo.packageName;
            String dexPath = ainfo.applicationInfo.sourceDir;
            String dexOutputDir = getApplicationInfo().dataDir;
            String libPath = ainfo.applicationInfo.nativeLibraryDir;
    
            DexClassLoader dexClassLoader = new DexClassLoader(dexPath,
                    dexOutputDir,libPath,this.getClass().getClassLoader());
            try{
                Class <?> clazz = dexClassLoader.loadClass(packageName+".PluginClass");
                Object obj = clazz.newInstance() ;
                Class [] params = new Class[2];
                params[0]= Integer.TYPE;
                params[1] = Integer.TYPE ;
                Method action = clazz.getMethod("function1", params) ;
                Integer ret = (Integer)action.invoke(obj, 1,2);
                Log.e(TAG, "return value is :"+ ret);
                
            }catch ( ClassNotFoundException e){
    
            }catch (InstantiationException e2 ){
    
            }catch (IllegalAccessException e3){
    
            }catch (NoSuchMethodException e4){
    
            }catch (InvocationTargetException e5){
    
            }
        }
    

    DexClassLoader方法参数:

    dexPath:目标所在的apk或者jar文件的路径,装载器将从路径中寻找指定的目标类。

    dexOutputDir:由于dex 文件在APK或者 jar文件中,所以在装载前面前先要从里面解压出dex文件,这个路径就是dex文件存放的路径,在 android系统中,一个应用程序对应一个linux用户id ,应用程序只对自己的数据目录有写的权限,所以我们存放在这个路径中。

    libPath :目标类中使用的C/C++库。

    最后一个参数是该装载器的父装载器,一般为当前执行类的装载器。

     这里我们得到的Class对象是CLassLoader可以识别的类,而PluginClass是程序执行后可以识别的类,此时仅仅装载了PluginClass的程序代码,还没有创建出其对象 ,接下来可以使用Class.newInsance()方法来调用PluginClass类的构造方法,并返回一个真正的PluginClass对象。

      但是我们不能直接去调用 PluginClass的任何方法,只能通过反射去调用其方法。

      反射机制时主要使用了Method类,Class对象的getMethod()方法可以返回这个类中任何方法,getMethod()有两个参数 ,一个是要访问的函数名,另一个是函数的参数类型。

      得到目标类的Method对象后,就可以调用Method对象的invoke方法,这个方法的第一个参数是执行目标函数的对象。

     

  • 相关阅读:
    问题 A: 【递归入门】全排列
    第一个struct2程序(2)
    第一个struct2程序
    Java学习 第二节
    重学Java
    Servlet过滤器
    struct2
    Java web struct入门基础知识
    one by one 项目 part 6
    软件工程导论 桩模块和驱动模块
  • 原文地址:https://www.cnblogs.com/chuiyuan/p/4781955.html
Copyright © 2011-2022 走看看