热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【12】Kotlin函数泛型协程

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.(2)天生我才必有大用(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.(4)做难事必有所得(5)精神乃真




(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~



【12】Kotlin函数泛型与协程


文章目录


  • 【12】Kotlin函数泛型与协程
    • 1.项目增加WebView模块
    • 2.高阶函数续
      • 2.1普通函数中定义高阶函数
        • 2.1.1定义
        • 2.2使用

      • 2.2函数参数有默认值
      • 2.3高阶函数一个形参
      • 2.4高阶函数两个形参
      • 2.5由一个函数直接完成另一个函数的业务操作
      • 2.6高阶函数三数相乘
      • 2.7给泛型增加扩展类型
      • 2.8链式调用
      • 2.9扩展函数高阶函数有参数
      • 2.10执行自定义线程
      • 2.11自定义轮循器

    • 3.项目代码优化
    • 4.Kotlin泛型
      • 4.1泛型的读取模式
      • 4.2泛型的上限与下限
      • 4.3泛型场景1可修改不能获取
      • 4.4泛型场景2不可修改能获取
      • 4.5Kotlin泛型与java泛型对应关系
      • 4.6 in out关键字实现权限的读取模式
      • 4.7限定类只能修改不能读取
      • 4.8限定类可以获取,不能修改

    • 5.协程使用篇
      • 5.1线程环境到协程环境的切换
      • 5.2不使用协程更新UI
      • 5.3使用协程更新UI
      • 5.4阻塞式协程切换线程
      • 5.5非阻塞式协程切换线程
      • 5.6协程与线程的概念
      • 5.7自主学习协程
      • 5.8Rxjava的线程切换
      • 5.9协程跟随main线程的结束而结束
      • 5.10阻塞式与非阻塞式协程混合
      • 5.11结束协程

    • 6.打赏鼓励
      • 6.1微信打赏
      • 6.2支付宝打赏



1.项目增加WebView模块

package com.gdc.kotlinproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebSettings
import com.gdc.kotlinproject.config.Flag
import kotlinx.android.synthetic.main.activity_detail_link.*
class DetailLinkActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail_link)
//1.隐藏ActionBar
supportActionBar?.hide()
//2.获取上个页面传递过来的url
val mUrl: String? = intent.getStringExtra(Flag.URL_KEY)
//3.设置WebView的一些参数
//(1)获取WebView参数设置
val mWebSettings:WebSettings = web_view.settings
//(2)将图片调整到适合webview的大小
mWebSettings.useWideViewPort = false
//(3)支持js
mWebSettings.JavascriptEnabled = true
//(4)支持自动加载图片
mWebSettings.loadsImagesAutomatically = true
/*
*(5)利用WebView直接加载网页链接
* - 每次启动这个activity 所加载的url网页路径肯定是不一样的 , Intent传值
* - ?.意思是这个参数可以为空,并且程序继续运行下去
* - !!.的意思是这个参数如果为空,就抛出异常
*/
web_view.loadUrl(mUrl!!)
}
}

2.高阶函数续


2.1普通函数中定义高阶函数


2.1.1定义

/**
* 1.普通函数中定义高阶函数
* (1)一个参数无返回
* myMethod:(String)-> Unit
*/
fun show1(name:String,myMethod:(String)-> Unit){
myMethod(name)
}

2.2使用

fun main() {
//1.调用方式1
show1("Derry"){
println("输出1:$it")
}
//1.调用方式2
show1("张华",myMethod={
println("输出2:$it")
})
//1.调用方式3
show1("杨红",{
println("输出3:$it")
})
}

2.2函数参数有默认值

fun show2(name:String="李连杰",myMethod:(String)-> Unit){
myMethod(name)
}

//1.调用有默认值的
show2{
println("输出4:$it")
}

2.3高阶函数一个形参

fun sum1(myMethod:(Int) -> Unit){
myMethod(11)
}

sum1 {
println("输出5:$it")
}
sum1 ({
println("输出6:$it")
})

2.4高阶函数两个形参

fun sum2(myMethod:(Int,Boolean) -> Unit){
myMethod(11,true)
}

/**
* 1.两个参数就没法默认it
* (1)需要手动指定参数名
* (2)只有一个参数时就是默认的it
*/
sum2({
n1,b1->
})

