一、背景
在Android O版本之后,findViewById 函数现在返回的是 <T extends View>,所以以后 findViewById 就不需要强转了。如果项目中compileSdkVersion >= 26,使用findViewById就会提示警告,表示可以不用再写强转了。如下所示:
所以看到这部分的时候就觉得不舒服,而且AS代码区右侧会提示标黄的小警告,光标移上去会提示:Casting 'item.findViewById(R.id.xxx)' to 'TextView' is redundant.
故而觉得此事的解决对强迫症患者挺有必要的,而且也是代码规范迟早要做的事情。所以使用python编写了这个脚本工具。命名为afc.py (auto findViewById cut)。
二、分析
关于findViewById的用法,不外乎如下几类情况:
1.仅findViewById a. TextView tv1 = (TextView)findViewById(R.id.tv);//无空格 b. TextView tv2 = (TextView) findViewById(R.id.tv);//有空格 c. TextView tv3 = (TextView)root.findViewById(R.id.tv); d. TextView tv4 = (TextView) root.findViewById(R.id.tv); 正则1:\(\w+\)\s*(?=((\w+\.)?findViewById\(R\.id\.\w+\);)) 2.findViewById后set操作 e. ((TextView)findViewById(R.id.tv)).setText("text");//设置文字 f. ((TextView) findViewById(R.id.tv)).setOnClickListener(xxx);//设置点击 g. ((TextView)root.findViewById(R.id.tv)).setText(“text”); h. ((TextView) root.findViewById(R.id.tv)).setOnClickListener(xxx); 正则2:\(\(\w+\)\s*(\w+\.)?findViewById\(R\.id\.\w+\)\)(?=\.(setOnClickListener|set...)) 正则3:(\w+\.)?findViewById\(R\.id\.\w+\)
这里我将他们对应的正则表达式也给了出来。其中e和g是不能忽略强转的。后面的方法是特定的类型才具有的。
三、正则
正则1: \(\w+\)\s*(?=((\w+\.)?findViewById\(R\.id\.\w+\);))
(?=...)代表...是在这个匹配的前面
\s*代表空格个数0-n个
\(\w+\)代表()和英文字符
(\w+\.)?代表若干英文字符和点的组合有0-1个
其他就是字面意思。所以正则1匹配的就是a,b,c,d这些类型的行。
正则2:\(\(\w+\)\s*(\w+\.)?findViewById\(R\.id\.\w+\)\)(?=\.(setOnClickListener|set...))
这个就好理解多了。意思就是匹配f,h这些类型的行。只要在最后的setOnClickListener|set...里面不去包含setText就可以顺利排除这些不能忽略强转的用法了。
正则3:(\w+\.)?findViewById\(R\.id\.\w+\)
含义略。这个正则存在的意义就是替换正则2匹配的内容,比如:正则2匹配出来了((TextView)root.findViewById(R.id.tv)),正则3从这中间拿出root.findViewById(R.id.tv)。从而进行最终的文本替换。
四、脚本
#!/usr/bin/python # coding=utf-8 import os,re,fileinput,sys #根据文件扩展名判断文件类型 def endWith(s, *endstring): array = map(s.endswith,endstring) if True in array: return True else: return False def searchFiles(dirname): # 匹配该样式类型的行:(TextView)findViewById(R.id.tv); pattern1 = re.compile(ur'\(\w+\)\s*(?=((\w+\.)?findViewById\(R\.id\.\w+\);))') # 匹配该样式类型的行:findViewById(R.id.xxx) 或 root.findViewById(R.id.xxx) pattern3Str = ur'(\w+\.)?findViewById\(R\.id\.\w+\)\)' pattern3 = re.compile(pattern3Str) # 区分下面两类的行:setText的类型转换不能忽略,而setOnClickListener可以 # ((TextView)findViewById(R.id.tv)).setText("text"); # ((TextView) findViewById(R.id.tv)).setOnClickListener(xxx); # 可以忽略的加入下面数组 pattern2List = ['setOnClickListener'] # 匹配该样式类型的行 ((TextView) findViewById(R.id.tv)) 或 ((TextView)root.findViewById(R.id.tv)) pattern2Str = ur'\(\(\w+\)\s*' + pattern3Str + '(?=\.(' + '|'.join(pattern2List) + '))' pattern2 = re.compile(pattern2Str) count1 = 0 count2 = 0 for root,dirs,files in os.walk(dirname): for file in files: if endWith(file, '.java'): # 打开文件 filename = root + os.sep + file #绝对路径 filename = filename.replace("\\","\\\\") #将路径中的单反斜杠替换为双反斜杠,因为单反斜杠可能会导致将路径中的内容进行转义了,replace函数中"\\"表示单反斜杠,"\\\\"表示双反斜杠 # fileinput模块支持文件的边读边写 for line in fileinput.input(filename, inplace=True): # 返回一个含两个元素的元组,索引0为替换后的行,索引1为该行替换次数 result1 = re.subn(pattern1, "", line) line = result1[0] count1 = count1 + result1[1] # 找到符合模式2的要替换的部分 toreplace = re.search(pattern2, line) if toreplace != None: # 从要替换中找到要替换为的部分 replaced = re.search(pattern3, toreplace.group(0)) if replaced != None: # 执行最终的替换 result2 = re.subn(pattern2, replaced.group(0), line) line = result2[0] count2 = count2 + result2[1] # 将模式1和模式2的结果写回文件 print line.rstrip() print '成功!findViewById总转换数:%d个。' % (count1 + count2) print '模式1的替换数:%d个;' % count1 print '模式2的替换数:%d个。' % count2 if __name__ == '__main__': searchFiles(sys.argv[1])
五、使用及结果
使用方法非常简单,如下:
python afc.py (本地仓库路径)
例如:
代码修改完后,就去提pr集赞merge代码吧。遇到的问题:checkstyle的时候可能会有没有使用的import。
适用范围:凡compileSdkVersion >= 26的Android仓库同学均可使用。
相关推荐
自动生成FindViewById工具
用DOM4J 写的一个小工具类 避免麻烦的FindViewById的书写
一个根据布局文件自动生成findViewById代码的android studio插件
自动生成findviewbyid插件演示demo
该工具支持activity 对话框 view Fragment;支持链式操作 支持自动转换成子类而无需再次强制转换;支持常用属性的快速设置 支持点击事件的快速绑定 是不是很酷啊 "> 支持链式操作 vq id R id TextView1 text "I...
Android开发中经常使用 findviewbyid来找控件, 这个工具类可以方便的生成代码,减少代码的书写。
自动生成findViewById方法,可以选择是生成全局变量还是局部变量 链接 GsonFormat 快速将json字符串转换成一个Java Bean,免去我们根据json字符串手写对应Java Bean的过程。 链接 Json to Pojo generator json
需要导入jar包该工具类直接extends viewutils ,所有的findviewbyid都使用$来表示!
化你还得明白其中的基本原理,好了,下面开始正式的介绍自动化方法有哪些: 方法一:借助相关网站资源。 点击有惊喜 使用方法如图: 方法二:使用findviewbyme插件 第一步:安装插件 1.1打开Androidstudio中的...
这是可以让你告别繁杂的findViewById的一个实例,通过注解的方式来实现。
Android注解省去findviewbyid,在Android开发的过程中有很多控件都要findviewbyid的,这样太麻烦了。
一个简单的注解实现 findViewById 和 setOnClickListener 的例子
简单的注解类,代替android中的findViewById().
简单实现Android的findviewbyid IOC框架
简单的插件,允许一键创建Butterknife视图注射。减少findViewById()和setonclicktListener()重复代码量
自定义注解,实现了findViewById 和 OnCLIckListener 注解不会去新建一个OnClickListener对象,所有view都指向一个listener, 然后通过反射调用方法去执行
Android技术知识点:如何使用视图绑定来消除findViewById()
为了减少频繁的调用findViewById(R.id...),可以采用一些注入框架,可以简化自己的代码,让你更专注于实际的功能开发,butterknife就是这样的一个框架.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,...
AndroidFindView FindViewById无需转换类型进口 将其添加到项目库的末尾的build.gradle中: repositories { // ... maven { url " https://jitpack.io " }} 步骤2.在表单中添加依赖项 dependencies { compile ' ...
快速生成findviewbyid的插件.zip,A plugin for android developer, with the plugin you can generate "findViewById" code quickly.