总结
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
下面介绍的是动态加载未安装的apk.然后读取apk中图片,显示在宿主app中
1.首先准备换肤的apk
skindemo-debug.apk
skindemo2-debug.apk
这2个apk中都有一张图片,然后我们push这两个apk到sdcard中就可以
资源加载问题,怎么通过Resources 加载另外一个apk中的图片
/**
* 获取AssetManager 用来加载插件资源
*
* @param pFilePath 插件的路径
* @return
*/
private AssetManager createAssetManager(String pFilePath) {
try {
final AssetManager assetManager = AssetManager.class.newInstance();
final Class> assetManagerClazz = Class.forName(“android.content.res.AssetManager”);
final Method addAssetPathMethod = assetManagerClazz.getDeclaredMethod(“addAssetPath”, String.class);
addAssetPathMethod.setAccessible(true);
addAssetPathMethod.invoke(assetManager, pFilePath);
return assetManager;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//这个Resources就可以加载非宿主apk中的资源
private Resources createResources(String pFilePath) {
final AssetManager assetManager = createAssetManager(pFilePath);
Resources superRes = this.getResources();
return new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
}
3.宿主apk,动态换肤的点击事件代码
private boolean mChange = false;
private String skinType = “”;
private int APK_TYPE;
/**
* 替换bg
*/
public void replace(View view) {
if (!mChange) {
skinType = “skindemo-debug.apk”;
APK_TYPE = 1;
mChange = true;
} else {
skinType = “skindemo2-debug.apk”;
APK_TYPE = 2;
mChange = false;
}
final String path = Environment.getExternalStorageDirectory() + File.separator + skinType;
final String pkgName = getUninstallApkPkgName(this, path);
dynamicLoadApk(path, pkgName);
}
private void dynamicLoadApk(String pApkFilePath, String pApkPacketName) {
File file = getDir(“dex”, Context.MODE_PRIVATE);
//第一个参数:是dex压缩文件的路径
//第二个参数:是dex解压缩后存放的目录
//第三个参数:是C/C++依赖的本地库文件目录,可以为null
//第四个参数:是上一级的类加载器
DexClassLoader classLoader = new DexClassLoader(pApkFilePath, file.getAbsolutePath(), null, getClassLoader());
try {
final Class> loadClazz = classLoader.loadClass(pApkPacketName + “.R$drawable”);
//插件中皮肤的名称是skin_one
final Field skinOneField = APK_TYPE == 1 ? loadClazz.getDeclaredField(“skin_one”) : loadClazz.getDeclaredField(“skin_two”);
skinOneField.setAccessible(true);
//反射获取skin_one的resousreId
final int resousreId = (int) skinOneField.get(R.id.class);
//可以加载插件资源的Resources
final Resources resources = createResources(pApkFilePath);
if (resources != null) {
final Drawable drawable = resources.getDrawable(resousreId);
linearLayout.setBackgroundDrawable(drawable);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据sdcard路径,获取未安装apk的信息
*
* @param context
* @param pApkFilePath apk文件的path
* @return
*/
private String getUninstallApkPkgName(Context context, String pApkFilePath) {
PackageManager pm = context.getPackageManager();
PackageInfo pkgInfo = pm.getPackageArchiveInfo(pApkFilePath, PackageManager.GET_ACTIVITIES);
if (pkgInfo != null) {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
最后送福利了,现在关注我可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿**
[外链图片转存中…(img-muBLOg1L-1715845054195)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!