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

原文来自 https://medium.com/uptech-team/how-kotlin-became-our-primary-language-for-android-3af7fd6a994c#.wx1cnbt6o
几个月以前我们的团队决定尝试新的事物:完全用 Kotlin 开发一款商业应用,JetBrains 开发的新的程序语言。以前我们有 Kotlin 的经验,但是在更小的规模上:将应用程序的一部分转到新的语言或者在青睐的项目上尝试。然而,用新的程序语言开发商业应用程序引入一些困难:
我们深深扎根于以 Java 为基础的安卓开发。切换到 Kotlin 是相当困难的,特别是对于没有优先函数式编程经验的开发者
一些资料并没有用。Dagger 没有很好的开箱即用
所有这些都可能导致错过交付日期以及应用程序的稳定性问题。
一个人应该有强烈的动力去转型。我们的动力是相信 Kotlin 将是 Android 平台开发的规则改变者。 这是乐趣。
保持 Kotlin 引用打开,我们开始开发 Voter 应用程序。 Kotlin是一种具有 100%Java 互操作性的JVM语言,如果您熟悉 Java,那么学习 Kotlin 很容易。然而,如果你想充分利用语言,理解函数式编程概念是至关重要的。
学习函数式编程需要一点时间。所以要耐心。
函数式编程不是容易的,至少在开始的时候,知道它变得有趣。我强烈建议采取 Martin Ordersky 的“使用 Scala 函数式编程语言"的系列课程。Scala 有时可能是压倒性的,但是它给了一个伟大的概述新的函数式编程语言思维。你可以将 Kotlin 当作 Scala 的简单版本。
什么使我们转向 Kotlin 一边
函数式编程风格
Kotlin 是与 Java 的 100% 互操作性。另外。Kotlin 是一种函数式语言,后者允许写更优雅,表达性的代码。
1.函数纯度
纯函数(不具有副作用的函数)的概念是最重要的函数式概念,它允许我们大大降低代码复杂性和摆脱大多数可变状态。
在命令式编程语言如 JavaScript,Java 和 C# 中,副作用无处不在。这使得调试非常困难,因为变量可以在程序中的任何位置更改。所以当你有一个 bug ,因为变量在错误的时间更改为错误的值,你找哪?每个地方?那不好。
注意我们如何处理数据而不改变它的内容。
fun flatTree(tree: TreeNode): List<TreeNode> 
  =  listOf(tree, *tree.children.flatMap(::flatTree).toTypedArray())
2.高阶函数
高阶函数将函数用作参数,返回函数或两者
高阶函数无处不在。你只需将函数传递给集合,使代码更容易阅读。titles.map { it.toUpperCase()}  读起来像简单的英语。不是很好?
让我们想想一种情况,我们想计算不同类型的未读消息的数量。典型的方法是:
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
          }
        }
      }
    }
  }
正如你所看到的,当引入新的需求时,代码变得不可读和不可管理。让我们看看如何用高阶函数解决这个问题:
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})
  }
我们可以想象一下用例,我们想要参数化 fold 函数参数,比方说,计算未读消息的乘积。使用高阶函数的另一个例子是用简单的高阶函数替换大量的监听器。
BillingView : LinearLayout {
var billingChangeListener: (() -> Unit)? = null
...
}
... // in an activity far, far away
billingView.billingChangeListener { updateUI() }
3.不变性
不变性使得更容易编写,使用及推理代码(类不变创建依次,然后不改变)。你的应用程序组建的内部状态将更一致。Kotlin通过引入 val 关键字以及 Kotlin 集合来强制不变性,Kotlin集合在默认情况下是不可变的。一旦 val 或者一个集合被初始化,你就可以确定它的有效性。(有关val关键字的更准确定义,请参阅 UPD )。
data class Address(val line1: String, val city: String)
val items = listOf(Address("242 5th St", "Los Angeles"),   Address("Dovzhenka St. 5", "Kiev"))
Null安全
这个语言特性使我们认真考虑了关于模型类中字段的可空性。以前,你不确定在 DTO 中的字段是否已初始化,@Nullable 和@NotNull 注释有帮助,但没有那么多。现在,使用Kotlin,你准确的知道什么字段可以为 null,什么字段被初始化(例如,Dagger 注入的字段),并且你对这些字段有严格的控制。结果?几乎没有NullPointerExceptions。(在内部我们称“?”为”鹅“操作符,因为它看起来像一个鹅的脖子)
brand?.let { badge.enabled = brand.isNewBadge }
// Can also be written as 
badge.enabled = brand?.isNewBadge?:false
Anko
Anko DSL 是一个伟大的库,大大简化了工作视图、线程和 Android 生命周期。Github 描述说,Anko 是“令人愉快的 Android 应用程序开发”,证明的确如此。
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()
    }
}
注意,当在 Activity 中调用 uiThread 时,如果 isFinishing 为 true,块将不会执行。 我们实际上不使用这个功能,因为 RxJava 处理我们的应用程序中的所有线程,但它是一个很好的功能。
使用 Anko 而不是 XML 。虽然 Anko 还没有准备好替换标准的 Android UI 构建,有时它是非常方便的。
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)
  }
}
正如你所看到的,Anko DSL允许你在 Android 内置视图中使用自定义视图,这是它比标准 XML 有很大的优势。
Kotlin Adnroid 扩展:移除ButterKnife 依赖
@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;
无聊吗?我打赌你股东但没有阅读。在 Kotlin, 你不需要这些。你可以只是通过其 @id XML 参数引用视图属性,这些属性将与你的 XML 文件中声明的名称相同。更多信息可以在官方文档中找到。
其他简洁的功能
1.扩展函数和构建器
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 }
}
apply、let 和扩展函数可以轻松地用于创建优雅的构建器
2.对于初学者快速破解
在前几天,你经常绊倒在一个问题:你不知道如何在 Kotlin 中写一个相当简单的 Java 表达式。
一个简单的诀窍是在 Java 中编写一段代码,然后将其粘贴到 Kotlin 文件中。 感谢 JetBrains 这家伙,它会自动转换为 Kotlin。 变态,但非常好用!
3.摆脱不必要的依赖
Kotlin 替换了许多第三方库,如 ButterKnife,Google Autovalue,Retrolambda,Lombok 和一些 RxJava 代码。
总结
作为一个软件开发团队,我们面临的挑战是交付优秀的产品并有效的完成工作。尽管开始有效地用 Kotlin 开发你需要一些必要的函数式编程知识,投资时间去学习真的有回报。我相信 Kotlin 是对常规 Android 开发的一个重大改进,它允许我们及时提供优秀的应用程序,并且更少的 bug。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值