反思 系列博客是我的一种新学习办法的查验,该系列来历和目录请参看 这儿 。

概述

换肤功用 并非奇技淫巧,而是已非常遍及,特别当Android Q推出了 深色办法 之后,国内绝大多数干流运用都至javascript少供给了 日间夜间 两种办法。

关于无感的用户而言,这个功用实属鸡肋,但从别的一个视点上来说,这也是产品在雕琢 用户极致体会 过程中的一次查验,为实例化目标有几种办法不同情形下,不同偏好android/yunos的用户供给更多的选择性。

哔哩哔哩 为例,除了供给以上两种主题之外,还免费供给了布满 少女心 的粉色主题:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

从产品的前瞻性上来看,国内涵换肤功用的探求较国外是抢先的,抽象的来看待Android Q深色办法,也无非是新增一种主题算了,因而,开发者应该将视点放在更高的层级上:为产品供给一android的drawable类套完善的换肤方案,而非只是是 适配深色办法

想清楚这一点,开发者就不会将目光仅局限于实例化需求技术自身——关于整个换肤体系而言,涵盖了UI、产品、开发、实例化查验、运维等多名人物不同的重视点,而这些重视点究竟却都android下载依托研制协助做决议方案,举例如下:

  • UI:界说不同的UI组件不同的色彩特征,这些特征究竟在不同的主题下,代表不同的色彩(日间办法下标题是黑色,可是夜间办法下,标题应该是白色)。
  • 产品:界说换肤功用的事务流程,从简略的换肤主页,换肤的交互,到不同主题下的不同展现、付费战略等等。
  • 开发:供给换肤功用的研制才干。
  • 查验:保证换肤功用的安稳性,比方主动源码网站化查验和方便取色东西。android/yunos
  • 运维:保证线上问题的快速定位和及时处理。

除此之外,还有更多可以深化考虑的技术点,比方,跟着主题越来越多,必定导致A源码编辑器编程猫下载PK包体积的增大,是否有必要引进长途动态加载(do源码共享网wnload & install)的才干?凭借不同人物的视角,咱们可以android手机提前规划好前景,接下来的编码也就愈加遂心应手。

本文将针对 Android 运用整个换肤体系进行概括性的描绘,读者应抛开对 代码完毕的细节 的执著,从不同人物的需求去考虑,java怎样读一斑而知全豹 ,为产品打造出健旺有力的技术支撑。

一、界说UI标准Go

换肤标准的意图是什么?关于java难学吗UI规划实例化和开发人员而言,规划与开发都应该依据一致且无实例化是什么意思缺的标准之上进行,以APP为例:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

关于UI规划人员,在APP不同的主题google下,控件的色彩不再是java怎样读一个单一的值,而应该用一个通用的key来进行界说,如上图所示,「标题」的色彩,在日间应该是黑色#000000,而深色办法下则应googleplay该为白色#FFFFFF,同理,「次级标题」、「主布风光」、「分割线色彩」,都应该跟android下载着不同的主题下,对应不同的值。

实例化划人员在规划时,仅需求针对页面每一个公积金元素填充好对应的key,依据标准很java工作培训班清楚地完毕UI规划:

色彩Key 日间办法 深色办法 备注
skinPrimaryTextColor #000000 #FFFFFF 标题字体色彩
skinSecondaryTextColor #CCCCCC #CCCCCC 次级标题源码资本字体色彩
skinM宫颈癌ainBgColor #FFF源码编辑器手机版下载FFF #333333 页面主布风光
skinSecondaryBgColor #EEEEEE #java面试题000000 次级java怎样读布景、分隔android/yunos线布java怎样读风光android体系
其他更googleplay多…
skinProgressBarColor #000000 #FFFFFF 进度条色彩

这关于开发人员的功率进步愈加明显,开发者源码码头不再需求实例化一个类关心具体色彩的值,只需求将对应的coloandroid下载装置r填充到布局中即可:

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text宫颈癌="Handroid下载ello World"
androiGod:textColor="@color/skinPrimaryTextColor" />

二、构建产品化思想:皮肤包

怎样衡量一个开发人java言语员的才源码编辑器手机版下载能——对凌乱功用快速、安稳的交给?

假定只是单纯的认可这个理念,那么关于换肤功用的完毕反而简略了,以标题色彩skinPrimaryTextCojava工作培训班lor为例,我只需求声明两个color资源:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="skinPrimaryTextColor"&gtandroid手机;#000000</color>
<color name="skinPrimaryTextCo龚俊lor_Dark">#FFFFFF</colorjavascript>
</resources>

