前言

  Android动态加载(下)——加载已安装APK中的类和资源。

声明   欢迎转载,但请保留文章原始出处:)     51CTO:http://www.51cto.com     农民伯伯: http://over140.blog.51cto.com

    Android中文Wiki:http://wikidroid.sinaapp.com

正文

  一、目标

    注意被调用的APK在Android系统中是已经安装的。

上篇文章:Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

    从当前APK中调用另外一个已安装APK的字符串、颜色值、图片、布局文件资源以及Activity。

    

  二、实现

    2.1   被调用工程

       基本沿用上个工程的,添加了被调用的字符串、图片等,所以这里就不贴了,后面有下载工程的链接。

    2.2   调用工程代码

复制代码 public classTestAActivity extendsActivity{

/** TestB包名 */
private static finalStringPACKAGE_TEST_B="com.nmbb.b";

@Override
public voidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try{
finalContextctxTestB=getTestBContext();
Resourcesres=ctxTestB.getResources();
// 获取字符串string
Stringhello=res.getString(getId(res,"string","hello"));
((TextView)findViewById(R.id.testb_string)).setText(hello);

// 获取图片Drawable
Drawabledrawable=res
.getDrawable(getId(res,"drawable","testb"));
((ImageView)findViewById(R.id.testb_drawable))
.setImageDrawable(drawable);

// 获取颜色值
intcolor=res.getColor(getId(res,"color","white"));
((TextView)findViewById(R.id.testb_color))
.setBackgroundColor(color);

// 获取布局文件
Viewview=getView(ctxTestB,getId(res,"layout","main"));
LinearLayoutlayout=(LinearLayout)findViewById(R.id.testb_layout);
layout.addView(view);

// 启动TestBActivity
findViewById(R.id.testb_activity).setOnClickListener(
newOnClickListener(){
@Override
public voidonClick(Viewv){
try{
@SuppressWarnings("rawtypes")
Classcls=ctxTestB.getClassLoader()
.loadClass("com.nmbb.TestBActivity");
startActivity( newIntent(ctxTestB,cls));
} catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
});
} catch(NameNotFoundExceptione){
e.printStackTrace();
}
}

/**
*获取资源对应的编号
*
*
@param testb
*
@param resName
*
@param resType
*layout、drawable、string
*
@return
*/
private intgetId(Resourcestestb,StringresType,StringresName){
returntestb.getIdentifier(resName,resType,PACKAGE_TEST_B);
}

/**
*获取视图
*
*
@param ctx
*
@param id
*
@return
*/
publicViewgetView(Contextctx, intid){
return((LayoutInflater)ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(id,
null);
}

/**
*获取TestB的Context
*
*
@return
*
@throws NameNotFoundException
*/
privateContextgetTestBContext() throwsNameNotFoundException{
returncreatePackageContext(PACKAGE_TEST_B,
Context.CONTEXT_IGNORE_SECURITY|Context.CONTEXT_INCLUDE_CODE); 复制代码

}

    代码说明:

      基本原理:通过package获取被调用应用的Context,通过Context获取相应的资源、类。

    注意:

      a). 网上许多文章是通过当前工程的R.id来调用被调用工程的资源 ,这是错误的,即使不报错那也是凑巧,因为R是自动生成的,两个应用的id是没有办法对应的,所以需要通过getIdentifier来查找。

      b). Context.CONTEXT_INCLUDE_CODE一般情况下是不需要加的,如果layout里面包含了自定义控件,就需要加上。注意不能在当前工程强制转换获得这个自定义控件,因为这是在两个ClassLoader中,无法转换。

      c). 获取这些资源是不需要shareUserId的。

  三、总结

    与上篇文章相比,获取资源更加方便,但也存在一些限制:

    3.1  被调用的apk必须已经安装,降低用户体验。

    3.2  style是无法动态设置的,即使能够取到。

    3.3  从目前研究结果来看,被调用工程如果使用自定义控件,会受到比较大的限制,不能强制转换使用(原因前面已经讲过)。

    3.4  由于一个工程里面混入了两个Context,比较容易造成混淆,取资源也比较麻烦。这里分享一下批量隐射两个apk id的办法,可以通过反射获取两个apk的R类,一次获取每一个id和值,通过名称一一匹配上,这样就不用手工传入字符串了。

复制代码 @SuppressWarnings("rawtypes")
private staticHashMap<String,Integer>getR(Classcls) throwsClassNotFoundException,InstantiationException,IllegalAccessException{
HashMap<String,Integer>result= newHashMap<String,Integer>();
for(Classr:cls.getClasses()){
if(!r.getName().endsWith("styleable")){
Objectowner=r.newInstance();
for(Fieldfield:r.getFields()){
result.put(field.getName(),field.getInt(owner));
}
}
}
returnresult; 复制代码

}

  四、下载

    Test2012-4-19.zip

  五、文章

    Android类动态加载技术

结束

  如果是做大面积的换肤,还比较复杂,这种方式也不是很方便,这也是为什么现在市面上做换肤的很少,有也是很简单的换肤。这几天想到的另外一个方案,还没有实践,有效果了再拿出来分享,欢迎大家交流 :)

更多相关文章

  1. Android Studio GitHub 提交项目代码
  2. 第一行代码 Android读书笔记(一)
  3. Android Gradle编译学习日记之二(使用 Gradle 编译 Eclipse,引入依
  4. 【初用Android Studio】快捷键之代码提示
  5. android 教程资源推荐
  6. Android Studio通过修改图标资源值实现图标的修改以及修改APP名
  7. Android与JS代码交互
  8. 将Eclipse代码导入到Android Studio的两种方式

随机推荐

  1. mysql 8.0.20 winx64.zip压缩版安装配置
  2. MySQL数据库主从同步实战过程详解
  3. MySQL数据库基础入门之常用命令小结
  4. MySQL数据库入门之备份数据库操作详解
  5. MySQL数据库入门之多实例配置方法详解
  6. MySQL数据库基础篇之入门基础命令小结
  7. Ubuntu18.0.4下mysql 8.0.20 安装配置方
  8. mysql 8.0.20 安装配置方法图文教程
  9. mysql8.0.20下载安装及遇到的问题(图文详
  10. MySQL 8.0.20 安装教程图文详解(windows