2.5由一个函数直接完成另一个函数的业务操作

/**
* 1.高阶函数
*/
fun thread01(myMethod:(Int) -> String){
var ret = myMethod(99)
println(ret)
}

/**
* 1.将Int转换为String类型
*/
fun run01(number:Int):String = "OK $number"

fun main() {
//以前是在{}里面直接做业务操作
thread01() {
""
}
/**
* 1.组合使用函数
* (1)::run01的结果拿过来使用,意思是直接交给run01去完成thread01的业务操作
* (2)将run01变成函数类型的对象将给thread01函数
*/
thread01(::run01)
}

//将run01变成函数类型的对象将给thread01函数
val r01 = ::run01
var r02 = r01
thread01(r01)
thread01(r02)

2.6高阶函数三数相乘

/**
* 1.三数相乘
* (1)高阶函数返回一个泛型
* myMethod:(Int,Int,Int)-> R
*
* (2)函数也返回一个泛型
*/
fun sum(n1:Int,n2:Int,n3:Int,myMethod:(Int,Int,Int)-> R):R{
return myMethod(n1,n2,n3)
}

fun main() {
//Unit
//String
//Boolean
//Double
var ret = sum(10,20,30){
i1,i2,i3 ->
println("i1:$i1,i2:$i2,i3:$i3")
//其他操作
"Ok"
true
9999.3
}
println(ret)
}

2.7给泛型增加扩展类型

val name = "张三"
val age = 24
val sex = 'M'
fun main() {
name.myApply()
age.myApply()
sex.myApply()
func().myApply()
}
fun func(){
}

在这里插入图片描述

/**
* (1)返回类型泛型
* (2)给泛型增加扩展函数
* (3)意味着类中的属性、函数都可以使用扩展函数
*/
fun T.myApply(){
}

2.8链式调用

/**
* (1)返回类型泛型
* (2)给泛型增加扩展函数
* (3)意味着类中的属性、函数都可以使用扩展函数
* (4)无参的高阶函数
*/
fun T.myApply1(myMethod:() ->Unit):T{
//T:就是this
myMethod()
return this
}

/**
* 链式调用
*/
val length = name.myApply1 {
}.myApply1() {
}.myApply1() {
}.length as Double

2.9扩展函数高阶函数有参数

/**
* (1)扩展函数
* (2)返回类型泛型
* (3)高阶函数有参数无返回值
* myMethod:(T) -> Unit
* (4)it == T == this
*/
fun T.myAlso(myMethod:(T) -> Unit):T{
//it == T == this==name
myMethod(this)
return this
}

val d = name.myAlso {
it.length
println("ret:$it")
}.myAlso {
it.length
}.myAlso {
it.length
}.length as Double

/**
* (1)返回值泛型R
* (2)高阶函数返回泛型R
* myMethod: (T) -> R
*/
fun T.myLet(myMethod: (T) -> R):R = myMethod(this)

2.10执行自定义线程

/**
* 1.自定义线程封装
* (1)start:是否启动标识
* (2)name:线程名称
* (3)myMethod高阶函数
* (4)返回线程
* (5)如果启动线程就直接启动,不启动,则返回线程对象
*/
fun ktrun(
start:Boolean = true,
name:String ? = null,
myMethod:() -> Unit):Thread{
val thread = object :Thread(){
override fun run() {
super.run()
myMethod()
}
}
name?: "myThread1"
if(start){
thread.start()
}
return thread
}

fun main() {
ktrun(){
//1.耗时操作
println("如果设置了启动线程,则执行自定义线程")
}
}

2.11自定义轮循器

/**
* 自定义轮循器,传入多少次就跌代多少次
*/
fun doCounts(counts:Int,myMethod:(Int) -> Unit){
//0-counts区间
for(index in 0 until counts){
myMethod(index)
}
}

doCounts(100){
println("执行了一次下标是:$it")
}

3.项目代码优化

/**
* (1)返回类型泛型
* (2)给泛型增加扩展函数
* (3)意味着类中的属性、函数都可以使用扩展函数
* (4)无参的高阶函数
*/
fun T.myApply(myMethod:T.() ->Unit):T{
//T:就是this
myMethod()
return this
}

