前言


  如同第一章我们说的,宿主程序通过 dexclassloader 将插件的类加载进来,然后通过反射去调用它的方法,这样Activity就被当成了一个普通的类来执行了,因此系统不再接管它的生命周期,也就是说Activity的生命周期函数失效了。针对这样的问题,有网友想出使用Fragment来解决此问题,Fragment既有类似于Activity的生命周期,又有类似于View的界面,因此选它比较合适,具体的做法是将Fragment加入到宿主的代理Activity内部,其生命周期将完全由代理Activity来管理,当然采用这种方法的弊端就是:要求apk尽量采用Fragment来实现,并且在页面跳转的时候比较麻烦,因此我们这里就放弃了这个做法,我们依然通过反射的方法来做。

实现


  我们直接看实现吧。

  首先是在宿主工程的生命周期函数进行反射:

 package com.bryan.host;

 import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import dalvik.system.DexClassLoader; import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.os.Bundle;
import android.provider.MediaStore.Video; public class ProxyActivity extends Activity
{
/* 接收mainActivity传来的*/
... /* classloder来的object*/
... /* 用来加载资源的*/
... @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); ....
} /* 加载插件的主activity*/
protected void OpenDefaultActivity()
{
...
} /* 加载插件的指定activity*/
@SuppressLint("NewApi") protected void OpenAppointActivity(final String className)
{
...
} protected void loadResources()
{
...
} /* 重写这两个加载资源的函数 */
.... /* 反射其他生命周期函数 */
@Override
protected void onStart() {
super.onStart();
ReflectOnFunction("onStart");
} @Override
protected void onResume() {
super.onResume();
ReflectOnFunction("onResume");
} @Override
protected void onPause() {
super.onPause();
ReflectOnFunction("onPause");
} @Override
protected void onStop() {
super.onStop();
ReflectOnFunction("onStop");
} @Override
protected void onDestroy() {
super.onDestroy();
ReflectOnFunction("onDestroy");
} private void ReflectOnFunction(String FunctionName)
{
Method onFunction;
try
{
onFunction = mlocaClass.getDeclaredMethod(FunctionName, new Class[] {});
onFunction.setAccessible(true);
onFunction.invoke(mobject);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

  插件工程中,我们可以直接在实际看到的Activity中直接加入反射,修改代码,也可以在BaseActivity中进行完成(这里我选了后者),为了看起来统一:、

 package com.bryan.plugin;

 import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams; public class BaseActivity extends Activity
{
/* 宿主工程中的代理Activity*/
protected Activity mProxyActivity; /* 判断是被谁调起的,如果是宿主调起的为1 */
int Who = 0; public void setProxy(Activity proxyActivity)
{
mProxyActivity = proxyActivity;
} @Override
protected void onCreate(Bundle savedInstanceState)
{
...
} ...... @Override
protected void onResume() {
if (mProxyActivity == this)
super.onResume();
} @Override
protected void onPause() {
if (mProxyActivity == this)
super.onPause();
} @Override
protected void onStop() {
if (mProxyActivity == this)
super.onStop();
} @Override
protected void onDestroy() {
if (mProxyActivity == this)
super.onDestroy();
}
}

  插件的实际看到的类中直接重写这些方法,维持默认的状态就可以了:

 package com.bryan.plugin;

 import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout; public class MainActivity extends BaseActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 初始化处理布局
InitView();
} ..... @Override
protected void onStart() {
super.onStart();
PluginLog.pluginLog("onStart");
} @Override
protected void onPause() {
super.onPause();
PluginLog.pluginLog("onPause");
} @Override
protected void onResume() {
super.onResume();
PluginLog.pluginLog("onResume");
} @Override
protected void onStop() {
super.onStop();
PluginLog.pluginLog("onStop");
} @Override
protected void onDestroy() {
super.onDestroy();
PluginLog.pluginLog("onDestroy");
}
}

  代码中的 pluginLog 只是我自己打log用的,不必关系它的实现细节。

结果


  在宿主程序拉起App后在Logcat中可以看到:

  到此为止,一个相对完整的插件的化的例子就算是做完了,当然这里面有很多可以优化的地方,不过我完成这三篇文章的目的也就是对于插件化原理的一个简单探索,让想了解插件原理的人入个门。由于本人是测试,不是开发出身,因此文章内难免会有写错误的地方,希望大家能不吝赐教。

  点击下载源代码

