android activity动态加载

来源:互联网 发布:杀病毒的软件 编辑:程序博客网 时间:2024/05/19 20:20

通过分析QQGame的项目,发现其存在两种方式:

1. 不安装游戏apk,直接启动

我这里只说其原理,详情讲查看:探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法

其原理是:

  1. 把apk里的class文件通过DexClassLoader把apk里的class文件全部加载到java虚拟机里,如果要使用其中的某个class时,就要使用反射来调用。

  2. 如果这个类是Activity的子类,那如何来启动,Activity的子类是由android系统来创建,处理方法是:把Activity的子类当做一个有着Activity相应接口的类,在项目里创建一个空的Activity类,其里面不做任何事情,只是用反射调用真正的Activity的方法,代码如下:

 

Java代码  收藏代码
  1. public class MainActivity extends Activity {  
  2.     private static final String TAG = "MainActivity";  
  3.       
  4.     private Class mActivityClass;  
  5.     private Object mActivityInstance;  
  6.   
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.   
  12.         Button btn = (Button) findViewById(R.id.btn);  
  13.         btn.setOnClickListener(new OnClickListener() {  
  14.   
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                 Bundle paramBundle = new Bundle();  
  18.                 paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY"true);  
  19.                 String dexpath = "/mnt/sdcard/TestB.apk";  
  20.                 String dexoutputpath = "/mnt/sdcard/";  
  21.                 LoadAPK(paramBundle, dexpath, dexoutputpath);  
  22.             }  
  23.         });  
  24.     }  
  25.       
  26.     @Override  
  27.     protected void onStart() {  
  28.         super.onStart();  
  29.         try {  
  30.             Method method = mActivityClass.getDeclaredMethod(  
  31.                     "onStart");  
  32.             method.setAccessible(true);  
  33.             method.invoke(mActivityInstance);  
  34.         } catch (Exception e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.     }  
  38.       
  39.     @Override  
  40.     protected void onResume() {  
  41.         super.onResume();  
  42.         try {  
  43.             Method method = mActivityClass.getDeclaredMethod(  
  44.                     "onResume");  
  45.             method.setAccessible(true);  
  46.             method.invoke(mActivityInstance);  
  47.         } catch (Exception e) {  
  48.             e.printStackTrace();  
  49.         }  
  50.     }  
  51.       
  52.     @Override  
  53.     protected void onPause() {  
  54.         super.onPause();  
  55.         try {  
  56.             Method method = mActivityClass.getDeclaredMethod(  
  57.                     "onPause");  
  58.             method.setAccessible(true);  
  59.             method.invoke(mActivityInstance);  
  60.         } catch (Exception e) {  
  61.             e.printStackTrace();  
  62.         }  
  63.     }  
  64.       
  65.     @Override  
  66.     protected void onStop() {  
  67.         super.onStop();  
  68.         try {  
  69.             Method method = mActivityClass.getDeclaredMethod(  
  70.                     "onStop");  
  71.             method.setAccessible(true);  
  72.             method.invoke(mActivityInstance);  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         }  
  76.     }  
  77.       
  78.     @Override  
  79.     protected void onDestroy() {  
  80.         super.onDestroy();  
  81.         try {  
  82.             Method method = mActivityClass.getDeclaredMethod(  
  83.                     "onDestroy");  
  84.             method.setAccessible(true);  
  85.             method.invoke(mActivityInstance);  
  86.         } catch (Exception e) {  
  87.             e.printStackTrace();  
  88.         }  
  89.     }  
  90.   
  91.     public void LoadAPK(Bundle paramBundle, String dexpath, String dexoutputpath) {  
  92.         ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();  
  93.         DexClassLoader localDexClassLoader = new DexClassLoader(dexpath,  
  94.                 dexoutputpath, null, localClassLoader);  
  95.         try {  
  96.             PackageInfo plocalObject = getPackageManager()  
  97.                     .getPackageArchiveInfo(dexpath, 1);  
  98.   
  99.             if ((plocalObject.activities != null)  
  100.                     && (plocalObject.activities.length > 0)) {  
  101.                 String activityname = plocalObject.activities[0].name;  
  102.                 Log.d(TAG, "activityname = " + activityname);  
  103.   
  104.                 Class localClass = localDexClassLoader.loadClass(activityname);  
  105.                 mActivityClass = localClass;  
  106.                 Constructor localConstructor = localClass  
  107.                         .getConstructor(new Class[] {});  
  108.                 Object instance = localConstructor.newInstance(new Object[] {});  
  109.                 Log.d(TAG, "instance = " + instance);  
  110.                 mActivityInstance = instance;  
  111.   
  112.                 Method localMethodSetActivity = localClass.getDeclaredMethod(  
  113.                         "setActivity"new Class[] { Activity.class });  
  114.                 localMethodSetActivity.setAccessible(true);  
  115.                 localMethodSetActivity.invoke(instance, new Object[] { this });  
  116.   
  117.                 Method methodonCreate = localClass.getDeclaredMethod(  
  118.                         "onCreate"new Class[] { Bundle.class });  
  119.                 methodonCreate.setAccessible(true);  
  120.                 methodonCreate.invoke(instance, new Object[] { paramBundle });  
  121.             }  
  122.             return;  
  123.         } catch (Exception ex) {  
  124.             ex.printStackTrace();  
  125.         }  
  126.     }  
  127. }  

 

 从上面可以看到,由于我们不能像系统一样初始化Activity,所以只能用一个Activity做为了容器,来调用其Activity相应的生命周期方法。

在另外的Activity里,把显示的view设置到传过来的Activity里面,同时,所有要与系统交互的,都要通过传过来的activity对象,这个和我们最开始的那个框架差不多。

 

这样做的好处:

  1. 可以做到apk,不安装的情况下,就可以启动这个apk

  2. 对于qqgame,由于只有一个Activity,而且游戏的图片资源都是自己加载的,所以很适合用这种方式

不足之处:

  1. 不能把res里的资源文件交给系统来管理,也就是资源(图片等等),都要自己去sdcard里去读取,去维护。

  2. 如果有多个Activity时,就会很麻烦,由于只是把些类加载进来,但不能由系统来初始化,那些startActivity的方法基本上不能用(虽然可以模拟,但会有很多的问题)

  3. 由于有这种限制,所以QQ的项目里,现在还只有QQGame用了这种模式

 

2. 安装游戏apk,再进行启动

这种模式比较简单:

1. 不要用启动的Activity

2. 把第一个启动的Activity加一个约定的Catergory:

 

Xml代码  收藏代码
  1. <category android:name="android.intent.category.XXXX" />  

还后,在门户的项目里,对当前手机进行探测,看有多少个含有这个类别的Activity,可以进行显示出来了。

 

结论:

对了我们这种应用app的程序,用这种方式,会大大加大开发的复杂度,不过其第二种方法不错,但要变化着使用。

使用交叉推荐:

  1. 在每个不同的项目里,都加入对其他产品的推荐(同时,检测用户手机里已经安装过的apk)。

  2. 有一些功能,还可以让用户跳到其他的apk实现。

0 0
原创粉丝点击