关于做者html
郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的工做,欢迎交流技术方面的问题,能够去个人Github提issue或者发邮件至guoxiaoxingse@163.com与我交流。java
文章目录android
注:文章中"举例"字样表明所举的例子,"区别"字样代码Kotlin与Java不一样的地方,git
更多文章请参见文章目录。程序员
本篇文章是本系列文章的开篇文章,主要介绍Java中的编程概念(语句、函数、类等)是如何映射到Kotlin的代码中的。本文的目的在于帮助你们快速理解Java里的语法在Kotlin中如何实现,以及
它们之间有什么区别。github
Kotlin是一种在Java虚拟机上运行的静态类型编程语言。express
写在前面的总结,从Java过分到Kotlin,有哪些被替换的地方。🤔apache
Android Stduio 3.0已经正式支持Kotlin,若是你是第一次接触Kotlin,你能够看一下下面3篇文章,跑一下Demo,体会一下Kotlin。编程
Kotlin常见的控制语句有:bash
Kotlin的控制语句和Java有所区别🤔,它们具有更强大的功能,在介绍控制语句以前,咱们要先理解两条规则:
在Kotlin中,if是表达式,而在Java中if是语句。
关于Kotlin的表达式,有两条规则须要咱们理解:
在Java中全部的控制语句都是表达式,而在Kotlin中,除了循环(for、do与do/while)是语句外,其余大部分控制结构都是表达式,都有值。
而偏偏在Java中是表达式的赋值操做(a = 1)在Kotlin中倒是语句,这样有助于避免比较操做(==)和赋值(=)操做之间的混淆。
有了上面两条规则,咱们不难理解如下例子。
举例
val a = 1
val b = 2
val ifResult = if (a > b) a else b
val whenResult = when (a > b) {
true -> a
else -> b
}
val number = try {
Integer.parseInt("1")
} catch (e: NumberFormatException) {
null
}
for (i: Int in 1..100){
Logger.d(i)
}
for((key, value) in map){
````//使用key,value
}
//变量 a 和 b 的值取自对集合中的元素上调用 component1() 和 component2() 的返回值。
for ((a, b) in collection) { …… }复制代码
Kotlin提供了很是多相似于RxJava的操做符,为平常的开发提供了极大的方便。更多操做符能够参考操做符列表
函数还能够用中缀表示法调用,当它们是成员函数或扩展函数;它们只有一个参数;它们用 infix 关键字标注。
/** * 用infix定义一个中缀函数 */
infix fun Int.shl(x: Int) {
println("I am a infix method")
}
/** * 中缀调用 */
fun useInfixMethod() {
1 shl 2
}复制代码
解构声明是将一个对象解构成多个变量,一个解构声明会同时建立多个变量。
要实现解构声明,咱们须要添加componentN函数,componentN函数指定要返回的域,并使用operator标记
class Teacher(val name: String, val age: Int) : Person(name, age), IBehavior {
override fun talk() {
super<Person>.talk()
super<IBehavior>.talk()
}
operator fun component1(): Any {
return name
}
operator fun component2(): Any {
return age
}
}复制代码
而后咱们就可使用解构声明批量的建立变量,解构赋值是按照omponentN函数的顺序来执行的。
val teacher = Teacher("LiLei", 20)
val (name, age) = teacher
Logger.d("name: " + name)
Logger.d("age: " + age)复制代码
若是咱们在解构声明中不须要某个变量,用下划线代替便可。
val (_, age) = teacher复制代码
函数的声明以fun关键字开始,函数名称紧跟其后,而后是形参列表,形参列表后面是返回值,若是没有指定返回值,默认的返回值是Unit。
举例
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}复制代码
若是函数中只有一个表达式,能够将这个表达式做为完整的函数体,称为表达式函数体,例如:
fun max(a: Int, b: Int): Int = if (a > b) a else b复制代码
Kotlin变量的声明从关键字var与val开始,Kotlin会自动进行类型推导,所以你无需显式的声明类型。
举例
val name = "Nick"
var age = 10复制代码
默认状况下,应该尽量的使用val关键字来声明变量,仅在必要的时候使用var,使用不可变引用,不能够对象以及无反作用的函数可让你的代码更加接近函数式编程风格。
注:这里提一下Kotlin的package结构,和Java同样Kotlin也有包的概念,可是Kotlin对源码的文件组织更为自由,多个类能够在同一个文件中,文件的名字和目录也能够随意选择,可是咱们仍是
会按照Java的目录布局去组织源码,这是一种良好的实践,但在Kotlin中不少类都很是小,例如数据类,这种状况下,咱们一般把它放在一个文件里。
在Java中定义函数时,有些参数有默认值,这就致使会定义大量的重载函数(参考Thread的构造函数),而在Kotlin中能够利用参数的默认值来避免这个问题。
/** * 函数能够带默认参数,@JvmOverloads注解能够在编译时生成重载函数 */
@JvmOverloads
fun maxWithDefault(a: Int = 1, b: Int = 2): Int {
return if (a > b) a else b
}复制代码
注:可是Java中没有参数默认值的概念,为了方便Java调用Kotlin,能够用@JvmOverloads去注解它,@JvmOverloads注解能够在编译时生成重载函数。
回想一下,咱们的项目中是否是有不少Utils类,它们一种静态的方式被咱们调用。这些Utils类自己没有实际意义,只是做为函数的容器,而在Kotlin中咱们无需
这么作,咱们能够把这些函数和属性直接定义在代码文件的顶层,不用从属任何类,而后用一种导包的方式使用它。
定义
/** * 顶层函数,能够直接导包而后使用 */
val topProperty = "I am a top property"
/** * 顶层函数,能够直接导包而后使用 */
fun topMethod(property: String) {
println("I am a top method")
}
class Method {
}复制代码
调用
import com.guoxiaoxing.kotlin.demo._02_method.topMethod
import com.guoxiaoxing.kotlin.demo._02_method.topProperty
object MethodClient {
@JvmStatic
fun main(args: Array<String>) {
topMethod(topProperty)
}
}复制代码
Kotlin的一大优点就在于它能够平滑的与Java进行集成,例如咱们想要用Kotlin为Java里的类添加一个方法,这时咱们不要去修改Java的源码,而是可使用扩展函数与属性。
/** * 为String类添加一个扩展属性extensionProperty,这个String类能够是Kotlin、Java甚至其余任何JVM语言编写的类 */
val String.extensionProperty
get() = "I am a extension property"
/** * 为String类添加一个扩展函数extensionMethod(),这个String类能够是Kotlin、Java甚至其余任何JVM语言编写的类 */
fun String.extensionMethod() {
println("I am a extension method")
}
/** * 使用扩展函数 */
fun useExtensionMethod() {
val a = "string"
a.extensionProperty
a.extensionMethod()
}复制代码
好的代码设计就是尽可能减小重复代码,不少时候咱们会把重复的代码提取成一个函数进行调用,Kotlin更进一步,它容许你在函数的内部定义函数进行调用。
/** * 为了代码的简洁性,咱们还能够定义局部函数 */
fun outerMethod() {
fun innerMethod() {
}
}复制代码
Kotlin中类使用class关键声明、接口使用Interface声明,使用冒号(:)代替了extends与implements关键字,能够实现多个接口,可是只能继承一个类。
Kotlin中也有和Java中类似的类与接口的概念,可是有所区别🤔
访问修饰符
可见性
open class BaseClass {
open fun extendClass() {
}
}
interface BaseInterface {
val name: String
fun implementInterface()
}
class Clasz(override val name: String) : BaseClass(), BaseInterface {
override fun extendClass() {
println("I override the BaseClass")
}
override fun implementInterface() {
println("I implment the BaseInterface")
}
}复制代码
构造方法
Kotlin里的构造方法分为主构造函数和从构造方法,主构造函数是类头的一部分,它跟在类名后,类初始化的代码能够放在init代码块里完成。Kotlin也支持参数默认值,因此咱们无需像Java那样提供多个重载的构造方法来提供参数默认值。
class Clasz(override val name: String){
/**************************************** 构造方法与初始化 *********************************************/
init {
//TODO 初始化类,在类建立时被调用
}
/** * 从构造函数 * * 若是类有一个主构造函数,每一个次构造函数须要委托给主构造函数, 能够直接委托或者经过别 * 的次构造函数间接委托。委托到同一个类的另外一个构造函数用 this 关键字便可 */
constructor(name: String, age: Int) : this(name) {
println("I am a secondary constructor")
}
}复制代码
嵌套的类默认不是内部类,不持有外部类引用,也没法使用外部类成员变量,若是想定义成内部类,须要用关键字inner声明,内部类是持有外部类引用的,可使用
外部类成员变量。
class Clasz {
private var outerProperty = "I am a outer property"
/**************************************** 嵌套类与内部类 ***********************************************/
/** * 嵌套类,不持有外部类引用,也没法使用外部类成员变量 */
class nestClass() {
fun nestMethod() {
}
}
/** * 内部类,持有外部类引用,可使用外部类成员变量 */
inner class innerClass() {
fun nestMethod() {
outerProperty = "I cam use outerProperty"
}
}
}复制代码
在Java中咱们会用到协议只保存数据的类,咱们呀为它们写大量重复的方法,在Kotlin只须要用用data关键字标记。
data class Model(val name: String)复制代码
就这么简单的一行代码,你将获得:
为了保证数据类的一致性,数据类必须知足:
Kotlin没有static的概念,可是提供了object关键字,它表明了在建立一个类的同时并提供一个对象。
object关键字一般用在:
object Single {
}复制代码
/** * 匿名内部类 */
view.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View?) {
}
})复制代码
另外还有一种companion object(伴生对象),伴生对象是一种声明在类中的普通对象,它也能够有本身的名字,实现一个接口或者有扩展函数和属性。
Kotlin的伴生对象会被编译成常见静态字段,能够经过ClassName.Companion来访问它,若是伴生对象有名字,则用这个名字替换掉Companion。
class Singleton {
/** * 单例 */
companion object {
val instance by lazy { Singleton() }
}
}复制代码
若是你尚未尝试过Kotlin,Android Stduio 3.0已经正式支持Kotlin,若是你是第一次接触Kotlin,你能够看一下下面3篇文章,跑一下Demo,体会一下Kotlin。
利用kotlin-android-extensions,咱们能够直接使用xml文件里的文件id,和findViewById说再见。
注:目前只能在Activity、Fragment、Adapter上使用。
依赖配置
apply plugin: 'kotlin-android-extensions'复制代码
导入属性
// 使用来自主代码集的 R.layout.activity_main
import kotlinx.android.synthetic.main.activity_main.*
// 若是是Adapter则在后面多加个View R.layout.adapter_layout
import kotlinx.android.synthetic.main.adapter_layout.view.*
class MyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.setText("Hello, world!")
// 而不是 findViewById(R.id.textView) as TextView
}
}复制代码
更多细节:kotlinlang.org/docs/tutori…
Anke是一个Android开发的工具库,它能够经过Anko DSL代码书写代替XML来进行UI布局。这是一个很是有效的特性,固然它也有许多有用的functions,能够大大提高咱们的开发效率。
例如:
以上就是本篇文章上半部分的所有内容,下半部分咱们会来深刻探讨泛型、注解、反射、Kotlin类型系统、Lambda与高阶函数以及DSL构建等方面的内容。
--------------------------------------我是Kotlin项目的分割线😆------------------------------------------
Android平台上图片/视频选择,编辑和压缩的一站式解决方案。
图片/视频的选择,编辑和压缩是业务中的常见需求,Phoenix完整的实现了这些功能,并提供了优雅的调用方式。Phoenix的核心功能基于Kotlin实现,外层接口基于Java实现,方便Kotlin与Java双方的调用。
特色
功能
主题
在项目根目录build.gradle文件里添加
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}复制代码
添加依赖
//图片/视频选择、拍照、图片/视频预览
compile 'com.github.guoxiaoxing.phoenix:phoenix-ui:0.0.11'
//选填 - 图片压缩,开启功能:Phoenix.with().enableCompress(true),获取结果:MediaEntity.getCompressPath()
compile 'com.github.guoxiaoxing.phoenix:phoenix-compress-picture:0.0.11'
//选填 - 视频压缩,开启功能:Phoenix.with().enableCompress(true),获取结果:MediaEntity.getCompressPath()
compile 'com.github.guoxiaoxing.phoenix:phoenix-compress-video:0.0.11'复制代码
Phoenix.with()
.theme(PhoenixOption.THEME_DEFAULT)// 主题
.fileType(MimeType.ofAll())//显示的文件类型图片、视频、图片和视频
.maxPickNumber(10)// 最大选择数量
.minPickNumber(0)// 最小选择数量
.spanCount(4)// 每行显示个数
.pickMode(PhoenixConstant.MULTIPLE)// 多选/单选
.enablePreview(true)// 是否开启预览
.enableCamera(true)// 是否开启拍照
.enableAnimation(true)// 选择界面图片点击效果
.enableCompress(true)// 是否开启压缩
.thumbnailHeight(160)// 选择界面图片高度
.thumbnailWidth(160)// 选择界面图片宽度
.enableClickSound(true)//ƒ 是否开启点击声音
.pickedMediaList(pickList)// 已选图片数据
.videoSecond(0)//显示多少秒之内的视频
.onPickerListener(new OnPickerListener() {
@Override
public void onPickSuccess(List<MediaEntity> pickList) {
adapter.setList(pickList);
adapter.notifyDataSetChanged();
}
@Override
public void onPickFailed(String errorMessage) {
}
}).start(MainActivity.this, PhoenixOption.TYPE_PICK_MEDIA);复制代码
最后的start()方法用来完成启动某项功能,根据type不一样启动不一样的功能,具体含义以下:
//功能 - 选择图片/视频/音频
public static final int TYPE_PICK_MEDIA = 0x000001;
//功能 - 拍照
public static final int TYPE_TAKE_PICTURE = 0x000002;
//功能 - 预览
public static final int TYPE_BROWSER_PICTURE = 0x000003;复制代码
欢迎加入改进本项目
Copyright 2017 Guoxiaoxing
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.复制代码