【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支付宝打赏
标签:12,协程,函数,Kotlin,fun,线程,myMethod,泛型 来源: https://blog.csdn.net/xiogjie_67/article/details/117638862