Kotlin 作为 Android 开发语言相比传统 Java 有什么优势

Kotlin 作为 Android 开发语言相比传统 Java 有什么优势,第1张

Kotlin 语言相对 Java 有很多优势,比如官网介绍的简洁、安全,例子见 Kotlin 中文站 首页,部分示例解析见下文。Kotlin 具有现代(也有称下一代的)静态编程语言的很多特点,如类型推断、多范式支持、可空性表达、扩展函数、DSL 支持等。另外对于安卓开发还提供了 Kotlin 安卓扩展和 Anko 库,参见 Kotlin 用于 Android 。关于与 Java 互 *** 作,尤其是 Java 调用 Kotlin 是大家普遍觉得坑的地方,除了默认 final 外,还有一个主要原因应该就是名字修饰,解决方式可以按照它修饰后名字去引用,或者在 Kotlin 端使用 @JvmName 注解来生成便于 Java 使用的名字。具体参见 Java 中调用 Kotlin

```

/

  author:CQ

  Date:2020-04-09

  Description:调拨出入库类型选择d出框

/

class AllotTypeDialog : Dialog {

    private var cox: Context =null

    private var allotTitle: TextView =null// 标题

    private var allotRecyclerView: RecyclerView =null // 列表

    private var allotSure: TextView =null // 确定按钮

    private var allotTypeDialogAdapter: AllotTypeDialogAdapter =null // 适配器

    private var list: MutableList =null// list

    private var onSelectTypeListener: OnSelectTypeListener =null // 选择类型监听

    private var selectIn: String =""

    public fun SetOnSelectTypeListener(onSelectTypeListener: OnSelectTypeListener) {

        thisonSelectTypeListener = onSelectTypeListener

    }

    constructor(context: Context) :super(context) {

            cox = context

            initView()

        }

      constructor(context: Context, themeStyle: Int, select: String) :super(context, themeStyle) {

            cox = context

            thisselectIn = select

            initView()

    }

    private fun initView() {

list =mutableListOf()

onInitData()

}

private fun onInitData() {

val selectList =selectInsplit(",")

list!!run {

            add(AllotTypeBean(0, "全部", selectListsize ==9))

add(AllotTypeBean(1, "渠道调拨", selectListcontains("1")))

add(AllotTypeBean(2, "渠道调退", selectListcontains("2")))

add(AllotTypeBean(3, "店铺配货", selectListcontains("3")))

add(AllotTypeBean(4, "店铺配退", selectListcontains("4")))

add(AllotTypeBean(5, "批发销货", selectListcontains("5")))

add(AllotTypeBean(6, "批发退货", selectListcontains("6")))

add(AllotTypeBean(9, "仓库移仓", selectListcontains("9")))

add(AllotTypeBean(10, "门店横调", selectListcontains("10")))

add(AllotTypeBean(30, "越级调拨", selectListcontains("30")))

}

    }

override fun onCreate(savedInstanceState: Bundle) {

superonCreate(savedInstanceState)

var dialogWindow =window

        dialogWindowsetGravity(GravityCENTER)

setContentView(Rlayoutdialog_allot_type)

allotTitle = findViewById(Riddialog_allot_type_title)

allotRecyclerView = findViewById(Riddialog_allot_type_recycleView)

allotSure = findViewById(Riddialog_allot_type_sure)

allotSure!!setOnClickListener{

            var select =""

            for (iin 1 until list!!size) {

if (list!![i]isCheck)

select +="${list!![i]type},"

            }

if (select =="") {

(cox as AllotAbsActivity)toastMsg("请选择类型")

}else {

select = selectsubstring(0, selectlength -1)

if (onSelectTypeListener !=null) {

onSelectTypeListener!!onSelect(select)

}

dismiss()

}

}

        allotTypeDialogAdapter = AllotTypeDialogAdapter(cox!!, list!!)

allotRecyclerView!!layoutManager = LinearLayoutManager(cox)

allotRecyclerView!!adapter =allotTypeDialogAdapter

        allotTypeDialogAdapter!!setOnClickItemListener(object : AllotTypeDialogAdapterOnClickItemListener {

override fun onClickItem(position: Int) {

if (position ==0) {

list!![0]isCheck = !list!![0]isCheck

                    for (iin 1 until list!!size) {

list!![i]isCheck =list!![0]isCheck

                    }

}else {

list!![position]isCheck = !list!![position]isCheck

                    var selectAll =true

                    for (iin 1 until list!!size) {

if (!list!![i]isCheck)

selectAll =false

                    }

list!![0]isCheck = selectAll

}

allotTypeDialogAdapter!!setOnRefresh(list!!)

}

})

var windowManager = (cox as Activity)windowManager

        var display = windowManagerdefaultDisplay

        var lp =windowattributes

        lpwidth = displaywidth 4 /5

        windowattributes = lp

setCanceledOnTouchOutside(true)

}

/

获取显示类型

/

    public fun getTypeShow(): String {

var show =""

        for (iin 1 until list!!size) {

if (list!![i]isCheck)

show +="${list!![i]name},"

        }

if (show =="")

return show

return showsubstring(0, showlength -1)

}

public interface OnSelectTypeListener {

fun onSelect(select: String)

}

}

1、来了老弟?

2、映射为List: map{},mapIndexed{},mapNotNull{},mapIndexedNotNull{}

val numbers = setOf(1, 2, 3)

println(numbersmap { it 3 })

//[3, 6, 9]

println(numbersmapIndexed { idx, value -> value idx })

//[0, 2, 6]

3、双路合并

(1)zip()将两个集合中具有相同位置的元素构建配对。

val list1 = listOf(1, 2, 3)

val list2 = listOf("a", "b", "c")

val list = list1zip(list2)

println(list)

//[(1, a), (2, b), (3, c)]

val list3 = list1zip(list2) { l1, l2 -> "${l1}----${l2}" }

println(list3)

//[1----a, 2----b, 3----c]

(2)反向转换unzip(),listunzip()得到一个Pair对象

val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)

println(numberPairsunzip())

//([one, two, three, four], [1, 2, 3, 4])

4、关联

根据集合元素和与其关联的某些值构建 Map。

(1) Map associateWith() 。其中原始集合的元素是键,值来自给定的转换函数。 如果两个元素相等,则仅保留最后一个。

val numbers = listOf("one", "two", "three", "four")

val map = numbersassociateWith { itlength }

println(map)

//{one=3, two=3, three=5, four=4}

(2) associateBy()。 键来自给定的转换函数,原始集合中的元素是值。也可以使用keySelector和valueTransform设置键和值。两个元素相等,则仅保留最后一个。

val numbers = listOf("one", "two", "three", "four")

println(numbersassociateBy { itfirst()toUpperCase() })

//{O=one, T=three, F=four}

println(numbersassociateBy(keySelector = { itfirst()toUpperCase() }, valueTransform = { itlength }))

//{O=3, T=5, F=4}

(3)associate()。键和值都是根据集合元素生成的。associate() 会生成临时的 Pair 对象,这可能会影响性能。

data class FullName(val firstName: String, val lastName: String)

fun parseFullName(fullName: String): FullName {

    val nameParts = fullNamesplit(" ")

    if (namePartssize == 2) {

        return FullName(nameParts[0], nameParts[1])

    } else throw Exception("Wrong name format")

}

val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")

println(namesassociate { name -> parseFullName(name)let { itlastName to itfirstName } })

//{Adams=Alice, Brown=Brian, Campbell=Clara}

5、打平

flatMap()可以打平集合中对象的某个类型为list的字段的值。

data class StringContainer(val values: List<String>)

val containers = listOf(

        StringContainer(listOf("one", "two", "three")),

        StringContainer(listOf("four", "five", "six")),

        StringContainer(listOf("seven", "eight"))

)

println(containers)

//[StringContainer(values=[one, two, three]), StringContainer(values=[four, five, six]), StringContainer(values=[seven, eight])]

println(containersflatMap { itvalues })

//[one, two, three, four, five, six, seven, eight]

//即可以打平集合中对象的某个类型为list的字段的值

6、字符串表示

(1)joinToString() 根据提供的参数从集合元素构建单个 String。

val numbers = listOf("one", "two", "three", "four")

println(numbers)

//[one, two, three, four]

println(numbersjoinToString())

//one, two, three, four

println(numbersjoinToString("-", "开始", "结束"))

//开始one-two-three-four结束

println(numbersjoinToString("-", "开始", "结束", 3))

//开始one-two-three-结束

println(numbersjoinToString("-", "开始", "结束", 3, "等等"))

//开始one-two-three-等等结束

println(numbersjoinToString("-", "开始", "结束", 3, "等等", { it -> ittoUpperCase() }))

//开始ONE-TWO-THREE-等等结束

(2)joinTo() 执行相同的 *** 作,但将结果附加到给定的 Appendable (可追加的)对象。

val numbers = listOf("one", "two", "three", "four")

val listString = StringBuffer("The list of numbers: ")

numbersjoinTo(listString, "-", "开始", "结束", 3, "等等", { it -> ittoUpperCase() })

println(listString)

//The list of numbers: 开始ONE-TWO-THREE-等等结束

7、过滤

(1)filter()。只能检查集合中元素的值。

val numbers = listOf("one", "two", "three", "four")

val longerThan3 = numbersfilter { itlength > 3 }

println(longerThan3)

//[three, four]

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)

val filteredMap = numbersMapfilter { (key, value) -> keyendsWith("1") && value > 10 }

println(filteredMap)

//{key11=11}

(2)filterIndexed()。可以检查元素的索引和元素的值。

val numbers = listOf("one", "two", "three", "four")

val filteredIdx = numbersfilterIndexed { index, value -> (index != 0) && (valuelength < 5) }

println(filteredIdx)

//[two, four]

(3) filterNot()。使用否定条件来过滤集合。

val numbers = listOf("one", "two", "three", "four")

val filteredNot = numbersfilterNot { itlength <= 3 }

println(filteredNot)

//[three, four]

(4)filterIsInstance<T>() 返回给定类型的集合元素。

val numbers = listOf(null, 1, "two", 30, "four")

println(numbersfilterIsInstance<String>())

//[two, four]

(5)filterNotNull() 返回所有的非空元素。在一个 List<T> 上被调用时,filterNotNull() 返回一个 List<T: Any>。

val numbers = listOf(null, "one", "two", null)

println(numbersfilterNotNull())

//[one, two]

8、划分

partition() – 根据集合中元素的值进行过滤,并且返回一个Pair<List,List>。第一个list表示符合条件的集合;第二个list表示不符合条件的集合。

val numbers = listOf("one", "two", "three", "four")

val (match, rest) = numberspartition { itlength > 3 }

println(match)

//[three, four]

println(rest)

//[one, two]

9、集合元素检查

(1)

如果至少有一个元素匹配给定谓词,那么 any() 返回 true。

如果没有元素与给定谓词匹配,那么 none() 返回 true。

如果所有元素都匹配给定谓词,那么 all() 返回 true。注意,在一个空集合上调用 all() 始终都会返回 true 。

val numbers = listOf("one", "two", "three", "four")

println(numbersany { itendsWith("e") })

//true

println(numbersnone { itendsWith("a") })

//true

println(numbersall { itendsWith("e") })

//false

println(emptyList<Int>()all { it > 5 })

//true

(2)当any() 和 none()不设置条件时, 它们只是用来检查集合是否为空。 如果集合中有元素(即使是null),any() 返回 true,否则返回 false;none() 则相反

10、集合加减:plus与minus

val numbers = listOf("one", "two", "three", "three", "four")

//集合加和,第二个 *** 作数可以是集合,也可以是元素

val plusList = numbers + "five"

println(plusList)

//[one, two, three, three, four, five]

//如果第二个 *** 作数是一个集合,那么移除其元素在原始集合中的 所有 出现。

val minusList1 = numbers - listOf("three")

println(minusList1)

//[one, two, four]

//如果第二个 *** 作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现

val minusList2 = numbers - "three"

println(minusList2)

//[one, two, three, four]

11、分组

(1) groupBy()

val numbers = listOf("one", "two", "three", "four", "five")

//根据转换函数得到key,value来自于集合的元素

println(numbersgroupBy { itfirst()toUpperCase() })

//{O=[one], T=[two, three], F=[four, five]}

//根据转换函数得到key,value来自于对原有集合元素的转换结果

println(numbersgroupBy(keySelector = { itfirst() }, valueTransform = { ittoUpperCase() }))

//{O=[one], T=[two, three], F=[four, five]}

(2) grouping()

在分组后,对所有的分组进行一次 *** 作。eachCount() 计算每个组中的元素。还有fold()、reduce()、aggregate()等。

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbersgroupingBy { itfirst() }eachCount())

//{o=1, t=2, f=2, s=1}

12、取集合的一部分

(1)slice() 返回给定索引处的集合元素列表。

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbersslice(13))

//[two, three, four]

println(numbersslice(04 step 2))

//[one, three, five]

println(numbersslice(setOf(3, 5, 0)))

//[four, six, one]

(2)take和drop

val numbers = listOf("one", "two", "three", "four", "five", "six")

//从头开始获取指定数量的元素

println(numberstake(3))

//[one, two, three]

//从尾部开始获取指定数量的元素

println(numberstakeLast(3))

//[four, five, six]

//从头开始去除给定数量的元素

println(numbersdrop(1))

//[two, three, four, five, six]

//从尾部开始去除给定数量的元素

println(numbersdropLast(5))

//[one]

(3)takeWhile()和dropWhile()

val numbers = listOf("one", "two", "three", "four", "five", "six")

//不停地获取元素,直到遇到使表达式为false的首个元素。如果首个集合元素便使表达式为false,则结果为空。

println(numberstakeWhile { !itstartsWith('f') })

//[one, two, three]

//从尾部开始,如上

println(numberstakeLastWhile { it != "three" })

//[four, five, six]

//不停地删除元素,直到遇到使表达式为false的首个元素,然后返回剩余的元素。如果首个集合元素便使表达式为false,则返回集合所有的元素。

println(numbersdropWhile { itlength == 3 })

//[three, four, five, six]

//从尾部开始,如上

println(numbersdropLastWhile { itcontains('i') })

//[one, two, three, four]

(4)chunked()

将集合分为指定大小的子集

val numbers = (013)toList()

println(numberschunked(3))

//[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]

val numbers = (013)toList()

//将集合切割成指定大小的子集后,对子集元素进行转换

println(numberschunked(3) { itsum() })

//[3, 12, 21, 30, 25]

(5)windowed()

val numbers = listOf("one", "two", "three", "four", "five")

//检索指定大小的所有可能子集

println(numberswindowed(3))

//[[one, two, three], [two, three, four], [three, four, five]]

//设置步长

println(numberswindowed(3, 2))

//[[one, two, three], [three, four, five]]

//partialWindows为true时,即使剩余的元素数量小于窗口长度,也会返回结果

println(numberswindowed(3, 2, true))

//[[one, two, three], [three, four, five], [five]]

//对得到的所有子集进行转换

println(numberswindowed(3, 2, true, { list -> listmap { ittoUpperCase() } }))

//[[ONE, TWO, THREE], [THREE, FOUR, FIVE], [FIVE]]

(6)zipWithNext()

val numbers = listOf("one", "two", "three", "four", "five")

//从头开始,返回所有的相邻元素对(Pair)

println(numberszipWithNext())

//[(one, two), (two, three), (three, four), (four, five)]

//s1,s2即相邻元素对

println(numberszipWithNext { s1, s2 -> s1length > s2length })

13、取单个元素

(1)elementAt()获取指定索引处的元素

val str = linkedSetOf("one", "two", "three", "four", "five")elementAt(3)

(2)elementAtOrNull()

val numbers = listOf("one", "two", "three", "four", "five")

//越界后返回null

println(numberselementAtOrNull(5))

//null

(3)elementAtOrElse()

val numbers = listOf("one", "two", "three", "four", "five")

//越界后返回lambda表达式的结果

println(numberselementAtOrElse(5) { index -> "The value for index $index is undefined" })

//The value for index 5 is undefined

(4)first()和last()

first()和last()也可以根据表达式查找。但是如果没有查找到目标元素,将会抛出异常。用 firstOrNull() 和 lastOrNull()替代,如果没有找到,会返回null。

可以使用find() 代替 firstOrNull();使用 findLast() 代替 lastOrNull()

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbersfirst { itlength > 3 })

//three

println(numberslast { itstartsWith("f") })

//five

(5) random()

随机返回一个元素。对于空集合会抛出异常。可以使用randomOrNull()替代,会返回null。

14、排序

(1)sortedWith(comparator: Comparator<in T>)

//compareBy()可根据给定的lambda表达式返回Comparator

println(listOf("aaa", "bb", "c")sortedWith(compareBy { itlength }))

//[c, bb, aaa]

(2) sorted() 和 sortedDescending()

val numbers = listOf("one", "two", "three", "four")

//自然升序

println(numberssorted())

//[four, one, three, two]

//自然降序

println(numberssortedDescending())

//[two, three, one, four]

(3) sortedBy(lambda表达式) 和 sortedByDescending(lambda表达式)

val numbers = listOf("one", "two", "three", "four")

val sortedNumbers = numberssortedBy { itlength }

println(sortedNumbers)

//[one, two, four, three]

val sortedByLast = numberssortedByDescending { itlast() }

println(sortedByLast)

//[four, two, one, three]

(4)reversed()和asReversed()

var numbers = mutableListOf("one", "two", "three", "four")

//返回原有集合的倒序副本,且和原有集合没有关联

println(numbersreversed())

//[four, three, two, one]

//返回原有集合的倒序视图,且和原有集合相关联。即改变原有的集合,已得到的倒序视图会发生改变。

val reversedNumbers = numbersasReversed()

println(reversedNumbers)

//[four, three, two, one]

numbersadd("five")

println(reversedNumbers)

//[five, four, three, two, one]

(5)shuffled()

返回一个以随机顺序排列的含有原有集合元素的新list

val numbers = listOf("one", "two", "three", "four")

println(numbersshuffled())

15、聚合

(1)聚合 *** 作如min()、max()、average()、sum()这些都只是对于数字类型的集合可用。count()计算集合中元素数量。

minBy{}、maxBy{}接收一个表达式;minWith{}、maxWith{}接收一个Comparator对象,可以由compareBy{}产生。

sumBy{}、sumByDouble{}接收一个表达式。前者对int类型的元素求和,并返回int。后者对Double类型的元素求和,并返回Double。

(2)fold()和reduce()。以及OrNull版本。

val numbers = listOf(5, 1, 3, 2)

//第一步的两个 *** 作数分别是集合中第一个和第二个元素。(则第一个元素无法乘以2)

println(numbersreduce { sum, element -> sum + element 2 })

//17

//为sum设置了初始值。每一次的 *** 作数都是sum和当前的集合元素。(可以保证每一个元素都乘以2)

println(numbersfold(0) { sum, element -> sum + element 2 })

//22

(3) reduceRight() 和 foldRight()从尾部开始进行计算。以及OrNull版本。

(4)foldIndexed()和reduceIndexed()将元素索引作为参数进行 *** 作。以及OrNull版本。

val numbers = listOf(5, 2, 10, 4)

println(numbersfoldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })

//15

println(numbersreduceIndexed { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })

//15

(5)reduceRightIndexed() 与 foldRightIndexed()从尾部开始进行计算。以及OrNull版本。

16、List *** 作

(1)getOrElse()、getOrNull()

val numbers = listOf(1, 2, 3, 4)

//越界时,返回null

println(numbersgetOrNull(5))

//越界时,返回表达式的结果,it等于index

println(numbersgetOrElse(6, { it }))

(2) indexOf() 返回元素第一个位置。 lastIndexOf() 返回元素最后一个位置。

(3)indexOfFirst() 和 indexOfLast() 可以接收一个表达式。

(4)二分查找 binarySearch()

要求该列表按照一定的顺序(自然排序或函数参数中提供的另一种排序)按升序排序过。

查询失败将返回 (-insertionPoint - 1),其中 insertionPoint 为应插入此元素的索引,以便列表保持排序。

如果存在多个目标元素返回其任一索引。

val numbers = mutableListOf("one", "two", "three", "four")

numberssort()

println(numbers)

//four, one, three, two]

println(numbersbinarySearch("two"))

// 3

println(numbersbinarySearch("z"))

// -5

println(numbersbinarySearch("two", 0, 2))

// -3

(5)通过Comparator使用二分查找

data class Product(val name: String, val price: Double)

val productList = listOf(

        Product("WebStorm", 490),

        Product("AppCode", 990),

        Product("DotTrace", 1290),

        Product("ReSharper", 1490))

println(productListbinarySearch(Product("AppCode", 990), compareBy<Product> { itprice }thenBy { itname }))

(6)fill()将集合中所有元素更新为指定值

val numbers = mutableListOf(1, 2, 3, 4)

numbersfill(3)

println(numbers)

//[3, 3, 3, 3]

17、set *** 作

(1)union()获取并集。对于有序集合, *** 作数顺序决定元素顺序。a union b

(2)intersect()获取交集。a intersect b

(3)subtract()获取差集。a subtract b 

18、map *** 作

filter()、filterKeys()、filterValues()

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)

println(numbersMapfilter { (key, value) -> keyendsWith("1") && value > 10 })

//{key11=11}

println(numbersMapfilterKeys { itendsWith("1") })

//{key1=1, key11=11}

println(numbersMapfilterValues { it < 10 })

//{key1=1, key2=2, key3=3}

前言,因为需要写一个播放器测试,需要读取到手机文件路径以获取到 mp4 格式文件的路径,进而播放,发现网络上的大多有问题,这里写下以作笔记记录。

1存储方式分为三部分:

先理解, 路径、绝对路径/相对路径、规范路径

总结: 路径 包含 绝对路径/相对路径 , 绝对路径 包含 规范路径 ,而 相对路径 不包含 规范路径 。

真实返回:

(待写)

参考 >

2011年出来的。由 JetBrain 的牛人 Dmitry Jemerov 在2011年开始带队开发,主要是解决Java之前被诟病已久的问题,而且积极借鉴了 Scala、Ruby 等新语言在开发效率和简洁性上的优势。由于是全新开发和设计的语言,当然在各方面上都有着其先进性,也就是重新设计的 Java现代版;比起 Scala 更加interoperate with Java,比如说很多 Kotlin 的库都可以一直复用 Java libraries。

Kotlin是JVM和Android的实用编程语言,结合了OO和功能特性,专注于互 *** 作性,安全性,清晰度和工具支持。

作为通用语言,Kotlin 可以在Java工作的地方工作:服务器端应用程序,移动应用程序(Android),桌面应用程序。它适用于所有主要的工具和服务,如

IntelliJ IDEA,Android Studio和Eclipse

Maven,Gradle和Ant

Spring Boot (Kotlin支持今天发布!)

GitHub,Slack甚至Minecraft :)

Kotlin的关键重点之一是混合Java + Kotlin项目的互 *** 作性和无缝支持,使采用更容易,从而减少了样板代码和更多的类型安全性。此外,Kotlin有一个广泛的标准库,使日常任务轻松流畅,同时保持字节码足迹低。当然,也可以在Kotlin中使用任何Java库。反之亦然。


kotlin语言学习教程:网页链接

个人博客:haichenyicom。感谢关注

  java中的构造函数是与类名相同即可,kotlin里面的构造函数是用constructor关键字表示。

  kotlin里面的构造函数分为主构造函数和次构造函数。 主构造函数只能有一个,次构造函数个数不限制,可以有一个或者多个

  啥是主构造方法?啥是次构造方法呢?

  我们可以看到主构造方法是没有方法体的,那么,我们需要初始化的数据应该放到哪呢?kotlin提供了init方法,给我们初始化数据。

  那么,问题来了,次构造方法有方法体,会执行这个init模块吗?

结论: 不管是什么构造方法,先执行init模块逻辑,后执行构造方法的逻辑

  简单的说一下继承,this和super两个关键字,跟java差不多;

  this是调用自己的,super是调用父类的

  类BBB继承类AAA,其中BBB分别有一个参数的构造方法和两个参数的构造方法;一个参数的构造方法用的this关键字调用自己的两个参数的构造;而两个参数的构造方法用的super关键字调用的父类两个参数的构造方法;这里控制台打印的数据:

说到了这个类,讲一下怎么重写属性的set/get方法

  这里一个person类,里面有三个属性:name,age,address;在name和age下面分别写了set,get方法,address没写。

重点:

  这里,我就只重写了name和age的set,get方法,没有重写address的set,get方法

  这里,我再存名字的时候在名字的后面加上了>

目前很多开发组都用上协程来处理异步任务了,但是有的地方协程提供的原生API还是不足以应付,比方说一些SDK提供了传入Executor的接口(以便复用调用者的线程池来执行异步任务),这时候可以用这JDK提供的线程池,或者封装一下协程也可以满足需求。

协程提供了 DispatchersDefault DispatchersIO 分别用于 计算密集型 任务和 IO密集型 任务,类似于RxJava的 Schedulerscomputation() Schedulersio()

但两者有所差异,比如RxJava的 Schedulersio() 不做并发限制,而 Dispatchersio() 做了并发限制:

考虑到当前移动设备的CPU核心数都不超过64,所以可以认为协程的 DispatchersIO 的最大并发为64。

DispatchersDefault 的并发限制为:

考虑到目前Android设备核心数都在2个以上,所以可以认为 DispatchersDefault 的最大并发为 CPU cores。

DispatchersDefault DispatchersIO 是共享协程自己的线程池的,二者可以复用线程。

不过目前这两个Dispatchers 并未完全满足项目中的需求,有时我们需要一些自定义的并发限制,其中最常见的是串行。

RxJava有 Schedulerssingle() ,但这个 Schedulerssingle() 和AsyncTask的 SERAIL_EXECOTOR 一样,是全局串行,不同的任务处在同一个串行队列,会相互堵塞,因而可能会引发问题。

或许也是因为这个原因,kotlin协程没有定义“DispatchersSingle"。

对于需要串行的场景,可以这样实现:

这样可以实现局部的串行,但和协程的线程池是相互独立的,不能复用线程。

线程池的好处:

然彼此独立创建线程池的话,会大打折扣。

如何既复用协程的线程池,又自主控制并发呢?

一个办法就是套队列来控制并发,然后还是任务还是执行在线程池之上。

AsyncTask 就是这样实现的:

用SerialExecutor的execute的任务会先进入队列,当mActive为空时从队列获取任务赋值给mActive然后通过线程池 THREAD_POOL_EXECUTOR 执行。

当然AsyncTask 的SerialExecutor是全局唯一的,所以会有上面提到的各种任务相互堵塞的问题。可以通过创建不同是的SerialExecutor实例来达到各业务各自串行。

在Kotlin环境下,我们可以利用协程和Channel来实现:

添加Log编写测试如下:

执行结果:

第一个任务可以顺利通过send(), 而随后的任务被suspend, 直到前面的任务执行完(执行block),调用recevie(), 然后下一个任务通过send() ……依此类推。

最终,消耗4s完成任务。

如果Channel的参数改成2,则能有两个任务可以通过send() :

最终,消耗2s完成任务。

关于参数可以参考Channel的构造函数:

在前面的实现中, 我们关注UNLIMITED, BUFFERED 以及 capacity > 0 的情况即可:

不过, [DispatchersIO] 本身有并发限制(目前版本是64),

所有对于 ChannelUNLIMITED 和 capacity > 64 的情况,和capacity=64的情况是相同的。

我们可以为不同的业务创建不同的Channel实例,从而各自控制并发且最终在协程的线程池上执行任务。

简要示意图如下:

为了简化,我们假设Dispatchers的并发限制为4。

通过Channel可以实现并发的控制,但是日常开发中有的地方并不是简单地执行个任务,而是需要一个ExecutorService或者Executor。

我们可以通过Channel封装一下:

需要简单地控制并发的地方,直接定义Channel然后调用runBlock即可;

需要Executor的地方,可创建ChannelExecutor来执行。

这章理一下channel,先分享一句学习时候看到的话: Do not communicate by sharing memory; instead, share memory by communicating 。本来好像是用在 go 上的,但也有着异曲同工之妙啊

channel 顾名思义是管道,有入口与出口。因此最底层有 sendChannel&receiveChannel

Produce = Coroutine + Channel

produce 也是产生协程,跟普通的 launch 不同他会返回一个 receiveChannel ,后面会看到 receiveChannel 是一个迭代器,同时会 suspend 在 hasNext和next() 上,因此另一个协程就可以使用 forin 等待接受。

同时, produce 发射完成后是会自己关闭的,省的我们自己关闭信道:

通过 job 的 invokeOnCompletion 实现。

与 produce 相反返回 sendChannel

我们看这里用了 offer 而不是 send ,我们可以把 forin 先简单的写成以下形式:

假设队列里没有东西时, enqueue 一个 receiveHasNext 进行等待。过会解释一下 channel 的原理。现在只要知道,当有 sendersend 时,与 receive 关联的 cont 就会被调用 resume ,那么显而易见,当 action 正在处理时队列中没有 receiver ,而 offer 是不会 suspend 的,因此事件就被抛弃。

这里我们使用 CONFALTED ,即合并所有事件,因此接受者永远处理最近一个。原理如下:

当 offer 失败时需要 suspend 等待,(说明还没有接受者或者人家正忙着),插入 sendBuffered ,同时移除前面已有的 sendBuffered

这样永远是最近一个生效。

其实看 abstractChannel 会先看到一个 queue ,这时候显而易见会把它当做是像 linkedlist 那种塞数据的地方。但其实 queue 是用来放 receive/send node 。当队列为空时, send 时会先从队列取第一个 receiveNode ,取不到就 suspend ,把自己当成 sendNode 放入;不然就把数据直接交给 receiveNode 。

具体channel实现时,例如 ArrayChannel(buffer) ,会多加一个 buffer 队列,当队列为空时, send 时会先从队列取第一个 receiveNode ,取不到就放入 buffer 队列,如果 buffer 队列满了,把自己当成 sendNode 放入就 suspend ;同时把不然就把数据直接交给 receiveNode 。

参考

select 可以等任何一个回来,也可以等 await :

跟 linux 里的 select 其实类似,(能知道是哪个吗?):

能看到 onReceive 是实现 SelectCaluse1 ,同时在 selectBuilderImpl 环境下:

所以会往 queue 中 enqueue 两个 receive节点。 以

同时能看到如果任何一次 select 节点获取数据以后:

会调用 blockstartCoroutineUnintercepted :

之前讲过 startCoroutineUnintercepted 其实就是 functioninvoke() ,所以就调用 blockinvoke(select的completion是自己) ,获得值后通过 uContresume 即可。

这个和 defered 即 job(Support) 搞在一起:

可以看到当任务成功后, select 会被继续进行

首先解决一个问题,一个 sender 多个 receiver 是怎么处理的。

因为是1vs1消费。只有第一个会收到,因为它插在等待队列的第一个。用 broadcast 可以保证大家都收到。它维护一个 subscribe 的 user list ,所有消费者都能收到 channelsend 的 element

可以实现跟 RX 一样的 *** 作符,接受者收到后经过转换再进行发送返回最终新的 receiveChannel

channel 是 hot 的。

Provide abstraction for cold streams

这个todo,后续再说。

Even smarter async with coroutine actors

官方文档

以上就是关于Kotlin 作为 Android 开发语言相比传统 Java 有什么优势全部的内容,包括:Kotlin 作为 Android 开发语言相比传统 Java 有什么优势、使用kotlin自定义dialog详解、kotlin集合高效使用等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9823964.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-02
下一篇2023-05-02

发表评论

登录后才能评论

评论列表(0条)

    保存