主頁 > 移動端開發 > 帶著問題學,協程到底是什么?

帶著問題學,協程到底是什么?

2021-06-16 18:02:49 移動端開發

前言

隨著kotlinAndroid開發領域越來越火,協程在各個專案中的應用也逐漸變得廣泛

但是協程到底是什么呢?

協程其實是個古老的概念,已經非常成熟了,但大家對它的概念一直存在各種疑問,眾說紛紛
有人說協程是輕量級的執行緒,也有人說kotlin協程其實本質是一套執行緒切換方案

顯然這對初學者不太友好,當不清楚一個東西是什么的時候,就很難進入為什么怎么辦的階段了
本文主要就是回答這個問題,主要包括以下內容
1.關于協程的一些前置知識
2.協程到底是什么?
3.kotlin協程的一些基本概念,掛起函式,CPS轉換,狀態機等
以上問題總結為思維導圖如下:

1. 關于協程的一些前置知識

為了了解協程,我們可以從以下幾個切入點出發
1.什么是行程?為什么要有行程?
2.什么是執行緒?為什么要有執行緒?行程和執行緒有什么區別?
3.什么是協作式,什么是搶占式?
4.為什么要引入協程?是為了解決什么問題?

1.1 什么是行程?

我們在背行程的定義的時候,可能會經常看到一句話

行程是資源分配的最小單位

這個資源分配怎么理解呢?

在單核CPU中,同一時刻只有一個程式在記憶體中被CPU呼叫運行

假設有AB兩個程式,A正在運行,此時需要讀取大量輸入資料(IO操作),那么CPU只能干等,直到A資料讀取完畢,再繼續往下執行,A執行完,再去執行程式B,白白浪費CPU資源,

這種方式會浪費CPU資源,我們可能更想要下面這種方式

當程式A讀取資料的時,切換 到程式B去執行,當A讀取完資料,讓程式B暫停,切換 回程式A執行?

在計算機里 切換 這個名詞被細分為兩種狀態:

掛起:保存程式的當前狀態,暫停當前程式; 激活:恢復程式狀態,繼續執行程式;

這種切換,涉及到了 程式狀態的保存和恢復,而且程式AB所需的系統資源(記憶體、硬碟等)是不一樣的,那還需要一個東西來記錄程式AB各自需要什么資源,還有系統控制程式AB切換,要一個標志來識別等等,所以就有了一個叫 行程的抽象,

1.1.1 行程的定義

行程是一個具有一定獨立功能的程式在一個資料集上的一次動態執行的程序,是作業系統進行資源分配和調度的一個獨立單位,是應用程式運行的載體主要由以下三部分組成:

1.程式:描述行程要完成的功能及如何完成;
2.資料集:程式在執行程序中所需的資源;
3.行程控制塊:記錄行程的外部特征,描述執行變化程序,系統利用它來控制、管理行程,系統感知行程存在的唯一標志,

1.1.2 為什么要有行程

其實上文我們已經分析過了,作業系統之所以要支持多行程,是為了提高CPU的利用率
而為了切換行程,需要行程支持掛起恢復,不同行程間需要的資源不同,所以這也是為什么行程間資源需要隔離,這也是行程是資源分配的最小單位的原因

1.2 什么是執行緒?

1.2.1 執行緒的定義

輕量級的行程,基本的CPU執行單元,亦是 程式執行程序中的最小單元,由 執行緒ID程式計數器暫存器組合堆疊 共同組成,
執行緒的引入減小了程式并發執行時的開銷,提高了作業系統的并發性能,

1.2.2 為什么要有執行緒?

這個問題也很好理解,行程的出現使得多個程式得以 并發 執行,提高了系統效率及資源利用率,但存在下述問題:

  1. 單個行程只能干一件事,行程中的代碼依舊是串行執行,
  2. 執行程序如果堵塞,整個行程就會掛起,即使行程中某些作業不依賴于正在等待的資源,也不會執行,
  3. 多個行程間的記憶體無法共享,行程間通訊比較麻煩,

執行緒的出現是為了降低背景關系切換消耗,提高系統的并發性,并突破一個行程只能干一件事的缺陷,使得行程內并發成為可能,

1.2.3 行程與執行緒的區別

  • 1.一個程式至少有一個行程,一個行程至少有一個執行緒,可以把行程理解做 執行緒的容器;
  • 2.行程在執行程序中擁有 獨立的記憶體單元,該行程里的多個執行緒 共享記憶體;
  • 3.行程可以拓展到 多機,執行緒最多適合 多核;
  • 4.每個獨立執行緒有一個程式運行的入口、順序執行列和程式出口,但不能獨立運行,需依存于應用程式中,由應用程式提供多個執行緒執行控制;
  • 5.「行程」是「資源分配」的最小單位,「執行緒」是 「CPU調度」的最小單位
  • 6.行程和執行緒都是一個時間段的描述,是 CPU作業時間段的描述,只是顆粒大小不同,

