(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 <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支付寶打賞

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/286354.html
標籤:其他
上一篇:C++中cout的格式使用
