代码地址如下:
http://www.demodashi.com/demo/13504.html

问题

先来看一个正常的写法:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/tv_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="TEXT_VIEW"android:textSize="22sp"/><Buttonandroid:id="@+id/btn_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="BUTTON"/>
</LinearLayout>
public class StartActivity extends AppCompatActivity implements View.OnClickListener {private TextView tv_test;private Button btn_test;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_start);// init viewtv_test = findViewById(R.id.tv_test);btn_test = findViewById(R.id.btn_test);// init listenerbtn_test.setOnClickListener(this);tv_test.setText("Text changed!");}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_test:Toast.makeText(this, "click", Toast.LENGTH_SHORT).show();break;}}
}

以上的那些变量的定义、findViewById、setOnClickListener等等,写起来重复繁琐,我们下面就是要解决这些问题。

流行的解决方法

一、DataBinding
  • 没有解决setOnClickListener的问题,解决了也是很繁琐,需要设置各种Handler
public class StartActivity extends AppCompatActivity implements View.OnClickListener {private ActivityStartBinding mBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = DataBindingUtil.setContentView(this, R.layout.activity_start);mBinding.tvTest.setText("Text changed!");mBinding.btnTest.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_test:Toast.makeText(this, "click", Toast.LENGTH_SHORT).show();break;}}
}
二、ButterKnife
  • 还是要定义各种变量,当界面比较复杂的时候,代码看起来就没那么好看了
  • 在子module中使用会非常繁琐
public class StartActivity extends AppCompatActivity {@BindView(R.id.tv_test) TextView tv_test;@BindView(R.id.btn_test) Button btn_test;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_start);ButterKnife.bind(this);tv_test.setText("Text changed!");}@OnClick(R.id.btn_test)public void onClick(View v) {switch (v.getId()) {case R.id.btn_test:Toast.makeText(this, "click", Toast.LENGTH_SHORT).show();break;}}
}
三、直接使用 android:onClick=“onClick”
  • Fragment中设置此属性无效
  • 支持库中的组件如AppCompatButton等等,设置此属性无效

还有很多其它解决方法,这里就不一一列举了。

我的解决方法

  • 凡是设置了id的view,直接使用即可,变量名为id名
  • 凡是设置了android:onClick="onClick",在Activity中实现onClick方法即可
@BindActivity(value = R.layout.activity_main, layoutFilename = "activity_main", extendsClass = "android.support.v7.app.AppCompatActivity")
public class MainActivity extends MainActivity_ {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv_test.setText("Text changed!");}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_test:Toast.makeText(this, "click", Toast.LENGTH_SHORT).show();break;}}
}

实现过程

原理是配置一些注解,在编译期间生成相应文件,那些繁琐的代码就放在相应文件中了。

  • 定义注解

传入三个参数:布局文件ID、布局文件名、需要继承的类

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface BindActivity {/*** layoutResID*/int value();String layoutFilename();String extendsClass();
}
  • 继承AbstractProcessor类,在编译期间会回调到此类的process方法,在此方法中获取注解,生成相应文件
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {Project project = Project.init();Set<? extends Element> bindActivityElements = roundEnvironment.getElementsAnnotatedWith(BindActivity.class);for (Element element : bindActivityElements) {BindActivityHandler handler = new BindActivityHandler(mFiler, mElementUtils);handler.bind(project, element);}Set<? extends Element> bindFragmentElements = roundEnvironment.getElementsAnnotatedWith(BindFragment.class);for (Element element : bindFragmentElements) {BindFragmentHandler handler = new BindFragmentHandler(mFiler, mElementUtils);handler.bind(project, element);}return false;
}
  • 读取settings.gradle文件,获取所有module,在遍历module下面的所有布局文件

  • 解释布局文件,获取所有设置了id和设置了onclick的view