1.3 協作式 & 搶占式

單核CPU,同一時刻只有一個行程在執行,這么多行程,CPU的時間片該如何分配呢?

1.3.1 協作式多任務

早期的作業系統采用的就是協作時多任務,即:由行程主動讓出執行權,如當前行程需等待IO操作,主動讓出CPU,由系統調度下一個行程,
每個行程都循規蹈矩,該讓出CPU就讓出CPU,是挺和諧的,但也存在一個隱患:單個行程可以完全霸占CPU

計算機中的行程良莠不齊,先不說那種居心叵測的行程了,如果是健壯性比較差的行程,運行中途發生了死回圈、死鎖等,會導致整個系統陷入癱瘓!
在這種魚龍混雜的大環境下,把執行權托付給行程自身,肯定是不科學的,于是由作業系統控制的搶占式多任務橫空出世

1.3.2 搶占式多任務

由作業系統決定執行權,作業系統具有從任何一個行程取走控制權和使另一個行程獲得控制權的能力,
系統公平合理地為每個行程分配時間片,行程用完就休眠,甚至時間片沒用完,但有更緊急的事件要優先執行,也會強制讓行程休眠,
這就是所謂的時間片輪轉調度

時間片輪轉調度是一種最古老,最簡單,最公平且使用最廣的演算法,每個行程被分配一個時間段,稱作它的時間片,即該行程允許運行的時間,
如果在時間片結束時行程還在運行,則CPU將被剝奪并分配給另一個行程,如果行程在時間片結束前阻塞或結束,則CPU當即進行切換,調度程式所要做的就是維護一張就緒行程串列,當行程用完它的時間片后,它被移到佇列的末尾,

有了行程設計的經驗,執行緒也做成了搶占式多任務,但也帶來了新的——執行緒安全問題,這個一般通過加鎖的方式來解決,這里就不綴述了,

1.4 為什么要引入協程?

上面介紹行程與執行緒的時候也提到了,之所以引入行程與執行緒是為了異步并發的執行任務,提高系統效率及資源利用率
但作為Java開發者,我們很清楚執行緒并發是多么的危險,寫出來的異步代碼是多么的難以維護,

Java中,我們一般通過回呼來處理異步任務,但是當異步任務嵌套時,往往程式就會變得很復雜與難維護

舉個例子,當我們需要完成這樣一個需求:查詢用戶資訊 --> 查找該用戶的好友串列 --> 查找該好友的動態
看一下Java回呼的代碼

getUserInfo(new CallBack() {
    @Override
    public void onSuccess(String user) {
        if (user != null) {
            System.out.println(user);
            getFriendList(user, new CallBack() {
                @Override
                public void onSuccess(String friendList) {
                    if (friendList != null) {
                        System.out.println(friendList);
                        getFeedList(friendList, new CallBack() {
                            @Override
                            public void onSuccess(String feed) {
                                if (feed != null) {
                                    System.out.println(feed);
                                }
                            }
                        });
                    }
                }
            });
        }
    }
});

這就是傳說中的回呼地獄,如果用kotlin協程實作同樣的需求呢?

val user = getUserInfo()
val friendList = getFriendList(user)
val feedList = getFeedList(friendList)

相比之下,可以說是非常簡潔了

Kotlin 協程的核心競爭力在于:它能簡化異步并發任務,以同步方式寫異步代碼
這也是為什么要引入協程的原因了:簡化異步并發任務

2.到底什么是協程

2.1 什么是協程?

一種非搶占式(協作式)的任務調度模式,程式可以主動掛起或者恢復執行,

2.2 協程與執行緒的區別是什么?

協程基于執行緒,但相對于執行緒輕量很多,可理解為在用戶層模擬執行緒操作;每創建一個協程,都有一個內核態行程動態系結,用戶態下實作調度、切換,真正執行任務的還是內核執行緒,

執行緒的背景關系切換都需要內核參與,而協程的背景關系切換,完全由用戶去控制,避免了大量的中斷參與,減少了執行緒背景關系切換與調度消耗的資源,

執行緒是作業系統層面的概念,協程是語言層面的概念

執行緒與協程最大的區別在于:執行緒是被動掛起恢復,協程是主動掛起恢復

2.3 協程可以怎樣分類?

根據 是否開辟相應的函式呼叫堆疊 又分成兩類:

  • 有堆疊協程:有自己的呼叫堆疊,可在任意函式呼叫層級掛起,并轉移調度權;
  • 無堆疊協程:沒有自己的呼叫堆疊,掛起點的狀態通過狀態機或閉包等語法來實作;

