成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用Kotlin開發Android項目是一種什么樣的感受?

移動開發
從初學 Kotlin,到嘗試性的寫一點體驗代碼,再到實驗性的做一些封裝工作,到最后摸爬滾打著寫了一個項目。不得不說過程中還是遇上了不少的問題,盡管有不少坑是源于我自己的選擇,比如使用了 anko 布局放棄了 xml,但是總體來說,這門語言帶給我的驚喜是完全足以讓我忽略路上的坎坷。

前言

從初學 Kotlin,到嘗試性的寫一點體驗代碼,再到實驗性的做一些封裝工作,到***摸爬滾打著寫了一個項目。不得不說過程中還是遇上了不少的問題,盡管有不少坑是源于我自己的選擇,比如使用了 anko 布局放棄了 xml,但是總體來說,這門語言帶給我的驚喜是完全足以讓我忽略路上的坎坷。

這篇文章僅僅是想整理一下這一路走過來的一些感想和驚喜,隨著我對 Kotlin 的學習和使用,會長期修改。

用Kotlin開發Android項目是一種什么樣的感受?

正文

1.有了空安全,再也不怕服務端返回空對象了

簡單一點的例子,那就是 String 和 String?是兩種不同的類型。String 已經確定是不會為空,一定有值;而 String?則是未知的,也許有值,也許是空。在使用對象的屬性和方法的時候,String 類型的對象可以毫無顧忌的直接使用,而 String?類型需要你先做非空判斷。

 

  1. fun demo() { 
  2.     val string1: String = "string1" 
  3.     val string2: String? = null 
  4.     val string3: String? = "string3" 
  5.      
  6.     println(string1.length) 
  7.     println(string2?.length) 
  8.     println(string3?.length) 

輸出結果為:

 

  1. null 

盡管 string2 是一個空對象,也并沒有因為我調用了它的屬性/方法就報空指針。而你所需要做的,僅僅是加一個"?"。

如果說這樣還體現不出空安全的好處,那么看下面的例子:

 

  1. val a: A? = A() 
  2. println(a?.b?.c) 

試想一下當每一級的屬性皆有可能為空的時候,JAVA 中我們需要怎么處理?

2.轉型與智能轉換,省力又省心

我寫過這樣子的 JAVA 代碼

 

  1. if(view instanceof TextView) { 
  2.     TextView textView = (TextView) view
  3.     textView.setText("text"); 

而在 Kotlin 中的寫法則有所不同

 

  1. if(view is TextView) { 
  2.     TextView textView = view as TextView 
  3.     textView.setText("text"

縮減代碼之后對比更加明顯

 

  1. JAVA 
  2.  
  3. if(view instanceof TextView) { 
  4.     ((TextView) view).setText("text"); 
  5.  
  6. Kotlin 
  7.  
  8. if(view is TextView) { 
  9.     (view as TextView).setText("text"

相比于 JAVA 在對象前加 (Class) 這樣子的寫法,Kotlin 是在對象之后添加 as Class 來實現轉型。至少我個人而言,在習慣了 as Class 順暢的寫法之后,是再難以忍受 JAVA 中前置的寫法,哪怕有 cast 快捷鍵的存在,仍然很容易打斷我寫代碼的順序和思路

事實上,Kotlin 此處可以更簡單:

 

  1. if(view is TextView) { 
  2.     view.setText("text"

因為當前上下文已經判明 view 就是 TextView,所以在當前代碼塊中 view 不再是 View 類,而是 TextView 類。這就是 Kotlin 的智能轉換。

接著上面的空安全來舉個例子,常規思路下,既然 String 和 String? 是不同的類型,是不是我有可能會寫出這樣的代碼?

 

  1. val a: A? = A() 
  2. if (a != null) { 
  3.     println(a?.b) 

這樣子寫,Kotlin 反而會給你顯示一個高亮的警告,說這是一個不必要的 safe call。至于為什么,因為你前面已經寫了 a != null 了啊,于是 a 在這個代碼塊里不再是 A? 類型, 而是 A 類型。

 

  1. val a: A? = A() 
  2. if (a != null) { 
  3.     println(a.b) 

智能轉換還有一個經常出現的場景,那就是 switch case 語句中。在 Kotlin 中,則是 when 語法。

 

  1. fun testWhen(obj: Any) { 
  2.     when(obj) { 
  3.         is Int -> { 
  4.             println("obj is a int"
  5.             println(obj + 1) 
  6.         } 
  7.  
  8.         is String -> { 
  9.             println("obj is a string"
  10.             println(obj.length) 
  11.         } 
  12.  
  13.         else -> { 
  14.             println("obj is something i don't care"
  15.         } 
  16.     } 
  17.  
  18. fun main(args: Array<String>) { 
  19.     testWhen(98) 
  20.     testWhen("98"

輸出如下:

 

  1. obj is a int 
  2. 99 
  3. obj is a string 

可以看出在已經判斷出是 String 的條件下,原本是一個 Any 類的 obj 對象,我可以直接使用屬于 String 類的 .length 屬性。而在 JAVA 中,我們需要這樣做:

 

  1. System.out.println("obj is a string"
  2. String string = (String) obj; 
  3. System.out.println(string.length) 

或者

 

  1. System.out.println("obj is a string"
  2. System.out.println(((String) obj).length) 

前者打斷了編寫和閱讀的連貫性,后者嘛。。

Kotlin 的智能程度遠不止如此,即便是現在,在編寫代碼的時候還會偶爾蹦一個高亮警告出來,這時候我才知道原來我的寫法是多余的,Kotlin 已經幫我處理了好了。此處不再一一贅述。

3.比 switch 更強大的 when

通過上面智能轉化的例子,已經展示了一部分 when 的功能。但相對于 JAVA 的 switch,Kotlin 的 when 帶給我的驚喜遠遠不止這么一點。

例如:

 

  1. fun testWhen(intInt) { 
  2.     when(int) { 
  3.         in 10 .. Int.MAX_VALUE -> println("${int} 太大了我懶得算"
  4.         2, 3, 5, 7 -> println("${int} 是質數"
  5.         else -> println("${int} 不是質數"
  6.     } 
  7.  
  8. fun main(args: Array<String>) { 
  9.     (0..10).forEach { testWhen(it) } 

輸出如下:

  1. 不是質數
  2. 不是質數
  3. 是質數
  4. 是質數
  5. 不是質數
  6. 是質數
  7. 不是質數
  8. 是質數
  9. 不是質數
  10. 不是質數
  11. 太大了我懶得算

和 JAVA 中死板的 switch-case 語句不同,在 when 中,我既可以用參數去匹配 10 到 Int.MAX_VALUE 的區間,也可以去匹配 2, 3, 5, 7 這一組值,當然我這里沒有列舉所有特性。when 的靈活、簡潔,使得我在使用它的時候變得相當開心(和 JAVA 的 switch 對比的話)

4.容器的操作符

自從迷上 RxJava 之后,我實在很難再回到從前,這其中就有 RxJava 中許多方便的操作符。而 Kotlin 中,容器自身帶有一系列的操作符,可以非常簡潔的去實現一些邏輯。

例如:

 

  1. (0 until container.childCount) 
  2.         .map { container.getChildAt(it) } 
  3.         .filter { it.visibility == View.GONE } 
  4.         .forEach { it.visibility = View.VISIBLE } 

上述代碼首先創建了一個 0 到 container.childCount - 1 的區間;再用 map 操作符配合取出 child 的代碼將這個 Int 的集合轉化為了 childView 的集合;然后在用 filter 操作符對集合做篩選,選出 childView 中所有可見性為 GONE 的作為一個新的集合;最終 forEach 遍歷把所有的 childView 都設置為 VISIBLE。

這里再貼上 JAVA 的代碼作為對比。

 

  1. for(int i = 0; i < container.childCount - 1;  i++) { 
  2.     View childView = container.getChildAt(i); 
  3.     if(childView.getVisibility() == View.GONE) { 
  4.         childView.setVisibility(View.VISIBLE); 
  5.     } 

這里就不詳細的去描述這種鏈式的寫法有什么優點了。

5.線程切換,so easy

既然上面提到了 RxJava,不得不想起 RxJava 的另一個優點——線程調度。Kotlin 中有一個專為 Android 開發量身打造的庫,名為 anko,其中包含了許多可以簡化開發的代碼,其中就對線程進行了簡化。

 

  1. async { 
  2.     val response = URL("https://www.baidu.com").readText() 
  3.     uiThread { 
  4.         textView.text = response 
  5.     } 

上面的代碼很簡單,通過 async 方法將代碼實現在一個異步的線程中,在讀取到 http 請求的響應了之后,再通過 uiThread 方法切換回 ui 線程將 response 顯示在 textView 上。

拋開內部的實現,你再也不需要為了一個簡簡單單的異步任務去寫一大堆的無效代碼。按照慣例,這里似乎應該貼上 JAVA 的代碼做對比,但請原諒我不想刷屏(啊哈哈)

6.一個關鍵字實現單例

沒錯,就是一個關鍵字就可以實現單例:

 

  1. object Log { 
  2.     fun i(string: String) { 
  3.         println(string) 
  4.     } 
  5.  
  6. fun main(args: Array<String>) { 
  7.     Log.i("test"

再見,單例模式

7.自動 getter、setter 及 class 簡潔聲明

JAVA 中有如下類

 

  1. class Person { 
  2.     private String name
  3.  
  4.     public Person(String name) { 
  5.         this.name = name
  6.     } 
  7.  
  8.     public void setName(String name) { 
  9.         this.name = name
  10.     } 
  11.  
  12.     public void getName() { 
  13.         return name
  14.     } 
  15.  
  16. Person person = new Person("張三"); 

Person person = new Person("張三");

可以看出,標準寫法下,一個屬性對應了 get 和 set 兩個方法,需要手動寫的代碼量相當大。當然有快捷鍵幫助我們生成這些代碼,但是考慮到各種復雜情形總歸不***。

而 Kotlin 中是這樣的:

 

  1. class Person(var name: String) 
  2. val person = Person("張三"); 

還可以添加默認值:

 

  1. class Person(var name: String = "張三"
  2. val person = Person() 

再附上我項目中一個比較復雜的數據類:

 

  1. data class Column
  2.         var subId: String?, 
  3.         var subTitle: String?, 
  4.         var subImg: String?, 
  5.         var subCreatetime: String?, 
  6.         var subUpdatetime: String?, 
  7.         var subFocusnum: Int?, 
  8.         var lastId: String?, 
  9.         var lastMsg: String?, 
  10.         var lastType: String?, 
  11.         var lastMember: String?, 
  12.         var lastTIme: String?, 
  13.         var focus: String?, 
  14.         var subDesc: String?, 
  15.         var subLikenum: Int?, 
  16.         var subContentnum: Int?, 
  17.         var pushSet: String? 

一眼望去,沒有多余代碼。這是為什么我認為 Kotlin 代碼比 JAVA 代碼要更容易寫得干凈的原因之一。

8. DSL 式編程

說起 dsl ,Android 開發者接觸的最多的或許就是 gradle 了

例如:

 

  1. android { 
  2.     compileSdkVersion 23 
  3.     buildToolsVersion "23.0.2" 
  4.  
  5.     defaultConfig { 
  6.         applicationId "com.zll.demo" 
  7.         minSdkVersion 15 
  8.         targetSdkVersion 23 
  9.         versionCode 1 
  10.         versionName "1.0" 
  11.     } 
  12.     buildTypes { 
  13.         release { 
  14.             minifyEnabled false 
  15.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
  16.         } 
  17.     } 

這就是一段 Groovy 的 DSL,用來聲明編譯配置

那么在 Android 項目的代碼中使用 DSL 是一種什么樣的感覺呢?

 

  1. override fun onCreate(savedInstanceState: Bundle?) { 
  2.     super.onCreate(savedInstanceState) 
  3.  
  4.     val homeFragment = HomeFragment() 
  5.     val columnFragment = ColumnFragment() 
  6.     val mineFragment = MineFragment() 
  7.  
  8.     setContentView( 
  9.             tabPages { 
  10.                 backgroundColor = R.color.white 
  11.                 dividerColor = R.color.colorPrimary 
  12.                 behavior = ByeBurgerBottomBehavior(context, null
  13.  
  14.                 tabFragment { 
  15.                     icon = R.drawable.selector_tab_home 
  16.                     body = homeFragment 
  17.                     onSelect { toast("home selected") } 
  18.                 } 
  19.  
  20.                 tabFragment { 
  21.                     icon = R.drawable.selector_tab_search 
  22.                     body = columnFragment 
  23.                 } 
  24.  
  25.                 tabImage { 
  26.                     imageResource = R.drawable.selector_tab_photo 
  27.                     onClick { showSheet() } 
  28.                 } 
  29.  
  30.                 tabFragment { 
  31.                     icon = R.drawable.selector_tab_mine 
  32.                     body = mineFragment 
  33.                 } 
  34.             } 
  35.     ) 

 

[[231055]]

沒錯,上面的代碼就是用來構建這個主界面的 viewPager + fragments + tabBar 的。以 tabPages 作為開始,設置背景色,分割線等屬性;再用 tabFrament 添加 fragment + tabButton,tabImage 方法則只添加 tabButton。所見的代碼都是在做配置,而具體的實現則被封裝了起來。

前面提到過 anko 這個庫,其實也可以用來替代 xml 做布局用:

 

  1. override fun onCreate(savedInstanceState: Bundle?) { 
  2.     super.onCreate(savedInstanceState) 
  3.  
  4.     verticalLayout { 
  5.         textView { 
  6.             text = "這是標題" 
  7.         }.lparams { 
  8.             width = matchParent 
  9.             height = dip(44) 
  10.         } 
  11.  
  12.         textView { 
  13.             text = "這是內容" 
  14.             gravity = Gravity.CENTER 
  15.         }.lparams { 
  16.             width = matchParent 
  17.             height = matchParent 
  18.         } 
  19.     } 

相比于用 JAVA 代碼做布局,這種 DSL 的方式也是在做配置,把布局的實現代碼封裝在了背后,和 xml 布局很接近。

關于 DSL 和 anko 布局,以后會有專門的文章做介紹,這里就此打住。

9.委托/代理,SharedPreference 不再麻煩

通過 Kotlin 中的委托功能,我們能輕易的寫出一個 SharedPreference 的代理類

 

  1. class Preference<T>(val context: Context, val name: String?, val default: T) : ReadWriteProperty<Any?, T> { 
  2.     val prefs by lazy { 
  3.         context.getSharedPreferences("xxxx", Context.MODE_PRIVATE) 
  4.     } 
  5.  
  6.     override fun getValue(thisRef: Any?, property: KProperty<*>): T = with(prefs) { 
  7.         val res: Any = when (default) { 
  8.             is Long -> { 
  9.                 getLong(name, 0) 
  10.             } 
  11.             is String -> { 
  12.                 getString(namedefault
  13.             } 
  14.             is Float -> { 
  15.                 getFloat(namedefault
  16.             } 
  17.             is Int -> { 
  18.                 getInt(namedefault
  19.             } 
  20.             is Boolean -> { 
  21.                 getBoolean(namedefault
  22.             } 
  23.             else -> { 
  24.                 throw IllegalArgumentException("This type can't be saved into Preferences"
  25.             } 
  26.         } 
  27.         res as T 
  28.     } 
  29.  
  30.     override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = with(prefs.edit()) { 
  31.         when (value) { 
  32.             is Long -> putLong(name, value) 
  33.             is String -> putString(name, value) 
  34.             is Float -> putFloat(name, value) 
  35.             is Int -> putInt(name, value) 
  36.             is Boolean -> putBoolean(name, value) 
  37.             else -> { 
  38.                 throw IllegalArgumentException("This type can't be saved into Preferences"
  39.             } 
  40.         }.apply() 
  41.     } 

暫且跳過原理,我們去看怎么使用

 

  1. class EntranceActivity : BaseActivity() { 
  2.      
  3.     private var userId: String by Preference(this, "userId"""
  4.  
  5.     override fun onCreate(savedInstanceState: Bundle?) { 
  6.         testUserId() 
  7.     } 
  8.      
  9.     fun testUserId() { 
  10.         if (userId.isEmpty()) { 
  11.             println("userId is empty"
  12.             userId = "default userId" 
  13.         } else { 
  14.             println("userId is $userId"
  15.         } 
  16.     } 

重復啟動 app 輸出結果:

 

  1. userId is empty 
  2. userId is default userId 
  3. userId is default userId 
  4. ... 

***次啟動 app 的時候從 SharedPreference 中取出來的 userId 是空的,可是后面卻不為空。由此可見,userId = "default userId" 這句代碼成功的將 SharedPreference 中的值修改成功了。

也就是說,在這個 Preference 代理的幫助下,SharedPreference 存取操作變得和普通的對象調用、賦值一樣的簡單。

10.擴展,和工具類說拜拜

很久很久以前,有人和我說過,工具類本身就是一種違反面向對象思想的東西。可是當時我就想了,你不讓我用工具類,那有些代碼我該怎么寫呢?直到我知道了擴展這個概念,我才豁然開朗。

 

  1. fun ImageView.displayUrl(url: String?) { 
  2.     if (url == null || url.isEmpty() || url == "url") { 
  3.         imageResource = R.mipmap.ic_launcher 
  4.     } else { 
  5.         Glide.with(context) 
  6.                 .load(ColumnServer.SERVER_URL + url) 
  7.                 .into(this) 
  8.     } 
  9. ... 
  10. val imageView = findViewById(R.id.avatarIv) as ImageView 
  11. imageView.displayUrl(url) 

上述代碼可理解為:

  1. 我給 ImageView 這個類擴展了一個名為 displayUrl 的方法,這個方法接收一個名為 url 的 String?類對象。如不出意外,會通過 Glide 加載這個 url 的圖片,顯示在當前的 imageView 上;
  2. 我在另一個地方通過 findViewById 拿到了一個 ImageView 類的實例,然后調用這個 imageView 的displayUrl 方法,試圖加載我傳入的 url

通過擴展來為 ImageView 添加方法,相比于通過繼承 ImageView 來寫一個 CustomImageView,再添加方法而言,侵入性更低,不需要在代碼中全寫 CustomImageView,也不需要在 xml 布局中將包名寫死,造成移植的麻煩。

這事用工具類當然也可以做,比如做成 ImageUtil.displayUrl(imageView, url),但是工具類閱讀起來并沒有擴展出來的方法讀起來更自然更流暢。

擴展是 Kotlin 相比于 JAVA 的一大殺器

責任編輯:未麗燕 來源: 安卓巴士
相關推薦

2018-05-30 15:07:37

KotlinAndroid開發

2019-07-08 17:34:29

共享辦公ideaPod文印

2019-04-03 14:51:18

CPU性能工藝

2015-11-03 08:51:21

程序員怪物

2020-11-06 17:49:38

程序員技術開發

2015-09-09 09:41:28

十年代碼

2017-03-10 09:09:41

C語言體驗

2015-12-03 09:23:25

程序員產品經理

2015-04-08 10:40:09

2021-01-14 21:46:02

Vue.jsReact框架

2010-08-02 13:30:34

移動開發移動開發平臺

2017-04-06 15:00:38

編程語言

2017-08-17 13:14:01

2020-04-07 08:05:51

程序員互聯網職業

2019-01-11 10:39:24

軟件架構虛擬空間機器人

2015-02-04 10:55:14

2016-08-30 21:09:33

2025-01-06 08:00:54

2014-02-25 09:55:07

敏捷開發

2015-01-21 15:35:58

開源
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 龙珠z在线观看 | 欧美日韩视频在线 | 成人在线视频网站 | 中文字幕一区二区不卡 | 亚洲综合在线视频 | 国产精品美女久久久久久久网站 | 国产欧美精品区一区二区三区 | 亚洲欧洲中文 | 国产福利在线 | 在线中文字幕亚洲 | 国产99免费视频 | 偷牌自拍 | 日本福利在线 | 国产欧美在线 | 亚洲综合视频 | 一区二区三区欧美 | 欧美成人免费在线视频 | 亚洲综合激情 | 337p日本欧洲亚洲大胆鲁鲁 | 中文字幕在线观看www | 久久久国产视频 | 欧美日韩综合一区 | 中文字幕av一区 | 久久国产成人精品国产成人亚洲 | 一区二区国产精品 | 人人叉| 欧美一级二级视频 | 精精国产xxxx视频在线播放7 | 成人永久免费 | 成人免费视频网站在线观看 | 三级在线免费 | 欧美精品一区二区三区在线 | 三级成人在线 | 福利精品 | 久久久成人免费视频 | 在线免费观看黄a | 亚洲高清成人 | 日日日操 | 在线中文字幕亚洲 | 黄色三级免费网站 | 欧美成人一区二区三区 |