笔者成功脱节了凌乱的编码完毕,在Activity中我只需2行代码即可:

public void initView() {
if (isLightMode) {    // 日间办法
tv.setTextColor(R.color.skinPandroid/yunosrimaryTextColor);
} else {              // 夜间办法
tv.setTextColor(R.color.skinPrimaryTandroid什么意思extColor_Dark);
}源码之家
}

这种完毕并非一无可取,从完毕的难度而言,至少可以维护开发者为数不多的发囊。

当然,这种方案有「优化空间」,比方供给封装的东西办法 看似脱节 无尽的if-else

/**
* 获取当时皮肤下实在的color资源,悉数android手机color的获取都必须经过该办法。
**/
@ColorRes
public static int getColorRjava开发es(@ColorRes int colorandroid什么意思Res) {
// 伪代码
if (isLightMode) {     // 日间办法
return colorRes;    // skinPri源码网站maryTextColor
} else {               // 夜间办法
return colorRes + "_Dark";   // skinPrimaryTextColor_Dark
}
}
// 代码中运用该办法,设置标题和次级标题色彩
tv.setTextColor(SkinUtil.getColorRes(R.color.skinPrimaryTextColor));
tvSjava言语ubTitle.setTextColor(SkinUtil.getColorRes(R.color.skinSeco工商银行ndaryTextColor));

很明显,return colorRes +java工作培训班 "_Dark"这行代码作为int类型的返回值是不成立的,读者无需重视具体完毕,由于这种封装仍 未脱节粗笨的 if-else 完毕 的实质。

可以预见,跟着主题数量逐渐增多,换肤源码之家相关的代码越来越臃肿,最要害的问题是,悉数控件的相关色彩都强耦合于换肤相关代码自身,每个UI容器(Activity/Fragment/自界说Vie源码之家w)等需求追加Java代码手动设实例化servlet类反常置。

此外,当皮肤数量达到必定规划时,color资源的巨大必定影响到apk体积,因android体系此主题资源的动态加实例化是什么意思载发势在必行,实例化数组用户设备运用时默许只需一个主题,其它主题 按需下载和设备 ,比方淘宝:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

到了这儿,皮肤包 的概念应运而出,开发者需求将单个主题的色彩资源视为一个 皮肤包,在不同的主题下,对javascript不同的皮肤包进行加载和资源替换:

<!--日间办法皮肤包的colors.xml-->
<resources>
<color name="实例化目标有几种办法skinPrimaryT源码网站extColor">#000000<实例化需求/color>
...
</resources>
<!--深色办法皮肤包的colors.xml-->
<resources>
<color name=实例化目标"skinPrimaryTexjava工作培训班tColor">#FFFFFF</color>
...
</resources>

这样,关于事务代码而言,开发者不再需求重视具体是哪个主题,只需求按惯例的办法进行色彩的指定,体系会依据当时的色彩资源对View进行填充:

<!--当时切换到什么主题,体系就用对应的色彩值进行填充-->
<TextView
android:layout_width="wrap_content"
android:实例化layout_height="wrap_content"
android:text="实例化Hello World"
android:textColor="@color/skinPrimaryTextColor" /&javaeegt;

回到宫颈癌前期症状本末java言语节初步的问题,产品化思想也是一个优异的开发者不可或缺的才实例化是什么意思能:先依据需求罗列不同的完毕方案,做出对应的权实例化目标有几种办法衡,终究着手源码网站编码。

三、整合思路

现在停止,悉数都还停留在源码编辑器手机版下载需求提出和规划阶段,java怎样读跟着需求的清楚,技术难点逐一罗列在开发者面前。

1.动态改写机制

开发者源码编辑器手机版下载面对的第一个实例化servlet类反常问题:怎样完毕换肤后的 动态改写 功用。

以微信注册页面为例Android,手动切换到深色办法后,微信进行了页面的改写:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

读者不禁会问,动态改写的意义是什么 ,让当时页面重建或许APP重启不行吗?

当然可行,可是 不合理源码编辑器由于页面重建意味着页面情况的丢掉,用户无法接受一个表单页面已填信息被重置;而假定要补偿这个问题,对每个页面重建追加情况的保存(Activity.onSaveInstanceState()),在完毕的视点来看狗狗币,也是一个巨大的工程量。

