`

自动化findViewById缩减工具

阅读更多

一、背景

在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工具

    本文将深入探讨"自动生成FindViewById工具"的相关知识点,以及如何利用它来提升开发效率。 首先,`findViewById`是Android SDK中的一个方法,存在于`View`类中。它的主要作用是通过控件的ID在当前视图层次结构中...

    避免枯燥的FindViewById的工具类

    使用这个工具类,我们可以在初始化时一次性解析整个布局,然后在需要时通过`ViewFinder.findViewById`快速获取视图,大大减少了代码量和冗余。例如: ```java ViewFinder finder = new ViewFinder(this, R.layout....

    Android-一个根据布局文件自动生成findViewById代码的androidstudio插件

    总之,FindViewHelper这类插件是Android开发者的好帮手,它们通过自动化代码生成来提高开发效率,降低了手动编写`findViewById`的负担。如果你是一名Android开发者,掌握如何有效地使用这类工具将极大地提升你的开发...

    自动生成findviewbyid插件演示demo

    自动生成findviewbyid插件演示demo

    findViewById的快捷工具类

    该工具支持activity 对话框 view Fragment;支持链式操作 支持自动转换成子类而无需再次强制转换;支持常用属性的快速设置 支持点击事件的快速绑定 是不是很酷啊 "&gt; 支持链式操作 vq id R id TextView1 text &quot;I...

    告别findViewById的Demo

    在Android中,我们可以通过使用注解处理器来自动化findViewById的过程。 在这个Demo中,可能会使用到如Butter Knife、ViewBinding或Jetpack的ViewInjector等库。这些库都提供了注解,比如@BindView,开发者可以在...

    Android findviewbyId代码生成器

    总之,`Android findViewById 代码生成器`是提升Android开发效率的重要辅助工具,通过自动化的方式减少重复劳动,使开发者能更专注于核心业务的实现,从而提高整体项目开发的效率和质量。在实际使用中,选择一个稳定...

    Android代码-Android-Studio-Plugins-cn

    自动生成findViewById方法,可以选择是生成全局变量还是局部变量 链接 GsonFormat 快速将json字符串转换成一个Java Bean,免去我们根据json字符串手写对应Java Bean的过程。 链接 Json to Pojo generator json

    安卓findviewbyid简写

    需要导入jar包该工具类直接extends viewutils ,所有的findviewbyid都使用$来表示!

    注解-findViewById

    总的来说,“注解-findViewById”是一个提高Android开发效率和代码可读性的实践,通过使用注解工具库,我们可以避免编写繁琐的视图查找代码,使我们的应用更加模块化和易于维护。开发者可以根据项目需求选择合适的...

    android自动生成findviewbyid,省时又省力!!!

    虽然自动化工具能显著提高开发速度,但对于初学者而言,理解`findViewById`的基本原理至关重要。学习如何手动编写`findViewById`可以帮助你更好地理解视图层级、活动(Activity)和布局管理器等Android基础知识。因此...

    一个简单的注解实现 findViewById 和 setOnClickListener 的例子

    在这个例子中,我们将创建自定义注解来自动处理findViewById和setOnClickListener的绑定,从而减少手动操作。 首先,我们需要创建一个注解处理器。注解处理器是一个在编译期间运行的Java类,它会检查源代码中特定...

    Android注解省去findviewbyid

    这些工具的使用能够显著提升代码的可读性和可维护性,减少了因手动操作`findViewById`可能导致的错误。 总结来说,Android注解的使用,尤其是像Butter Knife这样的库,可以极大地优化开发流程,提高效率,使代码...

    简单实现Android的findviewbyid IOC框架

    此外,还可以考虑使用注解处理器和反射技术来进一步自动化视图注入过程,如Butter Knife或Dagger等成熟的DI库。 总之,通过实现一个简单的IOC框架,我们可以改善Android应用的代码结构,减少`findViewById`的使用,...

    Android技术知识点:如何使用视图绑定来消除findViewById()

    在Android开发中,`findViewById()`方法长久以来一直是布局与代码之间建立联系的桥梁。然而,随着版本的更新,Google引入了一种新的特性——视图绑定(View Binding),它旨在简化UI元素的引用,提高代码的可读性和...

    ButterknifeZelezny

    简单的插件,允许一键创建Butterknife视图注射。减少findViewById()和setonclicktListener()重复代码量

    自定义注解实现findviewbyid 和 setOnclick

    自定义注解,实现了findViewById 和 OnCLIckListener 注解不会去新建一个OnClickListener对象,所有view都指向一个listener, 然后通过反射调用方法去执行

    安卓开发框架工具类相关-为了减少频繁的调用findViewById(R.id...)可以采用一些注入框架可以简化自己的代码让你更专注于实际的功能开发butterknife就是这样的一个框架.rar

    为了减少频繁的调用findViewById(R.id...),可以采用一些注入框架,可以简化自己的代码,让你更专注于实际的功能开发,butterknife就是这样的一个框架.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,...

    Android中findViewById返回为空null的快速解决办法

    这样可以避免在视图控件初始化阶段调用findViewById方法,导致返回为空null。 Android中findViewById返回为空null的快速解决办法可以通过使用LayoutInflater来inflate视图控件,然后使用findViewById方法来获取视图...

    AndroidGUI27中findViewById返回null的快速解决办法

    AndroidGUI27中findViewById返回null的快速解决办法 AndroidGUI27中findViewById返回null的快速解决办法是Android应用开发中常见的问题。findViewById是Android中获取界面元素对象的方法,但是有时候它会返回null,...

Global site tag (gtag.js) - Google Analytics