android 开发中写过最多的代码估计就是findViewById了。自从大神JakeWharton开发出了ButterKnife,编码效率大大提升。8.4.0之前的版本在工程分多个模块的时候就不能使用了,后来大神继续修复轮子,在非主模块中我们需要用R2来代替。因为子模块中R不是final 修饰的,资源合并也会变更数值。最近要做组件化,本来使用最新版本的ButterKnife也没什么问题,偏偏我们项目中用的是7.0的旧版本,不支持分业务模块使用。升级版本吧,又有那么多要全局替换,当然也不是难事,不过就是想多思考一下。随便看看源码,其实原来大神要解决的子模块R文件没有final修饰,以及int数值合并后改变的问题是可以规避。只要生成文件不用数字常量,用引用就可以了。
先看看原来的生成类。 我们注意到类似view = finder.findRequiredView(source, 2131299940, “field ‘viewOrderStatusBar’”); 2131299940这都是用R.id.XXX对应的常量,子模块中这样写就行不通了,因为会变啊。。。
package com.tts.scenery.tkpay;
import android.view.View;
import butterknife.ButterKnife.Finder;
import butterknife.ButterKnife.ViewBinder;
public class SceneryPayFinishActivity$$ViewBinder<T extends com.tts.scenery.tkpay.SceneryPayFinishActivity> implements ViewBinder<T> {
@Override public void bind(final Finder finder, final T target, Object source) {
View view;
view = finder.findRequiredView(source, 2131299940, "field 'viewOrderStatusBar'");
target.viewOrderStatusBar = finder.castView(view, 2131299940, "field 'viewOrderStatusBar'");
view = finder.findRequiredView(source, 2131299744, "field 'tvStatusTitle'");
target.tvStatusTitle = finder.castView(view, 2131299744, "field 'tvStatusTitle'");
view = finder.findRequiredView(source, 2131297756, "field 'layoutStatusTitle'");
target.layoutStatusTitle = finder.castView(view, 2131297756, "field 'layoutStatusTitle'");
view = finder.findRequiredView(source, 2131299743, "field 'tvStatusDetail'");
target.tvStatusDetail = finder.castView(view, 2131299743, "field 'tvStatusDetail'");
view = finder.findRequiredView(source, 2131297754, "field 'layoutStatusDetail'");
target.layoutStatusDetail = finder.castView(view, 2131297754, "field 'layoutStatusDetail'");
view = finder.findRequiredView(source, 2131299386, "field 'tvInfo'");
target.tvInfo = finder.castView(view, 2131299386, "field 'tvInfo'");
view = finder.findRequiredView(source, 2131297632, "field 'layoutInfo'");
target.layoutInfo = finder.castView(view, 2131297632, "field 'layoutInfo'");
view = finder.findRequiredView(source, 2131296442, "field 'btn1' and method 'onClick'");
target.btn1 = finder.castView(view, 2131296442, "field 'btn1'");
view.setOnClickListener(
new butterknife.internal.DebouncingOnClickListener() {
@Override public void doClick(
android.view.View p0
) {
target.onClick(p0);
}
});
view = finder.findRequiredView(source, 2131296444, "field 'btn2' and method 'onClick'");
target.btn2 = finder.castView(view, 2131296444, "field 'btn2'");
view.setOnClickListener(
new butterknife.internal.DebouncingOnClickListener() {
@Override public void doClick(
android.view.View p0
) {
target.onClick(p0);
}
});
view = finder.findRequiredView(source, 2131297633, "field 'layoutInfoButtons'");
target.layoutInfoButtons = finder.castView(view, 2131297633, "field 'layoutInfoButtons'");
view = finder.findRequiredView(source, 2131297658, "field 'layoutMorePrivilege' and method 'onClick'");
target.layoutMorePrivilege = finder.castView(view, 2131297658, "field 'layoutMorePrivilege'");
view.setOnClickListener(
new butterknife.internal.DebouncingOnClickListener() {
@Override public void doClick(
android.view.View p0
) {
target.onClick(p0);
}
});
view = finder.findRequiredView(source, 2131297440, "field 'ivLoading'");
target.ivLoading = finder.castView(view, 2131297440, "field 'ivLoading'");
view = finder.findRequiredView(source, 2131299426, "field 'tvLoading'");
target.tvLoading = finder.castView(view, 2131299426, "field 'tvLoading'");
view = finder.findRequiredView(source, 2131297648, "field 'layoutLoading'");
target.layoutLoading = finder.castView(view, 2131297648, "field 'layoutLoading'");
view = finder.findRequiredView(source, 2131298461, "field 'promotionLV'");
target.promotionLV = finder.castView(view, 2131298461, "field 'promotionLV'");
view = finder.findRequiredView(source, 2131296443, "field 'mBtn1Old' and method 'onClick'");
target.mBtn1Old = finder.castView(view, 2131296443, "field 'mBtn1Old'");
view.setOnClickListener(
new butterknife.internal.DebouncingOnClickListener() {
@Override public void doClick(
android.view.View p0
) {
target.onClick(p0);
}
});
view = finder.findRequiredView(source, 2131296445, "field 'mBtn2Old' and method 'onClick'");
target.mBtn2Old = finder.castView(view, 2131296445, "field 'mBtn2Old'");
view.setOnClickListener(
new butterknife.internal.DebouncingOnClickListener() {
@Override public void doClick(
android.view.View p0
) {
target.onClick(p0);
}
});
view = finder.findRequiredView(source, 2131297634, "field 'mLayoutInfoButtonsOld'");
target.mLayoutInfoButtonsOld = finder.castView(view, 2131297634, "field 'mLayoutInfoButtonsOld'");
view = finder.findRequiredView(source, 2131296900, "field 'mDividerLine'");
target.mDividerLine = view;
}
@Override public void unbind(T target) {
target.viewOrderStatusBar = null;
target.tvStatusTitle = null;
target.layoutStatusTitle = null;
target.tvStatusDetail = null;
target.layoutStatusDetail = null;
target.tvInfo = null;
target.layoutInfo = null;
target.btn1 = null;
target.btn2 = null;
target.layoutInfoButtons = null;
target.layoutMorePrivilege = null;
target.ivLoading = null;
target.tvLoading = null;
target.layoutLoading = null;
target.promotionLV = null;
target.mBtn1Old = null;
target.mBtn2Old = null;
target.mLayoutInfoButtonsOld = null;
target.mDividerLine = null;
}
}
折腾了一下午,改写了常用的Bind,和OnClick等相关类,注解处理器,以及对用的代码生成插件。同样功能的类我都加C前缀做了区别。其中遇到的困难大概就是在不同模块时,插件要找到对应的包名做id的前缀,我就是从项目文件BuildConfig.java中找到APPLICATION_ID。大功告成。下面就是新的生成形式。
package com.tts.hybird.train.home.view;
import android.view.View;
import com.tts.trip.bind.CButterKnife.Finder;
import com.tts.trip.bind.CButterKnife.ViewBinder;
public class TrainSelectDateActivity$$CCViewBinder<T extends com.tts.hybird.train.home.view.TrainSelectDateActivity> implements ViewBinder<T> {
@Override public void bind(final Finder finder, final T target, Object source) {
View view;
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.tv_TitleBarText, "field 'tvTitleBarText'");
target.tvTitleBarText = finder.castView(view, com.tts.hybird.train.R.id.tv_TitleBarText, "field 'tvTitleBarText'");
view.setOnClickListener(
new com.tts.trip.bind.CDebouncingOnClickListener("com.tts.hybird.train.R.id.tv_TitleBarText") {
@Override public void doClick(
android.view.View p0,
java.lang.String p1
) {
target.onViewClicked(p0, p1);
}
});
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.tv_TitleBarTextSmall, "field 'tvTitleBarTextSmall'");
target.tvTitleBarTextSmall = finder.castView(view, com.tts.hybird.train.R.id.tv_TitleBarTextSmall, "field 'tvTitleBarTextSmall'");
view.setOnClickListener(
new com.tts.trip.bind.CDebouncingOnClickListener("com.tts.hybird.train.R.id.tv_TitleBarTextSmall") {
@Override public void doClick(
android.view.View p0,
java.lang.String p1
) {
target.onViewClicked(p0, p1);
}
});
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.iv_TitleBarBack, "field 'ivTitleBarBack'");
target.ivTitleBarBack = finder.castView(view, com.tts.hybird.train.R.id.iv_TitleBarBack, "field 'ivTitleBarBack'");
view.setOnClickListener(
new com.tts.trip.bind.CDebouncingOnClickListener("com.tts.hybird.train.R.id.iv_TitleBarBack") {
@Override public void doClick(
android.view.View p0,
java.lang.String p1
) {
target.onViewClicked(p0, p1);
}
});
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.iv_TitleBarRightBtn, "field 'ivTitleBarRightBtn'");
target.ivTitleBarRightBtn = finder.castView(view, com.tts.hybird.train.R.id.iv_TitleBarRightBtn, "field 'ivTitleBarRightBtn'");
view.setOnClickListener(
new com.tts.trip.bind.CDebouncingOnClickListener("com.tts.hybird.train.R.id.iv_TitleBarRightBtn") {
@Override public void doClick(
android.view.View p0,
java.lang.String p1
) {
target.onViewClicked(p0, p1);
}
});
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.tv_TitleBarRightText, "field 'tvTitleBarRightText'");
target.tvTitleBarRightText = finder.castView(view, com.tts.hybird.train.R.id.tv_TitleBarRightText, "field 'tvTitleBarRightText'");
view.setOnClickListener(
new com.tts.trip.bind.CDebouncingOnClickListener("com.tts.hybird.train.R.id.tv_TitleBarRightText") {
@Override public void doClick(
android.view.View p0,
java.lang.String p1
) {
target.onViewClicked(p0, p1);
}
});
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.layout_TitleBarRight, "field 'layoutTitleBarRight'");
target.layoutTitleBarRight = finder.castView(view, com.tts.hybird.train.R.id.layout_TitleBarRight, "field 'layoutTitleBarRight'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.root_title_rl, "field 'rootTitleRl'");
target.rootTitleRl = finder.castView(view, com.tts.hybird.train.R.id.root_title_rl, "field 'rootTitleRl'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.m_train_tv_pre_sale_day_count, "field 'mTrainTvPreSaleDayCount'");
target.mTrainTvPreSaleDayCount = finder.castView(view, com.tts.hybird.train.R.id.m_train_tv_pre_sale_day_count, "field 'mTrainTvPreSaleDayCount'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.m_train_layout_notice, "field 'mTrainLayoutNotice'");
target.mTrainLayoutNotice = finder.castView(view, com.tts.hybird.train.R.id.m_train_layout_notice, "field 'mTrainLayoutNotice'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.m_train_vs_cal_one, "field 'mTrainVsCalOne'");
target.mTrainVsCalOne = finder.castView(view, com.tts.hybird.train.R.id.m_train_vs_cal_one, "field 'mTrainVsCalOne'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.m_train_vs_cal_two, "field 'mTrainVsCalTwo'");
target.mTrainVsCalTwo = finder.castView(view, com.tts.hybird.train.R.id.m_train_vs_cal_two, "field 'mTrainVsCalTwo'");
view = finder.findRequiredView(source, com.tts.hybird.train.R.id.m_train_vs_cal_three, "field 'mTrainVsCalThree'");
target.mTrainVsCalThree = finder.castView(view, com.tts.hybird.train.R.id.m_train_vs_cal_three, "field 'mTrainVsCalThree'");
}
@Override public void unbind(T target) {
target.tvTitleBarText = null;
target.tvTitleBarTextSmall = null;
target.ivTitleBarBack = null;
target.ivTitleBarRightBtn = null;
target.tvTitleBarRightText = null;
target.layoutTitleBarRight = null;
target.rootTitleRl = null;
target.mTrainTvPreSaleDayCount = null;
target.mTrainLayoutNotice = null;
target.mTrainVsCalOne = null;
target.mTrainVsCalTwo = null;
target.mTrainVsCalThree = null;
}
}
新插件生成的代码。
public class TrainSelectDateActivity
extends TrainBaseActivity<TrainSelectDatePresenter>
implements ITrainSelectDateView {
@CBind("com.tts.hybird.train.R.id.tv_TitleBarText")
TextView tvTitleBarText;
@CBind("com.tts.hybird.train.R.id.tv_TitleBarTextSmall")
TextView tvTitleBarTextSmall;
@CBind("com.tts.hybird.train.R.id.iv_TitleBarBack")
ImageView ivTitleBarBack;
@CBind("com.tts.hybird.train.R.id.iv_TitleBarRightBtn")
ImageView ivTitleBarRightBtn;
@CBind("com.tts.hybird.train.R.id.tv_TitleBarRightText")
TextView tvTitleBarRightText;
@CBind("com.tts.hybird.train.R.id.layout_TitleBarRight")
LinearLayout layoutTitleBarRight;
@CBind("com.tts.hybird.train.R.id.root_title_rl")
RelativeLayout rootTitleRl;
@CBind("com.tts.hybird.train.R.id.m_train_tv_pre_sale_day_count")
TextView mTrainTvPreSaleDayCount;
@CBind("com.tts.hybird.train.R.id.m_train_layout_notice")
LinearLayout mTrainLayoutNotice;
@CBind("com.tts.hybird.train.R.id.m_train_vs_cal_one")
ViewStub mTrainVsCalOne;
@CBind("com.tts.hybird.train.R.id.m_train_vs_cal_two")
ViewStub mTrainVsCalTwo;
@CBind("com.tts.hybird.train.R.id.m_train_vs_cal_three")
ViewStub mTrainVsCalThree;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.m_train_activity_select_date)
CButterKnife.bind(this);
}
@COnClick({"com.tts.hybird.train.R.id.tv_TitleBarText", "com.tts.hybird.train.R.id.tv_TitleBarTextSmall", "com.tts.hybird.train.R.id.iv_TitleBarBack", "com.tts.hybird.train.R.id.iv_TitleBarRightBtn", "com.tts.hybird.train.R.id.tv_TitleBarRightText"})
public void onViewClicked(View view, final String idName) {
switch (idName) {
case "com.tts.hybird.train.R.id.tv_TitleBarText":
break;
case "com.tts.hybird.train.R.id.tv_TitleBarTextSmall":
break;
case "com.tts.hybird.train.R.id.iv_TitleBarBack":
break;
case "com.tts.hybird.train.R.id.iv_TitleBarRightBtn":
break;
case "com.tts.hybird.train.R.id.tv_TitleBarRightText":
break;
}
}
现在主模块和子模块可以无差别的使用,尽量依靠生成,改写时候要注意下。今天太晚了,就先不贴源码了