【段建华】Kotlin在Android开发中最佳实践探讨

cheesecuttle

2017/12/31 发布于 技术 分类

2017年,droidcon 第2次来到中国,并将于2017年11月在北京盛大开幕。参会人群包括业界领袖、技术大咖、技术开发者、大众创业者及领域从业者。大会将邀请来自Google、微软、Facebook、Ebay、Intel、Telenav、阿里巴巴、腾讯、小米、乐视、联想等国内外安卓技术与应用领域的大咖,沿袭历年国际大会特色,聚焦行业最前沿技术,碰撞切磋技术火花。

文字内容
1. A Deep Dive Into Kotlin By ٕඌখ∍԰ 1
2. About me • ٕඌখ∍԰(droidyue.com)തओ • @Flipboard Chinaʢ‫ޣ‬൘Бʣ • GDGཌ༯‫ٳ‬ཚࢃഽ 2
3. ඍ৴ೡҰೡ䎔஫ 3
4. Kotlin • An official language for Android recently • Powered by Jetbrains 4
5. Why Kotlin • Concise • Safe • interoperable • tool-friendly 5
6. But •How to interoperate with Java •How to write the idiomatic Kotlin code •What are the pitfalls and how to avoid them •The common best practices 6
7. Null Safety //nullable and non-null are two types //to make it possible to check nullability at compile time var id: String = "" id = null //compile error var title: String? = "" title = null 7
8. We have less NPEs But we could not avoid them 8
9. !! is dangerous fun test(value: String?) { value?.length value!!.length // treat the value as non-null } 9
10. Never use multiple !! user.contactInfo!!.emailContacts!!.primaryEmail //Exception in thread "main" kotlin.KotlinNullPointerException //a better way user.contactInfo?.emailContacts?.primaryEmail 10
11. !! in collection filtering fun getItemNames(items: List<Item?>) { items.filter { it != null }.map { it!!.title // not smart here, we need to recheck nullability } //If we change the filter criteria, we may encounter npe items.filterNotNull().map { it.title //smart here } } 11
12. Look out for Platform types • Any reference in Java may be null • It’s not practical to keep null-safety for these from Java • Types of Java declarations are treated specially in Kotlin and called platform types 12
13. • It’s described as Type! such as String! • T! means "T or T?” • (Mutable)Collection<T>! means "Java collection of T may be mutable or not, may be nullable or not" • But if the variable annotated with Nullability annotations(Nullable,NonNull,etc), they are no longer platform types any more. 13
14. Solutions • Use annotations for Java variables and functions • It would be better to treat T! as T? for safety 14
15. // In JavaMain.java public static List<String> getList() { String[] seasons = {"Spring, Summer, Autumn, Winter"}; return Collections.unmodifiableList(Arrays.asList(seasons)); } //Kotlin code fun mutableListPlatformTypes() { //wrong way // NPE or UnsupportedOperationException JavaMain.getList().add("Kotlin") val list = mutableListOf<String>() JavaMain.getList()?.let {//maybe null list.addAll(it) //use a new list } list.add("Kotlin") } 15
16. Check for deserialization //need to check null(especially data from servers) data class IPInfoResponse(val status: Int, val ip: String) { fun isValid(): Boolean { return status == 0 && !TextUtils.isEmpty(ip) } } 16
17. Prefer val to var • val is read-only • var is readable and writable 17
18. fun getItemTitle(item: Item) { var title: String? if (item.isValid()) { title = item.title } else { title = "Not found" } //the var title may be re-assigned to other value //value could be returned through if/else clause val title2 = if (item.isValid()) { item.title } else { "Not Found" } } 18
19. val item = getItem(position) //value returned by when clause return when(item?.type) { "hotmix" -> ITEM_TYPE_HOTMIX "promoted" -> ITEM_TYPE_PROMOTED "list" -> ITEM_TYPE_ITEM_LIST "sudoku" -> ITEM_TYPE_SUDOKU else -> ITEM_TYPE_SEARCHBOX } 19
20. Object • It’s quick to implement Singleton • Companion object stores properties and functions of Class • Do not use Object to store static methods, Use the top-level functions 20
21. class SSOServiceManager { companion object { private val APPID = "" private val SSO_SCOPE = "get_simple_userinfo" val RESULT_OK = -1 val instance = QQServiceManager() } } 21
22. • let • apply • with • run Standard.kt 22
23. Let //let is a scoping function DbConnection.getConnection().let { connection -> } // connection is no longer visible here //let is also an alternative for null testing item?.let { //code here } 23
24. Apply //without apply val intentFilter = IntentFilter() intentFilter. addAction(Intent.ACTION_PACKAGE_ADDED) intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED) intentFilter.addDataScheme("package") //Use apply to group object initialization statements to allow for cleaner, easier to read code. IntentFilter().apply { addAction(Intent.ACTION_PACKAGE_ADDED) addAction(Intent.ACTION_PACKAGE_REMOVED) addDataScheme("package") } 24
25. IntentFilter().apply { addAction(Intent.ACTION_PACKAGE_ADDED) addAction(Intent.ACTION_PACKAGE_REMOVED) addDataScheme("package") }.let { //use let to do the non-initialization work context.applicationContext.registerReceiver(packageBroadcastReceiver, it) } 25
26. With val w = Window() with(w) { setWidth(100) setHeight(200) setBackground(RED) } 26
27. Run //run it's a combination of let and apply. val a = "HelloWorld".replace("World","") a.run { println(length) } 27
28. Inline • Inline is a method of optimization(less methods) • It’s not the JIT inline 28
29. inline fun <T> T?.runIfNotNull(block: (T) -> Unit): T? { if (this != null) { block(this) } return this } fun testInline(arg: Any?) { println("testInlineStart") arg.runIfNotNull { println("arg is not null") } println("testInlineStop") } //after inlined fun testInline(arg: Any?) { println("testInlineStart") if (arg != null) { println("arg is not null") } println("testInlineStop") } 29
30. Inline scenario • Inline works best for functions with lambda parameter(avoid inner class) • If a little method is often called, You can inline it. • Too many inline functions would increase the compiler’s pressure 30
31. Annotations • @JvmStatic mark elements as static • @JvmField mark val/var as Java field 31
32. object SocialShareHelper { @JvmField val TARGET_WECHAT = 1 val TARGET_WEIBO = 2 } int target = getShareTarget(); switch (target) { case SocialShareHelper.TARGET_WECHAT: break; case SocialShareHelper.INSTANCE.getTARGET_WEIBO():// error Kotlin’s pitfall break; } 32
33. Prefer equal to == • In Kotlin, == is used to check Strings equality • But it will be confused to use it in a mixed project 33
34. No Checked Exceptions //Checked Exceptions decreased productivity and little or no increase in code quality. //we could try-catch exceptions depending on our experience. fun PackageManager.isPackageExisting(targetPkg: String): Boolean { return try { getPackageInfo(targetPkg, PackageManager.GET_META_DATA) true } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() false } } 34
35. Gifts 35