2.4 Kotlin中的協程是什么?

"假"協程,Kotlin在語言級別并沒有實作一種同步機制(鎖),還是依靠Kotlin-JVM的提供的Java關鍵字(如synchronized),即鎖的實作還是交給執行緒處理
因而Kotlin協程本質上只是一套基于原生Java執行緒池 的封裝,

Kotlin 協程的核心競爭力在于:它能簡化異步并發任務,以同步方式寫異步代碼,
下面介紹一些kotin協程中的基本概念

3. 什么是掛起函式?

我們知道使用suspend關鍵字修飾的函式叫做掛起函式,掛起函式只能在協程體內或者其他掛起函式內使用.

協程內部掛起函式的呼叫處被稱為掛起點,掛起點如果出現異步呼叫,那么當前協程就被掛起,直到對應的Continuationresume函式被呼叫才會恢復執行

我們下面來看看掛起函式具體執行的細節


可以看出kotlin協程可以做到一行代碼切換執行緒
這些是怎么做到的呢,主要是通過suspend關鍵字

3.1 什么是suspend

suspend 的本質,就是 CallBack

suspend fun getUserInfo(): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "BoyCoder"
}

不過當我們寫掛起函式的時候,并沒有寫callback,所謂的callback從何而來呢?
我們看下反編譯的結果

//                              Continuation 等價于 CallBack
//                                         ↓         
public static final Object getUserInfo(Continuation $completion) {
  ...
  return "BoyCoder";
}

public interface Continuation<in T> {
    public val context: CoroutineContext
//      相當于 onSuccess     結果   
//                 ↓         ↓
    public fun resumeWith(result: Result<T>)
}
復制代碼

可以看出

1.編譯器會給掛起函式添加一個Continuation引數,這被稱為CPS 轉換(Continuation-Passing-Style Transformation)
2.suspend函式不能在協程體外呼叫的原因也可以知道了,就是因為這個Continuation實體的傳遞

4. 什么是CPS轉換

下面用影片演示掛起函式在 CPS 轉換程序中,函式簽名的變化:

可以看出主要有兩點變化
1.增加了Continuation型別的引數
2.回傳型別從String轉變成了Any

引數的變化我們之前講過,為什么回傳值要變呢?

4.1 掛起函式回傳值

掛起函式經過 CPS 轉換后,它的回傳值有一個重要作用:標志該掛起函式有沒有被掛起,
聽起來有點奇怪,掛起函式還會不掛起嗎?

只要被suspend修飾的函式都是掛起函式,但是不是所有掛起函式都會被掛起
只有當掛起函式里包含異步操作時,它才會被真正掛起

由于 suspend 修飾的函式,既可能回傳 CoroutineSingletons.COROUTINE_SUSPENDED,表示掛起
也可能回傳同步運行的結果,甚至可能回傳 null為了適配所有的可能性,CPS 轉換后的函式回傳值型別就只能是 Any?了,

4.2 小結

1.suspend修飾的函式就是掛起函式
2.掛起函式,在執行的時候并不一定都會掛起
3.掛起函式只能在其他掛起函式中被呼叫
4.掛起函式里包含異步操作的時候,它才會真正被掛起

5. Continuation是什么?

Continuation詞源是continue,也就是繼續,接下來要做的事的意思
放到程式中Continuation則代表了,接下來要執行的代碼
以上面的代碼為例,當程式運行 getUserInfo() 的時候,它的 Continuation則是下圖紅框的代碼:

Continuation 就是接下來要運行的代碼,剩余未執行的代碼
理解了 Continuation,以后,CPS就容易理解了,它其實就是:將程式接下來要執行的代碼進行傳遞的一種模式

CPS 轉換,就是將原本的同步掛起函式轉換成CallBack 異步代碼的程序,
這個轉換是編譯器在背后做的,我們程式員對此無感知,

當然有人會問,這么簡單粗暴?三個掛起函式最終變成三個 Callback 嗎?
當然不是,思想仍然是CPS的思想,不過需要結合狀態機
CPS狀態機就是協程實作的核心

6. 狀態機

