【12】Kotlin函数泛型协程

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

【12】Kotlin函数泛型与协程

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 <R> 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> T.myApply(){

}

2.8链式调用

/**
 * (1)返回类型泛型
 * (2)给泛型增加扩展函数
 * (3)意味着类中的属性、函数都可以使用扩展函数
 * (4)无参的高阶函数
 */
fun <T> 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> 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,R> 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> T.myApply(myMethod:T.() ->Unit):T{
    //T:就是this
    myMethod()
    return this
}
	/**
     * 优化之前的代码
     * 1.创建客户端API接口
     * (1)WanAndroidAPI实例化
     * (2)XXXAPI实例化
     * (3)动态的实例化,可以使用到泛型
     * (4)fun <T> instanceRetrofit(apiInterface: Class<T>): T表示此为泛型方法
     * (5)apiInterface: Class<T>:表示此为泛型参数
     * (6): T表示返回类型为泛型
     */
    /*fun <T> instanceRetrofit(apiInterface: Class<T>) : 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 <T> instanceRetrofit(apiInterface: Class<T>) : 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<ParentClass> list = new ArrayList<ChildClass>();

        //(2)解决问题 ? extends ParentClass :权限获取模式,只能获取,不能修改
        List<? extends ParentClass> list = new ArrayList<ChildClass>();

        //(3)不能添加,不能对集合做修改操作
        //list.add(parentClass);
        //list.add(null);是特殊情况

        //(4)能获取
       ParentClass p = list.get(0);


        /**
         * (5)只能修改,不能获取的情况
         * ? super ChildClass,只能修改,不能获取
         */
        List<? super ChildClass> childList = new ArrayList<ParentClass>();

        //(6)能添加但是不能获取
        childList.add(childClass);

        //(7)不能获取
        //ChildClass c = childList.get(0);
    }

4.2泛型的上限与下限

public class TestOutIn<T extends String> {

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

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

        }
        
        //(2)不能修改
        //list.add(parentClass);
    }

    private void test2(){
        List<ChildClass> childList = new ArrayList<ChildClass>();
        //(1)show方法要求是传父类,而此处传子类,就可以修改泛型的参数
        show(childList);
    }

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

	/**
     * (1)不可以获取
     * (2)可以修改
     * @param list
     */
    private void show1(List<? super ChildClass> list){
        //ChildClass c = list.get(0);
        /*for(ChildClass c : list){

        }*/

        list.add(childClass);
    }

    private void test3(){
        List<ParentClass> parentList = new ArrayList<ParentClass>();
        //(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<? extends ParentClass> list = new ArrayList<ChildClass>();
     */
    val list : MutableList<out ParentClass> = ArrayList<ChildClass>()

    /**
     * 2.in 不能读取,只能修改
     * (1)同Java
     *  List<? super ChildClass> childList = new ArrayList<ParentClass>();
     */
    val list1 : MutableList<in ChildClass> = ArrayList<ParentClass>()
}

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

/**
 * @author XiongJie
 * @version appVer
 * @Package com.gdc.kotlin.generic.ktobj
 * @file
 * @Description:
 * 1.泛型的读取模式
 *
 * (1)Student <in T>:限定该类只能修改不能读取
 *
 * (2)为了解决多个函数都需要添加泛型读取模式限定,可以直接在类上做限定,一劳永逸
 *
 * 而Java是做不到的
 *
 * @date 2021-6-6 21:31
 * @since appVer
 */ 
class Student <in T> {

    fun a1(list:T){

    }

   /* fun a2(list:MutableList<in T>){

    }

    fun a3(list:MutableList<in T>){

    }

    fun a4(list:MutableList<in T>){

    }

    fun a5(list:MutableList<in T>){

    }

    fun a6(list:MutableList<in T>){

    }*/

    /**
     * 如此限定的好处
     */
    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<out T> {

    /**
     * 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支付宝打赏

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值