private void parserElement(Element element) {IdView view = null;for (Iterator<Attribute> it = element.attributeIterator(); it.hasNext(); ) {Attribute attribute = it.next();switch (attribute.getQualifiedName()) {case "android:id":view = new IdView();view.setType(element.getName());view.name = attribute.getValue().substring(5);idViews.add(view);break;case "android:onClick":// must set android:onClick="onClick"if (view != null && "onClick".equalsIgnoreCase(attribute.getValue())) {view.hasOnClick = true;}break;}}if (view != null) System.out.println(view.toString());
}
  • 根据注解找到对应的布局文件,生成对应的类文件

后会生成一个文件名类似MainActivity_的文件,和MainActivity在同一个目录,大致为build/generated/source/apt/debug/包名

@Override
public void bind(Project project, Element element) {String _package = getPackageName(element);String _class = getClassName(element);BindActivity bindActivity = element.getAnnotation(BindActivity.class);int layoutResID = bindActivity.value();String layoutFilename = bindActivity.layoutFilename();String extendsClass = bindActivity.extendsClass();Layout layout = project.getLayout(layoutFilename);if (layout != null) {try {JavaFileObject jfo = mFiler.createSourceFile(_package + "." + _class, new Element[]{});Writer writer = jfo.openWriter();StringBuilderHelper sb = new StringBuilderHelper();sb.line("package " + _package + ";");sb.line();sb.line("import android.os.Bundle;");sb.line("import android.support.annotation.Nullable;");sb.line("import android.view.View;");sb.line();sb.line("// Generated code, dot not edit!!!");sb.line();if (layout.hasOnClick()) {sb.line("public abstract class " + _class + " extends " + extendsClass + " implements View.OnClickListener {");} else {sb.line("public abstract class " + _class + " extends " + extendsClass + " {");}sb.line();sb.line____("protected final int layoutResID = " + layoutResID + ";");sb.line();sb.line____("protected View rootView;");for (IdView idView : layout.idViews) {sb.line____("protected " + idView.getType() + " " + idView.name + ";");}sb.line();sb.line____("@Override");sb.line____("protected void onCreate(@Nullable Bundle savedInstanceState) {");sb.line________("super.onCreate(savedInstanceState);");sb.line________("setContentView(layoutResID);");sb.line();for (IdView idView : layout.idViews) {sb.line________(idView.name + " = findViewById(R.id." + idView.name + ");");}sb.line();initOnClick(layout, sb);sb.line____("}");sb.line("}");writer.write(sb.toString());writer.flush();writer.close();} catch (IOException e) {e.printStackTrace();}}
}

使用方法

比如类为MainActivity,继承AppCompatActivity,布局文件为R.layout.activity_main

  • 设置类注解
@BindActivity(value = R.layout.activity_main, layoutFilename = "activity_main", extendsClass = "android.support.v7.app.AppCompatActivity")
  • 布局文件设置id属性和onClick属性
<Buttonandroid:id="@+id/btn_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="onClick"android:text="BUTTON"/>
  • MakeProject
  • 修改MainActivity继承MainActivity_即可

文件结构图

演示效果图

运行代码可能出现的问题

  • compileSdkVersion 27,可以改成你电脑中存在的SDK版本。

  • 这里用的是 gradle-4.4-all.zip,如果你用的是其它版本,那么可能会下载超级慢,建议改成你电脑中存在的gradle版本,改文件PermissionHelper/gradle/wrapper/gradle-wrapper.properties即可。

  • 其它问题可以直接联系我。一个完全摆脱findViewById的自动绑定库

代码地址如下:
http://www.demodashi.com/demo/13504.html

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

一个完全摆脱findViewById的自动绑定库相关推荐

  1. mixamo骨骼_Mixamo——在线三维人物角色骨骼自动绑定,上千动作库直接生成人物动画...

    Adobe在2015年的时候,完成了对Mixamo的收购,在其官网上,对Mixamo的介绍是:Animate 3D characters for games, film, and more(为游戏,电 ...

  2. arduino封装了一个无线串口模块LC12S的操作库

    前一段时间接触到一个比较好用的2.4G无线串口通信模块LC12S, 在淘宝上仅四五块钱,收发一体,比较好用. 我照着技术文档封装了这个设置操作的库 demo代码: #include <Ardui ...

  3. libgo高性能网络服务器,【开源】gnet: 一个轻量级且高性能的 Golang 网络库

    ![](https://ask.qcloudimg.com/http-save/1303222/sipe2g9n9h.png) # Github 主页 [https://github.com/panj ...

  4. 【开源推荐】gnet: 一个轻量级且高性能的 Go 网络库

    Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于事件驱 ...

  5. Gin 框架学习笔记(02)— 参数自动绑定到结构体

    参数绑定模型可以将请求体自动绑定到结构体中,目前支持绑定的请求类型有 JSON .XML .YAML 和标准表单 form数据 foo=bar&boo=baz 等.换句话说,只要定义好结构体, ...

  6. japid-controller自动绑定的数据类型

    参考文献:http://www.playframework.org/documentation/1.2.3/controllers 当参数名和HTTP请求中的参数名(即界面中的name)相同时,后台C ...

  7. Kimera:一个基于度量语义的SLAM开源库

    标题:Kimera:an Open-Source Library for Real-Time Metric-Semantic Localization and Mapping 作者:Antoni Ro ...

  8. 新JSON绑定库JSON-B发布公开预览版

    JSON-B这个有望添加到Java EE 8的JSON绑定库发布了公开预览版.该库以JSON Processing(不要同JSONP或JSON-with-padding混淆)为基础构建,旨在为诸如Ja ...

  9. JSBing-js自动绑定C++

    什么是JSB JSB是JavaScript binding的简称.Cocos2d-JS中使用的javascript引擎是Mozilla 的spidermonkey,而JSB绑定的目的就是让javasc ...

最新文章

  1. 祝福互动html页面,祝福.html
  2. 关于智能车竞赛总结 | 山东大学(威海) - 山魂五队
  3. 你的微服务敢独立交付么?
  4. android Camera2
  5. zzuli oj 1167逆转数(指针专题)
  6. SQL group by 和 order by 、where、having
  7. X5开发中buttongrounp对应contents组件切换时速度快点无效
  8. 超强!MDETR:基于Transformer的端到端目标检测神器!开源!
  9. Spring Boot 核心原理与源码解析 - 目录
  10. 表示数值的字符串 剑指offer
  11. java list 某个重复列_Java 开发的编程噩梦,这些坑你没踩过算我输
  12. 卸载WPS后office文档图标不能正常显示和WPS网盘图标无法删除
  13. 怎么用计算机直接截图,电脑图片截屏怎么截图
  14. 托福百日冲刺—词汇(14)
  15. 【Kotlin】FarawayPlayer
  16. 二级路由器设置为何要关闭DHCP服务
  17. java实验报告9 输入输出流
  18. 2021年煤矿安全监测监控模拟试题及煤矿安全监测监控理论考试
  19. 腾讯AI Lab「王者绝悟」亮相世界人工智能大会,展现「AI+游戏」全新可能
  20. 讯连科技威力导演20中文版

热门文章

  1. ado.net mysql 下载_ADO.Net连接Mysql
  2. 关于EXCEL相关类的一些函数解释
  3. MQTT进阶:web端远程控制LED灯
  4. MDK5中代码补全功能
  5. 【声传播】——角谱理论、模式理论及三维傅里叶变换
  6. oracle字符串使用函数,oracle函数大全-字符串处理函数
  7. ORA-39181: Only partial table data may be exported due to fine grain access control on OE.PURCHAS
  8. select下拉框option的样式修改
  9. Linux系统文件压缩与备份(5)
  10. centos7 重置root 密码