因而动态改写势在必行——用户无论是在运用内切换了皮肤包,仍是手动实例化目标的关键字切换了体系的深色办法,咱们怎样将这个告知龚俊进行下发,保证悉数页面都完毕对应的改写呢?

2.保存悉数页面的Activity

读者知道,咱们可以经过Applicati狗狗币on.registerActivityLifecycleCallbacks实例化servlet类反常()办法观察到运用内悉数Activandroid体系ijava怎样读ty的生命周期,这也意味着咱们可以持有悉数的Activity

public class MyApp extends Application {
// 当时运用内的悉数Ac宫崎骏tivity源码之家
private List<Activity> mPages = new Array源码List();
@Override
pujava言语blic void onCreate() {
super.onCreate();
registerActivityLifecycleCallbaandroidstudio装置教程cks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityC源码编辑器reated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
mPages.add(activi实例化一个类ty);
}
@java工作培训班Override
public void onActivityDestroyed(@NonNull Activi源码共享网ty activity) {
mPages.remove(activity);
}
// ...省掉其它生命周期
});
}
}

有了悉数android平板电脑价格Activity的引证,开发Java者就可以在接到换肤告知的时分,第一时间查验让悉数页面的悉数View去更新换肤。

3.本钱问题

但巨大的疑团随之映入眼帘,关于控件而言,更新换肤这个概念自身并不存在实例化是什么意思

什么意思呢? 当换肤告知抵达时,我无规律TextView更新文字色彩,也无规律View更新布风光彩——它们都只是体系的控件,实行的都是最根底的逻辑,说白了,开发者根本无法进行编码。

有同学说,那我直接让整个页面的整个View树悉数View都悉数从头烘托可以吗?可以,可是又回到了初步的问题,那就是悉数java言语Vie实例化数组w自身的情况也被重置了(比方EditText的文字被清零),退一步讲,即使这一点可以被接受,那么整个View树的从头烘托也会极大影响功用。

那么,怎样尽或许的 节省页面动态改写的本钱

开发者期望,换肤发生时,只对指定控件的指宫颈癌前期症状定特征进行动态更新,比Android如,TextView只重视更新backgroundtextColorViewGroup源码年代重视background,其他的特征不需求重置实例化一个类和批改,将设源码编辑器编程猫下载备的每一分功用都利用到极致:

public interface SkinSupportable {
void updateSkin源码编辑器编程猫下载();
}
class SkinCompatT源码extView extends TextView imgoogleplements SkinSupp狗狗币ortable {
public void updateSkin() {
// 运用当时android什么意思最新的资源更新 background 和 textColor
}
}
class SkinCompatFrameLayout extejava面试题nds FrameLayout implemjava面试题ents SkinSupportable {
public void updateSkinandroid下载装置() {
// 运用当时最新的资源更新 background
}
}

如代码所示,SkinSupportable是一个接口源码,完毕该接口的类意味着都支撑动态改写,当换肤发生时,咱们只需求拿到当时的Activity,并经过遍历View树,让悉数SkinSupportable的完毕类都去实行updateSkin办法进行自身的改写,那么整个页面也就完毕了换肤的改写,一同不会影响View自身当时其他的特征。

当然,这也意味着开发者需求将惯例的控件进行一轮掩盖性的封源码资本装,并供给出对应的依托:

imAndroidplementation 'skin枸杞.support:skin-support:1.0.0'                   // 根底控件支撑,比方SkinCompatTextView、SkinCompatFrameLay源码编辑器out等
implementation 'skin.su实例化类pport:skin-support-cardview:1.0.0'          // 三方控件支撑android下载装置,比方SkinC源码网站ompatCardView
implementation 'skin.support:skin-support-constraint-layo源码共享网ut:1.0.0' // 三方控件支撑,比方android是什么手机牌子SkinCompatConstraintLayout

从长期来看,针对实例化控件逐一封装,供给可组合选择的依托,关于换肤库的规划者而言,库自身的开发本钱其实并不高。

4.牵一发而动全身

但担任事务开发的开发者叫苦连天。

按照现在的规划,岂不是工程的xml文件中悉数控件都需求从头进行替换?

<!--运用前-->实例化需求
<android是什么手机牌子Text宫崎骏View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:textColojava工作培训班r="@color/skjava初学inPrimaryTextColor" />
<!--需求替换为-->
<skin.support.Sk实例化一个类inCompatTextjava开发View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
andandroid下载roid:text="Hello World"
android:textColo实例化目标有几种办法r="@color/skinPrimaryTextColor" />

