配置)
寫(xiě) Java/Kotlin 寫(xiě)了有幾年Android Studio 里的 import 管理一直是一個(gè)容易被忽略、但體驗(yàn)反饋極快的細(xì)節(jié)。項(xiàng)目進(jìn)入中后期一個(gè)文件被多人改過(guò)頂部 import 區(qū)長(zhǎng)出一堆根本用不到的類(lèi)引用看著礙眼review 的時(shí)候更是浪費(fèi)時(shí)間。這篇就把 Android Studio 里清理未使用 import 的方法從頭到尾梳理一遍單文件怎么清、多文件怎么清、怎么配置讓它自動(dòng)清以及清理過(guò)程中容易踩的坑。不管你是剛?cè)胄羞€是維護(hù)老項(xiàng)目這份清單都能直接用得上。1. 為什么必須較真未使用 import 帶來(lái)的連鎖反應(yīng)1.1 警告雖小閱讀成本卻高很多人覺(jué)得未使用的 import 不是編譯錯(cuò)誤放著不管也不影響功能。這句話對(duì)但只說(shuō)對(duì)了一半。它不影響 APK 運(yùn)行卻實(shí)實(shí)在在影響人讀代碼的效率。我維護(hù)過(guò)一個(gè)中型項(xiàng)目某個(gè)業(yè)務(wù)文件被迭代了兩年打開(kāi)一看import 區(qū)占了小半個(gè)屏幕里面至少三分之一是已經(jīng)不再使用的類(lèi)引用。新同事接手時(shí)第一件事往往是猜測(cè)這些 import 對(duì)應(yīng)的功能還在不在。比如看到一個(gè)對(duì)接第三方支付 SDK 的 import會(huì)以為這里還有支付邏輯結(jié)果全局搜索根本沒(méi)有使用點(diǎn)時(shí)間就這么浪費(fèi)了。更麻煩的是同名類(lèi)的誤導(dǎo)。Android 開(kāi)發(fā)里經(jīng)常出現(xiàn)工具類(lèi)、日期類(lèi)重名的情況比如自己項(xiàng)目里的 DateUtils 和引用庫(kù)里的 DateUtils 同時(shí)存在。如果 import 區(qū)殘留著舊類(lèi)后來(lái)者在閱讀代碼時(shí)很容易把使用點(diǎn)歸錯(cuò)類(lèi)輕則理解偏差重則改錯(cuò)地方。未使用 import 在 IDE 里是 Warning 級(jí)別的提示默認(rèn)在編輯器的 Problems 面板里能看到。它不會(huì)像 Error 一樣攔截你但累積多了Problems 面板被一堆無(wú)關(guān)警告淹沒(méi)真正的隱患反而被掩蓋。這也是我建議把它清掉的原因之一保持警告列表的干凈才能讓 IDE 在你需要的時(shí)候給你真正有用的提示。1.2 合并沖突與評(píng)審噪音多人協(xié)作的項(xiàng)目里import 區(qū)還是合并沖突的高發(fā)地帶。原因很簡(jiǎn)單import 集中在文件頂部?jī)蓚€(gè)分支各自新增了一個(gè)類(lèi)時(shí)Git 大概率會(huì)把兩處改動(dòng)識(shí)別成同一塊區(qū)域的沖突。保持 import 有序并且及時(shí)清理并不能完全消滅這類(lèi)沖突但能顯著降低它的頻率。如果每次都把 import 整理成標(biāo)準(zhǔn)順序、只保留當(dāng)前用到的至少不會(huì)因?yàn)橐欢褵o(wú)效 import 的存在讓 diff 變得沒(méi)法看。代碼評(píng)審時(shí)這也是個(gè)體驗(yàn)問(wèn)題。一次改動(dòng)只有幾十行核心邏輯import 區(qū)域卻刪了十幾行、改了幾十行評(píng)審人需要額外確認(rèn)每一個(gè)變化。雖說(shuō) Optimize Imports 的改動(dòng)大多是機(jī)械性的但在嚴(yán)格的團(tuán)隊(duì)流程里這種噪音會(huì)讓 review 變得痛苦也容易掩蓋真正的邏輯變更。1.3 IDE 索引與補(bǔ)全體驗(yàn)編譯速度上未使用 import 對(duì) javac 的影響其實(shí)微乎其微但不代表沒(méi)有代價(jià)。Android Studio 的代碼補(bǔ)全、錯(cuò)誤高亮、跳轉(zhuǎn)定義等功能都依賴(lài)符號(hào)索引import 區(qū)域里堆了太多無(wú)效引用索引和分析的開(kāi)銷(xiāo)會(huì)變大。最直觀的體驗(yàn)是你在按 Ctrl空格 補(bǔ)全類(lèi)名時(shí)候選列表里可能混入來(lái)自未使用 import 的干擾項(xiàng)。這類(lèi)情況在大型項(xiàng)目里更明顯。把 import 清理干凈補(bǔ)全候選列表更貼近當(dāng)前文件的真實(shí)依賴(lài)開(kāi)發(fā)時(shí)的流暢度會(huì)好一些。2. 單個(gè)文件的清理快捷鍵一梭子搞定2.1 主力快捷鍵與菜單路徑Android Studio 清理單個(gè)文件未使用 import 的核心操作叫 Optimize Imports是 IntelliJ 系 IDE 的老牌功能??旖萱I是Windows / LinuxCtrl Alt OmacOSControl Option O操作對(duì)象是當(dāng)前打開(kāi)且聚焦的編輯器文件。按一下IDE 會(huì)做三件事刪除未使用的 import把剩下的 import 按字母序重新排列按配置把同一包下的類(lèi)合并到一條 import 語(yǔ)句里。整個(gè)過(guò)程是即時(shí)的文件里所有 import 相關(guān)的整潔工作一次完成。如果你不習(xí)慣快捷鍵菜單路徑是 Code - Optimize Imports。對(duì)剛上手的人我更推薦先記快捷鍵因?yàn)樗彀亚謇韯?dòng)作變成肌肉記憶之后你會(huì)在提交代碼前順手按一下。這里有個(gè)需要注意的點(diǎn)Optimize Imports 不只是刪除未使用的類(lèi)它還會(huì)重排 import 順序。如果你當(dāng)前文件里的 import 本來(lái)就是亂的這個(gè)功能可以一并解決但如果團(tuán)隊(duì)對(duì) import 順序有特殊要求比如靜態(tài) import 必須放在最前面那就需要提前在 Code Style 里配置好跳過(guò)配置直接按快捷鍵可能會(huì)把順序整理成默認(rèn)結(jié)構(gòu)和團(tuán)隊(duì)規(guī)范不一致。配置方法后面專(zhuān)門(mén)講。2.2 只刪一個(gè) import 的情況有些場(chǎng)景你并不想全場(chǎng)清理只想刪掉某一條多余的 import。比如你在調(diào)試一個(gè)和第三方庫(kù)相關(guān)的 bug希望盡量少改動(dòng)文件內(nèi)容只移除確認(rèn)無(wú)效的那一行。最常用的做法是把光標(biāo)放在 import 那一行按 Alt Enter在彈出的菜單中選擇 Remove unused import。編輯器左側(cè)的燈泡圖標(biāo)也是同樣的入口。這種方式的好處是改動(dòng)最小、可控性最強(qiáng)缺點(diǎn)是效率低適合偶爾用一下不適合集中清理。我自己的習(xí)慣是日常開(kāi)發(fā)隨手清理用單個(gè) import 的快捷操作提交代碼前統(tǒng)一做一次整體的 Optimize Imports保證 import 區(qū)整體干凈且有序。兩種方式各有適用場(chǎng)景看你當(dāng)下的需求。2.3 快捷鍵沖突排查快捷鍵失效是很多人第一次接觸這個(gè)功能時(shí)遇到的問(wèn)題。最常見(jiàn)的原因是組合鍵被系統(tǒng)或者輸入法占用。比如在 Windows 上Ctrl Alt O 這類(lèi)組合鍵偶爾會(huì)被第三方輸入法組件用來(lái)切換中英文模式部分 Android 設(shè)備的廠商驅(qū)動(dòng)也可能攔截。因?yàn)?Android Studio 本身是開(kāi)源的 IDE 內(nèi)核第三方插件同樣會(huì)給這個(gè)快捷鍵掛上自己的動(dòng)作。排查方法很直接打開(kāi) Settings - Keymap在搜索框輸入 Optimize Imports看右側(cè)顯示的綁定是什么。如果發(fā)現(xiàn)快捷鍵綁定的動(dòng)作不是預(yù)期的或者有多個(gè)動(dòng)作共享同一個(gè)快捷鍵可以右鍵這個(gè)條目選擇 Add Keyboard Shortcut 重新設(shè)置一個(gè)自己順手的組合比如 Ctrl Shift O。我個(gè)人的做法是直接改成一個(gè)不會(huì)沖突的組合鍵一勞永逸避免每次換一臺(tái)機(jī)器都要重新適應(yīng)。3. 批量清理整個(gè)模塊文件多也不用慌3.1 Project 面板批量操作單個(gè)文件清理解決的是點(diǎn)狀問(wèn)題但真實(shí)項(xiàng)目里未使用 import 往往散布在幾十個(gè)甚至上百個(gè)文件里。一個(gè)個(gè)打開(kāi)再按快捷鍵效率太低這時(shí)候需要批量處理。在 Project 面板中選中一個(gè)包目錄、多個(gè)文件、甚至整個(gè)模塊目錄右鍵菜單里會(huì)出現(xiàn) Optimize Imports 選項(xiàng)。點(diǎn)擊后IDE 會(huì)彈出一個(gè)確認(rèn)對(duì)話框顯示即將處理的文件范圍確認(rèn)后對(duì)所有選中文件統(tǒng)一執(zhí)行清理和排序。實(shí)測(cè)下來(lái)這個(gè)操作對(duì)中型模塊幾十個(gè)文件基本是秒級(jí)完成大型模塊幾百上千個(gè)文件也只需要幾秒鐘。處理過(guò)程中底部進(jìn)度條會(huì)顯示當(dāng)前掃描到的文件如果項(xiàng)目里有生成代碼目錄比如 build 目錄下的自動(dòng)生成文件建議在操作前先把它們從選擇范圍里排除掉或者用文件類(lèi)型過(guò)濾避免無(wú)意義的改動(dòng)。選中整個(gè)模塊目錄批量處理時(shí)改動(dòng)量會(huì)非常大。我之前對(duì)一個(gè)幾百文件的模塊直接跑了一次Git 狀態(tài)里瞬間多了一百多個(gè)改動(dòng)文件。好處是代碼確實(shí)干凈了壞處是這次提交的可讀性非常差而且一旦中間有文件清理錯(cuò)了回滾成本也高。3.2 批量操作前的準(zhǔn)備和回滾策略批量清理 import 前我的標(biāo)準(zhǔn)流程是先確認(rèn)當(dāng)前分支處于干凈狀態(tài)至少保證改動(dòng)都能被 Git 追蹤然后從模塊下最核心的源碼目錄開(kāi)始處理不要第一次就把所有目錄全部勾選處理完馬上編譯一次確認(rèn)沒(méi)有因?yàn)檎`刪導(dǎo)致編譯錯(cuò)誤。如果清理之后發(fā)現(xiàn)某些文件的改動(dòng)不是預(yù)期結(jié)果最直接的辦法是用 Git 的 checkout 命令回滾指定文件而不是一個(gè)個(gè)手動(dòng)恢復(fù) import。具體到 Android Studio 里可以在 Version Control 工具窗口中選中目標(biāo)文件右鍵選擇 Revert只撤銷(xiāo)清理相關(guān)的改動(dòng)不影響其他文件的成果。還有一個(gè)經(jīng)驗(yàn)批量清理最好放在解耦的小任務(wù)里不要和功能開(kāi)發(fā)混在同一個(gè)提交中。因?yàn)?import 優(yōu)化產(chǎn)生的 diff 噪音很大混在一起后后續(xù)如果要回溯某個(gè)功能改動(dòng)得從一堆 import 變化里翻很痛苦。單獨(dú)一個(gè) commit 記錄cleanup imports后面隨時(shí)可以單獨(dú)回滾或 diff。3.3 Code Cleanup 和 Inspect Code 的配合除了 Optimize ImportsAndroid Studio 還有一個(gè)更綜合的功能叫 Code Cleanup。路徑是右鍵選中目標(biāo)范圍 - Analyze - Code Cleanup。它會(huì)彈出一個(gè)配置窗口里面列出各種可執(zhí)行的清理操作其中就包括 Optimize Imports還有移除冗余代碼、簡(jiǎn)化表達(dá)式等。如果你只是想清理 import直接使用 Optimize Imports 即可如果想順手做一輪代碼凈化可以用 Code Cleanup。我個(gè)人的經(jīng)驗(yàn)是Code Cleanup 適合在專(zhuān)門(mén)的技術(shù)債清理任務(wù)里用不適合日常提交。因?yàn)樗那謇矸秶鷱V很容易動(dòng)到多余的東西比如格式化規(guī)則、 lambda 替換、字符串拼接方式等這些改動(dòng)如果團(tuán)隊(duì)沒(méi)有統(tǒng)一認(rèn)可會(huì)在評(píng)審時(shí)引發(fā)不少爭(zhēng)論。另外Code - Inspect Code 可以用來(lái)提前發(fā)現(xiàn)問(wèn)題文件。選擇整個(gè)模塊運(yùn)行一次代碼檢查然后在結(jié)果面板中過(guò)濾 Unused import 分類(lèi)就能看到所有存在未使用 import 的文件列表。這時(shí)候你可以用鼠標(biāo)選中這些文件回到 Project 面板批量?jī)?yōu)化比盲目全選模塊處理更有針對(duì)性。4. 配置層面根治讓 import 自動(dòng)保持干凈4.1 Auto Import 兩個(gè)開(kāi)關(guān)怎么選手動(dòng)清理再勤快也不如讓 IDE 在寫(xiě)代碼時(shí)就把 import 管好。Android Studio 的 Settings - Editor - General - Auto Import 頁(yè)面里有兩個(gè)開(kāi)關(guān)需要重點(diǎn)理解。第一個(gè)是 Add unambiguous imports on the fly。它的作用是在你敲代碼引用一個(gè)還沒(méi)有導(dǎo)入的類(lèi)時(shí)IDE 自動(dòng)幫你加上唯一的 import不需要你手動(dòng)按 Alt Enter。這個(gè)功能適合大多數(shù)人因?yàn)榻^大多數(shù)情況下一個(gè)類(lèi)名的候選只有一個(gè)自動(dòng)導(dǎo)入不會(huì)出錯(cuò)。唯一需要注意的是如果同一個(gè)類(lèi)名存在多個(gè)候選IDE 不會(huì)自動(dòng)導(dǎo)入而是等你手動(dòng)選擇這正是它防止誤導(dǎo)入的設(shè)計(jì)。第二個(gè)是 Optimize imports on the fly。它的作用是在你編輯文件時(shí)后臺(tái)自動(dòng)清理當(dāng)前文件里的未使用 import。打開(kāi)之后刪除一段舊代碼時(shí)相關(guān)的 import 會(huì)跟著消失不需要刻意去清。這兩個(gè)開(kāi)關(guān)我建議配合使用一個(gè)負(fù)責(zé)加一個(gè)負(fù)責(zé)清日常開(kāi)發(fā)的 import 區(qū)域基本能保持干凈。不過(guò)要注意Optimize imports on the fly 只作用于你當(dāng)前正打開(kāi)編輯的文件不會(huì)自動(dòng)掃描整個(gè)項(xiàng)目中那些沒(méi)有被打開(kāi)的文件。所以已經(jīng)存在的存量垃圾還是需要用上一節(jié)講的批量操作處理一遍。我見(jiàn)過(guò)一些團(tuán)隊(duì)為了減少 diff 噪音選擇關(guān)閉 Optimize imports on the fly然后在提交前統(tǒng)一執(zhí)行一次 Optimize Imports。這也是一種可行的策略但需要每個(gè)人都養(yǎng)成習(xí)慣否則 import 垃圾還是會(huì)在代碼合并過(guò)程中慢慢積累。個(gè)人項(xiàng)目我傾向于全部打開(kāi)少想一件事。4.2 import 布局與通配符閾值配置清理 import 不只是刪和排還有排序規(guī)則和通配符策略。這些配置在 Settings - Editor - Code Style 里Java 和 Kotlin 分別設(shè)置。Java 語(yǔ)言的配置路徑是 Code Style - Java - Imports。比較關(guān)鍵的選項(xiàng)有兩塊。一個(gè)是 Import Layout它定義一個(gè)文件里 import 語(yǔ)句的排序規(guī)則默認(rèn)是普通 import 按字母序排列靜態(tài) import 放在另一組。如果你的項(xiàng)目規(guī)范要求靜態(tài) import 先于普通 import或者要求兩組之間空一行都可以在這里調(diào)整。另一個(gè)是 Class count to use import with 和 Names count to use static import with 這兩個(gè)是通配符閾值。默認(rèn)值通常是 5意思是當(dāng)一個(gè)包下同一個(gè)文件引用了超過(guò) 5 個(gè)類(lèi)時(shí)Optimize Imports 會(huì)把這些類(lèi)合并成一條 import xxx.*。很多團(tuán)隊(duì)不喜歡通配符 import因?yàn)轱@式列出每個(gè)類(lèi)更利于追蹤依賴(lài)做法是把這個(gè)閾值改成一個(gè)很大的值比如 999這樣 IDE 就永遠(yuǎn)不會(huì)自動(dòng)生成通配符 import。Kotlin 的配置在 Code Style - Kotlin - Imports里面也有一組類(lèi)似設(shè)置。需要注意Kotlin 中通配符 import 在官方文檔里本來(lái)就不建議使用默認(rèn)的閾值邏輯也會(huì)更保守。如果你在混合項(xiàng)目中同時(shí)維護(hù) Java 和 Kotlin兩邊都要檢查一遍避免出現(xiàn) Java 和 Kotlin 風(fēng)格不一致的情況。配置好之后由 Optimize Imports 生成的排序結(jié)果才具備一致性。這個(gè)一致性在多人協(xié)作里非常重要因?yàn)樗?import 區(qū)的 diff 變得可預(yù)測(cè)。4.3 團(tuán)隊(duì)統(tǒng)一配置的落地方式個(gè)人配置好了怎么讓團(tuán)隊(duì)成員也保持一致很多團(tuán)隊(duì)會(huì)在評(píng)審時(shí)約定 import 規(guī)范但人肉把關(guān)效率低。更靠譜的做法是把這部分配置納入 IDE 的共享機(jī)制。團(tuán)隊(duì)級(jí)配置文件可以放到項(xiàng)目的 .idea 目錄下通過(guò)版本控制系統(tǒng)讓所有成員共用。但 .idea 目錄里有大量個(gè)人配置直接整目錄共享容易互相覆蓋所以更精細(xì)的做法是單獨(dú)導(dǎo)出 Code Style 配置。在 Settings - Editor - Code Style 里可以點(diǎn)擊設(shè)置圖標(biāo)選擇 Export生成一份配置文件放到項(xiàng)目文檔庫(kù)中讓新人導(dǎo)入。另外如果項(xiàng)目代碼使用 EditorConfig 管理格式也可以在里面寫(xiě)部分 import 相關(guān)配置比如禁用通配符導(dǎo)入但 EditorConfig 對(duì) import 排序的支持有限不能完全替代 IDE 的 Code Style 配置。最穩(wěn)妥的組合是核心 Code Style 配置通過(guò)團(tuán)隊(duì)共享文件分發(fā)EditorConfig 只做兜底。我見(jiàn)過(guò)一些團(tuán)隊(duì)用自動(dòng)化手段在提交代碼時(shí)用 Git 鉤子對(duì)暫存文件執(zhí)行 Optimize Imports保證進(jìn)入倉(cāng)庫(kù)的代碼都是干凈的。這個(gè)方案細(xì)節(jié)比較多需要謹(jǐn)慎處理但它在徹底解放人手上確實(shí)是有效的。小團(tuán)隊(duì)可以先從約定開(kāi)始慢慢過(guò)渡到自動(dòng)化。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 清理后編譯報(bào)錯(cuò)怎么辦理論上刪除未使用的 import 不會(huì)引發(fā)編譯錯(cuò)誤因?yàn)榉?hào)解析依賴(lài)的是類(lèi)路徑而不是 import 語(yǔ)句本身。但我在實(shí)際項(xiàng)目中確實(shí)遇到過(guò)清理完 import 之后編譯失敗的情況需要具體情況具體分析。一類(lèi)常見(jiàn)場(chǎng)景是反射調(diào)用。代碼里用字符串形式做反射或動(dòng)態(tài)加載時(shí)IDE 無(wú)法從源碼層面判斷某個(gè) import 是否被使用。比如你用 Class.forName 加載一個(gè)類(lèi)這個(gè)類(lèi)的 import 可能被 IDE 標(biāo)記為 unused清理掉之后反射調(diào)用依然能工作因?yàn)榉瓷溆玫氖亲址薅?import 無(wú)關(guān)。這種情況下編譯失敗其實(shí)不是刪掉 import 導(dǎo)致的直接后果真正原因是某個(gè)依賴(lài)在新版本環(huán)境中沒(méi)有被正確傳遞只是清理動(dòng)作讓問(wèn)題暴露了。另一類(lèi)場(chǎng)景是 IDE 索引過(guò)期。文件改動(dòng)較多或者長(zhǎng)時(shí)間沒(méi)重啟 IDE 時(shí)符號(hào)解析可能不準(zhǔn)導(dǎo)致某些明明還有使用的 import 被誤判為 unused。批量清理之后一編譯就報(bào)錯(cuò) cannot find symbol。這種情況的處理方法是先驗(yàn)證一下報(bào)錯(cuò)的符號(hào)是不是真的需要 import如果是手動(dòng)加回來(lái)如果報(bào)錯(cuò)很集中更合適的方法是用 File - Invalidate Caches / Restart 清理索引緩存再重新編譯。我的習(xí)慣是批量清理后第一件事就是編譯不要延遲到提交后再驗(yàn)證。如果模塊很大至少編一次主 debug 變體確保清理沒(méi)有引入編譯問(wèn)題。5.2 誤刪了有用 import 的處理誤刪 import 不管是誰(shuí)都會(huì)遇到關(guān)鍵是怎么快速恢復(fù)。最推薦的永遠(yuǎn)是用版本控制回滾而不是手動(dòng)補(bǔ)上。操作上如果在批量清理后立即發(fā)現(xiàn)編譯錯(cuò)誤用 Ctrl Z 撤銷(xiāo)最近一次動(dòng)作可以讓所有文件恢復(fù)到清理前狀態(tài)。如果已經(jīng)過(guò)了好幾個(gè)操作撤銷(xiāo)鏈太長(zhǎng)那就從 Version Control 窗口里找到對(duì)應(yīng)文件右鍵 Revert 該文件把整個(gè)文件恢復(fù)到最近一次提交版本。需要注意Revert 是從 Git 倉(cāng)庫(kù)恢復(fù)如果這個(gè)文件在清理之前還有其他工作區(qū)的未提交改動(dòng)這些改動(dòng)也會(huì)一并被撤銷(xiāo)。所以使用 Revert 前要確認(rèn)這個(gè)文件的本地改動(dòng)都不需要保留。另一種避免誤刪的方法是分批處理。不要一次對(duì)一個(gè)超大模塊做全量?jī)?yōu)化而是按包或按目錄分批執(zhí)行每批執(zhí)行后編譯驗(yàn)證再把改動(dòng)提交。這樣即使誤刪影響的文件范圍也小排查起來(lái)快得多。5.3 快捷鍵失效與緩存異常除了前面講的快捷鍵沖突還有一種情況是快捷鍵本身工作正常但在某些文件上 Optimize Imports 的菜單是灰的怎么點(diǎn)都沒(méi)反應(yīng)。遇到這個(gè)問(wèn)題優(yōu)先考慮文件類(lèi)型。如果你正在打開(kāi)的是 .gradle 文件、XML 文件或者某些非源碼文件這個(gè)功能本來(lái)就不適用菜單置灰是正?,F(xiàn)象。Java 和 Kotlin 文件才支持這個(gè)功能。如果確認(rèn)是源碼文件但功能沒(méi)有生效可能是 IDE 的代碼分析沒(méi)有完成。大型項(xiàng)目首次打開(kāi)時(shí)索引構(gòu)建需要時(shí)間索引沒(méi)建好之前分析類(lèi)操作會(huì)受限??梢缘鹊撞繝顟B(tài)欄的進(jìn)度條跑完再執(zhí)行一次 Optimize Imports。如果索引一直卡住Inspect Code 也無(wú)法執(zhí)行就需要 Invalidate Caches 后重啟 IDE 重建索引。還有一個(gè)小概率情況是插件沖突。裝了代碼生成或者字節(jié)碼修改類(lèi)插件后插件可能改變編輯器的高亮和解析邏輯導(dǎo)致 import 狀態(tài)判斷異常。排查方法是進(jìn)入安全模式禁用第三方插件后再試。這個(gè)問(wèn)題比較少見(jiàn)但遇到時(shí)排查思路要清醒。5.4 快速定位所有未使用 import 的文件項(xiàng)目很大時(shí)你不知道哪些文件有未使用 import總不能一個(gè)個(gè)點(diǎn)開(kāi)看。有兩個(gè)方法可以快速摸清存量。第一種是使用 Problems 工具窗口。打開(kāi)一個(gè)文件時(shí)Problems 面板會(huì)匯總當(dāng)前文件的警告包括 Unused import。逐個(gè)文件看依然低效但對(duì)單個(gè)文件的日常檢查很有用。第二種是運(yùn)行 Code - Inspect Code。選擇整個(gè)模塊或項(xiàng)目等待檢查完成后在結(jié)果面板中搜索 Unused importIDE 會(huì)列出所有檢出這個(gè)問(wèn)題的文件和具體 import 行。這時(shí)候?qū)φ战Y(jié)果在 Project 面板里選中這些文件批量執(zhí)行 Optimize Imports就能做到精準(zhǔn)清理。順便說(shuō)一下Android 項(xiàng)目里要注意生成代碼目錄。比如 build/generated 下的代碼、路由生成類(lèi)、數(shù)據(jù)綁定類(lèi)它們有時(shí)也會(huì)出現(xiàn)未使用的 import 警告但這些文件是構(gòu)建過(guò)程中自動(dòng)生成的不必手動(dòng)清理。批量操作時(shí)把生成目錄排除掉可以省很多事。6. Kotlin 項(xiàng)目與團(tuán)隊(duì)協(xié)作細(xì)節(jié)6.1 Kotlin 文件清理的差異現(xiàn)在很多新項(xiàng)目已經(jīng)全面 Kotlin 化Kotlin 文件的 import 清理邏輯和 Java 有些細(xì)微差別值得單獨(dú)說(shuō)一下。Kotlin 里未使用的 import編輯器里的表現(xiàn)是文字變灰鼠標(biāo)移上去會(huì)有 Unused import 警告??旖萱I和菜單路徑與 Java 完全一樣所以不存在額外的記憶成本。但 Kotlin 有個(gè) Java 沒(méi)有的特點(diǎn)import 時(shí)可以給導(dǎo)入的類(lèi)起別名比如 import com.example.databinding.FooBinding as Foo。別名如果不使用同樣會(huì)被判定為未使用Optimize Imports 也會(huì)一并刪掉。這個(gè)行為對(duì) Java 轉(zhuǎn) Kotlin 的開(kāi)發(fā)者是容易忽略的。Kotlin 的頂層函數(shù)和擴(kuò)展函數(shù)在 import 時(shí)也很特殊。如果導(dǎo)入的是一個(gè)擴(kuò)展函數(shù)但沒(méi)有實(shí)際調(diào)用IDE 會(huì)把它標(biāo)記為 unused。清理時(shí)要注意擴(kuò)展函數(shù)和普通類(lèi)的刪除標(biāo)準(zhǔn)完全一樣都是看有沒(méi)有實(shí)際使用點(diǎn)不存在特殊豁免。還有一點(diǎn)Kotlin 文件里同一個(gè)包下的類(lèi)不需要顯式導(dǎo)入IDE 默認(rèn)能識(shí)別同包類(lèi)。如果你批量?jī)?yōu)化整個(gè)模塊涉及 Kotlin 文件的 import 改動(dòng)會(huì)自然適配這一點(diǎn)不需要手動(dòng)干預(yù)。但在 diff 檢查時(shí)注意不要誤以為某些同包 import 被誤刪了它其實(shí)屬于無(wú)效導(dǎo)入。6.2 提交代碼前的一攬子檢查清理 import 這件事我建議把它嵌到提交代碼前的檢查清單里而不是出了問(wèn)題再處理。尤其多人協(xié)作的項(xiàng)目里一個(gè)人的 import 規(guī)范會(huì)影響很多人的 review 體驗(yàn)。我在實(shí)際協(xié)作中總結(jié)出來(lái)的提交流程大致是這樣寫(xiě)完全部功能后先對(duì)自己改動(dòng)的文件逐個(gè)執(zhí)行一次 Optimize Imports然后看一次 diff重點(diǎn)確認(rèn) import 變化里沒(méi)有誤刪的內(nèi)容再編譯一次最后才提交。如果用了 Git 的 staged 文件暫存可以在 stage 之后對(duì)暫存文件統(tǒng)一執(zhí)行 Optimize Imports確保進(jìn)入倉(cāng)庫(kù)的文件是干凈的。如果有持續(xù)集成流水線可以在上面掛一個(gè)靜態(tài)檢查步驟專(zhuān)門(mén)檢查 import 配置和代碼風(fēng)格。這一步不需要非常復(fù)雜跑一遍項(xiàng)目已有的 lint 和 ktlint/detekt 之類(lèi)工具就能攔截大部分類(lèi)似問(wèn)題。你會(huì)發(fā)現(xiàn)配置一次之后后續(xù)的 code review 會(huì)輕松很多因?yàn)檫@些噪音問(wèn)題基本不會(huì)再出現(xiàn)在討論里。最后再分享一個(gè)我在實(shí)際維護(hù)老項(xiàng)目時(shí)的小習(xí)慣每次接手的模塊第一次做功能開(kāi)發(fā)時(shí)我都會(huì)順手執(zhí)行一次批量 Optimize Imports把該模塊的歷史 import 垃圾一次清完。這個(gè)動(dòng)作成本很低但之后每次打開(kāi)這個(gè)目錄代碼都清爽很多。清理 import 不是炫技更像是一種日常工作紀(jì)律。真正把它用好靠的不是記得住快捷鍵而是理解它背后的排序規(guī)則、自動(dòng)化配置和團(tuán)隊(duì)協(xié)作方式再把這些落實(shí)到每天的提交習(xí)慣里。