Android插件化学习之路(五)之代理Activity

简单模式中,使用ClassLoader加载外部的Dex或Apk文件,可以加载一些本地APP不存在的类,从而执行一些新的代码逻辑。但是使用这种方法却不能直接启动插件里的Activity。

Freedom框架,我个人手写的0反射插件化框架

启动插件中Activity的两个主要问题

Activity等组件是需要在Manifest中注册后才能以标准Intent的方式启动的,通过ClassLoader加载并实例化的Activity实例只是一个普通的Java对象,能调用对象的方法,但是它没有生命周期,而且Activity等系统组件是需要Android的上下文环境的(Context等资源),没有这些东西Activity根本无法工作。

使用插件APK里的Activity需要解决两个问题:

  1. 如何使插件APK里的Activity具有生命周期;
  2. 如何使插件APK里的Activity具有上下文环境(使用R资源);
    代理Activity模式为解决这两个问题提供了一种思路。

代理Activity模式

这种模式的特点是:主项目APK注册一个代理Activity(命名为ProxyActivity),ProxyActivity是一个普通的Activity,但只是一个空壳,自身并没有什么业务逻辑。每次打开插件APK里的某一个Activity的时候,都是在主项目里使用标准的方式启动ProxyActivity,再在ProxyActivity的生命周期里同步调用插件中的Activity实例的生命周期方法,从而执行插件APK的业务逻辑。

ProxyActivity + 没注册的Activity = 标准的Activity

第二个问题,我们在上一篇博客中已经解决了,下面我们来分析使插件APK里的Activity具有生命周期的问题

处理插件Activity的生命周期

目前还真的没什么办法能够处理这个问题,一个Activity的启动,如果不采用标准的Intent方式,没有经历过Android系统Framework层级的一系列初始化和注册过程,它的生命周期方法是不会被系统调用的(除非你能够修改Android系统的一些代码,而这已经是另一个领域的话题了,这里不展开)。

那我们可以在主项目里创建一个ProxyActivity,再由它去代理调用插件Activity的生命周期方法(这也是代理模式叫法的由来)。用ProxyActivity(一个标准的Activity实例)的生命周期同步控制插件Activity(普通类的实例)的生命周期,同步的方式可以有下面两种:

• 在ProxyActivity生命周期里用反射调用插件Activity相应生命周期的方法,简单粗暴。
• 把插件Activity的生命周期抽象成接口,在ProxyActivity的生命周期里调用。另外,多了这一层接口,也方便主项目控制插件Activity。

用反射调用插件Activity相应生命周期

我们要在代理activity中去反射apk中activity的所有生命周期的方法,然后将activity的生命周期和代理activity的生命周期进行同步。首先,反射activity生命周期的所有方法,还反射了onActivityResult这个方法,尽管它不是典型的生命周期方法,但是它很有用。

1.	protected void instantiateLifecircleMethods(Class<?> localClass) {  
2.	    String[] methodNames = new String[] {  
3.	            "onRestart",  
4.	            "onStart",  
5.	            "onResume",  
6.	            "onPause",  
7.	            "onStop",  
8.	            "onDestory"  
9.	    };  
10.	    for (String methodName : methodNames) {  
11.	        Method method = null;  
12.	        try {  
13.	            method = localClass.getDeclaredMethod(methodName, new Class[] { });  
14.	            method.setAccessible(true);  
15.	        } catch (NoSuchMethodException e) {  
16.	            e.printStackTrace();  
17.	        }  
18.	        mActivityLifecircleMethods.put(methodName, method);  
19.	    }  
20.	  
21.	    Method onCreate = null;  
22.	    try {  
23.	        onCreate = localClass.getDeclaredMethod("onCreate", new Class[] { Bundle.class });  
24.	        onCreate.setAccessible(true);  
25.	    } catch (NoSuchMethodException e) {  
26.	        e.printStackTrace();  
27.	    }  
28.	    mActivityLifecircleMethods.put("onCreate", onCreate);  
29.	  
30.	    Method onActivityResult = null;  
31.	    try {  
32.	        onActivityResult = localClass.getDeclaredMethod("onActivityResult",  
33.	                new Class[] { int.class, int.class, Intent.class });  
34.	        onActivityResult.setAccessible(true);  
35.	    } catch (NoSuchMethodException e) {  
36.	        e.printStackTrace();  
37.	    }  
38.	    mActivityLifecircleMethods.put("onActivityResult", onActivityResult);  
39.	}  

其次,同步生命周期,主要看一下onResume和onPause,其他方法是类似的。看如下代码,很好理解,就是当系统调用代理activity生命周期方法的时候,就通过反射去显式调用apk中activity的对应方法。

1.	@Override  
2.	protected void onResume() {  
3.	    super.onResume();  
4.	    Method onResume = mActivityLifecircleMethods.get("onResume");  
5.	    if (onResume != null) {  
6.	        try {  
7.	            onResume.invoke(mRemoteActivity, new Object[] { });  
8.	        } catch (Exception e) {  
9.	            e.printStackTrace();  
10.	        }  
11.	    }  
12.	}  
13.	  
14.	@Override  
15.	protected void onPause() {  
16.	    Method onPause = mActivityLifecircleMethods.get("onPause");  
17.	    if (onPause != null) {  
18.	        try {  
19.	            onPause.invoke(mRemoteActivity, new Object[] { });  
20.	        } catch (Exception e) {  
21.	            e.printStackTrace();  
22.	        }  
23.	    }  
24.	    super.onPause();  
25.	}  

把插件Activity的生命周期抽象成接口,在ProxyActivity的生命周期里调用

采用反射去管理activity的生命周期,这样存在一些不便,比如反射代码写起来复杂,并且过多使用反射有一定的性能开销。针对这个问题,可以采用接口机制,将activity的大部分生命周期方法提取出来作为一个接口(DLPlugin),然后通过代理activity(DLProxyActivity)去调用插件activity实现的生命周期方法,这样就完成了插件activity的生命周期管理,并且没有采用反射,当我们想增加一个新的生命周期方法的时候,只需要在接口中声明一下同时在代理activity中实现一下即可.

public interface DLPlugin {

    public void onStart();
    public void onRestart();
    public void onActivityResult(int requestCode, int resultCode, Intent data);
    public void onResume();
    public void onPause();
    public void onStop();
    public void onDestroy();
    public void onCreate(Bundle savedInstanceState);
    public void setProxy(Activity proxyActivity, String dexPath);
    public void onSaveInstanceState(Bundle outState);
    public void onNewIntent(Intent intent);
    public void onRestoreInstanceState(Bundle savedInstanceState);
    public boolean onTouchEvent(MotionEvent event);
    public boolean onKeyUp(int keyCode, KeyEvent event);
    public void onWindowAttributesChanged(LayoutParams params);
    public void onWindowFocusChanged(boolean hasFocus);

在代理类DLProxyActivity中的实现

...
    @Override
    protected void onStart() {
        mRemoteActivity.onStart();
        super.onStart();
    }

    @Override
    protected void onRestart() {
        mRemoteActivity.onRestart();
        super.onRestart();
    }

    @Override
    protected void onResume() {
        mRemoteActivity.onResume();
        super.onResume();
    }

    @Override
    protected void onPause() {
        mRemoteActivity.onPause();
        super.onPause();
    }

    @Override
    protected void onStop() {
        mRemoteActivity.onStop();
        super.onStop();
    }
...

通过以上两种方式,就可以解决插件Activity的生命周期的问题,现在一般推荐第二种方式。

参考文章:http://blog.csdn.net/singwhatiwanna/article/details/23387079

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的代码家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值