




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
目寫(xiě)在關(guān)于這本書(shū)適合你關(guān)于介什么是我們通過(guò)Kotlin得到什準(zhǔn)備Android安裝Kotlin創(chuàng)建一個(gè)新的在 Studio中創(chuàng)建一個(gè)項(xiàng)配置把MainActivity轉(zhuǎn)換成Kotlin測(cè)試是否一切類(lèi)和怎么定義一個(gè)函構(gòu)造方目寫(xiě)在關(guān)于這本書(shū)適合你關(guān)于介什么是我們通過(guò)Kotlin得到什準(zhǔn)備Android安裝Kotlin創(chuàng)建一個(gè)新的在 Studio中創(chuàng)建一個(gè)項(xiàng)配置把MainActivity轉(zhuǎn)換成Kotlin測(cè)試是否一切類(lèi)和怎么定義一個(gè)函構(gòu)造方法和函數(shù)參編寫(xiě)你的第一創(chuàng)建一個(gè)TheRecycler變量和屬基本類(lèi)變1屬Anko和擴(kuò)展的函Anko是什么開(kāi)始使用擴(kuò)展函從API中獲取執(zhí)行一個(gè)在主線程以外執(zhí)行額外的函復(fù)制一個(gè)數(shù)據(jù)映射對(duì)象到變解析轉(zhuǎn)換json到數(shù)構(gòu)建domain在UI中繪制操作符重操作符例擴(kuò)展函數(shù)中的操作使Forecastlist可點(diǎn)屬Anko和擴(kuò)展的函Anko是什么開(kāi)始使用擴(kuò)展函從API中獲取執(zhí)行一個(gè)在主線程以外執(zhí)行額外的函復(fù)制一個(gè)數(shù)據(jù)映射對(duì)象到變解析轉(zhuǎn)換json到數(shù)構(gòu)建domain在UI中繪制操作符重操作符例擴(kuò)展函數(shù)中的操作使Forecastlist可點(diǎn)簡(jiǎn)化ForecastListAdapter的擴(kuò)展語(yǔ)可見(jiàn)性修飾潤(rùn)色我們的代KotlinAndroid2重構(gòu)我們的代Application單例化和屬性的Applicaton委托屬標(biāo)準(zhǔn)委怎么去創(chuàng)建一個(gè)自定義的委重新實(shí)現(xiàn)Application創(chuàng)建一個(gè)實(shí)現(xiàn)依賴(lài)注集合和函數(shù)操總數(shù)操作過(guò)濾操作映射操作元素操作生產(chǎn)操作順序操作從數(shù)據(jù)庫(kù)中保重構(gòu)我們的代Application單例化和屬性的Applicaton委托屬標(biāo)準(zhǔn)委怎么去創(chuàng)建一個(gè)自定義的委重新實(shí)現(xiàn)Application創(chuàng)建一個(gè)實(shí)現(xiàn)依賴(lài)注集合和函數(shù)操總數(shù)操作過(guò)濾操作映射操作元素操作生產(chǎn)操作順序操作從數(shù)據(jù)庫(kù)中保存或查詢(xún)創(chuàng)建數(shù)據(jù)庫(kù)model寫(xiě)入和查詢(xún)數(shù)Kotlin中的null可null類(lèi)型怎么工可null性和Java創(chuàng)建業(yè)務(wù)邏輯來(lái)訪問(wèn)IfWhen表達(dá)3ForWhile和do/while創(chuàng)建一個(gè)詳情準(zhǔn)備請(qǐng)?zhí)峁┮粋€(gè)新的啟動(dòng)一個(gè)activity:reified接口和委接委在我們的App中實(shí)現(xiàn)一個(gè)例泛基變泛型例設(shè)置創(chuàng)建一個(gè)設(shè)置泛型preference測(cè)試你的Unit其它的概ForWhile和do/while創(chuàng)建一個(gè)詳情準(zhǔn)備請(qǐng)?zhí)峁┮粋€(gè)新的啟動(dòng)一個(gè)activity:reified接口和委接委在我們的App中實(shí)現(xiàn)一個(gè)例泛基變泛型例設(shè)置創(chuàng)建一個(gè)設(shè)置泛型preference測(cè)試你的Unit其它的概枚密封(Sealed)異常結(jié)4《Kotlinforandroiddevelopers》中文版翻《Kotlinforandroiddevelopers》中文版翻錯(cuò)別字、病句、翻譯錯(cuò)誤等問(wèn)題可以提issues。請(qǐng)說(shuō)明錯(cuò)誤原因在線閱讀或下載在線/wangjiegulu/kotlin-for-android-developers-5寫(xiě)在前寫(xiě)在前寫(xiě)在前寫(xiě)在前學(xué)習(xí)通過(guò)Kotlin語(yǔ)言來(lái)簡(jiǎn)單地開(kāi)發(fā)android6關(guān)于本關(guān)于本關(guān)于本關(guān)于本在這本書(shū)中,我會(huì)使用Kon作為主要的語(yǔ)言來(lái)開(kāi)發(fā)一個(gè)d應(yīng)用。方式是通過(guò)開(kāi)發(fā)一個(gè)應(yīng)用來(lái)學(xué)習(xí)這門(mén)語(yǔ)言,而不是根據(jù)傳統(tǒng)的結(jié)構(gòu)來(lái)學(xué)習(xí)。我會(huì)在感興趣的點(diǎn)停下來(lái)通過(guò)與Java1.對(duì)比的方式講講Ko這本書(shū)并不是一本語(yǔ)言參考書(shū),但它是一個(gè)Android開(kāi)發(fā)者去學(xué)習(xí)Kotlin并且使用我們?cè)谌粘I町?dāng)中都會(huì)遇到的典型問(wèn)題。這本書(shū)是非常具有實(shí)踐性的,所以我建議你在電腦面前跟著我的例子和代碼實(shí)踐。無(wú)論何時(shí)你都可以在有一些想法的時(shí)候深入到實(shí)踐中去。我會(huì)及時(shí)根據(jù)新的KoAnd開(kāi)發(fā)者的一個(gè)完美的工具,正因?yàn)槿绱?,歡迎大家的想法和幫助。感謝你將成為這個(gè)激動(dòng)人心的項(xiàng)目的一部7這本書(shū)適合你寫(xiě)這本書(shū)是為了幫助那些有興趣使用Kotlin語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā)的Androi開(kāi)發(fā)者。如果你符合下面這些情況,那這本書(shū)是適合你的:你有相關(guān)Android這本書(shū)適合你寫(xiě)這本書(shū)是為了幫助那些有興趣使用Kotlin語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā)的Androi開(kāi)發(fā)者。如果你符合下面這些情況,那這本書(shū)是適合你的:你有相關(guān)Android開(kāi)發(fā)和SDK的基本知你希望跟隨一個(gè)使用Kotlin語(yǔ)言編寫(xiě)的例子來(lái)學(xué)習(xí)Kotlin你需要一個(gè)怎么去使用更簡(jiǎn)潔生動(dòng)的語(yǔ)言來(lái)解決日常生活遇到的典型問(wèn)題的指另一方面,這本書(shū)可能不太適合你,因這本書(shū)不是Kon圣經(jīng)。我會(huì)去解釋所有Kotn的基本語(yǔ)法,甚至包括在過(guò)程中遇到我需要的一些相對(duì)比較復(fù)雜的想法。所以你是通過(guò)一個(gè)例子去學(xué)習(xí),而不是其他方式。我不會(huì)去解釋怎么樣去開(kāi)發(fā)一個(gè)Andd應(yīng)用。你不需要很深的開(kāi)發(fā)知識(shí),但是至少了解基礎(chǔ),比如AnddS,G,Java語(yǔ)言和Andd。你可能會(huì)從中學(xué)到一些關(guān)于Android開(kāi)發(fā)的一些新的東這本書(shū)不是函數(shù)式編程語(yǔ)言指南。當(dāng)然由于7完全不是函數(shù)式風(fēng)格的,會(huì)解釋你需要知道的東西,但是不會(huì)很深入地去講解函數(shù)式編程的話8關(guān)于作關(guān)于作關(guān)于作關(guān)于作 Antonio一開(kāi)始是CRM技術(shù)顧問(wèn),但是一段時(shí)間之后,他尋找著新的激情,他發(fā)了And的手機(jī)公司帶領(lǐng)多個(gè)項(xiàng)目作為新的冒險(xiǎn)。你可以在Twitter上關(guān)注他@lime_cl9介介如果你覺(jué)得Java7是一個(gè)過(guò)期的語(yǔ)言,并決定找一個(gè)更現(xiàn)代的語(yǔ)言代替。恭喜你!就如你知道的,雖然Java介介如果你覺(jué)得Java7是一個(gè)過(guò)期的語(yǔ)言,并決定找一個(gè)更現(xiàn)代的語(yǔ)言代替。恭喜你!就如你知道的,雖然Java8已經(jīng)發(fā)布了,它包含了很多我們期待的像現(xiàn)代語(yǔ)言中那樣的改善,但是我們Android開(kāi)發(fā)者還是被迫在使用Java7.這是因?yàn)榉傻膯?wèn)題。但是就算沒(méi)有這個(gè)限制,并且新的Android設(shè)備從今天開(kāi)始使用新的能理解Java8VM,在當(dāng)前的設(shè)備過(guò)期、幾乎沒(méi)有人使用它們之前我們也不能使用Java8,所以但是并不是沒(méi)有補(bǔ)救的方法。多虧使用了JVM,我們可以使用任何語(yǔ)言去編Android應(yīng)用,只要它能夠編譯成JVM能夠認(rèn)識(shí)的字節(jié)碼就可以上述的每一種語(yǔ)言都有它的利弊,如果你還沒(méi)有真正確定你該使用那種語(yǔ)言,我建議你可以去嘗試一下它們。什么是什么是Kon,如前面所說(shuō),它是Jet什么是什么是Kon,如前面所說(shuō),它是Jets開(kāi)發(fā)的基于M的語(yǔ)言。Jets因?yàn)閯?chuàng)造了一個(gè)強(qiáng)大的Java開(kāi)發(fā)E被大家所熟知。AnddSdo,官方的Andd,就是基于e,作為一個(gè)該平臺(tái)的插件。對(duì)Jva開(kāi)發(fā)者來(lái)說(shuō),Kon是非常直覺(jué)化的,并且非常容易學(xué)習(xí)。語(yǔ)言的大部分內(nèi)容都是與我們知道的非常相似,不同的地方,它的基礎(chǔ)概念也能迅速地掌握它。但是這僅僅是開(kāi)發(fā)語(yǔ)言和開(kāi)發(fā)工具之間的整合。相比7的優(yōu)勢(shì)到底是什么呢它更加易表現(xiàn):這是它最重要的優(yōu)點(diǎn)之一。你可以編寫(xiě)少得多的代它更加安全:Ko是空安全的,也就是說(shuō)在我們編譯時(shí)期就處理了各種的情況,避免了執(zhí)行時(shí)異常。如果一個(gè)對(duì)象可以是。你可以節(jié)約很多調(diào)試空指針異常的時(shí)間,解決掉。它是函數(shù)式的:Ko樣,它使用了很多函數(shù)式編程的概念,比如,使用s去訪問(wèn)這個(gè)類(lèi)中的代碼。它是高度互操作性的:你可以繼續(xù)使用所有的你用Java寫(xiě)的代碼和庫(kù),因?yàn)閭€(gè)語(yǔ)言之間的互操作性是完美的。甚至可以在一個(gè)項(xiàng)目中使用Ko和兩種語(yǔ)言混合編程。我們通過(guò)Kotlin得到什我們通過(guò)我們通過(guò)Kotlin得到什我們通過(guò)Kotlin得到什不深入Kot語(yǔ)言(我們會(huì)在下一章再去學(xué)習(xí)),這里有一些Java少生成)這些代碼publicclass{privatelongid;privateStringname;privateStringurl;privateStringmbid;publiclong{return}publicvoidsetId(long{this.id=}publicString{return}publicvoidsetName(String{=}publicString{return}我們通過(guò)Kotlin得到什使用Kotlin,我我們通過(guò)Kotlin得到什使用Kotlin,我們只需要通過(guò)數(shù)據(jù)這個(gè)數(shù)據(jù)類(lèi),它會(huì)自動(dòng)生成所有屬性和它們的訪問(wèn)器,以及一些有用的方法,比如,dataArtist(varid:Long,varname:String,varurl:String,varmbid:publicvoidsetUrl(String{this.url=}publicString{return}publicvoidsetMbid(String{this.mbid=}@OverridepublicString{return"Artist{"+"id="+id+",name='"+name+'\''",url='"+url+'\''",mbid='"+mbid+'\''+}}我們通過(guò)Kotlin得到什當(dāng)我們通過(guò)Kotlin得到什當(dāng)我們使用Java開(kāi)發(fā)的時(shí)候,我們的代碼大多是防御性的。如果我們不到NullPointerException,我們就需要在使用它之前不停地去判斷它是否為 作符(寫(xiě)做?)來(lái)明確地指定一個(gè)對(duì)象是否能為空。我們可以像這樣去我們可以給任何類(lèi)添加函數(shù)。它比那些我們項(xiàng)目中典型的工具類(lèi)更加具有可讀性。舉個(gè)例子,我們可以給fagmenttoast的函數(shù):這里不能通過(guò)編譯Artist不能是nullvarnotNullArtist:Artist=nullArtist可以是varartist:Artist?=無(wú)法編譯artist可能是null,我們需要進(jìn)行處理只要在artistnull時(shí)才會(huì)打印智能轉(zhuǎn)換if(artist!={}////valname=artist?.name?:我們通過(guò)Kotlin得到什我們現(xiàn)在可以我們通過(guò)Kotlin得到什我們現(xiàn)在可以這么每次我們?nèi)ヂ暶饕粋€(gè)點(diǎn)擊所觸發(fā)的事件,可以只需要定義我們需要做些什么,而不是不得不去實(shí)現(xiàn)一個(gè)內(nèi)部類(lèi)?我們確實(shí)可以這么做,這個(gè)(或者其它更多我們感興趣的事件)我們需要感謝:語(yǔ)言的一些有趣的特性了,你可以考慮它是否是適合你的。如果你選擇繼續(xù),我們將在下一章開(kāi)始我們的實(shí)踐之旅。view.setOnClickListener{toast("Helloworld!")funFragment.toast(message:CharSequence,duration:Int=Toast.LENGTH_SHORT){}準(zhǔn)備工準(zhǔn)備工準(zhǔn)備工準(zhǔn)備工實(shí)踐當(dāng)中去。不要擔(dān)心,在第一章中會(huì)幫助你去搭建你的開(kāi)發(fā)環(huán)境,這樣你才能立即編寫(xiě)代碼。AndroidAndroidAndroidAndroidAndroidIDE,它是2013年發(fā)布的預(yù)覽版,并在2014年發(fā)布了正式版。AndroidStudio是IntellijIDEA的插件實(shí)現(xiàn),IntellijIDEA是由JetBrains就是JetBrains創(chuàng)造的。所以,正如你所見(jiàn),一切都這么緊密地結(jié)合起來(lái)轉(zhuǎn)移AnddSd是And開(kāi)發(fā)者一個(gè)重要的改變。首先,因?yàn)槲覀兎艞壛薱sJava第二,Gradle成為Android官方的系統(tǒng)構(gòu)建工具,這意味著版本構(gòu)建和部署的新可能性。最有趣的兩點(diǎn)是系統(tǒng)構(gòu)建和s)。如果你仍然在使用Eclipse,為了跟上這本書(shū),恐怕你需要轉(zhuǎn)移到我不會(huì)去覆蓋到AndroidStudio和Gradle的使用,因?yàn)檫@些都不是本書(shū)的重點(diǎn),但到相關(guān)基礎(chǔ)如果你還沒(méi)有AndroidStudio,點(diǎn)這里從官網(wǎng)下載安裝Kotlin安裝Kotlin插安裝Kotlin安裝Kotlin插Kotlin團(tuán)隊(duì)創(chuàng)建了一系列強(qiáng)大的插件讓我們更輕松地實(shí)現(xiàn)。前往AndroidStudio的中PluginKotn:這是一個(gè)基礎(chǔ)的插件。它能讓AddSdo懂得n代碼。它會(huì)每次在新的Kon語(yǔ)言版本發(fā)布的時(shí)候發(fā)布新的插件版本,這樣我們可以通過(guò)它發(fā)現(xiàn)新版本特性和棄用的警告。這是你要使用Kon編寫(xiě)dd應(yīng)用唯一的插件。但是我們現(xiàn)在還需要另外一個(gè)。KotlinAndroidExtensions:Kotlin團(tuán)隊(duì)還為Android開(kāi)發(fā)發(fā)布了另外一個(gè)有趣的插件。這個(gè)AndroidExtensions可以讓你自動(dòng)地從XML中注入所有的View到。你將會(huì)立即得到Activity中,舉個(gè)例子,你不需要個(gè)從屬性轉(zhuǎn)換過(guò)來(lái)的view。你將需要安裝這個(gè)插件來(lái)使用這個(gè)特性。我們會(huì)在下一章中深入地去講解這個(gè)?,F(xiàn)在我們的環(huán)境已經(jīng)可以理解Kotlin語(yǔ)言了,可以就像我們使用Java創(chuàng)建一個(gè)新的如果你創(chuàng)建一個(gè)新的如果你已經(jīng)使用過(guò)Studio和Gradle,那么這一章會(huì)比較簡(jiǎn)單。我不會(huì)很多細(xì)節(jié)和截圖,因?yàn)橛脩艚缑婧图?xì)節(jié)可能會(huì)一直變我們的應(yīng)用是由一個(gè)簡(jiǎn)單的天氣app組成,正如所使用的Google'sBeginnersCourseinUdacity。我們可能會(huì)關(guān)注不同的事情,但是app的想法都是一樣的,你較低,我推薦這個(gè),這個(gè)過(guò)程是比較容易在 Studio中創(chuàng)建一個(gè)項(xiàng)在AndroidStudio首先,打開(kāi)AndroidStudio名字,你可以任意取一個(gè)名字,比如:WeatherApp在 Studio中創(chuàng)建一個(gè)項(xiàng)在AndroidStudio首先,打開(kāi)AndroidStudio名字,你可以任意取一個(gè)名字,比如:WeatherApp。然后你需要輸入公司域至少15才能用。無(wú)論如何你把大部分的Anroid用戶作為了目標(biāo)?,F(xiàn)在不要選任何除了手機(jī)和平板的其它平我將選擇BlankActivity,因?yàn)槲掖龝?huì)兒會(huì)給你展示Kotlin插件一個(gè)好玩的小特暫時(shí)不用去關(guān)心Activity的名字,ayout等。這些你會(huì)在下一篇中知道。如果我們需hAddCreatenew配置配置Ko插件包括一個(gè)讓我們配置的工具。但是我還是傾向于保持我對(duì)e動(dòng)工具之前知道它是怎么工作的是個(gè)不錯(cuò)的主意。所以這次,我們將手動(dòng)去做。配置配置Ko插件包括一個(gè)讓我們配置的工具。但是我還是傾向于保持我對(duì)e動(dòng)工具之前知道它是怎么工作的是個(gè)不錯(cuò)的主意。所以這次,我們將手動(dòng)去做。首先,你需要如下修改父build.gradle正如你看到的,我們創(chuàng)建了一個(gè)變量來(lái)存儲(chǔ)當(dāng)前的Kotlin版本。你讀到這里的時(shí)的地方用到那個(gè)版本號(hào),比如你需要加上新的Kotlin。你會(huì)以更方便地在一個(gè)地方修改所有的版本號(hào)。并且使用相同的版本號(hào),更新的時(shí)候也不需要每個(gè)地方都修改。supportbuildscriptext.support_version=ext.kotlin_version=ext.anko_version='0.8.2'repositories{classpath'com.android.tools.build:gradle:1.5.0'}}}allprojects{}}配置標(biāo)準(zhǔn)庫(kù),Anko庫(kù),以及Kotlin和Kotlin配置標(biāo)準(zhǔn)庫(kù),Anko庫(kù),以及Kotlin和KotlinAnko是一個(gè)用來(lái)簡(jiǎn)化一些Android任務(wù)的很強(qiáng)大的Kotlin庫(kù)。我們之后將會(huì)學(xué)習(xí)部anko,但是現(xiàn)在來(lái)說(shuō)僅僅增加anko-common就足夠了。這個(gè)庫(kù)被分割成了一系列applyplugin:'com.android.application'applyplugin:'kotlin-android'applyplugin:'kotlin-android-extensions'android{}dependenciescompile"com.android.support:appcompat-v7:$support_version"compile"org.jetbrains.anko:anko-common:$anko_version"}buildscript{}dependencies}}把MainActivity轉(zhuǎn)換成Kotlin把把MainActivity轉(zhuǎn)換成Kotlin把MainActivity轉(zhuǎn)換成Kotlin代Kotlinplugin包含了一個(gè)有趣的特性,它能把Java代碼轉(zhuǎn)成Kotlin代碼。正如任何自所以我們?cè)贛ainActivity.java類(lèi)中使用它。打開(kāi)文件,然后選擇CodeConvertJavaFiletoKotlinFile。對(duì)比它們的不同之處,可以讓你更熟悉這門(mén)語(yǔ)言。測(cè)試是否一切測(cè)試是否一切多虧Kotlin和Java之間的互操作性,我們可以在Kotlin中像操作屬性一樣去操作庫(kù)中的getter/setter方法。我們之后再去講解屬性,但是我想提醒的是,我們可以用來(lái)代。編譯器將會(huì)把它轉(zhuǎn)換成一Java代碼,所以這樣使用是沒(méi)有任何性能開(kāi)銷(xiāo)現(xiàn)在運(yùn)行這個(gè)app,并且它是正常運(yùn)行的。檢查T(mén)extView是否是顯示的新的內(nèi)容如果你有疑問(wèn)或者想查看代碼,請(qǐng)?jiān)贙otlinforAndroidDevelopersrepository查overridefunonCreate(savedInstanceState:{super.onCreate(savedInstanceState)message.text="HelloKotlin!"}import測(cè)試是否一切測(cè)試是否一切化下一章會(huì)覆蓋你在轉(zhuǎn)換之后的ManActvity所看到的新的東西。一旦你理解了aKotlin之間的細(xì)微的變化,你將能更容易獨(dú)立寫(xiě)新的代碼了。類(lèi)和函類(lèi)和函類(lèi)和函類(lèi)和函Kotlin中的類(lèi)遵循一個(gè)簡(jiǎn)單的結(jié)構(gòu)。盡管與Java有一點(diǎn)細(xì)微的差別。你可怎么定義一個(gè)怎么定義一個(gè)怎么定義一個(gè)怎么定義一個(gè)類(lèi)名后面寫(xiě)上它的參數(shù)。如果這個(gè)類(lèi)沒(méi)有任何內(nèi)容可以省略大括號(hào):classPerson(name:String,surname:{}}classPerson(name:String,surname:class}類(lèi)繼默認(rèn)任何類(lèi)都是基礎(chǔ)繼承自Any(與java承類(lèi)繼默認(rèn)任何類(lèi)都是基礎(chǔ)繼承自Any(與java承其它類(lèi)。所有的類(lèi)默認(rèn)都是不可繼承的(final),所以我們只能繼承那些明明open或者abstract當(dāng)我們只有單個(gè)構(gòu)造器時(shí),我們需要在從父類(lèi)繼承下來(lái)的構(gòu)造器中指定需要的參Jaa中的r調(diào)用的。openclassAnimal(name:classPerson(name:String,surname:String):函函如果你沒(méi)有指定它的返回值,它就會(huì)返回Unit,與Java中的函函如果你沒(méi)有指定它的返回值,它就會(huì)返回Unit,與Java中的void類(lèi)似,但是Unit是一個(gè)真正的對(duì)象。你當(dāng)然也可以指定任何其它的返回類(lèi)型:小提示:分號(hào)不是必踐。當(dāng)你這么做了,你會(huì)發(fā)現(xiàn)這節(jié)約了你很多時(shí)間。然而如果返回的結(jié)果可以使用一個(gè)表達(dá)式計(jì)算出來(lái),你可以不使用括號(hào)而是使用等f(wàn)unadd(x:Int,y:Int):Int=x+funadd(x:Int,y:Int):{returnx+}funonCreate(savedInstanceState:Bundle?)}構(gòu)造方法和函數(shù)參構(gòu)造方法和函數(shù)參構(gòu)造方法和函數(shù)參構(gòu)造方法和函數(shù)參我們可以給參數(shù)指定一個(gè)默認(rèn)值使得它們變得可選,這是非常有幫助的。這里有一個(gè)例子,在Activity中創(chuàng)建了一個(gè)函數(shù)用來(lái)toas一段信息:這個(gè)與下面的Java代碼是一樣的這跟你想象的一樣復(fù)雜。再看看這個(gè)例voidtoast(String}voidtoast(Stringmessage,length){Toast.makeText(this,message,}toast("Hello",funtoast(message:String,length:Int={Toast.makeText(this,message,}funadd(x:Int,y:Int):{returnx+}構(gòu)造方法和函數(shù)參構(gòu)造方法和函數(shù)參而且甚至還有其它選擇,因?yàn)槟憧梢允褂脜?shù)名字來(lái)調(diào)用,這表示你可以通過(guò)在值前寫(xiě)明參數(shù)名來(lái)傳入你希望的參數(shù):小提示:String你可以在String[$className]$message"。表達(dá)式有一點(diǎn)復(fù)雜,你就需要使用一對(duì)大括號(hào)括起來(lái):"Yourname${}"$toast(message="Hello",length=toast("Hello","MyTag",funniceToast(message:tag:String=length:Int={Toast.makeText(this,"[$className]$message",}編寫(xiě)你的第一編寫(xiě)你的第一創(chuàng)建一個(gè)創(chuàng)建一個(gè)中然后,activity_main.xml會(huì)提示錯(cuò)誤)。暫且我們使用老的findViewByid()的方式:創(chuàng)建一個(gè)創(chuàng)建一個(gè)中然后,activity_main.xml會(huì)提示錯(cuò)誤)。暫且我們使用老的findViewByid()的方式:置,而不是通過(guò)setter,這個(gè)layout已經(jīng)足夠顯示一個(gè)列表了RecyclerViewvalforecastList=findViewById(R.id.forecast_list)asRecyclerVforecastList.layoutManager=dependenciescompilefileTree(dir:'libs',include:compile"com.android.support:appcompat-v7:$support_version"n"}創(chuàng)建一個(gè)對(duì)象實(shí)例創(chuàng)建一個(gè)對(duì)象實(shí)例TheRecyclerTheRecycler過(guò)RecyclerViewTheRecyclerTheRecycler過(guò)RecyclerView又是如此,我們可以像訪問(wèn)屬性一樣訪問(wèn)context和text。你可以保持以往那樣操(使用getters和setters),但是你會(huì)得到一個(gè)編譯器的警告。如果你還是傾Jaa中的使用方式,這個(gè)檢查可以被關(guān)閉。但是一旦你使用上了這種屬性調(diào)用的方式你就會(huì)愛(ài)上它,而且它也節(jié)省了額外的字符總量。classForecastListAdapter(valitems:List<String>):overridefunonCreateViewHolder(parent:ViewGroup,viewType:Int):ViewHolder{return}overridefunonBindViewHolder(holder:ViewHolder,position:Int){holder.textView.text=}overridefungetItemCount():Int=classViewHolder(valtextView:TextView):RecyclerView.View}TheRecyclerList的創(chuàng)盡管我會(huì)在本書(shū)后面來(lái)對(duì)TheRecyclerList的創(chuàng)盡管我會(huì)在本書(shū)后面來(lái)對(duì)Collection進(jìn)行講解,但是我現(xiàn)在僅僅簡(jiǎn)單地解你可以通過(guò)使用一個(gè)函創(chuàng)建一個(gè)常量的List(很快我們就會(huì)到的immutable)。它接收一個(gè)任何類(lèi)型的vararg(可變長(zhǎng)的參還有很多其它的函數(shù)可以選擇,比如setOf,arrayListOf或者h(yuǎn)ashSetOf。為了優(yōu)化項(xiàng)目的結(jié)構(gòu),我也移動(dòng)了一些類(lèi)到新的包里privatevalitemslistOf("Mon6/23-Sunny-31/17","Tue6/24-Foggy-21/8","Wed6/25-Cloudy-"Thurs6/26-Rainy-18/11","Fri6/27-Foggy-21/10","Sat6/28-TRAPPEDINWEATHERSTATION-"Sun6/29-Sunny-)overridefunonCreate(savedInstanceState:Bundle?)valforecastList=findViewById(R.id.forecast_list)asRecycforecastList.layoutManager=LinearLayoutManager(this)forecastList.adapter=ForecastListAdapter(items)}變量和屬變量和屬變量和屬變量和屬基本類(lèi)基本類(lèi)之處你可能需要考慮到:數(shù)字類(lèi)型中不會(huì)自動(dòng)轉(zhuǎn)型。舉個(gè)例子,你不能給Double基本類(lèi)基本類(lèi)之處你可能需要考慮到:數(shù)字類(lèi)型中不會(huì)自動(dòng)轉(zhuǎn)型。舉個(gè)例子,你不能給Double變量分配一字符Cha)不能直接作為一個(gè)數(shù)字來(lái)處理。在需要時(shí)我們需要把他們轉(zhuǎn)換為一個(gè)數(shù)字:還有很多其他的位操作符,比如sh1shsushrxor或inv。當(dāng)我//valbitwiseOr=FLAG1orFLAG2valbitwiseAnd=FLAG1andFLAG2//intbitwiseOr=FLAG1|FLAG2;intbitwiseAnd=FLAG1&FLAG2;valvali:Int=valvald:Double=基本類(lèi)具體的類(lèi)型一個(gè)String可基本類(lèi)具體的類(lèi)型一個(gè)String可以像數(shù)組那樣訪問(wèn),并且被迭vals=valcs[2這是一個(gè)字符迭代vals="Example"for(cins){}vali=12//AnvaliHex0x0f一個(gè)十六進(jìn)制的Intvall=3L//ALongvald=3.5//ADoublevalf=3.5F//A變變變量可以很簡(jiǎn)單地定義成可變(var)和不可變變變變量可以很簡(jiǎn)單地定義成可變(var)和不可變一個(gè)不可變對(duì)象意味著它在實(shí)例化之后就不能再去改變它的狀態(tài)了。如果你需要一個(gè)這個(gè)對(duì)象修改之后的版本,那就會(huì)再創(chuàng)建一個(gè)新的對(duì)象。這個(gè)讓編程更加具有健壯性和預(yù)估性。在Java個(gè)對(duì)象的代碼都可以去修改它,從而影響整個(gè)程序的其它地方。不可變對(duì)象也可以說(shuō)是線程安全的,因?yàn)樗鼈儫o(wú)法去改變,也不需要去定義訪問(wèn)控制,因?yàn)樗芯€程訪問(wèn)到的對(duì)象都是同一個(gè)。所以在Kotlin中,如變。一個(gè)重要的概念是:盡可能地使。除了個(gè)別情況(特別是在中,有很多類(lèi)我們是不會(huì)去直接調(diào)用構(gòu)造函數(shù)的),大多數(shù)時(shí)候是可以如果我們需要使用更多的范型類(lèi)型,則需要指vala:Any=valc:Context=vals="Example"http://AStringvali=23//AnIntvalactionBar=supportActionBar//AnActionBarinanActivity屬屬屬性與Java中的字段是屬屬屬性與Java中的字段是相同的,但是更加強(qiáng)大。屬性做的事情是字段加上getter上see。我們通過(guò)一個(gè)例子來(lái)比較他們的不同之處。這是Java修改所需要的代碼:在Kotlin中,只需要一個(gè)屬性就可以了如果沒(méi)有任何指定,屬性會(huì)默認(rèn)使用gettersetter。當(dāng)然它也可以修改為你自定義的代碼,并且不修改存在的代碼:publicclass{varname:String=}valperson=Person()="name"valname=publicclass{privateStringname;publicStringgetName(){return}publicvoidsetName(String{=}}Personperson=newPerson();Stringname=屬。可以使用field屬。可以使用field而不是直接訪問(wèn)這個(gè)屬性。backingfield只能在屬性訪問(wèn)器內(nèi)訪問(wèn)。就如在前面章節(jié)提到的,當(dāng)操作Jav代碼的時(shí)候,Koava文件中定義的see方法。編譯器會(huì)直接鏈接到它原始的getter/setter方法。所以當(dāng)我們直接訪問(wèn)屬性的時(shí)候不會(huì)有性能開(kāi)publicclasss{varname:String=get()=field.toUpperCase()field="Name:}}Anko是什么Anko是什么Anko是什么Anko是什么o是Jet開(kāi)發(fā)的一個(gè)強(qiáng)大的庫(kù)。它主要的目的是用來(lái)替代以前的方式來(lái)使用代碼生成I布局。這是一個(gè)很有趣的特性,我推薦你可以嘗試下,但是我在這個(gè)項(xiàng)目中暫時(shí)不使用它。對(duì)于我(可能是由于多年的繪制經(jīng)驗(yàn))來(lái)說(shuō)使用L更容易一些,但是你會(huì)喜歡那種方式的。然而,這個(gè)不是我們能在這個(gè)庫(kù)中得到的唯一一個(gè)功能。Anko子,但是你應(yīng)該快速地認(rèn)識(shí)到這個(gè)庫(kù)幫你解決了什么樣的問(wèn)盡管Anko任何時(shí)候使用ctrl點(diǎn)擊(Windows)或者cmd點(diǎn)擊(Mac)的方式跳轉(zhuǎn)開(kāi)始使用開(kāi)始使用在之前,讓我們來(lái)使用開(kāi)始使用開(kāi)始使用在之前,讓我們來(lái)使用Anko庫(kù)中的某些東西,它們都會(huì)以屬性名、方法等方式被導(dǎo)入。這是因?yàn)锳o使用了擴(kuò)展函數(shù)在And是什么,怎么去編寫(xiě)它。我們現(xiàn)在還不能使用庫(kù)中更多的東西,但是Anko能幫助我們簡(jiǎn)化代碼,比如化n,Acy之間的跳轉(zhuǎn),F(xiàn)的創(chuàng)建,數(shù)據(jù)庫(kù)的訪問(wèn),A的創(chuàng)建我們將會(huì)在實(shí)現(xiàn)這個(gè)App的過(guò)程中學(xué)習(xí)到很多有趣的例子。valforecastList:RecyclerView=擴(kuò)展函擴(kuò)展函擴(kuò)展函數(shù)數(shù)是指在一個(gè)類(lèi)上增加一種新的行為,甚至我們沒(méi)有這個(gè)類(lèi)代碼的訪問(wèn)權(quán)限。這是一個(gè)在缺少有用函數(shù)的類(lèi)上擴(kuò)展的方法。在Java中,通常會(huì)實(shí)現(xiàn)很多帶有stac擴(kuò)展函擴(kuò)展函擴(kuò)展函數(shù)數(shù)是指在一個(gè)類(lèi)上增加一種新的行為,甚至我們沒(méi)有這個(gè)類(lèi)代碼的訪問(wèn)權(quán)限。這是一個(gè)在缺少有用函數(shù)的類(lèi)上擴(kuò)展的方法。在Java中,通常會(huì)實(shí)現(xiàn)很多帶有stac方法的工具類(lèi)。Kon中擴(kuò)展函數(shù)的一個(gè)優(yōu)勢(shì)是我們不需要在調(diào)用方法的時(shí)候把整個(gè)對(duì)象當(dāng)作參數(shù)傳入。擴(kuò)展函數(shù)表現(xiàn)得就像是屬于這個(gè)類(lèi)的一樣,而且我們可以使用s舉個(gè)例子,我們可以創(chuàng)建一個(gè)toast函數(shù),這個(gè)函數(shù)不需要傳入任何contex,它可以Context或者它的子類(lèi)調(diào)用,比如Activity或者:這個(gè)方法可以在Activity內(nèi)部直接調(diào)用些針對(duì)CharSequence和resource的函數(shù),還有兩個(gè)不同的toast和longToast方子展示了使用他自己的see生成一個(gè)屬性的方式。Kotoast("Helloworld!")toast("Hellotoast("Helloworld!",funContext.toast(message:CharSequence,duration:Int=Toast.LENGTH_SHORT){Toast.makeText(this,message,}擴(kuò)展函新建的文件里。這是Anko擴(kuò)展函新建的文件里。這是Anko功能背后的魔法。現(xiàn)在通過(guò)以上,你也可以自己創(chuàng)建你的魔publicvarTextView.text:CharSequenceget()=getText()set(v)=執(zhí)行一個(gè)請(qǐng)執(zhí)行一個(gè)請(qǐng)一個(gè)簡(jiǎn)單的API請(qǐng)求,我們可以不使用任何第三方庫(kù)來(lái)簡(jiǎn)單地實(shí)而且,如你所見(jiàn),Kotlin提供了一些擴(kuò)展函數(shù)來(lái)讓請(qǐng)求變得更簡(jiǎn)單。首先,我們要?jiǎng)?chuàng)建一個(gè)新的Ret薦結(jié)果很大的響應(yīng),但是在我們這個(gè)例子中已經(jīng)足夠好如果你用這些代碼去比較Java,你會(huì)發(fā)現(xiàn)我們僅使用標(biāo)準(zhǔn)庫(kù)就節(jié)省了大量的代碼比、和需要達(dá)到相同效果所必要的代結(jié)果,管理連接狀態(tài)、等部分的代碼。很明顯,這些就是場(chǎng)景背后函數(shù)所作的事情,但是我們卻不用關(guān)心。在AndroidManifest.xml中添加::publicclassRequest(valurl:{publicfunrun()valforecastJsonStr=URL(url).readText()}}在主線程以外執(zhí)行在主線程以外執(zhí)行請(qǐng)果Activity已經(jīng)被在主線程以外執(zhí)行在主線程以外執(zhí)行請(qǐng)果Activity已經(jīng)被銷(xiāo)毀了,這里就會(huì)崩潰Anko提供了非常簡(jiǎn)單的DSL基本的async函數(shù)用于在其它線程執(zhí)行代碼,也可以選擇通過(guò)調(diào)用的UIThread有一個(gè)很不錯(cuò)的一點(diǎn)就是可以依賴(lài)于調(diào)用者。如果它是個(gè)Activity返回true假如你想使用Future來(lái)工作,async返回一個(gè)JavaFuture。而且如果你需要一個(gè)返回結(jié)果的Future,你可以使用asyncResult。真的很簡(jiǎn)單,對(duì)吧?而更加具有可讀性?,F(xiàn)在,我僅僅給請(qǐng)求送了一個(gè),來(lái)測(cè)試我們是否可以正確接收內(nèi)容,這樣我們才能在Acyso解析和轉(zhuǎn)換成繼續(xù)之前,學(xué)習(xí)什么是數(shù)據(jù)類(lèi)也是很重要檢查代碼并審查url請(qǐng)求和包結(jié)構(gòu)的代碼。你可以運(yùn)行app并且確保你可以在打印json日志和請(qǐng)求完畢之后的toastasync()uiThread{longToast("Requestperformed")}數(shù)據(jù)數(shù)據(jù)和setter。定義一個(gè)新的數(shù)據(jù)類(lèi)非常簡(jiǎn)dataclassForecast(valdate:Date,valtemperature:Float,valdetails:String)額外的函額外的函通過(guò)數(shù)據(jù)類(lèi),我們可以方便地得到很多有趣的函數(shù),一部分是來(lái)自屬性,我們之前已經(jīng)講過(guò)(從編寫(xiě)getter額外的函額外的函通過(guò)數(shù)據(jù)類(lèi),我們可以方便地得到很多有趣的函數(shù),一部分是來(lái)自屬性,我們之前已經(jīng)講過(guò)(從編寫(xiě)gettersette 它可以比較兩個(gè)對(duì)象的屬性來(lái)確保他們是相同 我們可以得到一個(gè)hash值,也是從屬性中計(jì)算出來(lái)的一系列可以映射對(duì)象到變量中的函數(shù)。我也很快就會(huì)講到這復(fù)制一個(gè)數(shù)據(jù)復(fù)制一個(gè)數(shù)據(jù)且不簡(jiǎn)潔的。舉個(gè)例子,如果我們需要修改Forecast中的temperature(溫度),我們可以復(fù)制一個(gè)數(shù)據(jù)復(fù)制一個(gè)數(shù)據(jù)且不簡(jiǎn)潔的。舉個(gè)例子,如果我們需要修改Forecast中的temperature(溫度),我們可以當(dāng)你使用Java類(lèi)時(shí)小心“不可修改性如果你決定使用不可修改來(lái)工作,你需要意識(shí)到Java不是根據(jù)這種思想來(lái)設(shè)計(jì)的,在某些情況下,我們?nèi)匀豢梢孕薷倪@些狀態(tài)。在上一個(gè)例子中,e對(duì)象,然后改變它的值。有個(gè)簡(jiǎn)單(不安全)法是記住所有需要修改狀態(tài)的對(duì)象作為一個(gè)規(guī)則,然后必要的時(shí)候去拷貝valf1=Forecast(Date(),27.5f,"Shinyday")valf2=f1.copy(temperature=30f)映射對(duì)象到變映射對(duì)象到變什么會(huì)有componentX函數(shù)被自動(dòng)創(chuàng)建。使用上面的Forecast上面這個(gè)多聲明會(huì)被編譯成下面的代這個(gè)特性背后的邏輯是非常強(qiáng)大的,它可以在很多情況下幫助我們簡(jiǎn)化代碼。舉個(gè)pke和:for((key,value)inmap)Log.d("map","key:$key,}valdate=valtemperature=ponent2()valdetails=ponent3()valf1=Forecast(Date(),27.5f,"Shinyday")val(date,temperature,details)=f1轉(zhuǎn)換json到數(shù)轉(zhuǎn)換json到數(shù)據(jù)我們現(xiàn)在知道怎么去創(chuàng)建一個(gè)數(shù)據(jù)類(lèi),那我們開(kāi)始準(zhǔn)備去解析數(shù)據(jù)。在date包轉(zhuǎn)換json到數(shù)轉(zhuǎn)換json到數(shù)據(jù)我們現(xiàn)在知道怎么去創(chuàng)建一個(gè)數(shù)據(jù)類(lèi),那我們開(kāi)始準(zhǔn)備去解析數(shù)據(jù)。在date包在我們當(dāng)前的U中,我們不會(huì)去使用所有的這些數(shù)據(jù)。我們會(huì)解析所有到類(lèi)里面,因?yàn)榭赡軙?huì)在以后某些情況下會(huì)用到。以下就是我們需要使用到的類(lèi):當(dāng)我們使用Gson來(lái)解析json到我們的類(lèi)中,這些屬性的名字必須要與json中的名一樣,或者可以指定一(序列化名稱(chēng))。一個(gè)好的實(shí)踐是大部分的軟件結(jié)構(gòu)中會(huì)根據(jù)我們app中布局來(lái)解耦成不同的模型。所以我喜歡serialiseddataclassForecastResult(valcity:City,vallist:List<ForecasdataclassCity(valid:Long,valname:String,valcoord:Coordvalcountry:String,valpopulation:Int)dataclassCoordinates(vallon:Float,vallat:Float)dataclassForecast(valdt:Long,valtemp:Temperature,valpressure:Float,valhumidity:Int,valweather:,valspeed:Float,valdeg:Int,valvalrain:dataclassTemperature(valday:Float,valmin:Float,valmax:valnight:Float,valeve:Float,val:dataclassWeather(valid:Long,valmain:String,valdescription:String,valicon:轉(zhuǎn)換json到數(shù)聲明簡(jiǎn)化這些類(lèi),因?yàn)槲視?huì)在app其它部分使用它之前解轉(zhuǎn)換json到數(shù)聲明簡(jiǎn)化這些類(lèi),因?yàn)槲視?huì)在app其它部分使用它之前解析這些類(lèi)。屬性名json結(jié)果中的名字是完全一樣然只接收一個(gè)城市的zipcode作為參數(shù)而不是一個(gè)完整的url,因此這樣變得更加具有可讀性。現(xiàn)在,我會(huì)把這個(gè)靜態(tài)的url放在一個(gè)companionobject(伴隨對(duì)象)中。如果我們之后還要對(duì)該API增加更多請(qǐng)求,我們需要提取Kotlin允許我們?nèi)ザx一些行為與靜態(tài)對(duì)象一樣的對(duì)象。盡管這些對(duì)象可以用眾所周知的模式來(lái)實(shí)現(xiàn),比如容易實(shí)現(xiàn)的單例模式。用Java中的靜態(tài)屬性或者方法以下是最后的代碼compilepublicclassForecastRequest(valzipCode:{companionobjectprivatevalAPP_ID="15646a06818f61f7b8d7823ca833e1ce"privatevalURL="/data/2.5/"privatevalCOMPLETE_URL="$URL&APPID=$APP_ID&q="}funexecute():ForecastResultvalforecastJsonStr=URL(COMPLETE_URL+returnGson().fromJson(forecastJsonStr,ForecastResult::}}companion轉(zhuǎn)換json到數(shù)轉(zhuǎn)換json到數(shù)構(gòu)建domain構(gòu)建domain首先,必須要定義一個(gè)Command這個(gè)command會(huì)執(zhí)行一個(gè)操作并且返回某種類(lèi)型的對(duì)象,這個(gè)類(lèi)型可以通過(guò)范型指定。構(gòu)建domain構(gòu)建domain首先,必須要定義一個(gè)Command這個(gè)command會(huì)執(zhí)行一個(gè)操作并且返回某種類(lèi)型的對(duì)象,這個(gè)類(lèi)型可以通過(guò)范型指定。你需要知道一個(gè)有趣的概念,一切kotlin函數(shù)都會(huì)返回一個(gè)值。如果沒(méi)有定,它就默認(rèn)返回一類(lèi)。所以如果我們想讓Command不返回?cái)?shù)據(jù),我可以指定它的類(lèi)型為UnitKotlin中的接口比8以前)中的強(qiáng)大多了,因?yàn)樗鼈兛梢园a是我們現(xiàn)在不需要更多的代碼,以后的章節(jié)中會(huì)仔細(xì)講這個(gè)話當(dāng)更多的功能被增加,這些類(lèi)可能會(huì)需要在以后被審查。但是現(xiàn)在這些類(lèi)對(duì)我們來(lái)說(shuō)已經(jīng)足夠了。個(gè)DataMapper:dataclassForecastList(valcity:String,valcountry:valdataclassForecast(valdate:String,valdescription:String,valhigh:Int,vallow:publicinterface{funexecute():}構(gòu)建domain當(dāng)我們使用了兩個(gè)相同名字的類(lèi),我們可以給其中一個(gè)指定一個(gè)別名,這樣我們就不需要寫(xiě)完整的包名了:這些代碼中另一個(gè)有趣的是我構(gòu)建domain當(dāng)我們使用了兩個(gè)相同名字的類(lèi),我們可以給其中一個(gè)指定一個(gè)別名,這樣我們就不需要寫(xiě)完整的包名了:這些代碼中另一個(gè)有趣的是我們從一個(gè)list中轉(zhuǎn)換為model的方法returnlist.map{convertForecastItemToDomain(it)importcom.antonioleiva.weatherapp.domain.model.ForecastasModepublicclassForecastDataMapperfunconvertFromDataModel(forecast:ForecastResult):ForecastList{privatefunconvertForecastListToDomain(list:List<Forecast>):returnlist.map{convertForecastItemToDomain(it)}privatefunconvertForecastItemToDomain(forecast:Forecast):ModelForecast{returnModelForecast(convertDate(forecast.dt),}privatefunconvertDate(date:Long):Stringvaldf=DateFormat.getDateInstance(DateFormat.MEDIUM,Lreturndf.format(date*}}構(gòu)建domain這一條語(yǔ)句,我們就可以循環(huán)這個(gè)集合并且返回一個(gè)轉(zhuǎn)換后的新的s。構(gòu)建domain這一條語(yǔ)句,我們就可以循環(huán)這個(gè)集合并且返回一個(gè)轉(zhuǎn)換后的新的s。在s中提供了很多不錯(cuò)的函數(shù)操作符,它們可以在這個(gè)s的每個(gè)ieJava,這是Ko現(xiàn)在,編寫(xiě)命令前的準(zhǔn)備就緒classRequestForecastCommand(valzipCode:String){overridefunexecute():{valforecastRequest=ForecastRequest(zipCode)}}在UI中繪制在UI中繪制數(shù)中的代在UI中繪制在UI中繪制數(shù)中的代碼有些小的改動(dòng),因?yàn)楝F(xiàn)在有真實(shí)的數(shù)據(jù)需要填adapter中。異步調(diào)用需要被重寫(xiě)Adapter也需要被修classForecastListAdapter(valweekForecast:ForecastList):overridefunonCreateViewHolder(parent:ViewGroup,viewType:ViewHolder?return}overridefunonBindViewHolder(holder:ViewHolder,position:Int){{holder.textView.text="$date-$description-}}overridefungetItemCount():Int=weekForecast.dailyForecasclassViewHolder(valtextView:TextView):RecyclerView.View}async()valresult=RequestForecastCommand("94043").execute()forecastList.adapter=}}在UI中繪制withh在UI中繪制withh是一個(gè)非常有用的函數(shù),它包含在Ko(第一個(gè)參數(shù))的一個(gè)擴(kuò)展函數(shù),我們可以就像作為hs一樣使用所有它的c方法和屬性。當(dāng)我們針對(duì)同一個(gè)對(duì)象做很多操作的時(shí)候這個(gè)非常有利于簡(jiǎn)化代碼。在這一章中有很多新的代碼加入,所以檢出庫(kù)中的代碼吧操作符重操作符重操作符重操作符重Kotin有一些為映射到這個(gè)方法。重載這些操作符可以增加代碼可讀性和簡(jiǎn)潔性。操作符操作符這里你可以看見(jiàn)一系列包括操作符和對(duì)應(yīng)方法的表。對(duì)應(yīng)方法必須在指定的類(lèi)中一元操作二元操作函a+a-操作符操作符這里你可以看見(jiàn)一系列包括操作符和對(duì)應(yīng)方法的表。對(duì)應(yīng)方法必須在指定的類(lèi)中一元操作二元操作函a+a-a*a/a%aina!ina+=a-=a*=a/=a%=函-a-操作符數(shù)組操作等于操作操作符和用來(lái)做身份檢查(它們分別是Java中的和),并且函數(shù)調(diào)方調(diào)操作符數(shù)組操作等于操作操作符和用來(lái)做身份檢查(它們分別是Java中的和),并且函數(shù)調(diào)方調(diào)a(i,a(i_1,...,operatorfunequals(other:Any?):函a==a?.equals(b)?:b===a!=!(a?.equals(b)?:b===函a[i,a[i_1,...,a.get(i_1,...,a[i]=a[i,j]=a.set(i,j,a[i_1,...,i_n]=a.set(i_1,...,i_n,操作符操作符例例你可以想象,KotlinList是實(shí)現(xiàn)了數(shù)組操作符的,所以我們可以像Java中的數(shù)組一例例你可以想象,KotlinList是實(shí)現(xiàn)了數(shù)組操作符的,所以我們可以像Java中的數(shù)組一式被直接設(shè)置如果你還記得,我們有一個(gè)叫ForecastList的數(shù)據(jù)類(lèi),它是由很多其他額外的信成的。有趣的是可以直接訪問(wèn)它的每一項(xiàng)而不是請(qǐng)求內(nèi)部的list得到某一項(xiàng)。完全不相關(guān)的事情,我要去實(shí)現(xiàn)方法,它能稍微能簡(jiǎn)化一點(diǎn)當(dāng)前當(dāng)然還有g(shù)etItemCount(overridefungetItemCount():Int=overridefunonBindViewHolder(holder:ViewHolder,position:Int){holder.textView.text="$date-$description-}}dataclassForecastList(valcity:String,valcountry:valdailyForecast:{operatorfunget(position:Int):Forecast=dailyForecast[pofunsize():Int=}valx=myList[2]myList[2]=4例例擴(kuò)展函數(shù)中的操作擴(kuò)展函數(shù)中的操作類(lèi)來(lái)讓第三方的庫(kù)能提供更多的操作。幾個(gè)例子,我們可以去像訪問(wèn)s擴(kuò)展函數(shù)中的操作擴(kuò)展函數(shù)中的操作類(lèi)來(lái)讓第三方的庫(kù)能提供更多的操作。幾個(gè)例子,我們可以去像訪問(wèn)s的方式去訪問(wèn)ViewGroup的別忘了去valcontainer:ViewGroup=find(R.id.container)valview=container[2]operatorfunViewGroup.get(position:Int):View=getChildAt(pos使Forecastlist可點(diǎn)使Forecast使Forecastlist可點(diǎn)使Forecastlist可點(diǎn)作為一個(gè)真正的,當(dāng)前列表的每一個(gè)e布局應(yīng)該做一些工作。第一件事就是創(chuàng)建一個(gè)合適的M述以及最高和最低溫度。所以讓我們創(chuàng)建一個(gè)名為l的<?xmlversion="1.0"encoding="utf-使Forecastlist可點(diǎn)Dom使Forecastlist可點(diǎn)Domn model和數(shù)據(jù)映射時(shí)必須生成完整的圖標(biāo)ul,所以我們可以這樣去加載tools:text="May14,tools:text="Light使Forecastlist可點(diǎn)在ForecastDataMapper我們從第一個(gè)請(qǐng)求中得到圖標(biāo)的code使Forecastlist可點(diǎn)在ForecastDataMapper我們從第一個(gè)請(qǐng)求中得到圖標(biāo)的code,用來(lái)組成完成的圖標(biāo)url。加載圖片最方式是使用圖片加載庫(kù)是一個(gè)不錯(cuò)的選擇。它需到build.gradle如此,Adapter也需要一個(gè)大的改動(dòng)了。還需要一個(gè)listener,我們來(lái)定義它如果你還記得上一課程,當(dāng)被調(diào)用時(shí)invoke方法可以被省略。所以我們來(lái)使用它publicinterface{operatorfuninvoke(forecast:}compileprivatefunconvertForecastItemToDomain(forecast:Forecast):ModelForecast{returnModelForecast(convertDate(forecast.dt),}privatefungenerateIconUrl(iconCode:String):=dataclassForecast(valdate:String,valdescription:valhigh:Int,vallow:Int,valiconUrl:使Forecastlist可點(diǎn)使Forecastlist可點(diǎn)classViewHolder(view:View,valitemClick::{privatevaliconView:ImageViewprivatevaldateView:TextViewprivatevaldescriptionView:TextViewprivatevalmaxTemperatureView:TextViewprivatevalminTemperatureView:initiconView=view.find(R.id.icon)dateView=descriptionView=view.find(R.id.description)maxTemperatureView=view.find(R.id.maxTemperature)minTemperatureView=}funbindForecast(forecast:{with(forecast)dateView.text=datedescriptionView.text=descriptionmaxTemperatureView.text="${high.toString()}"minTemperatureView.text="${low.toString()}"itemView.setOnClickListener{itemClick(forecast)}}}}使list可點(diǎn)了ctx使list可點(diǎn)了ctx性。所以我們要?jiǎng)?chuàng)建一個(gè)新的名叫ViewExtensions.kt替ui.utils從現(xiàn)在開(kāi)始,任何oxtx的話在其它類(lèi)中也會(huì)更有連貫性。而且,這是一個(gè)很好的怎么去使用擴(kuò)展屬性的例子。最后,MainActivity調(diào)用setAdapter,最后結(jié)果是這樣的valView.ctx:Contextget()=contextpublicclassForecastListAdapter(valweekForecast:ForecastList,valitemClick::overridefunonCreateViewHolder(parent:ViewGroup,viewType:ViewHoldervalview=.inflate(R.layout.item_forecast,parent,false)returnViewHolder(view,itemClick)}overridefunonBindViewHolder(holder:ViewHolder,position:Int){}}使Forecastlist可點(diǎn)使Forecastlist可點(diǎn)去代碼庫(kù)中更新新的代碼。UI開(kāi)始看起來(lái)更好了object:ForecastListAdapter.OnItemClickListener{overridefuninvoke(forecast:Forecast){}LLL是非常有用實(shí)現(xiàn)它們。在Ko,我們把一個(gè)函數(shù)作為另一個(gè)函數(shù)的參數(shù)。簡(jiǎn)化簡(jiǎn)化我們用Android中非常典型的例子去解簡(jiǎn)化簡(jiǎn)化我們用Android中非常典型的例子去解釋它是怎么事件的回調(diào),我首先要編寫(xiě)一個(gè)OnClickListener接口:然后我們要編寫(xiě)一個(gè)匿名內(nèi)部類(lèi)去實(shí)現(xiàn)這個(gè)接我們將把上面的代碼轉(zhuǎn)換成Kotlin(使用了Anko的toast函數(shù)funsetOnClickListener(listener:(View)->view.setOnClickListener(object:{overridefunonClick(v:View){}}OnClickListener(){@OverridepublicvoidonClick(Viewv){Toast.makeText(v.getContext(),"Click",Toast.LENGTH_SHO}publicinterface{voidonClick(View}簡(jiǎn)化一個(gè)表達(dá)式通過(guò)參數(shù)的形式被定義在箭頭的左邊(被圓括號(hào)包圍)箭頭的右邊返回結(jié)果值。在這個(gè)例子中,我們接收一個(gè),然后返回一個(gè)Unit(沒(méi)有簡(jiǎn)化一個(gè)表達(dá)式通過(guò)參數(shù)的形式被定義在箭頭的左邊(被圓括號(hào)包圍)箭頭的右邊返回結(jié)果值。在這個(gè)例子中,我們接收一個(gè),然后返回一個(gè)Unit(沒(méi)有東西)。所以根據(jù)這種思想,我們可以把前面的代碼簡(jiǎn)化成這到,我們甚至可以省略左邊的參數(shù):如果這個(gè)函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù),我們可以把這個(gè)函數(shù)移動(dòng)到圓括號(hào)外并且,最后,如果這個(gè)函數(shù)只有一個(gè)參數(shù),我們可以省略這個(gè)圓括比原始的Java5倍多,并且更加容易理解它所做的事情。非常讓人影響view.setOnClickListener{toast("Click")view.setOnClickListener(){toast("Click")view.setOnClickListener({view->ForecastListAdapter的clickForecastListAdapter的click在前面一章,我這么艱苦地寫(xiě)了cksteForecastListAdapter的clickForecastListAdapter的click在前面一章,我這么艱苦地寫(xiě)了ckstee的目的就是更好的在這一章中進(jìn)行開(kāi)發(fā)。然而現(xiàn)在是時(shí)候把你學(xué)到的東西用到實(shí)踐中去了。我們從FosLstA中刪除了stee接口,然后使用代替:西。ViewHolder中也可以這么修改:我們可以簡(jiǎn)化最后一句。如果這個(gè)函數(shù)只接收一個(gè)參數(shù),那我們可以使用it引valadapter=ForecastListAdapter(result){toast(it.date)valadapter=ForecastListAdapter(result){forecast->toast(forecast.date)}classViewHolder(view:View,valitemClick:(Forecast)->publicclassForecastListAdapter(valweekForecast:valitemClick:(Forecast)->擴(kuò)展語(yǔ)擴(kuò)展語(yǔ)多虧這些改變,我們可以去創(chuàng)擴(kuò)展語(yǔ)擴(kuò)展語(yǔ)多虧這些改變,我們可以去創(chuàng)建自己的builder和代碼塊。我們已經(jīng)在使用一些有趣的函數(shù),比如with。如下簡(jiǎn)單的實(shí)現(xiàn):類(lèi)型的讓這個(gè)對(duì)象去執(zhí)行這個(gè)函數(shù)。因?yàn)榈诙€(gè)參數(shù)是一個(gè)函數(shù),所以我們可以把它放在圓括號(hào)外面,所以我們可以創(chuàng)建一個(gè)代碼塊,在這這個(gè)代碼塊中我們可以使內(nèi)聯(lián)內(nèi)聯(lián)函數(shù)與普通的函數(shù)有點(diǎn)不同。一個(gè)內(nèi)聯(lián)函數(shù)會(huì)在編譯的時(shí)候被替換如果是一個(gè)普通的函數(shù),內(nèi)部會(huì)創(chuàng)建一個(gè)含有那個(gè)函數(shù)的對(duì)象。另一方成一個(gè)內(nèi)部的對(duì)象。dateView.text=datedescriptionView.text=descriptionmaxTemperatureView.text="$high"minTemperatureView.text="$low"itemView.setOnClickListener{itemClick(this)}}Tinlinefun<T>with(t:T,body:T.()->Unit){t.body()擴(kuò)展語(yǔ)它只是檢查版本,然后如果擴(kuò)展語(yǔ)它只是檢查版本,然后如果滿足條件則去執(zhí)行?,F(xiàn)在我們可以這么的DSL以查看Kotlinreference中使用DSL來(lái)編寫(xiě)HTMLAndroid{}inlinefunsupportsLollipop(code:()->Unit)if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP)}}可見(jiàn)性修飾可見(jiàn)性修飾Kotlin中不同的可見(jiàn)性修飾符是怎么工作的修飾,我們修飾,我們就不能在定義這個(gè)類(lèi)之另一方面,如果我們?cè)谝粋€(gè)類(lèi)里面使用了private修飾符,那訪問(wèn)權(quán)限就被限制,那么它們只會(huì)對(duì)被定義所在的文件可見(jiàn)。如果被定義在了類(lèi)或者接口中,那它們只對(duì)這個(gè)類(lèi)或者接口可見(jiàn)。這個(gè)修飾符只能被用在類(lèi)或者接口中的成員上。一個(gè)包成員不能被為protected。定義在一個(gè)成員中,就與Java中的方式一樣了:它可以被成員自如果是一個(gè)定的包成員的話,對(duì)所在的整個(gè)module它是一個(gè)其它領(lǐng)域的成員,它就需要依賴(lài)那個(gè)領(lǐng)域的可見(jiàn)性了。比如,如果我了一個(gè)private類(lèi),那么它的這個(gè)類(lèi)的可見(jiàn)性修飾的函數(shù)的可見(jiàn)性就會(huì)限制與它所我們可以訪問(wèn)同一個(gè)module中的internal修飾的類(lèi),但是不能訪問(wèn)其它module的。什么是塊,可以在AndroidStudio中創(chuàng)建不同的module什么是塊,可以在AndroidStudio中創(chuàng)建不同的module。在Eclipse中,這些module可以認(rèn)為是在一個(gè)workspace中的不同的projectcc的成員構(gòu)造所有構(gòu)造函構(gòu)造所有構(gòu)造函數(shù)默認(rèn)都是public的,它們類(lèi)是可見(jiàn)的,可以被其它地方使用。我們也可以使用這個(gè)語(yǔ)法來(lái)把構(gòu)造函數(shù)修改為private:classCprivateconstructor(a:Int){...潤(rùn)色我們的代潤(rùn)色我們的代我們已經(jīng)準(zhǔn)備好使?jié)櫳覀兊拇鷿?rùn)色我們的代我們已經(jīng)準(zhǔn)備好使來(lái)進(jìn)行重構(gòu)了,但是我們還有很多其它細(xì)節(jié)需性zipCode可以定義為private:所作的事情就是我們創(chuàng)建了一個(gè)不可修改的屬性z,它的值我們只能去得類(lèi)的時(shí)候,你覺(jué)得某些屬性因?yàn)槭鞘裁丛虿荒軐?duì)別人可見(jiàn),那就把它定義為private而且,在Kotlin中,我們不需要去指定一個(gè)函數(shù)的返回值類(lèi)型,它可以讓編譯器推斷出來(lái)。舉個(gè)省略返回值類(lèi)型的例子:我們可以省略返回值類(lèi)型的典型情景是當(dāng)我們要給一個(gè)函數(shù)或者一個(gè)屬性賦值的時(shí)候。而不需要去寫(xiě)代碼塊去實(shí)現(xiàn)。剩下的修改是相當(dāng)簡(jiǎn)單的,你可以在代碼庫(kù)中去同步下dataclassForecastList(...)funget(position:Int)=dailyForecast[position]funsize()=dailyForecast.size()}classRequestForecastCommand(privatevalzipCode:KotlinAndroidKotlinAndroid另一個(gè)Kotlin團(tuán)隊(duì)研發(fā)的可以讓開(kāi)發(fā)更簡(jiǎn)單的KotlinAndroidKotlinAndroid另一個(gè)Kotlin團(tuán)隊(duì)研發(fā)的可以讓開(kāi)發(fā)更簡(jiǎn)單的插件。當(dāng)前僅僅包括了view的綁定。這個(gè)插件自動(dòng)創(chuàng)建了很多的屬性來(lái)我們直接訪問(wèn)中的vvs。們將會(huì)是我們類(lèi)中非常重要的一部分。這些屬性的類(lèi)型也是來(lái)自XMLKotlin的標(biāo)準(zhǔn)庫(kù)那它背后是怎么工作的?該插件會(huì)代替任何屬性調(diào)用函數(shù),比如獲取到vw緩存功能,以免每次屬性被調(diào)用都會(huì)去重新獲取這個(gè)vw。需要注意的是這個(gè)緩存裝置只會(huì)或中才有效。如果它是在一個(gè)擴(kuò)展函數(shù)中改,所以不需要再去增加一個(gè)緩存功能。中但是插件不能被KotlinAndroidKotlin怎么去使用KotlinAndroid唯一一件需要這個(gè)插件怎么去使用KotlinAndroid唯一一件需要這個(gè)插件做的事情是在類(lèi)中增加一個(gè)特定的"手工"import來(lái)使用這或者Fragments的Android或fragment我們需要使用的import語(yǔ)句以kotlin.android.synthetic開(kāi)頭,然后加上我importkotlinx.android.synthetic.content_main.*import{}dependencies}}的Android前面說(shuō)的使用還是有的Android前面說(shuō)的使用還是有局限性的,因?yàn)榭赡苡泻芏啻a需要訪問(wèn)XML中的view。如,一個(gè)自定義view或者一個(gè)adapter。舉個(gè)例子,綁定一個(gè)xml中的view到另一view。唯一不同的就是:如果我們需要一個(gè)adapter,比如,我們現(xiàn)在要從inflater的View中訪問(wèn)屬view.textView.text=import重構(gòu)我們的代重構(gòu)我們的代現(xiàn)在是時(shí)候使用KotlinAndroidExtensions來(lái)修改我們的代碼了。修改相當(dāng)重構(gòu)我們的代重構(gòu)我們的代現(xiàn)在是時(shí)候使用KotlinAndroidExtensions來(lái)修改我們的代碼了。修改相當(dāng)我們從MainActivity開(kāi)始。我們當(dāng)前只是使用了forecastList然后現(xiàn)在,我們可以不需要findoverridefunonCreate(savedInstanceState:{super.onCreate(savedInstanceState)forecastList.layoutManager=LinearLayoutManager(this)}import重構(gòu)我們的代也可以從這個(gè)插件中受益。這里你可以使用一個(gè)裝置來(lái)綁定這些屬性到vie中,它可r的d代碼。首先,為item_forecast重構(gòu)我們的代也可以從這個(gè)插件中受益。這里你可以使用一個(gè)裝置來(lái)綁定這些屬性到vie中,它可r的d代碼。首先,為item_forecast可以在任何view中使用這些屬性,但是很顯然如果vie不包含要獲取的子view現(xiàn)在我們可以直接訪問(wèn)view的屬性了 Extensions插件幫助我們減少了很多模版代碼,并且簡(jiǎn)化了我們view的方式。從庫(kù)中檢出最新的代碼classViewHolder(view:View,valitemClick:(Forecast)->:{funbindForecast(forecast:{itemView.date.text=dateitemView.description.text=descriptionitemView.minTemperature.text="${low.toString()}"itemView.onClick{itemClick(forecast)}}}}importApplication單例化和屬性Application單例化和屬性的Application單例化和屬性的我們很快要去實(shí)現(xiàn)一個(gè)數(shù)據(jù)庫(kù),如果我們想要保持我們代碼的簡(jiǎn)潔性和層次性(而不是把所有代碼添加到Acy中),我們就要需要有一個(gè)更簡(jiǎn)單的訪問(wèn)canc的方式。ApplicatonApplicaton單例按照我們?cè)贘ava中一樣創(chuàng)建一ApplicatonApplicaton單例按照我們?cè)贘ava中一樣創(chuàng)建一個(gè)單例最簡(jiǎn)單的方個(gè)App:Android有一個(gè)問(wèn)題,就是我們不能去控制很多類(lèi)的構(gòu)造函數(shù)。比如,我們不能初化一個(gè)非null屬性,因?yàn)樗闹敌枰跇?gòu)造函數(shù)中去定義。所以我們需要一個(gè)可的變量,和一個(gè)返回非null值的函數(shù)。我們知道我們一直都有實(shí)例,但在它調(diào)用onCreate之前我們不能去操作任何事情,所以我們?yōu)榱税踩?,我們假設(shè)instance()函數(shù)將會(huì)總是返回一個(gè)非null的app實(shí)例。但是這個(gè)方案看起來(lái)有點(diǎn)不自然。我們需要定義個(gè)一個(gè)屬性(已經(jīng)有了getter和sette),然后通過(guò)一個(gè)函數(shù)來(lái)返回那個(gè)屬性。我們有其他方法去達(dá)到相似的效果么?是的,我們可以通過(guò)委托這個(gè)屬性的值給另外一個(gè)類(lèi)。這個(gè)就是我們知道classApp:{companionobjectprivatevarinstance:Application?=nullfuninstance()=instance!!}overridefuninstance=this}}Applicaton的委托屬性Applicaton的委托屬性委托屬委托屬我們可能需要一個(gè)屬性具有一些相同的行為,使用lazy或者observable可以委托屬委托屬我們可能需要一個(gè)屬性具有一些相同的行為,使用lazy或者observable可以一個(gè)委托屬性到一個(gè)類(lèi)的方法。這就是我們知道的委托屬性當(dāng)我們使用屬性的get或者set的時(shí)候,屬性委托的getValue和setValue就會(huì)被調(diào)用。屬性委托的結(jié)構(gòu)如據(jù)。setValue(val),就會(huì)只有一個(gè)getValue下面展示屬性委托是怎么設(shè)置它使用了byclassExamplevarp:Stringby}classDelegate<T>:ReadWriteProperty<Any?,T>fungetValue(thisRef:Any?,property:KProperty<*>):{return}funsetValue(thisRef:Any?,property:KProperty<*>,value:{}}委托屬委托屬標(biāo)準(zhǔn)委標(biāo)準(zhǔn)委Kotlin的標(biāo)準(zhǔn)庫(kù)中有一系列的標(biāo)準(zhǔn)委托。它們包括了大部分有用的委托,但是我們也可以創(chuàng)建我們自己的委托。它包含一
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 控制技術(shù)綜合試題及答案
- 技術(shù)開(kāi)發(fā)試題及答案
- 首爾兼職面試經(jīng)典題庫(kù):各類(lèi)職位的求職策略
- 游戲開(kāi)發(fā)面試實(shí)戰(zhàn):經(jīng)典游戲架構(gòu)面試題目及答案
- 學(xué)校水電安全知識(shí)培訓(xùn)課件
- 卓越職場(chǎng)面試技巧大全全系列題目及答案
- 國(guó)金證券面試題庫(kù)精粹:精英之路的關(guān)鍵一步
- 紅十字面試常見(jiàn)問(wèn)題及答案解析
- 10000培訓(xùn)知識(shí)點(diǎn)課件
- 學(xué)校全員消防知識(shí)培訓(xùn)課件
- 良性滑膜瘤(腱鞘巨細(xì)胞瘤)
- 農(nóng)用地管理知識(shí)講座
- 宮頸癌的教學(xué)查房
- 走進(jìn)重高培優(yōu)講義數(shù)學(xué)八年級(jí)上冊(cè)-(浙教版)
- 水泥廠安全資料之作業(yè)活動(dòng)現(xiàn)場(chǎng)隱患排查項(xiàng)目清單
- 蚊媒傳染病的預(yù)防與控制
- YY 1048-2016心肺轉(zhuǎn)流系統(tǒng)體外循環(huán)管道
- GB/T 33808-2017草銨膦原藥
- GB/T 25853-20108級(jí)非焊接吊鏈
- SL 537-2011 水工建筑物與堰槽測(cè)流規(guī)范
- 齊魯醫(yī)學(xué)機(jī)關(guān)領(lǐng)導(dǎo)干部健康知識(shí)講座
評(píng)論
0/150
提交評(píng)論