| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
JanaRno
8年前发布

Kotlin如何成为我们Android开发的主要语言

   <h2>引言</h2>    <p>Kotlin是一个基于JVM的新的编程语言,由JetBrains开发。JetBrains,作为目前广受欢迎的Java IDE IntelliJ的提供商,在Apache许可下已经开源其Kotlin编程语言。与Java相比,Kotlin的语法更简洁、更具表达性,而且提供了更多的特性,比如,高阶函数、操作符重载、字符串模板。它与Java高度可互操作,可以同时用在一个项目中。</p>    <p>Kotlin的定位非常有特点,它并不像Scala那样另起炉灶,Scala是一切尽量自己来,将类库,尤其是集合类都自己来了一遍。实在不够用了再用java的;而Kotlin是对现有Java的增强,尽量用Java的,不够用了再扩展,尤其体现在二者的容器库上,但同时始终保持对java的兼容。这种特点导致Kotlin的学习曲线极低。这是Kotlin官网首页重点强调的:“ <strong>100% interoperable with Java™</strong> ”。这意味着什么呢?或者换个问法:我什么时候可以开始在我的项目中引入Kotlin呢?我的回答是:现在就可以视你对kotlin的掌握程度,逐步引入kotlin的代码。</p>    <p>Dima Kovalenko 在 博客 中分享了他们团队使用Kotlin开发商业应用程序的心得和经验,并提供了一些参考资料。希望本文能对广大Android开发程序员有所启发。</p>    <p>几个月前,我们的团队决定开始新的尝试:完全应用Kotlin编程语言开发一个商业应用程序,这是JetBrains公司设计并开源的一种新编程语言。以前,我们有过Kotlin的经验,但那只是小规模应用:将应用程序的一部分转换到一种新的语言,或者应用在花里胡哨的项目。然而,用新的编程语言来开发商业应用程序,我们遇到了一些困难:</p>    <ul>     <li>我们深深扎根于基于Java的Android开发。切换到Kotlin相当困难,对于以前没有函数式编程经验的人员而言,尤为困难。</li>     <li>有些东西只是不工作。 Dagger也没有立即很好的使用。</li>    </ul>    <p>所有这些问题,都可能会导致项目无法按期交付、并带来应用程序的稳定性问题。</p>    <p>一个人应该有强烈的转型动力。我们的激励是:相信 <strong>Kotlin将是Android平台开发的颠覆者</strong> ——这只是一句 <strong>玩笑话</strong> 。</p>    <p>让我们打开Kotlin的参考书,开始开发 Voter应用程序 。Kotlin是一种与Java具有100%互操作性的JVM语言,如果您熟悉Java,那么学习Kotlin就会很容易。然而,如果想充分利用这个编程语言,理解函数式编程概念是至关重要的。</p>    <p>学习函数式编程需要一段时间。所以要有耐心。</p>    <p>至少在学习之初,函数式编程并不容易。我强烈建议使用 Martin Ordersky的“Scala中的函数式编程”的课程 来学习。Scala有时势不可挡,但它提供了一个极好的函数式编程思维的概述。你可以把Kotlin看成Scala的一个更简化的版本。</p>    <h2>为什么我们转向Kotlin阵营</h2>    <h3>函数式编程风格</h3>    <p>Kotlin与Java是100%可互操作的。此外,Kotlin是一种函数式语言。后者允许将表达性的代码编写得更优雅。</p>    <p>1.纯函数</p>    <p>纯函数(没有副作用的函数)是最重要的函数概念,它允许我们大大降低代码复杂性并消除大多数可变状态。</p>    <p>在JavaScript、Java和C#这些命令式编程语言中,副作用无处不在。这使得调试非常困难,因为变量可以在程序中的任何位置更改。所以当出现一个错误时,由于变量可以在错误的时间更改为错误的值,那么你到哪里去寻找错误呢?到处寻找错误吗?这可不好玩啊!</p>    <p>请注意我们是如何操作数据而不更改其内容的。</p>    <pre>  <code class="language-java">fun flatTree(tree: TreeNode): List<TreeNode>   = listOf(tree, *tree.children.flatMap(::flatTree).toTypedArray())</code></pre>    <p>2.高阶函数</p>    <p>高阶函数将函数用作参数,返回函数或将函数作为返回值的函数。</p>    <p>高阶函数无处不在。你只需将函数传递给集合,就能使代码更容易阅读。比如, titles.map {it.toUpperCase()} 读取简单的英语,是不是很棒?</p>    <p>让我们设想一种情况,假设要计算不同类型的未读消息的数量。典型的方法是:</p>    <pre>  <code class="language-java">private fun getUnreadCountFromUsers() {     val conversations = datasource.getConversations()     var count = 0     for (conversation in conversations) {       if (conversation.recipientId != null) {         for (message in conversation.messages) {           if (message.unread) {             count += 1           }         }       }     }   }     private fun getNumberOfUnreadAttachmentsInGroupConversations() {     val conversations = datasource.getConversations()     var count = 0     for (conversation in conversations) {       if (conversation.groupId != null) {         for (message in conversation.messages) {           if (message.unread && message.type == MessageType.ATTACHMENT) {             count += 1           }         }       }     }  }</code></pre>    <p>正如你所看到的,当引入新的需求时,代码变得难以理解、不可收拾。让我们看看如何使用高阶函数来解决这个问题:</p>    <pre>  <code class="language-java">private fun getNumberOfAttachmentsInGroupConvesationsFun() {     return getCount({conv -> conv.groupId != null}, {it -> it.type == MessageType.ATTACHMENT && it.unread})   }     private fun getUnreadCountFromUsersFun() {     return getCount({conv -> conv.recipientId != null}, {message -> message.unread})   }     private fun getTotalNumberOfMessages() = getCount({true}, {true})     private fun getCount(convFilter: (Conversation) -> Boolean, messageFilter: (Message) -> Boolean) {     datasource.getConversations()         .filter(convFilter)         .flatMap { it.messages }         .filter(messageFilter)         .fold(0, { count, message -> count + 1})  }</code></pre>    <p>我们还可以想象一下用例,假设想将 fold 函数变量参数化。比方说,计算未读消息的乘积。</p>    <p>使用高阶函数的另一个例子是用简单的高阶函数代替多个监听器:</p>    <p>BillingView : LinearLayout {</p>    <p>var billingChangeListener: (() -> Unit)? = null</p>    <p>...</p>    <p>}</p>    <p>... // in an activity far, far away</p>    <p>billingView.billingChangeListener { updateUI() }</p>    <p>3.不变性</p>    <p>不变性使得代码更容易编写,使用和推理代码(类不变性一次建立,然后不变——一劳永逸)。应用程序组件的内部状态将更加一致。Kotlin通过引入 val 关键字以及Kotlin集合来强制不变性,Kotlin集合在默认情况下是不可变的。 一旦 val 或者一个集合被初始化,你就可以确定它的有效性。(有关 val 关键字的更精确的定义,请参阅文末的更新)。</p>    <p>data class Address(val line1: String, val city: String)</p>    <p>valitems = listOf(Address("242 5th St", "Los Angeles"), Address("Dovzhenka St. 5", "Kiev"))</p>    <h3>空安全(Null-safety)</h3>    <p>这个语言特性使我们仔细考虑了模型类中字段的可空性。以前,当不确定DTO中的字段是否已初始化时,@Nullable和@NotNull的注释就能提供帮助,但也很有限。现在,使用Kotlin,就能让你准确知道什么字段可以为null,什么字段被初始化(例如,Dagger注入的字段),并且你可以对这些字段有严格的控制。结果?几乎没有 NullPointerExceptions 。(在内部我们管 ?. 叫做“鹅”操作符,因为它看起来像一个鹅的脖子。)</p>    <p>brand?.let { badge.enabled = brand.isNewBadge }</p>    <p>// Can also be written as</p>    <p>badge.enabled = brand?.isNewBadge?:false</p>    <h3>Anko</h3>    <p>Anko DSL是一个很了不起的的库,它大大简化了工作视图、线程和Android生命周期。据Github的描述,Anko是“令人愉快的Android应用程序开发”,事实证明,的确如此。</p>    <pre>  <code class="language-java">selector(items = listOf("Like", "Dislike") {     when (it) {       0 -> if (!liked) likePost()       else -> if (!disLiked) disLikePost()     }  }    doAsync {     // Long background task     uiThread {       alert(R.string.could_not_log_in) {         yesButton { dismiss() }         cancellable = false       }.show()     }  }</code></pre>    <p>注意,当 uiThread 在Activity内调用时,如果 isFinishing 为 true ,块将不会执行。我们实际上不使用这个功能,因为RxJava会处理应用程序中的所有线程,但它是一个很好的功能。</p>    <p>使用Anko而不是XML。虽然Anko还没有做好准备取代标准的Android UI构建,但有的时候,它非常方便。</p>    <pre>  <code class="language-java">verticalLayout() {     friendsPanel = friendsPanel.with(friendsData).lparams(width = matchParent)     politicalMapCardView {     setMarker(quizManager.getMarker())   }.lparams(width = matchParent) { topMargin = dip(10) }     cardView() {     verticalLayout() {       topPadding = dip(5)       textView(getString(R.string.register_question))       blueButtonView(text="Register here") {         onClick { browse("https://www.uptech.team") }       }     }   }.lparams(width = matchParent) {     topMargin = dip(10)     bottomMargin = dip(20)   }  }</code></pre>    <p>如您所见,Anko DSL允许您在Android内置视图中使用自定义视图。这一点与标准XML相比有很大的优势。</p>    <h3>Kotlin Android扩展:删除ButterKnife依赖</h3>    <pre>  <code class="language-java">@Bind(R.id.first_name)     protected EditText firstName;       @Bind(R.id.last_name)     protected EditText lastName;       @Bind(R.id.address_line1)     protected EditText addressLine1;       @Bind(R.id.address_line2)     protected EditText addressLine2;       @Bind(R.id.zip_code)     protected EditText zipCode;       @Bind(R.id.state)     protected TextView state;       @Bind(R.id.state_spinner)     protected HintSpinner stateSpinner;       @Bind(R.id.city)     protected EditText city;       @Bind(R.id.frag_shipping_address_save_btn)     protected Button saveBtn;       @Bind(R.id.agreement)     protected TextView agreement;       @Bind(R.id.email)     protected EditText email;       @Bind(R.id.password)     protected EditText password;       @Bind(R.id.create_account_container)     protected LinearLayout accountContainer;       @Bind(R.id.member_container)     protected LinearLayout memberContainer;       @Bind(R.id.logged_in_title)     protected TextView loggedInTitle;       @Bind(R.id.user_email)     protected TextView userEmail;       @Bind(R.id.sign_out)     protected TextView signOut;       @Bind(R.id.scrollview)     protected ScrollView scrollView;       @Bind(R.id.dummy)  protected EditText dummyView;</code></pre>    <p>上面那段代码读起来无聊吗?我敢打赌你一直滚动而没有阅读。在Kotlin,你并不需要任何这些东西。您可以通过其@id XML参数引用视图属性,这些属性将与XML文件中声明的名称相同。</p>    <h3>其他整洁的功能</h3>    <p>1.扩展功能和构建器</p>    <pre>  <code class="language-java">items = StoreInfo().apply { storeItems = fetchItems() }.let { manager.process(it) }  container.apply {   removeAllViews()   items.forEach { addView(ShopItemView(context).withData(it)) }  }    fun ShopItemView.withData(item: StoreItem): ShopItemView {   title = item.title   image = item.image   Brand.findById(item.id)?.let { brandName = it.name }  }</code></pre>    <p>apply 、 let 和扩展功能可以轻松地用于创建简洁的构建器。</p>    <p>2.为初学者快速破解</p>    <p>在最初的前几天,你经常被一个问题难倒:你不知道如何在Kotlin中写一个相当简单的Java表达式。这里有一个简单的诀窍,就是是在Java中编写一段代码,然后将其粘贴到Kotlin文件中。感谢JetBrains的工程师们,它会自动转换为Kotlin。 黑客的工作方式就像一个魔术!</p>    <p>3.摆脱不必要的依赖</p>    <p>Kotlin替换了许多第三方库,如ButterKnife、Google Autovalue、Retrolambda、Lombok和一些RxJava代码。</p>    <h2>总结</h2>    <p>作为一个软件开发团队,我们面临的主要挑战是提供优秀的产品,并有效地完成工作。虽说开始用Kotlin有效的开发软件,需要你有函数式编程的背景,但是,投入精力去学习是值得的,能给你巨大的回报。我相信,Kotlin是常规Android开发的一个重大改进,能让我们及时提供错误更少的、更加优秀的应用程序。</p>    <p>更新: val 实际上并不意味着“不可变的”,而是“只读”。</p>    <h2>参考文献</h2>    <ol>     <li><a href="/misc/goto?guid=4958971140044536092" rel="nofollow,noindex">《Kotlin 参考手册》</a></li>     <li><a href="/misc/goto?guid=4959732228090293908" rel="nofollow,noindex">《所以,你要成为一名函数式程序员》</a></li>     <li><a href="/misc/goto?guid=4959732228172241484" rel="nofollow,noindex">《为什么函数式编程很重要》</a></li>     <li><a href="/misc/goto?guid=4959732228257122972" rel="nofollow,noindex">《Java使用不可变对象编程的6大好处》</a></li>     <li><a href="/misc/goto?guid=4959732228335657639" rel="nofollow,noindex">《Anko DSL对Android XML-First》</a></li>     <li><a href="/misc/goto?guid=4959732228421825870" rel="nofollow,noindex">《将应用转换为纯Kotlin的经验教训》</a></li>     <li><a href="https://play.google.com/store/apps/details?id=app.voter.xyz&hl=en" rel="nofollow,noindex">《结果:应用程序投票选举:99.8%无故障用户》</a></li>     <li><a href="/misc/goto?guid=4959732228591334622" rel="nofollow,noindex">《Kotlin:val不意味着不可变,而意味着只读》</a></li>    </ol>    <p> </p>    <p>来自:http://www.infoq.com/cn/articles/how-kotlin-become-our-android-develop-language</p>    <p> </p>    
 本文由用户 JanaRno 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1483064242446.html
Kotlin 安卓开发