Kotlin 50行代碼實(shí)現(xiàn)清除Android項(xiàng)目中不用的圖片和資源

前言

Google 在I/O大會(huì)上宣布了官方支持kotlin作為android的開(kāi)發(fā)語(yǔ)言剂府。因此kotlin一下子進(jìn)入了android開(kāi)發(fā)同學(xué)們的實(shí)現(xiàn)掸掸,其實(shí)我很早就知道這門(mén)語(yǔ)言芹枷,也看了別人使用這門(mén)語(yǔ)言做android開(kāi)發(fā)庙楚,但是由于懶很魂,從來(lái)也沒(méi)有看過(guò)讶泰。正好借此機(jī)會(huì)咏瑟,大家都在趁熱乎勁學(xué)習(xí),我也翻開(kāi)了官方文檔看了看痪署,因?yàn)槲覍W(xué)習(xí)一門(mén)語(yǔ)言的方法就是簡(jiǎn)單瀏覽一下語(yǔ)法响蕴,然后直接開(kāi)始寫(xiě)一個(gè)簡(jiǎn)單的程序,這樣子在實(shí)現(xiàn)想要的功能的同時(shí)也就簡(jiǎn)單熟悉了一些常用的語(yǔ)法惠桃,于是就有了第一個(gè)練習(xí)的程序,也就有了這個(gè)分享辖试。

Kotlin優(yōu)點(diǎn)

Kotlin 的語(yǔ)法優(yōu)點(diǎn)還是很多的辜王。跟scala其實(shí)挺像的。如果寫(xiě)過(guò)scala罐孝,寫(xiě)這個(gè)會(huì)覺(jué)得挺順手的呐馆。

  • 集合鏈?zhǔn)秸{(diào)用,像rxjava一樣莲兢,有很多的操作符汹来,寫(xiě)起來(lái)很舒服,語(yǔ)法糖比較多改艇,看起來(lái)邏輯也很清晰易讀收班。
  • 代碼很精簡(jiǎn),很多可能在java中很復(fù)雜的代碼谒兄,在這里面就很精簡(jiǎn)摔桦,看起來(lái)很舒服。
    例如我想把a(bǔ)ndroid項(xiàng)目中的一個(gè)源文件讀出來(lái)承疲,但是想把注釋掉的行排除掉邻耕,然后把整個(gè)文件轉(zhuǎn)化成一個(gè)String,并且用換行符連接起來(lái)燕鸽,那么簡(jiǎn)單的一行代碼的函數(shù)就可以搞定:
fun fileToString(fn: File) = fn.readLines().filter { l -> !l.trim().startsWith("http://") }.asSequence().joinToString("\n")

不必像Java一樣還得寫(xiě)好些輸入輸出流兄世,讀取再篩選再拼接。雖然Java經(jīng)過(guò)封裝也可以做到啊研,但是Kotlin直接就可以做這些操作非常的簡(jiǎn)單直觀(guān)御滩。這就是上面兩個(gè)優(yōu)點(diǎn)

  • 兼容java,這個(gè)就是你以前在java中用的現(xiàn)在還是可以用,只是寫(xiě)法稍微有一單改動(dòng)悲伶。
    舉個(gè)例子,我想拿到某個(gè)文件下所有以某些xml,png,jpg啊這些結(jié)尾的文件的集合艾恼,那么給一個(gè)drawables的集合作為extensions參數(shù)給allFiles()這個(gè)函數(shù),java中常用的ArrayList我們就直接用就可以了麸锉,減少了很多不適應(yīng)的成本钠绍。
val drawables = sequenceOf("png", "jpg", "xml")
fun allFiles(f: File, extensions: Sequence<String>): Sequence<File> {
    val files = ArrayList<File>()
    if (f.isDirectory) {
        f.listFiles().map { f -> files.addAll(allFiles(f, extensions)) }
    } else if (extensions.any { ex -> f.name.endsWith("." + ex) }) {
        files.add(f)
    }
    return files.asSequence()
}

我體驗(yàn)到的大概就是這么多吧。其實(shí)也算不上什么新的優(yōu)點(diǎn)吧花沉,畢竟很多其他語(yǔ)言也是這樣的柳爽,可能對(duì)于平時(shí)寫(xiě)java的同學(xué)來(lái)說(shuō)確實(shí)感覺(jué)一下子清新了很多媳握,因?yàn)閖ava確實(shí)有很多繁雜的代碼。像我這樣的也只能有一點(diǎn)語(yǔ)法層面的感覺(jué)磷脯,畢竟我也是剛剛看了一會(huì)kotlin這個(gè)語(yǔ)言蛾找,沒(méi)有更多細(xì)致的了解。

實(shí)現(xiàn)

下面簡(jiǎn)單講一下如何實(shí)現(xiàn)這個(gè)功能的赵誓,雖然As貌似有這個(gè)功能打毛。但是我只是為了練習(xí)一下kotlin,也分享一下俩功。
流程很簡(jiǎn)單:

  • 1.掃描項(xiàng)目中所有的資源文件幻枉。
    也就是-hdpi", "-mdpi", "-xhdpi", "-xxhdpi", "-xxxhdpi"這幾個(gè)文件夾和xml資源放的文件夾中的png,jpg,xml這3種會(huì)在android項(xiàng)目中用到的資源文件。然后獲取他們的名字诡蜓,放到一個(gè)Set里面熬甫,因?yàn)?code>Set集合中value不可重復(fù),每個(gè)文件夾下可能有相同名字的資源文件蔓罚,所以放到Set里去重椿肩。