kotlin協程的實作依賴于狀態機
想要查看其實作,可以將kotin原始碼反編譯成位元組碼來查看編譯后的代碼
關于位元組碼的分析之前已經有很多人做過了,而且做的很好,下面給出狀態機的演示,

  1. 協程實作的核心就是CPS變換與狀態機
  2. 協程執行到掛起函式,一個函式如果被掛起了,它的回傳值會是:CoroutineSingletons.COROUTINE_SUSPENDED
  3. 掛起函式執行完成后,通過Continuation.resume方法回呼,這里的Continuation是通過CPS傳入的
  4. 傳入的Continuation實際上是ContinuationImpl,resume方法最后會再次回到invokeSuspend方法中
  5. invokeSuspend方法即是我們寫的代碼執行的地方,在協程運行程序中會執行多次
  6. invokeSuspend中通過狀態機實作狀態的流轉
  7. continuation.label 是狀態流轉的關鍵,label改變一次代表協程發生了一次掛起恢復
  8. 通過break label實作goTo的跳轉效果
  9. 我們寫在協程里的代碼,被拆分到狀態機里各個狀態中,分開執行
  10. 每次協程切換后,都會檢查是否發生例外
  11. 切換協程之前,狀態機會把之前的結果以成員變數的方式保存在 continuation 中,

以上是狀態機流轉的大概流程,讀者可跟著參考鏈接,過一下編譯后的位元組碼執行流程后,再來判斷這個流程是否正確

7. CoroutineContext是什么?

我們上面說了Continuation是繼續要執行的代碼,在實作上它也是一個介面

public interface Continuation<in T> {
    public val context: CoroutineContext
    public fun resumeWith(result: Result<T>)
}

1.Continuation主要由兩部分組成,一個context,一個resumeWith方法
2.通過resumeWith方法執行接下去的代碼
3.通過context獲取背景關銑澩,保存掛起時的一些狀態與資源

CoroutineContext即背景關系,主要承載了資源獲取,配置管理等作業,是執行環境相關的通用資料資源的統一提供者

CoroutineContext是一個特殊的集合,這個集合它既有Map的特點,也有Set的特點

集合的每一個元素都是Element,每個Element都有一個Key與之對應,對于相同KeyElement是不可以重復存在的Element之間可以通過+號組合起來,Element有幾個子類,CoroutineContext也主要由這幾個子類組成:

  • Job:協程的唯一標識,用來控制協程的生命周期(newactivecompletingcompletedcancellingcancelled);
  • CoroutineDispatcher:指定協程運行的執行緒(IODefaultMainUnconfined);
  • CoroutineName: 指定協程的名稱,默認為coroutine;
  • CoroutineExceptionHandler: 指定協程的例外處理器,用來處理未捕獲的例外.

7.1 CoroutineContext的資料結構

先來看看CoroutineContext的全家福

public interface CoroutineContext {

    //運算子[]多載,可以通過CoroutineContext[Key]這種形式來獲取與Key關聯的Element
    public operator fun <E : Element> get(key: Key<E>): E?

    //它是一個聚集函式,提供了從left到right遍歷CoroutineContext中每一個Element的能力,并對每一個Element做operation操作
    public fun <R> fold(initial: R, operation: (R, Element) -> R): R

    //運算子+多載,可以CoroutineContext + CoroutineContext這種形式把兩個CoroutineContext合并成一個
    public operator fun plus(context: CoroutineContext): CoroutineContext

    //回傳一個新的CoroutineContext,這個CoroutineContext洗掉了Key對應的Element
    public fun minusKey(key: Key<*>): CoroutineContext

    //Key定義,空實作,僅僅做一個標識
    public interface Key<E : Element>

   //Element定義,每個Element都是一個CoroutineContext
    public interface Element : CoroutineContext {

      	//每個Element都有一個Key實體
        public val key: Key<*>

      	//...
    }
}

1.CoroutineContext內主要存盤的就是Element,可以通過類似map[key] 來取值

2.Element也實作了CoroutineContext介面,這看起來很奇怪,為什么元素本身也是集合呢?主要是為了API設計方便,Element內只會存放自己

3.除了plus方法,CoroutineContext中的其他三個方法都被CombinedContextElementEmptyCoroutineContext重寫

4.CombinedContext就是CoroutineContext集合結構的實作,它里面是一個遞回定義,Element就是CombinedContext中的元素,而EmptyCoroutineContext就表示一個空的CoroutineContext,它里面是空實作

7.2 為什么CoroutineContext可以通過+號連接

CoroutineContext能通過+號連接,主要是因為重寫了plus方法
當通過+號連接時,實際上是包裝到了CombinedContext中,并指向上一個Context

如上所示,是一個單鏈表結構,在獲取時也是通過這種方式去查詢對應的key,操作大體邏輯都是先訪問當前element,不滿足,再訪問leftelement,順序都是從rightleft

最近我整理一些Android 開發相關的學習檔案、面試題,希望能幫助到大家學習提升,如有需要參考的可以點擊鏈接領取**點擊這里免費領取點擊這里免費領取

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/287765.html

標籤:其他

上一篇:想拿 20k 無壓力?Android開發必讀的一篇文章!

下一篇:Jetpack All In Compose ?看各種Jetpack庫在Compose中的使用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more