【Android开发学习笔记】【高级】【随笔】插件化——Activity生命周期的更多相关文章

  1. android开发学习笔记000

    使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...

  2. Android学习路线(十二)Activity生命周期——启动一个Activity

    DEMO下载地址:http://download.csdn.net/detail/sweetvvck/7728735 不像其他的编程模式那样应用是通过main()函数启动的.Android系统通过调用 ...

  3. android 点击返回键 以及 加载activity 生命周期 记录。。。,一目了然

    简叙 Activity 生命周期及android 返回按钮捕捉   @Override protected void onPostCreate(Bundle savedInstanceState) { ...

  4. 【Android开发学习笔记】【高级】【随笔】插件化——资源加载

    前言 上一节我们针对插件最基本的原理进行了一个简单的demo实现,但是由于插件的Context对象被宿主所接管,因此无法加载插件程序的资源.那么如何解决这个问题捏? 有人提出这样的方案:将apk中的资 ...

  5. android开发学习笔记系列(1)-android起航

    前言 在学习安卓的过程中,我觉得非常有必要将自己所学的东西进行整理,因为每每当我知道我应该是如何去实现功能的时候,有许多细节问题我总是会遗漏,因此我也萌生了写一系列博客来描述自己学习的路线,让我的an ...

  6. 【转】Android开发学习笔记(一)——初识Android

    对于一名程序员来说,“自顶向下”虽然是一种最普通不过的分析问题和解决问题的方式,但其却是简单且较为有效的一种.所以,将其应用到Android的学习中来,不至于将自己的冲动演变为一种盲目和不知所措. 根 ...

  7. Android开发学习笔记DDMS的使用

    打开DDMS DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务. DDMS里面包含了:Device(设备) F ...

  8. Android开发学习笔记:浅谈GridView

    GridView(网格视图)是按照行列的方式来显示内容的,一般用于显示图片,图片等内容,比如实现九宫格图,用GridView是首选,也是最简单的.主要用于设置Adapter. GridView常用的X ...

  9. 【转】Android开发学习笔记:5大布局方式详解

    Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...

随机推荐

  1. ZOJ 3157 Weapon

    题目传送门 题意:就是CF round# 329 B 的升级版,要求出相交点的个数 分析:逆序数用树状数组维护,求出非逆序数,然后所有情况(n * (n - 1)) / 2减之就是逆序数个数. #in ...

  2. js网页换肤

    使网页背景颜色可选黄/粉 <html> <head> <meta charset="utf-8"> <meta name="ge ...

  3. weblogic sockets 和 thread 问题解决

    原创文章,转载须注明出处. 这个问题网上很多答案,可惜没一个能解决.后来发现是weblogic 必须适配JDK 版本. 一般会报这个错误,There are: 5 active sockets, bu ...

  4. linux 快捷键

    截图: 打印: 全屏截图 alt+打印:窗口截图 shift+打印:区域截图 ctrl+打印:截图到剪贴板 显示桌面: ctrl+super+d 最大化最小化窗口 ctrl+alt+up/down 转 ...

  5. Toll-Free Bridge

    引 在深入了解桥接机制的时候看到一篇好文,虽然已经很久远,但是忍不住看了好几遍,心中诸多不解一扫而光.在此放上链接: 原文:http://ridiculousfish.com/blog/posts/b ...

  6. C/C++ 位运算符

    C/C++位操作运算符 操作符 功能 用法 ~ 位求反 ~expr << 左移 expr1 << expr2 >> 右移 expr1 >> expr2 ...

  7. 8.0 Qweb 报表编写步骤

    8.0 采用的是Qweb报表,摒弃了7.0中的RML报表. 1.首先在xml文件中注册一个报表: <report id="qweb_test_report" model=&q ...

  8. python基础数据类型

    整形:(不可变类型) >>> a = 123>>> type(a)<class 'int'> 长整形:(在python3中已经废弃了) >> ...

  9. 禁止用户自己停止SEP - 飞舞的菜刀 - 51CTO技术博客

    员工在自己的工作站上,右键点击状态栏SEP图标,停止SEP服务,导致管理员定制的策略失效,针对上述情况,请安装下述方法操作. 1. 打开SEPM. 2. 在[策略]里选中你所使用的[防病毒和防间谍软件 ...

  10. 彻底搞清楚字符编码: ASCII, ISO_8859, GB2312,UCS, Unicode, Utf-8

    彻底搞清楚字符编码: ASCII, ISO_8859, GB2312,UCS, Unicode, U 1.ASCII: 0-127(128-255未使用),美国标准 2.IS0-8859-1(lati ...