从另一个视点来看,这又是额定的本钱,假定哪一天想要除去或许替换换肤库,那么实例化需求无异于一次新的重构。

因而规划者需求尽量避免类似 牵一发而动全身 的规划,最好是让开发者无感知的感受到换肤库的 动态更新

5.着手点: LayoutInflater.Factory2

LayoutInflater 不了解的读者,可以参看笔者的 这篇文章 。

了解Lay实例化目标是什么意思outInflater的读者应该知道,在解析xml文件并实例java难学吗View的过程中,LayoutInflater经过自身的Factory2接口,将根底android/yunos控件阻挠并创立成对应的AppCompatXXXView,既避免了反射创立View对功用的影响,也保证了向下的兼容性:

switch (name) {
// 解析xml,根底组件都通android什么意思过new办法进行创立
case "TextViJavaew":
view =android是什么手机牌子 new AppCompatTextView(c实例化目标是什么意思ontext, attrJavas);
break;
case "ImageVie枸杞w":Java
view = new AppCompatImagjava面试题eView(context, attrs);
break;
case "Button":
view = new AppCompatButton(context, attrs);
break;
case "EditTandroid下载装置ext":实例化是什么意思
view = new AppCompatEdit实例化servlet类反常Text(context, attrs);
break;
// ...
default:
// 其他经过反射创立
}

一图以蔽之:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

因而,LayoutInflater自身的完毕思路为咱们供给了一个非常好的着手点,咱们只需求对这段逻辑进行阻挠,将控件的实例化托付给换肤库即可:

反思 | 敞开B站少女心形式,探求APP换肤机制的规划与完成

如图所示,咱们运用SkinCompatViewInflater实例化目标是什么意思阻挠替换了体系LayoutInfl宫崎骏ater自身的逻辑,以CardView为例,解析标签时,将CardView生成的逻辑托付给android的drawable类下面的依托库,假定工程中android是什么手机牌子增加了对应的依托,那么就能生成对应的SkinCompatCardView,其天然支撑了动态换肤功用。

当然,这悉数逻辑的完毕,来历于工程增加对应的依托,然后在APP启动时进行初始化:

implementation 'skin.android下载support:skin-support:1.0.0'
implementation 'skin.support:skin-support-cardview:1.0.0'
// implementation 'skin.support:skin-support-constraint-layout:1.0.0'  // 未增加ConstraintLayout换肤支撑
// App.onCreate()
SkinCompatManager.withApplication(this)
.addInflater(new SkinAppCompa实例化需求tViewInflater())   // 根底控件换肤
.addInflater(n狗狗币ew SkinCardViewInflater())        // cardView
//.addInflater(new SkinConstraintViewInflater())   // 未增加ConstraintLayout换肤支撑
.init();

Constrai实例化是什么意思ntLayout为例,当没有对应的依托时(),则会默许经过反射进行结构,生成标签自身对应的ConstraintLa实例化需求yout,其自身由于未完毕SkinSupportable,天然不会进行换肤更新。

这样,库的规划者为换肤库供给了足够的java怎样读灵活性,既避免了对现有工程大刀阔斧的批改,又保证极低的运用和搬家本钱,假定我期望 移除 或许实例化是什么意思 替换 换肤库,只需求删去build.gradle中的依托和A实例化目标有几种办法pplicationgoogleplay中初始化的代码就可以了。

四、深化性讨论

接下来笔者将针对换肤库自身更多细节进行深化性的讨论。

1、皮肤包加载战略

战略办法 在换肤库的规划过程中也有非常超卓的表现。

关于不同android下载的皮肤包而实例化一个类言,其 加载、设备的战略理应是不同的 ,举例来说:

  • 1、每个A源码交易网站源码PP都有一个默许的皮肤包(一般是日宫颈癌间办法),战略需求设备后立即对其进行加载;
  • 2、假定皮肤包是长途的,用户点击切换皮肤,需求从长途拉取,android体系下载成功java言语后进行设备加载;
  • 3、皮肤包下载设备成功,之后应该从本地SD卡进行加载;
  • 4、其他自界说加载战略,比方长途的皮肤包有加密,本地加载后解密等。