/**
* 优化之前的代码
* 1.创建客户端API接口
* (1)WanAndroidAPI实例化
* (2)XXXAPI实例化
* (3)动态的实例化,可以使用到泛型
* (4)fun instanceRetrofit(apiInterface: Class): T表示此为泛型方法
* (5)apiInterface: Class:表示此为泛型参数
* (6): T表示返回类型为泛型
*/
/*fun instanceRetrofit(apiInterface: Class) : T{
//1.1.1OKHttpClient请求服务器
val okHttpclient = OkHttpClient().newBuilder()
//1.1.1.1添加读取超时时间
.readTimeout(10000, TimeUnit.SECONDS)
//1.1.1.2添加连接超时时间
.connectTimeout(10000,TimeUnit.SECONDS)
//1.1.1.3添加写出超时时间
.writeTimeout(10000,TimeUnit.SECONDS)
.build()
val retrofit:Retrofit = Retrofit.Builder()
//1.1请求方 <-
.baseUrl(Flag.BASE_URL)
.client(okHttpclient)
//1.2响应方 ->
//1.2.1RxJava来处理
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//1.2.2Gson来解析JavaBean
.addConverterFactory(GsonConverterFactory.create())
.build()
//1.3将请求方与响应方建好后,将请求api的参数
return retrofit.create(apiInterface)
}*/
//优化后的代码
fun instanceRetrofit(apiInterface: Class) : T{
//1.1.1OKHttpClient请求服务器
val okHttpclient = OkHttpClient().newBuilder().myApply {
//1.1.1.1添加读取超时时间
readTimeout(10000, TimeUnit.SECONDS)
//1.1.1.2添加连接超时时间
connectTimeout(10000,TimeUnit.SECONDS)
//1.1.1.3添加写出超时时间
writeTimeout(10000,TimeUnit.SECONDS)
}.build()
val retrofit:Retrofit = Retrofit.Builder()
//1.1请求方 <-
.baseUrl(Flag.BASE_URL)
.client(okHttpclient)
//1.2响应方 ->
//1.2.1RxJava来处理
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//1.2.2Gson来解析JavaBean
.addConverterFactory(GsonConverterFactory.create())
.build()
//1.3将请求方与响应方建好后,将请求api的参数
return retrofit.create(apiInterface)
}

4.Kotlin泛型

(1)?是java泛型通配符
(2)*是Kotlin的通配符
(3)Kotlin简单平常的泛型与Java是一样的。
(4)泛型不一样的地方是out与in


4.1泛型的读取模式

private ParentClass parentClass = new ParentClass();

private ChildClass childClass = new ChildClass();
/**
* 泛型的读取模式
*/
public void test01(){
//(1)想实现这种多态,java是不支持的,使用权限模式解决
//List

list = new ArrayList();
//(2)解决问题 ? extends ParentClass :权限获取模式,只能获取,不能修改
List list = new ArrayList();
//(3)不能添加,不能对集合做修改操作
//list.add(parentClass);
//list.add(null);是特殊情况
//(4)能获取
ParentClass p = list.get(0);
/**
* (5)只能修改,不能获取的情况
* ? super ChildClass,只能修改,不能获取
*/
List childList = new ArrayList

();
//(6)能添加但是不能获取
childList.add(childClass);
//(7)不能获取
//ChildClass c = childList.get(0);
}

4.2泛型的上限与下限

