<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
眾所周知,黃油刀 ButterKnife 已經廢棄了,並且已經不再維護了,而一些老專案估計還有一堆這樣的程式碼,相信大家多多少少都有過被 @BindView
或者 @OnClick
支配的恐懼,而如果想要一個頁面一個頁面的移除的話,工作量也是非常大的,而這也是筆者寫這個外掛的原因了(這裡不講解外掛開發的相關知識)。
注:由於每個專案的封裝的多樣性、以及 layout 佈局的初始化有各種各樣的寫法,還有涉及到一些語法語意的聯絡,程式碼無法做到精準轉換(後面會舉一些例子),所以外掛無法做到百分百轉換成功,在轉換後建議手動檢查一下是否出錯。
本文對於沒有外掛開發以及 PSI 基礎的人可能會看不下去,可以直接 github傳送門 跳 github 連結並 clone 程式碼執行,一鍵完成 ButterKnife 的移除並替換成 ViewBinding 。
目前僅支援 Java
語言,因為相信如果專案中使用的是 Kotlin
,那肯定首選 KAE
或者 ViewBinding
了(優選 ViewBinding ,如今 KAE 也已經被移除了)。
該外掛中目前對不同的類有不同的轉換方式
由於 Activity 與 Fragment 對於佈局的塞入是比較統一的,所以可以做到比較精準的轉換為 ViewBinding,而自定義 View 雖然佈局的寫法也各式各樣,但是筆者也儘量修改統一了,而 ViewHolder 與 Dialog 比較複雜,直接修改成 findViewById 比較不容易出錯(如果對自己的專案寫法的統一很有信心的,也可以按照自己專案的寫法試著修改一下程式碼,都改成 ViewBinding 會更好),畢竟誰也不希望修改後的程式碼一團糟是吧~
首先我們需要研究一下使用了 ButterKnife 的程式碼是怎麼樣的,如果是自己使用過該外掛的同學肯定是很瞭解、它的寫法的,而對於筆者這種沒使用過,但是公司的老專案中 java 的部分全是使用了 ButterKnife 的就很難受了,然後列出我們需要關心的註解。
這裡不做過多講解,畢竟又不是教大家怎麼用 ButterKnife 是吧~
上面說到的相關注解是我們需要移除的,我們要針對我們轉換的不同方式對這些註解標記的變數與方法做不同的操作。
除此之外,我們需要移除的還有 ButterKnife 的 import 語句、繫結語句 bind()、以及解綁語句 unbind()。我們需要增加的有:layout 對應的 ViewBinding 類的初始化語句、import 語句。
瞭解完這些我們就可以開始寫外掛啦~
對於程式碼的編寫筆者這裡也會分幾個步驟去闡述:分別是 PSI 相關知識、檔案處理、編寫舉例、注意事項。
PSI 的全稱是 Program Structure Interface(程式結構介面),我們要分析程式碼以及修改程式碼的話,是離不開 PSI 的,檔案傳送門
一個 Class 檔案結構分別包含欄位表、屬性表、方法表等,每個欄位、方法也都有屬性表,但在 PSI
中,總體上只有 PsiFile
和 PsiElement
PsiFile
是一個介面,如果檔案是一個 java 檔案,那麼解析生成的 PsiFile 就是 PsiJavaFile
物件,如果是一個 Xml 檔案,則解析後生成的是 XmlFile
物件PsiElement
種類有:PsiClass、PsiField、PsiMethod、PsiCodeBlock、PsiStatement、PsiMethodCallExpression 等等其中,PsiJavaFile、PsiClass、PsiField、PsiMethod、PsiStatement 是我們本文涉及到的,大家可以先去看看檔案瞭解一下。
我們在選擇多級目錄的時候,會有很多的檔案,而我們需要在這些檔案中篩選出 java 檔案,以及篩選出 import 語句中含有 butterknife 的,因為如果該類使用了 ButterKnife ,則肯定需要 import 相關的類。
篩選 java 檔案的這部分程式碼在這裡就不貼出來了,很簡單的,大家可以直接去看程式碼就好。
判斷該類是否需要進行 ButterKnife 移除處理:
/** * 檢查是否有import butterknife相關,若沒有引入butterknife,則不需要操作 */ private fun checkIsNeedModify(): Boolean { val importStatement = psiJavaFile.importList?.importStatements?.find { it.qualifiedName?.lowercase(Locale.getDefault())?.contains("butterknife") == true } return importStatement != null }
在這裡需要先來一些前置知識,我們的外掛在獲取檔案的的時候,拿到的是 VirtualFile
,當該檔案是java檔案時,VirtualFile 可以通過 PSI 提供的api轉換成 PsiJavaFile
,然後我們可以通過 PsiFile
拿到 PsiClass
,其中,importList 是屬於 PsiFile 的,而上面說到那些 PsiElement 都是屬於 PsiClass 的。
下面貼一下這部分程式碼:
private fun handle(vFile: VirtualFile) { if (vFile.isDirectory) { handleDirectory(vFile) } else { // 判斷是否是java型別 if (vFile.fileType is JavaFileType) { // 轉換成psiFile val psiFile = PsiManager.getInstance(project!!).findFile(vFile) // 轉換成psiClass val psiClass = PsiTreeUtil.findChildOfAnyType(psiFile, PsiClass::class.java) handleSingleVirtualFile(vFile, psiFile, psiClass) } } }
這裡只需要瞭解的就是新增了註釋的那幾行程式碼。
我們需要對 PsiClass 進行分類,這裡目前是隻能按照大部分人對類的命名習慣來進行分析,如果有一些特殊的命名習慣的人,可以把程式碼 clone 下來自行修改一下再執行。
private fun checkClassType(psiClass: PsiClass) { val superType = psiClass.superClassType.toString() if (superType.contains("Activity")) { ActivityCodeParser(project, vFile, psiJavaFile, psiClass).execute() } else if (superType.contains("Fragment")) { FragmentCodeParser(project, vFile, psiJavaFile, psiClass).execute() } else if (superType.contains("ViewHolder") || superType.contains("Adapter<ViewHolder>")) { AdapterCodeParser(project, psiJavaFile, psiClass).execute() } else if (superType.contains("Adapter")) { // 這裡的判斷是為了不做處理,因為adapter的xml屬性是在viewHolder中初始化的 } else if (superType.contains("Dialog")) { DialogCodeParser(project, psiJavaFile, psiClass).execute() } else { // 自定義View CustomViewCodeParser(project, vFile, psiJavaFile, psiClass).execute() } }
我們通過拿到 PsiClass 繼承的父類別的型別來進行判斷,這裡的不足是程式碼中只拿了當前類的上一級繼承的父類別的型別,並沒有去判斷父類別是否還有父類別,因為筆者認為只要命名規範,這就不是什麼大問題。舉個例子,如果有人喜歡封裝一個名為 BaseFragment 的實則是一個 Activity 的基礎類別,然後由 MainActivity 去繼承,那這個外掛就不適用了
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45