因而,规划者应将皮肤包的加载和设备抽象为一个SkinLoaderStrategy接口,便于开发者更便利和灵活性的按需装备。

公积金外,由于加载实例化目标行为自身极大或许是耗时操作,java工作培训班因而应该操控好线程的调度,并及时经过界说SkinLoadejavaeerListener回调,对加载的进度和效果进行及时的告知:

/**
* 皮肤包加载战略.
*/
public interface SkinLoaderStrategy {
/**
* 加载皮肤包.
*/
String loa宫崎骏dSkinInBackground(Context context, String skinName, SkinLoaderListener listener);
}
/**
* 皮肤包加载监听.
*/
public interface SkinLoaderListener {
/*宫颈癌*
* 初步加载.
*/
void onStart();
/**
* 加载成功.
*/
void onSuccess();
/**
* 加载失利.
*/
void onFailed(String errjava初学Msg);
}

2、进一步节省功用

上文中,笔者说到,由于持有了全java工作培训班部的Activity的引证,所以换肤库在换肤后,可以查验让实例化类悉数页面的悉数View去更新换肤。

实际上「更新悉数页面动」一般是没必要的,更合理的办法是供给一个可实例化装备项,换肤枸杞成功时,默许只改写前台的Activity,其它源码码头页面在onResume实行后再java工作培训班更新java怎样读,这样可以大幅度降低烘托带来的功用影响。

此外,每次换肤重复的遍历View树进行改写也是一个耗时的操作,可以经过在L源码之家ayoutInflater创立View树的一同,将完毕了SkinSupportableView存在页面所属的一个调会集,当换肤发生时,只需求针对调会集的View进行更新即可。

终究,可以将上述文字中的ActivityView都经过弱引证去持有,以降低内存走宫颈癌前期症状漏的或许。

3、供给图片资源的换肤才干

已然color资源可以支撑换肤,drawable资源不移至理也应该供给支撑,这样页面的展现可以androidstudio装置教程愈加多元化,一般这种场景运用于页面的布景图,对此读者可以参看淘宝APP的换肤功用效果:

资源Key 日间办法 深色办法 备注
skinPrimaryTextColor #000000 #FFFFFF 标题字体色彩
skinSecondaryTextCojavaeelor #CCCCCC #CCCCCC 次级标题字体色彩
skinMainBgDrawable A图片 B图片 实例化servlet类反常面主布景图
skinProgressBarDrawable C动画 D动画 加载框动画
其他源码码头更多…

小结

小结并不是总结,还有更多内容可以扩展,比方:

  • 1、Android体系中Resources类是怎样完毕资源的替换的,换肤库中又做了哪些处理?
  • 2、LayoutInflater源码中清楚表明,一java言语LayoutInflater只能设置一次setFactory2(),否则会抛出异常,那么,换肤库是在哪个机遇进行Factory2的注入的呢,为什么要这样规划?
  • 3、怎样依据需求进一步扩展换肤库的功用,比方供给单页面不换肤的支撑,Java以及供给多个页面运用不同皮肤包的支撑?
  • 4、怎样供java工作培训班应更多查验阶段、运维阶段可以利用的东西?
  • 5、截止笔者发稿时,2021 Google IO 大会上又提出了狗狗币实例化需求的UI规划理念 Material You,将 主题 的概源码编辑器手机版下载念从APP上升到了整个操作体系,其关于现有的换肤功用是否有新的影响?

完毕实例化目标是什么意思没有结尾,开发者可以做到的是经过不断多方位的反思,为产品供给展现更多价实例化值的可宫颈癌能性,从而更进一步,完毕自身专业才干阶段性的跨过。

感谢

本文规划思路的建立,参看了GitHub上现在star数量最多的换肤库 AJavandroid-skin-support , 感谢作者 ximsfei 为开发者供给了这么优异的规划。

还要感谢 哔哩哔哩淘宝微信 多个优异的运用为本文供给了多种换肤宫颈癌功用的狗狗币展现。

再次感谢。


关于我

Hello,我是 却把清梅嗅 ,假定您实例化是什么意思觉得文章对您有价值,欢迎 ❤️,也欢迎重视我的 博客 或许 GitHub。

假定您觉得文章还差了那实例化么点东西,也请经过 重视 敦促我写出更好的文章——假设哪天我前进了呢?

  • 我的Android学源码编辑器编程猫下载习系androidstudio装置教程
  • 关于文章纠错
  • 关于知识付费
  • 关于《反思》系列