• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android动态加载Activity原理

Android动态加载Activity原理

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android mainactivity,android activity,android activity跳转,android baseactivity,android activity传值等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android动态加载Activity原理


activity的启动流程

加载一个Activity肯定不会像加载一般的类那样,因为activity作为系统的组件有自己的生命周期,有系统的很多回调控制,所以自定义一个DexClassLoader类加载器来加载插件中的Activity肯定是不可以的。

首先不得不了解一下activity的启动流程,当然只是简单的看一下,太详细的话很难研究清楚。

通过startActivity启动后,最终通过AMS进行跨进程回调到ApplicationThread的scheduleLaunchActivity,这时会创建一个ActivityClientRecord对象,这个对象表示一个Acticity以及他的相关信息,比如activityInfo字段包括了启动模式等,还有loadedApk,顾名思义指的是加载过了的APK,他会被放在一个Map中,应用包名到LoadedApk的键值对,包含了一个应用的相关信息。然后通过Handler切换到主线程执performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    // 1.创建ActivityClientRecord对象时没有对他的packageInfo赋值,所以它是null
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);
    }
    // ...
    Activity activity = null;
    try {
    	// 2.非常重要!!这个ClassLoader保存于LoadedApk对象中,它是用来加载我们写的activity的加载器
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        // 3.用加载器来加载activity类,这个会根据不同的intent加载匹配的activity
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
    	// 4.这里的异常也是非常非常重要的!!!后面就根据这个提示找到突破口。。。
        if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
    }
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            // 从这里就会执行到我们通常看到的activity的生命周期的onCreate里面
            mInstrumentation.callActivityOnCreate(activity, r.state);
            // 省略的是根据不同的状态执行生命周期
        }
        r.paused = true;
        mActivities.put(r.token, r);
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
    	// ...
    }
    return activity;
}

1.getPackageInfo方法最终返回一个LoadedApk对象,它会从一个HashMap的数据结构中取,mPackages维护了包名和LoadedApk的对应关系,即每一个应用有一个键值对对应。如果为null,就新创建一个LoadedApk对象,并将其添加到Map中,重点是这个对象的ClassLoader字段为null!

    public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
            int flags) {
    	// 为true
        boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
        boolean securityViolation = includeCode && ai.uid != 0
                && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
                        ? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
                        : true);
		// ...
        // includeCode为true
        // classloader为null!!!
        return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
    }

    private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
        synchronized (mPackages) {
            WeakReference ref;
            if (includeCode) {
            	// includeCode为true
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }
            LoadedApk packageInfo = ref != null ? ref.get() : null;
            if (packageInfo == null || (packageInfo.mResources != null && !packageInfo.mResources.getAssets().isUpToDate())) {
                if (localLOGV) // ...
                // packageInfo为null,创建一个LoadedApk,并且添加到mPackages里面
                packageInfo = new LoadedApk(this, aInfo, compatInfo, this, baseLoader, securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo. ) != 0);
                if (includeCode) {
                    mPackages.put(aInfo.packageName, new WeakReference(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName, new WeakReference(packageInfo));
                }
            }
            return packageInfo;
        }
    }

 

2.获取这个activity对应的类加载器,由于上面说过,mClassLoader为null,那么就会执行到ApplicationLoaders#getClassLoader(zip, libraryPath, mBaseClassLoader)方法。

public ClassLoader getClassLoader() {
    synchronized (this) {
        if (mClassLoader != null) {
            return mClassLoader;
        }
        // ...
        // 创建加载器,创建默认的加载器
        // zip为Apk的路径,libraryPath也就是JNI的路径
        mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, libraryPath, mBaseClassLoader);
        initializeJavaContextClassLoader();
        StrictMode.setThreadPolicy(oldPolicy);
        } else {
            if (mBaseClassLoader == null) {
                mClassLoader = ClassLoader.getSystemClassLoader();
            } else {
                mClassLoader = mBaseClassLoader;
            }
        }
        return mClassLoader;
    }
}
ApplicationLoaders使用单例它的getClassLoader方法根据传入的zip路径事实上也就是Apk的路径来创建加载器,返回的是一个PathClassLoader。并且PathClassLoader只能加载安装过的APK。这个加载器创建的时候传入的是当前应用APK的路径,理所应当的,想加载其他的APK就构造一个传递其他APK的类加载器。

3.用该类加载器加载我们要启动的activity,并反射创建一个activity实例

 

public Activity newActivity(ClassLoader cl, String className,Intent intent) throws InstantiationException,  IllegalAccessException, ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

总结一下上面的思路就是,当我们启动一个activity时,通过系统默认的PathClassLoader来加载这个activity,当然默认情况下只能加载本应用里面的activity,然后就由系统调用到这个activity的生命周期中。

4.这个地方的异常在后面的示例中会出现,到时候分析到原因后就可以找出我们动态加载Activity的思路了。

动态加载Activity:修改系统类加载器

按照这个思路,做这样的一个示例,按下按钮,打开插件中的Activity。

插件项目

plugin.dl.pluginactivity

|--MainActivity.java

内容很简单,就是一个布局上面写了这是插件中的Activity!并重写了他的onStart和onDestroy方法。

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 加载到宿主程序中之后,这个R.layout.activity_main就是宿主程序中的R.layout.activity_main了
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onStart() {
        super.onStart();
        Toast.makeText(this,"onStart", 0).show();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Toast.makeText(this,"onDestroy", 0).show();
    }
}

\

宿主项目

host.dl.hostactivity

|--MainActivity.java

包括

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android生命周期,activity生命周期
  • Android 面试题--Activity,android--activity
  • Android动态加载Activity原理
  • Android 配置文件(activity)元素
  • android自定义activity,androidactivity
  • Android Studio系列-Activity单元测试

相关文章

  • 2017-05-26docke swarm mode 集群应用之四-私有仓库harbor设置过程
  • 2017-05-26Android阻止AlertDialog关闭,androidalertdialog
  • 2017-05-26android 图片加载库 Glide 的使用介绍,
  • 2017-05-26Android Studio NDK开发
  • 2017-05-26Android Drawable的9种子类 介绍
  • 2017-05-26Hash Join与NLJOIN及MSJOIN
  • 2017-05-26Android 算法 关于递归和二分法的小算法,android二分法
  • 2017-05-26android中常见的设计模式有哪些?,android设计模式
  • 2017-05-26Android应用一般上架流程
  • 2017-05-26Android 应用程序集成FaceBook 登录,androidfacebook

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • onTouch和onTouchEvent,ontouch
    • Linux(CentOS 7)命令行模式安装VMware Tools
    • 1.7 界面原型设计
    • Android Studio 2.2.2导入Eclipse中创建的项目,androideclipse
    • popupwindow展示,popupwindow
    • 我的Android进阶之旅------)关于android:layout_weight属性的详细解析
    • zabbix 应用系统系统网络连接数的监测
    • Android Git 客户端,androidgit客户端
    • 改变RadioButton的文字位置以及距离,radiobutton文字
    • Android程序中--不能改变的事情,android程序--改变

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有