一觉醒来Kotlin成了Android的新宠儿【附代码】

简介:

前言

凌晨的谷歌I/O 2017开发者大会直播你有没有观看呢?安卓虽然已经成为了移动设备第一操作系统,全球采用Android操作系统的激活设备超过了20亿台。不过对于谷歌来说,需要依靠java来做安卓开发一直是一个心病,因为oracle公司因为java和谷歌在安卓系统上的诉讼搞得心力憔悴。

现在好了,谷歌官方正式支持Kotlin,成为官方认可的安卓开发第一语言,而且从Android Studio 3.0开始,将直接集成Kotlin而无需安装任何的插件。

正文

开始做安卓UI开发一直是使用XML文件来实现。虽然理论上,UI可以使用Java语言来实现,但并没有太多的用处。不久前,JetBrains推出了Kotlin,一种面向JVM的现代语言,可以很好的实现安卓UI。

Jetbrains宣称Anko是Android中更快,更轻松的开发风格。Kotlin提供Anko库来作为DSL(领域专用语言)去设计安卓界面,一个简单的例子:

下面的界面由一个图片和一个按钮组成:

使用Anko实现如下:

 
 
  1. verticalLayout{ 
  2.        imageView(R.drawable.anko_logo). 
  3.                 lparams(width= matchParent) { 
  4.                     padding = dip(20) 
  5.                     margin = dip(15) 
  6.         } 
  7.         button("Tap to Like") { 
  8.                 onClick { toast("Thanks for the love!") } 
  9.         } 
  10.     }  

我们定义了一个垂直的线性布局作为容器包含图片和按钮,使用lparams定义了布局的位置信息,由Kotlin的内联函数也实现了按钮的点击事件。

使用Anko的优点:

  • 我们可以将UI布局嵌入到代码中,从而使其类型安全。
  • 由于我们不用XML编写,所以它增加了效率,因为在分析XML浪费CPU时间。
  • 在UI的程序化转换之后,我们可以将Anko DSL片段放入一个函数中。这样便于代码重用。
  • 显然,代码更简洁,可读和可掌握性更高。

现在我们使用Anko Layout和Kotlin构建一个to-do app,来列出我们今天需要做的事。

你可以在GitHub上找到这个项目 to-do app

将Anko库添加到Android Studio:

在streamline-android-java-code-with-kotlin去学习如何添加Kotlin到你的安卓项目中,有了Kotlin,我们需要添加Anko依赖在app/build.gradle中,这样我们就可以顺利编译项目了。

 
 
  1. compile [size=1em]'org.jetbrains.anko:anko-sdk15:0.8.3' 
  2.  
  3. // sdk19,21,23 也可以使用 

可以根据你项目的minSdkVersion来添加这个依赖,上面的例子说明15<=minSdkVersion<19,你可以在Anko的GitHub库中找到自己需要的其他Anko依赖库。

我们准备使用下面的依赖库:

 
 
  1. compile 'org.jetbrains.anko:anko-design:0.8.3' 
  2.  
  3. compile 'org.jetbrains.anko:anko-appcompat-v7:0.8.3' 

在Activity中调用Anko布局:

我们不再使用XML来写布局文件,所以我们不需要XML View,所以也不需要findViewById()方法了。这里我们假设我们的Anko布局类为MainUI,然后我们可以开始写我们的activit内容:

 
 
  1. var ui =MainUI()           //MainUI类代替了XML布局 
  2.  
  3. ui.setContentView(this)   //this代表Activity类 