public class TestOutIn {

4.3泛型场景1可修改不能获取

private void show(List list){
//(1)能获取
list.get(0);
for (ParentClass p : list){
}

//(2)不能修改
//list.add(parentClass);
}
private void test2(){
List childList = new ArrayList();
//(1)show方法要求是传父类,而此处传子类,就可以修改泛型的参数
show(childList);
}

4.4泛型场景2不可修改能获取

/**
* (1)不可以获取
* (2)可以修改
* @param list
*/
private void show1(List list){
//ChildClass c = list.get(0);
/*for(ChildClass c : list){
}*/
list.add(childClass);
}
private void test3(){
List

parentList = new ArrayList

();
//(1)show1方法要求是传子类,但此处传的是父类,可以修改泛型参数
show1(parentList);
}

4.5Kotlin泛型与java泛型对应关系

在这里插入图片描述


4.6 in out关键字实现权限的读取模式

/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlin.generic.ktoutin
* @file
* @Description:
*
* 1.权限的读取模式
*
* @date 2021-6-6 20:53
* @since appVer
*/
val parentClass = ParentClass()
val childClass = ChildClass()
fun test01(){
/**
* 1.out 只能读取,不能修改
*(1)同Java
* List list = new ArrayList();
*/
val list : MutableList = ArrayList()
/**
* 2.in 不能读取,只能修改
* (1)同Java
* List childList = new ArrayList

();
*/
val list1 : MutableList = ArrayList

()
}

4.7限定类只能修改不能读取

/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlin.generic.ktobj
* @file
* @Description:
* 1.泛型的读取模式
*
* (1)Student :限定该类只能修改不能读取
*
* (2)为了解决多个函数都需要添加泛型读取模式限定,可以直接在类上做限定,一劳永逸
*
* 而Java是做不到的
*
* @date 2021-6-6 21:31
* @since appVer
*/
class Student {
fun a1(list:T){
}
/* fun a2(list:MutableList){
}
fun a3(list:MutableList){
}
fun a4(list:MutableList){
}
fun a5(list:MutableList){
}
fun a6(list:MutableList){
}*/
/**
* 如此限定的好处
*/
fun setData(data : T){
}
/**
* 不能从此类获取数据
*/
/*fun getData() : T{
}*/
}

4.8限定类可以获取,不能修改

/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlin.generic.ktobj
* @file
* @Description:
*
* (1)限定类可以获取,不能修改
*
* @date 2021-6-6 21:42
* @since appVer
*/
class Teacher {
/**
* 1.能获取
*/
fun getData() : T? = null
/**
* 2.不能修改
*/
/*fun setData(data:T){
}*/
}

5.协程使用篇


5.1线程环境到协程环境的切换

在这里插入图片描述

fun click1(view: View) = runBlocking{
/**
* (1)由main线程切换到协程环境,默认是main线程
* (2)runBlocking切换到的是外协程
* (3)launch切换到的是内协程
* (4)由main线程变为异步线程
* aunch(Dispatchers.IO)
* (5)轮循
*
*/
launch(Dispatchers.IO) {
Log.e("click1:","lunch ${Thread.currentThread().name}")
repeat(10){
Thread.sleep(1000)
Log.e("click:","计数中:${it}")
}
}
}

5.2不使用协程更新UI

private val mOkHttpClient : OkHttpClient = OkHttpClient()
private val mRequest = Request.Builder().url("http://www.baidu.com").get().build()
fun displayMethod(textView:TextView){
/**
* 切换为主线程更新UI
*/
val han = Handler(Looper.getMainLooper()){
textView.text = it.obj as String
false
}
/**
* 1.异步线程
*/
object : Thread(){
override fun run() {
super.run()
val result = mOkHttpClient.newCall(mRequest).execute().body()?.string()
val msg = han.obtainMessage()
msg.obj = result
han.sendMessage(msg)
}
}.start()
}

fun click2(view: View) = runBlocking{
/**
* 1.不使用协程,更新UI
*/
//displayMethod(textView)
/**
* 2.使用协程,更新UI
*/
displayMethodXC(textView)
}

5.3使用协程更新UI

/**
* 使用协程更新UI
*/
fun displayMethodXC(textView:TextView) = runBlocking{
/*launch {
val def = async(Dispatchers.IO) {
//1.异步线程
true
"String"
//2.不考虑异常的情况
mOkHttpClient.newCall(mRequest).execute().body()?.string()
}
*//**
* 3.main
* 可以拿到异步执行后的结果
*//*
textView.text = def.await()
}*/
/**
* 简化写法
*/
launch {
//协程外部是主线程
textView.text = async(Dispatchers.IO) {
//异步线程
mOkHttpClient.newCall(mRequest).execute().body()?.string()
}.await()
}

5.4阻塞式协程切换线程

/**
* 1.完成这种 异步线程 和 主线程 的切换,这个需求:之前我们用RxJava实现过了
*
* (1)注册耗时操作
* (2)注册耗时操作完成后,更新注册UI
* (3)登录耗时操作
* (4)登录耗时操作完成后,更新登录UI
*
* 2.这种方式是阻塞式的
* 加载框只有等所有操作执行完成后才能显示
*/
fun click3(view: View) = runBlocking{
launch {
val pro = ProgressDialog(this@XcActivity)
pro.setMessage("正在执行中...")
pro.show()
//1.注册耗时操作 异步
withContext(Dispatchers.IO){
Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
Thread.sleep(2000)
}
// 2.注册耗时操作完成后,更新注册UI main
Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
// 3.登录耗时操作 异步
withContext(Dispatchers.IO) {
Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
Thread.sleep(3000)
}
// 4.登录耗时操作完成后,更新登录UI
Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
}
}

5.5非阻塞式协程切换线程

/**
* 1.完成这种 异步线程 和 主线程 的切换,这个需求:之前我们用RxJava实现过了
*
* (1)注册耗时操作
* (2)注册耗时操作完成后,更新注册UI
* (3)登录耗时操作
* (4)登录耗时操作完成后,更新登录UI
*
* 2.非阻塞式协程
*/
fun click4(view: View) = runBlocking{
GlobalScope.launch(Dispatchers.Main) {
val pro = ProgressDialog(this@XcActivity)
pro.setMessage("正在执行中...")
pro.show()
//1.注册耗时操作 异步
withContext(Dispatchers.IO){
Log.d("click4", "1.注册耗时操作: ${Thread.currentThread().name}")
Thread.sleep(2000)
}
// 2.注册耗时操作完成后,更新注册UI main
Log.d("click4", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
// 3.登录耗时操作 异步
withContext(Dispatchers.IO) {
Log.d("click4", "3.登录耗时操作: ${Thread.currentThread().name}")
Thread.sleep(3000)
}
// 4.登录耗时操作完成后,更新登录UI
Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
pro.dismiss()
}
}

5.6协程与线程的概念

(1)线程


  • 是通过操作系统调度的
  • 依附于进程,在进程角度看,线程是轻量级的
  • 创建10000个线程,操作系统崩溃,内存溢出

(2)协程:


  • 更多是让用户来控制
  • 在线程角度看,协程是更轻量级的
  • 创建10000个线程,操作系统不会崩溃,更多是由代码控制

5.7自主学习协程

【协程电子书】


5.8Rxjava的线程切换

(1)比线程切换更加的方便


5.9协程跟随main线程的结束而结束

fun main() {
/**
* 1.非阻塞式协程:类似于守护线程
* (1)协程会跟随main线程的结束而结束
*/
GlobalScope.launch {
delay(1000)
println("中华人民共和国")
}
println("A")
/**
* main线程睡眠2秒
*/
//Thread.sleep(2000)
Thread.sleep(200)
println("B")
//main结束
}

5.10阻塞式与非阻塞式协程混合

/**
* @author XiongJie
* @version appVer
* @Package com.gdc.knowledge.kotlin.xc
* @file
* @Description:
* 1.线程切换为阻塞式协程当中
* (1)阻塞我们的执行
* @date 2021-6-6 23:27
* @since appVer
*/
fun main():Unit = runBlocking{//1.外协程
//非阻塞式执行
GlobalScope.launch {//2.内协程
delay(1000)
println("中华人民共和国")
}
//阻塞式执行的
println("A")
//阻塞式执行的
delay(2000)
//阻塞式执行的
println("B")
//main结束
}

5.11结束协程

/**
* @author XiongJie
* @version appVer
* @Package com.gdc.knowledge.kotlin.xc
* @file
* @Description:
* 1.结束协程
* 2.suspend线程挂起函数标记
* @date 2021-6-6 23:34
* @since appVer
*/
suspend fun main() {
val job = GlobalScope.launch {
repeat(100){
delay(20)
println("中华人民共和国$it")
}
}
println("A")
/**
* 只等待100毫秒,时间到结束协程
*/
Thread.sleep(100)
//面试题:使用job.cancel()可以结束,为什么还要使用cancelAndJoin()函数,主要是有时间差的区别
//job.cancel()//有一点点的时间差
job.cancelAndJoin()//一点点时间差,都不允许
}

6.打赏鼓励

感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!


6.1微信打赏

在这里插入图片描述


6.2支付宝打赏

在这里插入图片描述



推荐阅读
author-avatar
永久的花蕾
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有