• ClassLoader使用经验(一)


      在Android开发中,有时,会需要在应用中额外下载一些其他的插件,进行额外的功能。比如QQ的皮肤,掌阅的语音包,需要在使用过程中下载额外的apk,但是额外的apk无需安装我们即可使用里面的资源和方法。这样的功能就是用ClassLoader实现的。在此记录一些ClassLoader的使用方法与经验用以备忘。

      这里要实现的例子很简单。我在一个额外的工程B中实现一个Toast的方法,然后用工程A中的类去调用这个方法。

      首先来看看工程B:

      工程B中我先实现了一个简单的类

    public class ToastClass {
    
        public void alertMessage(Context context , String str){
            Toast.makeText(context , str , Toast.LENGTH_SHORT ).show();
        }
    
    }

      等会在工程A中传入上下文和要显示的内容即可弹出一个toast窗。

      但是,并不是任何apk中的内我们都能随意调用,我们首先要做一个协定。协定的方式是action,我们在AndroidManifest中的MainActivity的Intent-Filter中加入以下一行

    <action android:name="com.dream.fishbonelsy.blurtestdemo"/>

      这样,工程A就以此为凭据调用工程B中的类和方法。

      下面在工程A中,使用ClassLoader来获取这个apk

      

            // 获取APK
            Intent intent = new Intent("com.dream.fishbonelsy.blurtestdemo" , null);
            // 获取包管理器
            PackageManager packageManager = context.getPackageManager();
            List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
            // 获得指定的activity的信息
            ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
            // 获得包名
            String packageName = activityInfo.packageName;
            // 获得apk目录
            String apkPath = activityInfo.applicationInfo.sourceDir;
            //dex解压后的目录,注意,这个用宿主程序的目录,android中只允许程序读取写自己
            //目录下的文件
            String dexOutputDir = context.getApplicationInfo().dataDir;
            //native代码的目录
            String libPath = activityInfo.applicationInfo.nativeLibraryDir;
            //创建类加载器,把dex加载到虚拟机中
            DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,
                    this.getClass().getClassLoader());

      这里通过包管理器和工程B的action获得一系列需要的信息:apk目录,文件目录,native代码录目,包名。

      获取了包名之后,如果我们知道类名和方法名就可以直接调用了。

      

    //利用反射调用插件包内的类的方法
    
            try {
                Class<?> clazz = calssLoader.loadClass(packageName+".ToastClass");
    
                Object obj = clazz.newInstance();
                Class[] param = new Class[2];
                param[0] = Context.class;
                param[1] = String.class;
                Method method = clazz.getMethod("alertMessage", param);
                method.invoke(obj,context , "hello android");
    
                Log.i("Host", "return result is " );
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

      通过反射,我们即可调用工程B中的方法。

    Done

  • 相关阅读:
    PZISP自动下载软件运行时出现“应用程序无法启动,因为应用程序的并行配置不正确”
    分析Memcached客户端如何把缓存数据分布到多个服务器上
    WebApi参数传递总结
    [NHibernate]一对多关系(级联删除,级联添加)
    提高SQL查询效率
    jquery validate 详解
    Winform子窗体刷新父窗体
    Windows如何修改MySQL用户root密码
    MySQL 5.6 for Windows 解压缩版配置安装
    获取地图文档(*.mxd)中比例尺问题
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/5155083.html
Copyright © 2020-2023  润新知