现在我们创建一个Kotlin文件MainActivity.kt,写上如下代码:

 
 
  1. class MainActivity : AppCompatActivity() {    val task_list = ArrayList<String>()         //任务清单表 
  2.     override fun onCreate(savedInstanceState: Bundle?) { 
  3.        super.onCreate(savedInstanceState) 
  4.        savedInstanceState?.let {           val arrayList = savedInstanceState.get("ToDoList"
  5.            task_list.addAll(arrayList as List<String>) 
  6.        }       var adapter=TodoAdapter(task_list)      //定义适配器 
  7.        var ui = MainUI(adapter)                //定义将要使用的Anko UI 布局 
  8.        ui.setContentView(this)                 //给Activity设置Anko布局 
  9.    }   override fun onSaveInstanceState(outState: Bundle?) { 
  10.        outState?.putStringArrayList("ToDoList", task_list) 
  11.        super.onSaveInstanceState(outState) 
  12.      } 
  13.  }  

task_list是ArrayList,将填充ListView的TodoAdapter。MainUI(adapter)是我们的Anko UI文件,它采用TodoAdapter类作为适配器参数。所以,接下来我们再创建一个TodoAdapter类。

用于ListView的TodoAdapter适配器

TodoAdapter类有一个ArrayList<String>类型的list,并且继承了BaseAdapter。所以我们需要重写一下四个方法:

public int getCount()public Object getItem(int i)public long getItemId(int i)public View getView(int i, View view, ViewGroup viewGroup)

在getView()方法中我们需要使用Anko设计一个表元素的布局。

 
 
  1. public int getCount()public Object getItem(int i)public long getItemId(int i)public View getView(int i, View view, ViewGroup viewGroup) 
  2.  
  3.         在getView()方法中我们需要使用Anko设计一个表元素的布局。 
  4.  
  5. override fun getView(i : Int, v : View?, parent : ViewGroup?) : View { 
  6.               return with(parent!!.context) {              //任务数从1开始 
  7.               var taskNum: Int = i +1 
  8.              //清单表元素布局 
  9.              linearLayout { 
  10.                    lparams(width = matchParent, height = wrapContent) 
  11.                    padding = dip(10) 
  12.                    orientation = HORIZONTAL                   //任务号 
  13.                   textView { 
  14.                        id = R.id.taskNum 
  15.                        text=""+taskNum 
  16.                        textSize = 16f 
  17.                        typeface = Typeface.MONOSPACE 
  18.                        padding =dip(5) 
  19.                   }                  //任务名 
  20.                   textView { 
  21.                         id = R.id.taskName 
  22.                        text=list.get(i) 
  23.                        textSize = 16f 
  24.                        typeface = DEFAULT_BOLD 
  25.                        padding =dip(5) 
  26.                   } 
  27.              } 
  28.          } 
  29.       } 
  • 在这个方法中,我们返回一个包含一个horizontalListView布局列表项的视图。这是使用Kotlin的with语法完成的,它允许我们一次在对象实例上调用很多方法。
  • 每个列表项包含两个textview用于显示任务号和任务名称。
  • linearLayout,textView是扩展功能。扩展功能使我们有能力启用具有新功能的任何类。
  • text,textSize,typeface在android.widget.TextView有getter和setter方法,padding是Anko添加的属性。

继续下一步,我们需要定义列表的操作功能。因此,我们需要在TodoAdapter中定义add(String)和delete(Int)方法。add(String)将任务名称作为参数添加到任务中。delete(Int)将任务所在的位置作为参数来删除任务。下面是具体的实现:

 
 
  1. //将任务添加到任务清单的方法      
  2.  fun add(text: String) {          
  3.        list.add(list.size, text)          
  4.        notifyDataSetChanged()          //更新数据    }       //将任务从任务清单中移除的方法      
  5.  fun delete(i:Int) {         
  6.        list.removeAt(i)          
  7.        notifyDataSetChanged()          //更新数据      
  8.  }  

所以,现在我们设计了列表,我们也可以添加和删除项目到我们的列表中。接下来完成此适配器类的代码。

 
 
  1.  TodoAdapter(val list: ArrayList<String> = ArrayList<String>()) : BaseAdapter() {     
  2.                override fun getView(i : Int, v : View?, parent : ViewGroup?) : View {         
  3.                          return with(parent!!.context) {             
  4.                                    //taskNum will serve as the S.Noof the list starting from 1             
  5.                                    var taskNum: Int = i +1            
  6.                                    //Layout for a list view item             
  7.                                    linearLayout {                 
  8.                                           id = R.id.listItemContainer                 
  9.                                           lparams(width = matchParent, height = wrapContent)                 
  10.                                           padding = dip(10)                 
  11.                                           orientation = HORIZONTAL                 
  12.                                              textView {                     
  13.                                                    id = R.id.taskNum                    
  14.                                                    text=""+taskNum                    
  15.                                                    textSize = 16f                   
  16.                                                    typeface = Typeface.MONOSPACE                 
  17.                                                    padding =dip(5)                
  18.                                              }                 
  19.                                           textView {                    
  20.                                                   id = R.id.taskName                    
  21.                                                   text=list.get(i)                    
  22.                                                   textSize = 16f                     
  23.                                                   typeface = DEFAULT_BOLD                    
  24.                                                   padding =dip(5)                
  25.                                            }            
  26.                                     }         
  27.                                 }    
  28.                            }    
  29.            override fun getItem(position : Int) : String {         
  30.                       return list[position     
  31.             }     
  32.            override fun getCount() : Int {        
  33.                       return list.size    
  34.             }     
  35.            override fun getItemId(position : Int) : Long {         
  36.                      //can be used to return the item's ID column of table         
  37.                      eturn 0L     
  38.             }     
  39.            //function to add an item to the list     
  40.            fun add(text: String) {              
  41.                    list.add(list.size, text)         
  42.                    notifyDataSetChanged()    
  43.            }     
  44.           //function to delete an item from list    
  45.           fun delete(i:Int) {         
  46.                    list.removeAt(i)         
  47.                    notifyDataSetChanged()    
  48.           } 
  49.  

注意,使用Anko DSL类中必须要导入org.jetbrains.anko.*。

设计项目的外观

Anko为我们提供了在单独的Kotlin类中为Activity使用UI的便利。因此,每个屏幕都可以被认为是Kotlin类的UI-Activity匹配对。这个UI类是通过继承在org.jetbrains.anko包中定义的AnkoComponent<T>接口的功能来实现的。

除了这个接口,JetBrains还提供免费的DSL布局预览功能。下面是Anko DSL布局预览在Android Studio中的样子:

Anko Preview的相应插件可以从这里下载。请注意,在撰写本文时,Android Studio 2.2的Anko DSL 布局预览被列为开源issue。

回到正题,我们接下来设计MainUI类展示所有任务列表。MainUI类继承了AnkoComponent<T>接口,其中T指的是UI的所有者,activity的内容将会是这个UI。在我们的例子中,所有者就是我们已经在上面定义的MainActivity。接下来,在初始化时,我们必须将TodAadapter对象传递给此类,因为此适配器将用于填充列表。所以,MainUI声明变成:

 
 
  1. class MainUI(val todoAdapter : TodoAdapter) : AnkoComponent<MainActivity> 

现在我们需要重写方法 createView() ,使用 AnkoContext 对象作为参数并返回一个View 类型:

 
 
  1. override fun createView(ui: AnkoContext<MainActivity>): View = with(ui) { 
  2.  
  3. } 

我们在createView() 方法中UI定义返回给所有者即activity,在这里也就是MainActivity,所以接下来写createView() 方法:

Step1-设计首页

最初,首页是空列表。所以,我们有一个textView要求用户创建一天的Todo List:

 
 
  1. return relativeLayout {         
  2.                          //声明ListView         
  3.                         var todoList : ListView? =null        
  4.                         //当没有任务时显示textView内容"What's your Todo List for today?"         
  5.                         val hintListView = textView("What's your Todo List for today?") {             
  6.                                             textSize = 20f       
  7.                           }.lparams {             
  8.                     centerInParent()         
  9.                    } 
  10.        }  

centerInParent() 是将视图的布局定义为垂直和水平相对中心的辅助方法。因为它是一个todo性质的应用,其本质在于显示任务的列表。所以,我们在这里定义listView:

 
 
  1. //listView   
  2.   verticalLayout {                 
  3.                todoList=listView {                 
  4.               //assign adapter                 
  5.              adapter = todoAdapter               
  6.               }            
  7.       }.lparams {                 
  8.           margin = dip(5)            

todoAdapter是我们在MainUI类声明中定义成员变量。我们用todoAdapter的值初始化listView的adapter,这是一个TodoAdpater类的对象,将会用于填充列表。

为了帮助用户添加任务,我们在主屏幕的右下方提供了一个Material design风格的floatingActionButton。所以我们使用Anko编程floatingActionButton为:

 
 
  1. floatingActionButton {                           
  2.          imageResource = android.R.drawable.ic_input_add         
  3.           }.lparams {             
  4.                           //设置按钮在屏幕的右下方             
  5.                            margin = dip(10)             
  6.                            alignParentBottom()             
  7.                            alignParentEnd()             
  8.                            alignParentRight()             
  9.                            gravity = Gravity.BOTTOM or Gravity.END        
  10.     }  

篇幅所限,Step2、Step3请点击左下角“阅读原文”查看全部文章。

最后的想法

我们在开发此to-do app时没有使用任何XML布局资源,但我们能够以类似的风格设计应用程序。Anko从应用程序的activity或fragments中消除了呈现数据的负担,响应用户交互,连接数据库等这些负担。另外,隔离UI和Activity类使得应用程序更接近MVP(Model-View-Presenter)架构。你可以从这里了解Anko的高级功能。

虽然它有一些缺点,如较慢的编译和应用程序体积大,因为它在复用,维护和测试代码方面打包了很多东西。

第一次翻译这么长的文章,纯手打,如果有什么错误的地方还请指出包涵!也是因为自己对Kotlin的兴趣所以找了这篇文章来翻译,有兴趣的朋友可以看看学习一下。





作者:Ankul Jain
来源:51CTO
目录
相关文章
|
2天前
|
移动开发 API Android开发
构建高效Android应用:Kotlin协程的实践指南
【5月更文挑战第11天】 在移动开发领域,性能优化和资源管理是至关重要的。特别地,对于Android开发者来说,合理利用Kotlin协程可以极大地改善应用的响应性和稳定性。本文将深入探讨Kotlin协程在Android中的实际应用,包括它们如何简化异步编程模型、提高UI线程的响应性,以及减少内存消耗。我们将通过具体案例分析,了解如何在实际项目中有效地使用协程,从而帮助开发者构建更加高效的Android应用程序。
|
15小时前
|
移动开发 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优化实践
【5月更文挑战第13天】 在移动开发领域,Android平台的流畅体验至关重要。随着Kotlin语言的普及,协程作为其核心特性之一,为异步编程提供了简洁且高效的解决方案。本文将深入探讨Kotlin协程在Android应用中的优化使用,从基本概念到实际案例分析,旨在帮助开发者构建更加响应迅速、性能卓越的应用。我们将通过对比传统线程与协程的差异,展示如何利用协程简化代码结构,并通过优化实践减少资源消耗,提升用户体验。
|
1天前
|
移动开发 监控 Android开发
构建高效Android应用:Kotlin协程的实践与优化
【5月更文挑战第12天】 在移动开发领域,性能与响应性是衡量一个应用程序优劣的关键指标。特别是在Android平台上,由于设备的多样性和系统资源的限制,开发者需要精心编写代码以确保应用流畅运行。近年来,Kotlin语言因其简洁性和功能性而广受欢迎,尤其是其协程特性,为异步编程提供了强大而轻量级的解决方案。本文将深入探讨如何在Android应用中使用Kotlin协程来提升性能,以及如何针对实际问题进行优化,确保应用的高效稳定执行。
|
6天前
|
安全 Java Android开发
构建高效Android应用:采用Kotlin进行内存优化的策略
【5月更文挑战第8天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,合理管理内存资源是确保应用流畅运行的关键因素之一。近年来,Kotlin作为官方推荐的开发语言,以其简洁、安全和互操作性的特点受到开发者青睐。本文将深入探讨利用Kotlin语言特性,通过具体策略对Android应用的内存使用进行优化,旨在帮助开发者提高应用性能,减少内存消耗,避免常见的内存泄漏问题。
8 0
|
6天前
|
Android开发 Kotlin
Kotlin开发Android之基础问题记录
Kotlin开发Android之基础问题记录
16 1
|
6天前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin协程的全面应用
【5月更文挑战第7天】 在移动开发领域,性能优化与流畅的用户体验是至关重要的。随着Kotlin语言的流行,其并发神器——协程,已成为提升Android应用性能的重要工具。本文将深入探讨如何在Android项目中利用Kotlin协程进行异步编程、网络请求和数据库操作,以及如何通过协程简化代码结构,增强应用的响应性和稳定性。我们的目标是为开发者提供一套实用的协程使用模式和最佳实践,以便构建更加高效的Android应用。
23 3
|
7天前
|
移动开发 Java Android开发
Android应用开发:Kotlin语言的优势与实践
【5月更文挑战第7天】 在移动开发的世界中,Android平台的Kotlin语言以其高效、简洁的语法和强大的功能吸引了众多开发者。本文将深入探讨Kotlin语言的核心优势,并通过实际案例展示如何在Android应用开发中有效地运用这一现代编程语言。我们将从语言特性出发,逐步分析其在提升开发效率、改善代码质量以及增强应用性能方面的具体表现,为读者提供一个全面而细致的Kotlin应用开发指南。
|
7天前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin与协程的完美结合
【5月更文挑战第7天】 在移动开发领域,性能优化和资源管理始终是核心议题。随着Kotlin语言的普及,其提供的协程特性为Android开发者带来了异步编程的新范式。本文将深入探讨如何通过Kotlin协程来优化Android应用的性能,实现流畅的用户体验,并减少资源消耗。我们将分析协程的核心概念,并通过实际案例演示其在Android开发中的应用场景和优势。
|
9天前
|
移动开发 前端开发 Android开发
构建高效Android应用:探究Kotlin协程的优势
【5月更文挑战第4天】 在移动开发领域,尤其是对于Android开发者而言,编写响应迅速且高效的应用程序至关重要。Kotlin作为一种现代的编程语言,其提供的协程特性为异步编程带来了革命性的改变。本文将深入探讨Kotlin协程在Android开发中的应用优势,并通过实例代码展示如何利用协程简化异步任务处理,提高应用性能和用户体验。
|
10天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能对比
【5月更文挑战第4天】在移动开发的世界中,性能一直是衡量应用质量的重要指标。随着Kotlin的兴起,许多Android开发者开始考虑是否应该从传统的Java迁移到Kotlin。本文通过深入分析两者在Android平台上的性能差异,帮助开发者理解Kotlin在实际项目中的表现,并提供选择编程语言时的参考依据。
22 5