fun getFileName(f: File): String {
    return f.name.replace(".9.png", "").replace(".png", "").replace(".jpg", "").replace(".xml", "")
}
val drawables = sequenceOf("png", "jpg", "xml")
val resDirs = sequenceOf("-hdpi", "-mdpi", "-xhdpi", "-xxhdpi", "-xxxhdpi").map { s -> "app/src/main/res/mipmap$s" }.asSequence()
fun reses(): Sequence<File> = resDirs.map { str -> allFiles(File(str), drawables) }.flatten()
fun allNames() = reses().map { file -> getFileName(file) }.toSet()

這個(gè)功能實(shí)現(xiàn)很簡(jiǎn)單,就是掃描resDirs這幾個(gè)文件夾通過(guò)allFiles()這個(gè)方法獲取文件夾下面所有的以drawables這個(gè)集合中的字符結(jié)尾的文件豺谈。然后通過(guò)getFileName獲取到文件的名字郑象,放到Set中
為什么要名字?
因?yàn)槲覀冊(cè)诖a中都是寫(xiě)R.mipmap.xxx或者@mipmap/xxx這樣的核无,我們要拿名字去和代碼中用到的名字比較匹配扣唱。
通過(guò)上面的代碼我們就拿到了項(xiàng)目中allNames

  • 2.掃描項(xiàng)目中所有的代碼。
    也就是.kt .java .xml這3中文件中用到R.mipmap.xxx或者@mipmap/xxx的地方团南,解析出所有這些東西噪沙,就知道那些名字在項(xiàng)目中是出現(xiàn)過(guò)的。
val pattern = """@mipmap\/[a-zA-Z0-9_]+[^a-zA-Z0-9_]|R\.mipmap\.[A-Za-z0-9_]+[^a-zA-Z0-9_]""".toPattern()
val codes = sequenceOf("kt", "java", "xml")
val projects = sequenceOf("app")
val usedNames = projects.map { p ->
    allFiles(File(p + "/src"), codes).map { f -> fileToString(f) }.map { str ->
        val names = ArrayList<String>()
        val m = pattern.matcher(str)
        while (m.find()) {
            names.add(m.toMatchResult().group().dropLast(1).replace("@mipmap/", "").replace("R.mipmap.", ""))
        }
        names.asSequence()
    }.flatten()
}.flatten().toSet()

如果你還有其他的module吐根,可以加到projects集合里正歼。這個(gè)邏輯也挺簡(jiǎn)單的。跟上面一樣拷橘,首先通過(guò)allFiles()掃描src目錄下面所有以codes集合中字符串結(jié)尾的文件局义,然后通過(guò)最上面提到的fileToString方法把每個(gè)文件轉(zhuǎn)化成String,通過(guò)正則匹配找出其中用到R.mipmap.xxx或者@mipmap/xxx的地方冗疮,再取出名字放到Set里面萄唇。這樣我們就拿到了項(xiàng)目中用到過(guò)的所有的資源的名字usedNames

  • 3 allNames - usedNames = unusedNames
    這個(gè)道理就很簡(jiǎn)單了。
val unusedNames = allNames().filter { d -> !usedNames.contains(d) }.toSet()
  • 4 遍歷資源文件夾术幔,找到和unusedNames相同名字的文件另萤,刪除。
fun cleanDir(f: File) {
    if (f.isDirectory) {
        f.listFiles().forEach { f -> cleanDir(f) }
    } else {
        if (unusedNames.map { s -> getFileName(f) == s }.toSet().contains(true)) {
            f.delete()
        }
    }
}
fun clean() = resDirs.map { s -> File(s) }.forEach { f -> cleanDir(f) }

總結(jié)

短短50行代碼,很適合練習(xí)的一個(gè)小程序四敞,我花了大概幾個(gè)小時(shí)泛源,在沒(méi)寫(xiě)過(guò)kotlin的情況下寫(xiě)出來(lái)的,過(guò)程中感受了kotlin語(yǔ)法忿危,知道了一些大概的kotlin編程的方式达箍,也用了這些語(yǔ)法糖。雖然我感覺(jué)還是沒(méi)有scala簡(jiǎn)單铺厨,但是還是值得一試缎玫。希望給同樣是新手的你一點(diǎn)小的參考。
新手解滓,很多不正之處碘梢,還望指點(diǎn)。
所有代碼的地址:https://github.com/kingty/kotlin-script-demo/blob/master/clear.kts

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末伐蒂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肛鹏,更是在濱河造成了極大的恐慌逸邦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件在扰,死亡現(xiàn)場(chǎng)離奇詭異缕减,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芒珠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)桥狡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人皱卓,你說(shuō)我怎么就攤上這事裹芝。” “怎么了娜汁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵嫂易,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我掐禁,道長(zhǎng)怜械,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任傅事,我火速辦了婚禮缕允,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹭越。我一直安慰自己障本,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布般又。 她就那樣靜靜地躺著彼绷,像睡著了一般巍佑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寄悯,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天萤衰,我揣著相機(jī)與錄音,去河邊找鬼猜旬。 笑死脆栋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洒擦。 我是一名探鬼主播椿争,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼熟嫩!你這毒婦竟也來(lái)了秦踪?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤掸茅,失蹤者是張志新(化名)和其女友劉穎椅邓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體昧狮,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡景馁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逗鸣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合住。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撒璧,靈堂內(nèi)的尸體忽然破棺而出透葛,到底是詐尸還是另有隱情,我是刑警寧澤卿樱,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布获洲,位于F島的核電站,受9級(jí)特大地震影響殿如,放射性物質(zhì)發(fā)生泄漏贡珊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一涉馁、第九天 我趴在偏房一處隱蔽的房頂上張望门岔。 院中可真熱鬧,春花似錦烤送、人聲如沸寒随。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妻往。三九已至互艾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讯泣,已是汗流浹背纫普。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留好渠,地道東北人昨稼。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拳锚,于是被迫代替她去往敵國(guó)和親假栓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容