张春 发表于 2024-8-30 06:21:23

200行代码打造超越一线互联网公司的换肤架构(1),Android平台HTTPS抓包办理

至于xRecyclerView可以不消管,这里我们用不到(这是之前用到的,与本次无关),他只是一个RecyclerView的一个扩展框架,支持下拉革新和上拉加载,是一个在github上的一个开源项目。
这里我们直接来看看lib_skinloader这个库吧(这内里的内容大部门是泉源于Android-Skin-Loader这个框架,我只做了部门修改,重要是适配AppCompatActivity,原框架是基于最初的Activty开发的,在这里再次感谢开源作者),这个库就是今天所讲的核心内容
https://i-blog.csdnimg.cn/blog_migrate/34a9735f87d21ece183da1e48cb10606.png
我们都知道在Android中如果想去获取资源文件都必须通过Resources去获取。这个库的核心思想就是动态的去加载第三方包内里的包,获取到其Resources然后以获取到的这个Resources去获取第三方包内里的资源内容,最后设置到我们有需响应皮肤更改的View上。
这里我就只介绍load和base两个包,其他包的内容在讲解的时候会涉及到
###1.load包
我们先来看看这个load包内里的内容(实在这里就是今天核心内容的核心)。
https://i-blog.csdnimg.cn/blog_migrate/90b4d11155cdfff6b108768f5d83a2bd.png
内里有两个类文件:SkinInflaterFactory、SkinManager
我们先来看看SkinManager的实现,直接跳到load方法
public void load(String skinPackagePath, final ILoaderListener callback) {
new AsyncTask<String, Void, Resources>() {
protected void onPreExecute() {
if (callback != null) {
callback.onStart();
}
}
@Override
protected Resources doInBackground(String… params) {
try {
if (params.length == 1) {
String skinPkgPath = params;
Log.i(“loadSkin”, skinPkgPath);
File file = new File(skinPkgPath);
if (file == null || !file.exists()) {
return null;
}
PackageManager mPm = context.getPackageManager();
PackageInfo mInfo = mPm.getPackageArchiveInfo(skinPkgPath, PackageManager.GET_ACTIVITIES);
skinPackageName = mInfo.packageName;
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod(“addAssetPath”, String.class);
addAssetPath.invoke(assetManager, skinPkgPath);
Resources superRes = context.getResources();
Resources skinResource = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
SkinConfig.saveSkinPath(context, skinPkgPath);
skinPath = skinPkgPath;
isDefaultSkin = false;
return skinResource;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
protected void onPostExecute(Resources result) {
mResources = result;
if (mResources != null) {
if (callback != null) callback.onSuccess();
notifySkinUpdate();
} else {
isDefaultSkin = true;
if (callback != null) callback.onFailed();
}
}
}.execute(skinPackagePath);
}
这个方法有两个参数,第一个是皮肤包的路径,第二个就是一个简朴的回调
其中doInBackground方法内里就实现了动态的去获取皮肤包的Resources,当获取乐成之后,在onPostExecute方法中就将这个Resources赋值到我们定义好的变量中去,以方便我们之后的使用,注意到当获取到的这个Resources不为空时,也就是我们已经获取到了皮肤包内里的资源,我们就调用notifySkinUpdate()这个方法来关照界面去更改皮肤,如果为空就照旧使用默认的皮肤。
我们来看看notifySkinUpdate()的实现
https://i-blog.csdnimg.cn/blog_migrate/d0a11d0cc0795acccf904fac38c9b022.png
这里很简朴,就是去遍历mSkinObservers这个集合,然后去关照更新。对于ISkinUpdate是一个接口,每个必要皮肤更新的Activity都必要去实现这个接口。
SkinManager这个类内里还有诸如getColor(int resId)、getDrawable(int resId)这样的方法,就是去获取第三方包对应的资源文件,值得注意的是如果你的第三方包里没有对应的资源文件,那么就会使用默认的资源文件,如果你有需求,你完全可以去添加一些类似getMipmap(int resID)这样的方法。
对了,还有一个比较重要的方法忘了讲
https://i-blog.csdnimg.cn/blog_migrate/e9f8ca8fc08eeeab5c583fc1769b7a7d.png
这个方法就是恢复到系统的默认主题,原理和load都差不多,实现还简朴了许多。SkinManager这个类就说这么多,详细实现请到源码中去查看,许多地方我都给了注释。
我们再来看看SkinInflaterFactory,在这内里重要就是做一些填充View相关的一些工作。我实现的是LayoutInflaterFactory这个接口而不是文章之前提到的LayoutInflater.Factory这个接口是因为这里必要与AppCompatActivity兼容,如果你照旧用之前的那个就会出现一些错误,反正我刚弄的时候是折腾了很久的。不管怎么样原理始终是一样的。SkinInflaterFactory的作用就是去搜集那些有必要响应皮肤更改的View。 我们来看看onCreateView的实现
https://i-blog.csdnimg.cn/blog_migrate/87f237abbaa9994727f44f4f5bbb9ca7.png
首先我们先去判断这个当前将要View是否有更改皮肤的需求,如果没有我们就返回默认的实现。如果有,我们就本身行止置惩罚 来看看createView方法的实现
https://i-blog.csdnimg.cn/blog_migrate/8941614e13060d4acaa80b6ffb0170cf.png
看起来许多,实在这个方法就是去动态的去创建View。
下面来看看parseSkinAttr的实现:
https://i-blog.csdnimg.cn/blog_migrate/b97403f6745fdfe13e90827609048481.png
这个方法实在就是去搜集View中换肤的时候可以更改的属性,当我们换肤的时候就是去更改的这些属性的值,这里你必须要注意一点,这个属性的值一定要是引用类型的(比方:@color/red),万万不能写死,第二个if的判断就是这个作用。**到这里可能你就会有个疑问,我怎么知道哪些属性在换肤的时候必要更改。**如果你细心一点肯定注意到了这行代码
SkinAttr mSkinAttr = AttrFactory.get(attrName, id, entryName, typeName);
这里有个AttrFacory他的作用就是根据属性名,动态的去创建SkinAttr。在AttrFacory中定义了一些类似于这样的常量:
https://i-blog.csdnimg.cn/blog_migrate/bcbe914b7ff63f45a86c35b2006fc2cc.png
这就是我们换肤的时候可以更改的那些属性。SkinAttr是一个抽象类,比如background就会去创建一个BackgroundAttr,本项目所用到的属性全都在attr包中。SkinAttr是比较机动的一个地方,如果你有哪个属性在换肤的时候必要更改,你就去实现一个对应的SkinAttr。
在parseSkinAttr这个方法的最后我们将View和SkinAttr封装成了一个SkinItem然后添加到一个集合中去,最后还需注意的是,如果当前皮肤不是默认皮肤,一定要去apply一下,这样做重要是防止换了皮肤启动一些新的页面有可能导致换肤不实时的问题。SkinInflaterFactory这个类内里还提供了动态的添加SkinItem的方法,原理都和这里差不多,我就不过多的去说了。
load包内里的这两个类讲的差不多了,这里看懂了后面的内容也就是小菜一碟了,我相信你看了这里再去看源码一定会轻松地多。
###2.base包
https://i-blog.csdnimg.cn/blog_migrate/01d081910dcd190eb437d336886ad613.png
可以看见这个包内里肯定就是Activity、Fragment、Application的实现,作用肯定就是封装一些公用的方法和属性在内里。
下面我们一个一个来分析


[*]SkinBaseApplication:
可以看到这里我们对SkinManager做了一些初始化的操纵。以后我们有必要皮肤更改需求的应用一定要记得一定要继承于SkinBaseApplication。


[*]SkinBaseActivity 我们来看看其onCreate方法
https://i-blog.csdnimg.cn/blog_migrate/d2a1f32e514f76c18c3cc47a484708fb.png
在这里使用了我们之前自定义的View的InflaterFactory,来更换默认的Factory。记住一定要在super.onCreate(savedInstanceState);这个方法之前调用。SkinBaseActivity内里还提供了动态添加可以响应皮肤更改需求的View的相关方法。当然必要响应换肤更改的Activity都必要继承SkinBaseActivity。详细实现请看源码。
[*]SkinBaseFragment 这个和SkinBaseActivity的思想差不多。具体实现看源码,这里我只是给各人提供这个换肤框架的思想,让各人在看源码的时候更轻松。
这个框架就介绍到这,下面我们来看看怎么去使用。
在使用的时候一定要记得要Activity要去继承于SkinBaseActivity,Fragment要继承于SkinBaseFragment,Application要继承于SkinBaseApplication。当然把这个框架做为你的项目依赖项肯定是必不可少的。为了Demo的简朴,这里我只使用了下面三个颜色作为可以换肤的资源,当然如果你想要使用drawable文件也是可以办到的,前提是你一定要把这个Demo看懂。
https://i-blog.csdnimg.cn/blog_migrate/2bdf20916fc012abd650be014535f17a.png
来看一个布局文件
https://i-blog.csdnimg.cn/blog_migrate/c38294ac099d3fad64f3382c4db0742b.png
其中xmlns:skin=”http://schemas.android.com/android/skin“是我们自定义的,在SkinConfig有。 我们只需在有皮肤更改需求的View中参加skin:enable=”true” 就OK了。
再来看看MainActicvity的部门代码
https://i-blog.csdnimg.cn/blog_migrate/900aec78e40d52e4c5160bc5c4685dfe.png
这里就是动态的添加有皮肤更改需求的View。
上面就介绍完了在布局文件中使用方法和在代码中使用方法。
我们应该怎么去换肤呢?很简朴,只需调用SkinManager的load方法就可以了,把皮肤路径传进去就可以了,我的这个Demo为了简朴起见,没有做在线换肤的功能,只是在当地提供了可以更换的皮肤,看到这里我相信你对怎样在线换肤已经有想法了。
https://i-blog.csdnimg.cn/blog_migrate/160e64326594f5e3149310da67739e0b.png
最最后我们来看看怎么去开发皮肤包。实在这个是最简朴的,皮肤包实际上就是一个根本的Android项目,内里不包含类文件,只有资源文件。**这里只需注意 这里的资源文件名字一定要和原项目中的雷同,而且只用包含那些在皮肤更改时必要改变的那些就行了!**比方我的这个Demo就只是简朴对上面的三种颜色做了简朴的切换。开发了棕色和黑色两款皮肤,以是资源文件中只有三个color的值,开发完成之后我们必要将其打包成apk文件,为防止用户点击安装,我们将厥后缀改成了skin,这样做也具有标识性。如果照旧不太清晰可以直接去源码中查看。
自我介绍一下,小编13年上海交大结业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里不停到现在。
深知大多数初中级Android工程师,想要提升技能,往往是本身探索发展或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。本身不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简朴,就是渴望能够资助到想自学提升又不知道该从何学起的朋友,同时减轻各人的负担。
https://i-blog.csdnimg.cn/blog_migrate/88ed6062807a674353e9457f3e904a46.png
https://i-blog.csdnimg.cn/blog_migrate/1e236f255560a344a9a57f2245460bb7.png
https://i-blog.csdnimg.cn/blog_migrate/d6805d23ee9f01aa96bb176db30cab5c.png
https://i-blog.csdnimg.cn/blog_migrate/7bb64cb36cf1cadbe354c34ff83b1d61.png
https://i-blog.csdnimg.cn/blog_migrate/e0b210e1c79d0dc5a8df55553341de72.png
既有适合小白学习的零底子资料,也有适合3年以上履历的小伙伴深入学习提升的进阶课程,根本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部门目次截图出来,每个节点内里都包含大厂面经、学习笔记、源码课本、实战项目、讲解视频,而且会连续更新!
如果你觉得这些内容对你有资助,可以扫码获取!!(备注:Android)
https://i-blog.csdnimg.cn/blog_migrate/ec7dcc880278d4dc031fd3795188d37c.jpeg 尾声

你不踏出去一步,永远不知道本身潜力有多大,万万别被这个社会套在我们身上的枷锁给捆住了,30岁我不怕,35岁我一样不怕,去做本身想做的事,为本身拼一把吧!不试试怎么知道你不行呢?
改变人生,没有什么捷径可言,这条路必要本身亲自去走一走,只有深入思考,不停反思总结,保持学习的热情,一步一步构建本身完整的知识体系,才是最终的制胜之道,也是步伐员应该承担的使命。
   附上:我们之前因为秋招收集的二十套一二线互联网公司Android口试真题(含BAT、小米、华为、美团、滴滴)和我本身整理Android复习笔记(包含Android底子知识点、Android扩展知识点、Android源码解析、计划模式汇总、Gradle知识点、常见算法题汇总。)
https://i-blog.csdnimg.cn/blog_migrate/6ccaf1c4de55ed6f9264ef2fb7f64689.png
《互联网大厂口试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码课本》点击传送门即可获取!
题汇总。)**
[外链图片转存中…(img-C99NObZ3-1712318847781)]
《互联网大厂口试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码课本》点击传送门即可获取!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 200行代码打造超越一线互联网公司的换肤架构(1),Android平台HTTPS抓包办理