真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

flutter相機(jī)預(yù)覽,flutter 拍照

快速記單詞的方法有哪些

英語(yǔ)的學(xué)習(xí)很重要,如何輕松學(xué)好英語(yǔ)?如何快速記憶英語(yǔ)單詞呢?下面是由我給大家?guī)?lái)關(guān)于快速記單詞的方法,希望對(duì)大家有幫助!

成都創(chuàng)新互聯(lián)公司是一家朝氣蓬勃的網(wǎng)站建設(shè)公司。公司專注于為企業(yè)提供信息化建設(shè)解決方案。從事網(wǎng)站開(kāi)發(fā),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),網(wǎng)站模板,微信公眾號(hào)開(kāi)發(fā),軟件開(kāi)發(fā),微信小程序開(kāi)發(fā),十余年建站對(duì)成都OPP膠袋等多個(gè)方面,擁有豐富建站經(jīng)驗(yàn)。

快速記單詞的方法

1、單詞卡片——最直接的單詞操練教具

英語(yǔ)教學(xué)遵循先聽(tīng)說(shuō),后讀寫(xiě)的教學(xué)原則。圖片是培養(yǎng)小孩子的聽(tīng)說(shuō)能力,幫助小孩子建立單詞的音和義之間的聯(lián)系;而單詞卡片則是培養(yǎng)小孩子的單詞認(rèn)讀能力,幫助小孩子建立單詞的音、形之間的聯(lián)系。認(rèn)讀單詞是單詞教學(xué)的終極目標(biāo)。大聲說(shuō),小聲說(shuō),與學(xué)生唱反調(diào)。就是老師說(shuō)一個(gè)單詞,用的聲音量不同,一個(gè)大聲,一個(gè)小聲,學(xué)生要做出相反的,例如老師兩次朗讀cat,一次是大聲,一次是小聲,則學(xué)生跟著老師說(shuō),正確的是先小聲,后大聲,如果學(xué)生像老師一樣先大聲再小聲就錯(cuò)了。 設(shè)陷阱,讓學(xué)生跟讀卡片上的單詞,老師故意經(jīng)常讀錯(cuò),讀對(duì)的學(xué)生可以跟讀,讀錯(cuò)的就要求學(xué)生馬上做出反映,雙手叉腰,瞪著眼睛,做出生氣的樣子,但不準(zhǔn)發(fā)出任何聲音。 反映錯(cuò)誤的淘汰,也可采取小組記分! 踩地雷,選定一個(gè)單詞為地雷,老師領(lǐng)讀很多個(gè)單詞,讀到該單詞的時(shí)候,有誰(shuí)跟著讀了,就是中地雷了,其他學(xué)生就一起指著他說(shuō):one, two, three, bomb。

2、圖片——使用最頻繁的單詞操練教具

圖片可以用于每一節(jié)單詞教學(xué)課,不僅適用于單詞呈現(xiàn),也適用于單詞操練、鞏固環(huán)節(jié)。在課堂上,經(jīng)常會(huì)采用“What’s the next?”、“What’s missing?” 這兩個(gè)猜一猜的游戲。操作方便,而且面很廣?!癢hat’s the next?”:先讓小朋友快速看圖說(shuō)單詞,然后不打亂順序,從第一張單詞圖片開(kāi)始,讓小朋友猜一猜它后面的是什么。“What’s missing?”:從單詞圖片中隨意抽掉一張,讓小朋友猜一猜少了哪張。小孩子最喜歡競(jìng)爭(zhēng)性的游戲,在猜一猜的游戲中,孩子們顯得特別興奮,經(jīng)??梢月?tīng)到孩子們“Yeah”的歡呼聲。 對(duì)于稍長(zhǎng)的單詞,可以采用Hide and seek游戲:如French fries, 把這一圖片藏在某一個(gè)小朋友的位置上,讓小朋友來(lái)找,其余學(xué)生一起大喊French fries,如果據(jù)目標(biāo)越來(lái)越近,則喊得聲音越來(lái)越大,反之,則越輕。這一方法對(duì)稍長(zhǎng)的單詞很有效的。

3、動(dòng)畫(huà)——有趣的單詞操練媒體

動(dòng)畫(huà)課件集聲音、色彩、動(dòng)畫(huà)于一體,繪聲繪色,生動(dòng)逼真,有利于調(diào)動(dòng)學(xué)生的學(xué)習(xí)積極性和主動(dòng)性,激發(fā)并保持學(xué)生學(xué)習(xí)英語(yǔ)的興趣,使他們敢于說(shuō),樂(lè)于說(shuō),從而促進(jìn)學(xué)生語(yǔ)言表達(dá)能力的提高和發(fā)展。如教學(xué)顏色時(shí),我利用色彩大轉(zhuǎn)盤(pán),讓學(xué)生用I like…說(shuō)一說(shuō)自己喜歡的顏色,再轉(zhuǎn)動(dòng)轉(zhuǎn)盤(pán),比一比誰(shuí)是幸運(yùn)兒;又如在操練食物單詞時(shí),我利用Flash可以逐步呈現(xiàn)和快速呈現(xiàn)的特點(diǎn),讓學(xué)生在有限的時(shí)間里猜出單詞。

英語(yǔ)的學(xué)習(xí)方法

1、課前預(yù)習(xí)

預(yù)習(xí)可以使我們有心理準(zhǔn)備,可以幫助我們提高課堂效率。提前預(yù)習(xí)第二天內(nèi)容,可以充分了解自己的難點(diǎn)在何處,聽(tīng)課時(shí)就能夠有的放矢。

2 、課堂聽(tīng)講

一般在課堂節(jié)奏是一節(jié)課的45分鐘,前5分鐘復(fù)習(xí),中間25---30分鐘講解練習(xí),后10分鐘綜合訓(xùn)練及小結(jié)。在課堂上我們應(yīng)該做到以下幾點(diǎn):

(1)認(rèn)真聽(tīng),多動(dòng)筆。

上課全神貫注,認(rèn)真聽(tīng)講,做好筆記,無(wú)論聽(tīng)、說(shuō)、讀、寫(xiě)都要使自己始終活躍。我們應(yīng)該記錄什么呢?首先是老師講解時(shí)的重點(diǎn)句子,其次要記下老師板書(shū)的重要內(nèi)容,最后要記下這節(jié)課自己不懂的地方或者自己的一些所感所得。我們可以將這些記錄在課本上。

(2)積極參與。

英語(yǔ)是實(shí)踐性強(qiáng)的學(xué)科,要大膽地練習(xí),敢說(shuō)、敢讀,積極回答老師提出的問(wèn)題。

(3)松弛有度。

我們的精力有限,不可能整節(jié)課都全神貫注。在我們掌握很好的環(huán)節(jié),在老師調(diào)節(jié)課堂氣氛說(shuō)點(diǎn)笑話時(shí),在進(jìn)行小組活動(dòng)的時(shí)候,都是我們稍微放松的好時(shí)機(jī)。

3 、課后學(xué)習(xí)

(1)自習(xí)課的時(shí)候,老師要給大家做每日一練,也就是出幾個(gè)題目,練習(xí)當(dāng)天所學(xué)內(nèi)容。同學(xué)們要獨(dú)立完成,有不會(huì)的題目及時(shí)解決。

(2)回家后,先復(fù)習(xí)當(dāng)天所學(xué)知識(shí),再寫(xiě)家庭作業(yè),最后預(yù)習(xí)明天要學(xué)習(xí)的內(nèi)容。

(3)有時(shí)間就聽(tīng)課文錄音。吃飯時(shí),睡覺(jué)前,都是播放錄音的時(shí)間。即使隨便聽(tīng)也無(wú)所謂,我們需要的是創(chuàng)造盡可能多的英語(yǔ)氛圍。

(4)學(xué)習(xí)其他英語(yǔ)教材,作為課本的補(bǔ)充和完善。我們可以學(xué)到地道的英語(yǔ),讀到妙趣橫生的小故事,可以拓展我們的視野。

最容易記憶的三類英語(yǔ)單詞

一、象聲詞

象聲詞又稱擬聲詞,是模擬各種聲音的詞。它包括三類,即模擬物體發(fā)出的聲音、模擬人發(fā)出的聲音和模擬動(dòng)物發(fā)出的聲音。有的象聲詞與它所模擬的聲音非常相似,這樣的詞很容易記憶;有的象聲詞與它所模擬的聲音不完全相似(部分相似),但我們只要加以聯(lián)想,也容易記憶。而如果我們不知道一個(gè)象聲詞的來(lái)源(不知道它所模擬的聲音),這個(gè)詞就很難理解和記憶。例如:scud(飛毛腿、速跑)一詞就不易理解和記憶,但如果知道它是模擬“喀得喀得”的速跑聲,就很容易記住。

1.模擬物體發(fā)出的聲音,如:

bang一砰然作響,猛撞[擬“梆梆”撞擊聲]

bubble一冒泡,沸騰[擬水冒泡聲]

creak一咯吱咯吱作響[擬物體摩擦聲]

flutter一振翼,顫動(dòng)[擬反復(fù)拍動(dòng)聲]

gong一鑼[擬“哐哐”的鑼聲]

hack一砍,劈[擬“啪啪”的砍、劈聲]

iiggle一輕輕跳動(dòng)[擬跳動(dòng)聲]

kodak一小型照相機(jī)拍攝[擬攝影時(shí)照相機(jī)發(fā)出的“咔嗒”聲]

plonk一物體落下碰到另一物體表面時(shí)的撲通聲[擬“撲通”聲]

rustle一發(fā)沙沙聲[擬樹(shù)葉、紙張等摩擦?xí)r發(fā)時(shí)的“沙沙”聲]

sizzle一咝咝聲[擬油炸食物或水滴接觸熱鐵時(shí)的“咝咝”聲]

toot一(擬喇叭、號(hào)角、笛等的)嘟嘟聲,吹喇叭

whir(r)一呼呼聲[擬物體移動(dòng)、轉(zhuǎn)動(dòng)或飛行時(shí)的“呼呼”聲]

2.模擬人發(fā)出的聲音。如:

babble一牙牙學(xué)語(yǔ)聲[擬嬰孩學(xué)話“吧吧”聲]

cackle一咯咯地笑[擬“咯咯”笑聲]

groan一呻吟,哼聲[擬痛苦的呻吟聲]

hiccup一打嗝兒,打呃[擬打呃聲]

iabber一急促而不清楚地說(shuō)話[擬急促的說(shuō)話聲]

puff一吹氣[擬吹氣聲]

riot一騷動(dòng),暴亂[擬狂鬧聲、嗷嗷叫聲]

sip一呷飲,啜飲[擬吸吮聲]

titter一竊笑,傻笑[擬“嘁嘁咯咯”的竊笑聲]

whoop一哮喘聲,高呼聲[擬“呼呼”聲]

yawp一大聲叫嚷,嚎叫,喧鬧[擬吆喝聲、叫嚷聲]

3.模擬動(dòng)物發(fā)出的聲音。如:

caw一呱呱地叫[擬烏鴉叫聲]

coo一咕咕地叫[擬鴿子“咕咕”叫聲]

growl一嗥叫,怒吠[擬狗的低吠聲]

hoot一貓頭鷹叫聲[擬貓頭鷹“呼呼”叫聲]

mew一咪,喵[擬“喵喵”貓叫聲]

neigh一馬嘶[擬馬嘶聲]

quack—嘎嘎地叫,呱呱地叫[擬鴨子叫聲]

roar一(獅、虎等)吼叫,咆哮[擬野獸吼聲]

yowl一嚎叫,長(zhǎng)吼[擬狗、野貓等嚎叫聲]

二、與中文讀音相似、近似的單詞

這類單詞共有三種:

1.由英文譯成中文的,如:sofa(沙發(fā))、hysteria(歇斯底里)、humor(幽默)、ampere(安培)、brandy(白蘭地)、cartoon(卡通)、shampoo(香波)、trust(托拉斯)、poker(撲克牌)、salad(色拉)、tango(探戈)、pudding(布丁)、shock(休克)、heroin(海洛因)

2.由中文譯成英文的,如:typhoon(臺(tái)風(fēng))、kowtow(叩頭)、oolong(烏龍茶)、litchi(荔枝)、ginseng(人參)、longan(龍眼)等。

3.既非英譯中,亦非中譯英,而是中文、英文讀音巧合,如:tow(拖)、loot(擄)、bandage(繃帶)、fee(費(fèi))、tun(桶)等。

三、與另一單詞有聯(lián)系的單詞

對(duì)一個(gè)普通的英語(yǔ)學(xué)習(xí)者來(lái)說(shuō),graze(牛羊吃草)一詞也許是個(gè)陌生的單詞,但若告訴他這個(gè)單詞來(lái)自熟詞grass(草),他會(huì)馬上感到這個(gè)單詞不太陌生了,似乎是個(gè)“半熟臉”,也就很容易記住了。類似這種情況的陌生單詞在英語(yǔ)里為數(shù)不少。每一個(gè)這樣的生詞都有一個(gè)與它有內(nèi)在聯(lián)系的熟詞。它們的形、音、義都很相近,只要我們對(duì)照比較,便可馬上“變生為熟”,不易忘記。

如:dusk[聯(lián)系單詞:dust(灰塵、塵土),原義是“塵土色的”,引申為“昏暗的、微暗的”→黃昏];interval[inter-(在……之間),val=wall(v—W)墻;“在兩墻之間的空隙”引申為“在兩種事物之問(wèn)的空隙”→(空間或時(shí)間的)間隔、間隙];simpleton[對(duì)照simple簡(jiǎn)單的,引申為“頭腦簡(jiǎn)單的人”→傻子、愚蠢者];resemble[re.加強(qiáng)意義,sem來(lái)自same同樣的、相同的,引申為“差不多”→像、類似、相似]

猜你喜歡:

1. 背單詞的十大記憶法口訣

2. 最強(qiáng)的單詞記憶法--五步背單詞

3. 世界記憶大師教你記英語(yǔ)單詞

4. 記憶英語(yǔ)單詞的15種方法推薦

5. 巧記英語(yǔ)單詞的8種方法推薦

6. 最快記單詞的方法

flutter掃碼插件,支持自定義

nan_scan 是一款支持iOS和android 的掃碼器插件,支持用戶自定義頁(yè)面

1、配置:

android配置:在AndroidManifest.xml 下添加相機(jī)權(quán)限?uses-permission android:name="android.permission.CAMERA" /

iOS:在打開(kāi)xcode,在info.plist 下添加 Privacy - Camera Usage Description ,打開(kāi)相機(jī)權(quán)限

2、使用:

引入插件:在pubspec.yaml 中,

dependencies:

???nan_scan: 版本號(hào)

使用案例方法:

或者:

demo效果圖:

為什么除了Flutter之外,我們還需要另一個(gè)跨平臺(tái)開(kāi)發(fā)框架?

不久前,谷歌正式推出 Jetpack Compose 1.0 版本。近日,JetBrains 在此基礎(chǔ)上發(fā)布了 Compose Multiplatform Alpha 版本,旨在將 Compose 擴(kuò)展到桌面和 Web 端。

Compose Multiplatform 由 Compose for Desktop 和 Compose for Web 組成,通過(guò) Kotlin Multiplatform 支持許多不同的平臺(tái)。其中,Compose Desktop 采用 Google 的 Skia 圖形庫(kù),來(lái)實(shí)現(xiàn)在 Windows、macOS 和 Linux 上的 UI 繪制,借此在所有支持的操作系統(tǒng)中提供統(tǒng)一的體驗(yàn),類似于 Flutter 的做法。

根據(jù) Kotlin 團(tuán)隊(duì)的說(shuō)法,相比起 Electron 框架,Compose Multiplatform 在內(nèi)存消耗、安裝大小和 UI 渲染性能等方面將有更明顯的優(yōu)勢(shì)。隨著 Alpha 版本的發(fā)布,Compose Multiplatform 還收獲了新的 Android Studio 插件,包括對(duì)在 IDE 中顯示組件預(yù)覽的支持以及許多附加功能。

我們希望通過(guò)本文幫助大家進(jìn)一步了解 Compose 的跨平臺(tái)能力,以及 JetBrains 將 Compose 從 Android 擴(kuò)展到這些其他平臺(tái)背后的主要驅(qū)動(dòng)力是什么。

基于 Jetpack Compose 1.0

由谷歌打造的 Jetpack Compose 是一款用于在 Android 應(yīng)用程序之內(nèi)構(gòu)建用戶界面的官方框架,上周剛剛發(fā)布 1.0 版本。與此同時(shí),Android Studio 代號(hào)“極狐”的首個(gè)穩(wěn)定版 2020.3.1 也正式亮相。

盡管才剛迎來(lái) 1.0,但谷歌表示“目前 Play Store 中已經(jīng)有超過(guò) 2000 款應(yīng)用程序在使用 Compose——更重要的是,就連 Play Store 這款應(yīng)用本身也在使用 Compose?!惫雀璺矫孢€表示,“我們一直在與一些頂級(jí)應(yīng)用的開(kāi)發(fā)人員進(jìn)行合作,他們的反饋和支持幫助我們使 1.0 版本更加強(qiáng)大?!?/p>

Jetpack Compose for Android 迎來(lái) 1.0 版本

Compose 基于 Kotlin 開(kāi)發(fā),而 Kotlin 與 Android Studio(即官方指定的 Android IDE)均來(lái)自開(kāi)發(fā)工具廠商 JetBrains。雖然 Jetpack Compose 專為 Android 打造(與谷歌的 Flutter 框架不同), 但 JetBrains 公司堅(jiān)信 Compose 完全能夠獲得跨平臺(tái)能力 。

Compose for Desktop: 這只是開(kāi)始

Compose Multiplatform 可以說(shuō)是該框架面向 MacOS、Linux、Windows 以及 Web 開(kāi)設(shè)的一個(gè)端口,目前剛剛發(fā)布 1.0 Alpha 版本。雖然尚處于早期開(kāi)發(fā)階段,但 JetBrains 表示,其已經(jīng)“為開(kāi)發(fā)人員帶來(lái)能夠基本安全使用的穩(wěn)定 API”。

TheRegister 就此事詢問(wèn)了 JetBrains 公司 Compose 項(xiàng)目負(fù)責(zé)人 Nikolay Igotti,希望了解為什么該公司在擁有了已經(jīng)廣泛應(yīng)用于 IntelliJ IDEA IDE 及多種豐富變體的桌面應(yīng)用程序跨平臺(tái) Java 框架之外,還要費(fèi)力開(kāi)發(fā) Compose for Desktop。Igotti 的回答是,“舊有 Java 框架基本上就是修改版的 Swing。Swing 屬于默認(rèn) JDK UI 框架,Swing 和 AWT(Abstract Windows Toolkit,抽象窗口工具包)。Compose 則完全是另一碼事,當(dāng)然我們也在設(shè)計(jì)中考慮到了互操作性需求……Swing 這套框架太陳舊了,最早出現(xiàn)在上世紀(jì)九十年代末。多年來(lái)人們對(duì)于 UI 的設(shè)計(jì)思路已經(jīng)天翻地覆,Swing 顯然滿足不了要求了。”

JetBrains IDE 中的 Compose for Desktop 項(xiàng)目

Compose 與 Swing 有一個(gè)比較大的共同點(diǎn):與其他使用本機(jī)控件的跨平臺(tái)框架,比如例如 Java 的 SWT(Standard Widget Toolkit)以及微軟的 Xamarin 有所不同,它們選擇自主繪制控件。Compose 使用的 Skia 開(kāi)源圖形庫(kù),也在谷歌 Chrome、Flutter 及其他眾多框架當(dāng)中得到廣泛應(yīng)用。那這是否意味著 Compose 應(yīng)用程序?qū)](méi)有自己的原生外觀?對(duì)此,Igotti 的回應(yīng)是,“這取決于開(kāi)發(fā)人員的選擇,取決于他們?nèi)绾螢閼?yīng)用程序設(shè)置主題。在這方面,Compose 的情況與 Flutter 等其他框架沒(méi)什么區(qū)別?!?/p>

那 Compose for Desktop 應(yīng)用程序是否依賴于 JVM(Java Virtual Machine)運(yùn)行?Igotti 表示,“我們也知道,JVM 應(yīng)用程序的發(fā)布情況可能比較棘手。因此我們提供自己的 Gradle 插件,其使用 jpackage 與 Jlink 以 JVM 應(yīng)用程序?yàn)榛A(chǔ)制作原生應(yīng)用程序。Mac 的.dmg、Windows 的 MSI、Linux 的 deb 包等均可實(shí)現(xiàn),大家用不著擔(dān)心 JVM。”

也就是說(shuō),開(kāi)發(fā)成果將會(huì)是一款被精心包裹起來(lái)的 JVM 應(yīng)用程序。JetBrains 還有一款用于解決這個(gè)問(wèn)題的 Kotlin/Native 編譯器,“預(yù)計(jì)將在未來(lái)發(fā)布,或者專門(mén)用于桌面開(kāi)發(fā)。”

對(duì)應(yīng)用程序的另一種思考方式

那 Web 應(yīng)用程序方面呢?Igotti 回應(yīng)稱,“我們使用 Kotlin/JS 編譯器?!盋ompose 的 Web 版本不如桌面版先進(jìn),說(shuō)明文檔中也警告稱“API 尚未最終確定,預(yù)計(jì)會(huì)發(fā)生重大變化。”此外,雖然 Web 版本確實(shí)使用 Compose 模型,但 API 卻完全不同,而且會(huì)使用 HTML 與 CSS。所以,Web 版與 Compose for Desktop 之間能夠共享的代碼應(yīng)該比較少。

據(jù) Igotti 介紹,“Compose 代表著一種不同的應(yīng)用程序思考方式。狀態(tài)即 UI 的真實(shí)來(lái)源,而 UI 本身是無(wú)狀態(tài)的,其表達(dá)永遠(yuǎn)由狀態(tài)計(jì)算得出。在這方面,Compose for Web 采用一組相同的原語(yǔ),完全相同的狀態(tài)管理思路。但是對(duì)于具體的小部件集合與排列方式,Web 版與桌面版之間確實(shí)無(wú)法互通?!?/p>

說(shuō)到這里,為什么要把 Compose for Android 擴(kuò)展到多種其他平臺(tái)之上?“Compose 的目標(biāo)受眾主要分為三類。首先是使用 Kotlin 與 Compose 的 Android 開(kāi)發(fā)人員,他們希望把自己的開(kāi)發(fā)成果交付至其他平臺(tái);其二是純 Kotlin 開(kāi)發(fā)人員,他們希望以‘一次編寫(xiě)、隨處運(yùn)行’的方式開(kāi)發(fā)新的應(yīng)用程序;第三則是那些不太熟悉 Kotlin 或者 Compose,但又希望開(kāi)發(fā)出精美 UI 的用戶,我們希望能為他們提供實(shí)現(xiàn)目標(biāo)的工具?!?/p>

Igotti 并沒(méi)有給出具體的發(fā)布日期,但表示自己希望 Beta 版能在今年秋天發(fā)布,“我們也希望能在今年之內(nèi)推出 1.0 版本?!表?xiàng)目本身是完全開(kāi)源的,“二十一世紀(jì)了,框架在大多數(shù)人們心目中就不應(yīng)該收費(fèi)。我們只是想開(kāi)發(fā)一款長(zhǎng)期缺失的軟件”,補(bǔ)足 JetBrains 當(dāng)前商業(yè)模式中的工具鏈。

那么,JetBrains 會(huì)在自己的其他工具中使用 Compose 嗎?事實(shí)上,他們的 JetBrains Toolbox(用于管理已安裝的 IDE)已經(jīng)在使用 Compose,但 Igotti 表示短時(shí)間內(nèi) Compose 還無(wú)法取代 IntelliJ IDEA 等現(xiàn)有框架。“編輯器是其中最復(fù)雜也最重要的組件,經(jīng)歷了 20 年的發(fā)展演進(jìn),我們幾乎不可能在中途進(jìn)行重寫(xiě)了。無(wú)論是 JetBrains 還是我個(gè)人,都不打算強(qiáng)迫每個(gè)人都轉(zhuǎn)而使用 Compose。我們的目標(biāo)是為原有框架選項(xiàng)滿足不了的用戶提供新的解決方案?!?/p>

寫(xiě)在最后

那么,為什么除了 Flutter 之外,我們還需要另一個(gè)跨平臺(tái)框架?雖然谷歌的 Flutter 最開(kāi)始主要面向移動(dòng)設(shè)備,但現(xiàn)在也開(kāi)始向桌面及 iOS 進(jìn)軍,甚至比 Compose 還搶先了一步。不過(guò),根據(jù) StackOverflow 的最新調(diào)查, Flutter 使用的語(yǔ)言為 Dart;盡管 Dart 語(yǔ)言的人氣正在增長(zhǎng)(正是受到 Flutter 的推動(dòng)),但仍然無(wú)法與 Kotlin 相提并論。

Compose 代表著一種獨(dú)特的 UI 構(gòu)建方法,也許最期待 Compose 跨平臺(tái)功能的受眾,正是那些曾在 Android 上使用過(guò)它、又特別喜歡這種 UI 構(gòu)建體驗(yàn)的開(kāi)發(fā)者。

想要進(jìn)一步了解 Compose,國(guó)內(nèi) Android 開(kāi)發(fā)者可訪問(wèn)以下鏈接查看中文手冊(cè):

延伸閱讀:

Flutter浪潮下的音視頻研發(fā)探索

文/陳爐軍

整理/LiveVideoStack

大家好,我是阿里巴巴閑魚(yú)事業(yè)部的陳爐軍,本次分享的主題是Flutter浪潮下的音視頻研發(fā)探索,主要內(nèi)容是針對(duì)閑魚(yú)APP在當(dāng)下流行的跨平臺(tái)框架Flutter的大規(guī)模實(shí)踐,介紹其在音視頻領(lǐng)域碰到的一些困難以及解決方案。

分享內(nèi)容主要分為四個(gè)方面,首先會(huì)對(duì)Flutter有一個(gè)簡(jiǎn)單介紹以及選擇Flutter作為跨平臺(tái)框架的原因,其次會(huì)介紹Flutter中與音視頻關(guān)系非常大的外接紋理概念,以及對(duì)它做出的一些優(yōu)化。之后會(huì)對(duì)閑魚(yú)在音視頻實(shí)踐過(guò)程中碰到的一些Flutter問(wèn)題提出了一些解決方案——TPM音視頻框架。最后是閑魚(yú)Flutter多媒體開(kāi)源組件的介紹。

Flutter

Flutter是一個(gè)跨平臺(tái)框架,以往的做法是將音頻、視頻和網(wǎng)絡(luò)這些模塊都下沉到C++層或者ARM層,在其上封裝成一個(gè)音視頻的SDK,供UI層的PC、iOS和Android調(diào)用。

而Flutter做為一個(gè)UI層的跨平臺(tái)框架,顧名思義就是在UI層也實(shí)現(xiàn)了一個(gè)跨平臺(tái)開(kāi)發(fā)。可以預(yù)想的是未Flutter發(fā)展的好的話,會(huì)逐漸變?yōu)橐粋€(gè)從底層到UI層的一個(gè)全鏈路的跨平臺(tái)開(kāi)發(fā),技術(shù)人員分別負(fù)責(zé)SDK和UI層的開(kāi)發(fā)。

在Flutter之前已經(jīng)有很多跨平臺(tái)UI解決方案,那為什么選擇Flutter呢?

我們主要考慮性能和跨平臺(tái)的能力。

以往的跨平臺(tái)方案比如Weex,ReactNative,Cordova等等因?yàn)榧軜?gòu)的原因無(wú)法滿足性能要求,尤其是在音視頻這種性能要求幾乎苛刻的場(chǎng)景。

而諸如Xamarin等,雖然性能可以和原生App一致,但是大部分邏輯還是需要分平臺(tái)實(shí)現(xiàn)。

我們可以看一下,為什么Flutter可以實(shí)現(xiàn)高性能:

原生的native組件渲染以IOS為例,蘋(píng)果的UIKit通過(guò)調(diào)用平臺(tái)自己的繪制框架QuaztCore來(lái)實(shí)現(xiàn)UI的繪制,圖形繪制也是調(diào)用底層的API,比如OpenGL、Metal等。

而Flutter也是和原生API邏輯一致,也是通過(guò)調(diào)用底層的繪制框架層SKIA實(shí)現(xiàn)UI層。這樣相當(dāng)于Flutter他自己實(shí)現(xiàn)了一套UI框架,提供了一種性能超越原生API的跨平臺(tái)可能性。

但是我們說(shuō)一個(gè)框架最終性能怎樣,其實(shí)取決于設(shè)計(jì)者和開(kāi)發(fā)者。至于現(xiàn)在到底是一個(gè)什么狀況:

在閑魚(yú)的實(shí)踐中,我們發(fā)現(xiàn)在正常的開(kāi)發(fā)沒(méi)有特意的去優(yōu)化UI代碼的情況下,在一些低端機(jī)上,F(xiàn)lutter界面的流暢性是比Native界面要好的。

雖然現(xiàn)在閑魚(yú)某些場(chǎng)景下會(huì)有卡頓閃退等情況,但是這是一個(gè)新事物發(fā)展過(guò)程中的必然問(wèn)題,我們相信未來(lái)性能肯定不會(huì)成為限制Flutter發(fā)展的瓶頸的。

在閑魚(yú)實(shí)踐Flutter的過(guò)程中,混合棧和音視頻是其中比較難解決的兩個(gè)問(wèn)題,混合棧是指一個(gè)APP在Flutter過(guò)程中不可能一口氣將所有業(yè)務(wù)全部重寫(xiě)為Flutter,所以這是一個(gè)逐步迭代的過(guò)程,這期間原生native界面與Flutter界面共存的狀態(tài)就稱之為混合棧。閑魚(yú)在混合棧上也有一些比較好的輸出,例如FlutterBoost。

外接紋理

在講音視頻之前需要簡(jiǎn)要介紹一下外接紋理的概念,我們將它稱之為是Flutter和Frame之間的橋梁。

Flutter渲染一幀屏幕數(shù)據(jù)首先要做的是,GPU發(fā)出的VC信號(hào)在Flutter的UI線程,通過(guò)AOT編譯的機(jī)器碼結(jié)合當(dāng)前Dart Runtime,生成Layer Tree UI樹(shù),Layer Tree上每一個(gè)葉子節(jié)點(diǎn)都代表了當(dāng)前屏幕上所需要渲染的每一個(gè)元素,包含了這些元素渲染所需要的內(nèi)容。將Layer Tree拋給GPU線程,在GPU線程內(nèi)調(diào)用Skia去完成整個(gè)UI的渲染過(guò)程。Layer Tree中有PictureLayer和TextureLayer兩個(gè)比較重要的節(jié)點(diǎn)。PictureLayer主要負(fù)責(zé)屏幕圖片的渲染,F(xiàn)lutter內(nèi)部實(shí)現(xiàn)了一套圖片解碼邏輯,在IO線程將圖片讀取或者從網(wǎng)絡(luò)上拉取之后,通過(guò)解碼能夠在IO線程上加載出紋理,交給GPU線程將圖片渲染到屏幕上。但是由于音視頻場(chǎng)景下系統(tǒng)API太過(guò)繁多,業(yè)務(wù)場(chǎng)景過(guò)于復(fù)雜。Flutter沒(méi)有一套邏輯去實(shí)現(xiàn)跨平臺(tái)的音視頻組件,所以說(shuō)Flutter提出了一種讓第三方開(kāi)發(fā)者來(lái)實(shí)現(xiàn)音視頻組件的方式,而這些音視頻組件的視頻渲染出口,就是TextureLayer。

在整個(gè)Layer Tree渲染的過(guò)程中,TextureLayer的數(shù)據(jù)紋理需要由外部第三方開(kāi)發(fā)者來(lái)指定,可以把視頻數(shù)據(jù)和播放器數(shù)據(jù)送到TextureLayer里,由Flutter將這些數(shù)據(jù)渲染出來(lái)。

TextureLayer渲染過(guò)程:首先判斷Layer是否已經(jīng)初始化,如果沒(méi)有就創(chuàng)建一個(gè)Texture,然后將Texture Attach到一個(gè)SufaceTexture上。

這個(gè)SufaceTexture是音視頻的native代碼可以獲取到的對(duì)象,通過(guò)這個(gè)對(duì)象創(chuàng)建的Suface,我們可以將視頻數(shù)據(jù)、攝像頭數(shù)據(jù)解碼放到Suface中,然后Flutter端通過(guò)監(jiān)聽(tīng)SufaceTexture的數(shù)據(jù)更新就可以順利把剛才創(chuàng)建的數(shù)據(jù)更新到它的紋理中,然后再將紋理交給SKIA渲染到屏幕上。

然而我們?nèi)绻枰肍lutter實(shí)現(xiàn)美顏,濾鏡,人臉貼圖等等功能,就需要將視頻數(shù)據(jù)讀取出來(lái),更新到紋理中,再將GPU紋理經(jīng)過(guò)美顏濾鏡處理后生成一個(gè)處理后的紋理。按Flutter提供的現(xiàn)有能力,必須先將紋理中的數(shù)據(jù)從GPU讀出到CPU中,生成Bitmap后再寫(xiě)入Surface中,這樣在Flutter中才能順利的更新到視頻數(shù)據(jù),這樣做對(duì)系統(tǒng)性能的消耗很大。

通過(guò)對(duì)Flutter渲染過(guò)程分析,我們知道Flutter底層需要渲染的數(shù)據(jù)就是GPU紋理,而我們經(jīng)過(guò)美顏濾鏡處理完成以后的結(jié)果也是GPU紋理,如果可以將它直接交給Flutter渲染,那就可以避免GPU-CPU-GPU這樣的無(wú)用循環(huán)。這樣的方法是可行的,但是需要一個(gè)條件,就是OpenGL上下文共享。

OpenGL

在說(shuō)上下文之前,得提到一個(gè)和上線文息息相關(guān)的概念:線程。

Flutter引擎啟動(dòng)后會(huì)啟動(dòng)四個(gè)線程:

第一個(gè)線程是UI線程,這是Flutter自己定義的UI線程,主要負(fù)責(zé)GPU發(fā)出的VSync信號(hào)時(shí)候用當(dāng)前Dart編譯的機(jī)器碼和當(dāng)前運(yùn)行環(huán)境創(chuàng)建出Layer Tree。

還有就是IO線程和GPU線程。和大部分OpenGL處理解決方案中一樣,F(xiàn)lutter也采取一個(gè)線程責(zé)資源加載,一部分負(fù)責(zé)資源渲染這種思路。

兩個(gè)線程之間紋理共享有兩種方式。一種是EGLImage(IOS是 CVOpenGLESTextureCache)。一種是OpenGL Share Context。Flutter通過(guò)Share Context來(lái)實(shí)現(xiàn)紋理共享,將IO線程的Context和GPU線程的Context進(jìn)行Share,放到同一個(gè)Share Group下面,這樣兩個(gè)線程下資源是互相可見(jiàn)可以共享的。

Platform線程是主線程,F(xiàn)lutter中有一個(gè)很奇怪的設(shè)定,GPU線程和主線程共用一個(gè)Context。并且在主線程也有很多OpenGL 操作。

這樣的設(shè)計(jì)會(huì)給音視頻開(kāi)發(fā)帶來(lái)很多問(wèn)題,后面會(huì)詳細(xì)說(shuō)。

音視頻端美顏處理完成的OpenGL紋理能夠讓Flutter直接使用的條件就是Flutter的上下文需要和平臺(tái)音視頻相關(guān)的OpenGL上下文處在一個(gè)Share Group下面。

由于Flutter主線程的Context就是GPU的Context,所以在音視頻端主線程中有一些OpenGL操作的話,很有可能使Flutter整個(gè)OpenGL被破壞掉。所以需要將所有的OpenGL操作都限制在子線程中。

通過(guò)上述這兩個(gè)條件的處理,我們就可以在沒(méi)有增加GPU消耗的前提下實(shí)現(xiàn)美顏和濾鏡等等功能。

TPM

在經(jīng)過(guò)demo驗(yàn)證之后,我們將這個(gè)方案應(yīng)用到閑魚(yú)音視頻組件中,但改造過(guò)程中發(fā)現(xiàn)了一些問(wèn)題。

上圖是攝像頭采集數(shù)據(jù)轉(zhuǎn)換為紋理的一段代碼,其中有兩個(gè)操作:首先是切進(jìn)程,將后面的OpenGL操作都切到cameraQueue中。然后是設(shè)置一次上下文。然后這種限制條件或者說(shuō)是潛規(guī)則往往在開(kāi)發(fā)過(guò)程中容易被忽略的。而這個(gè)條件一旦忽略后果就是出現(xiàn)一些莫名其妙的詭異問(wèn)題極難排查。因此我們就希望能抽象出一套框架,由框架本身實(shí)現(xiàn)線程的切換、上下文和模塊生命周期等的管理,開(kāi)發(fā)者接入框架以后只需要安心實(shí)現(xiàn)自己的算法,而不需要關(guān)心這些潛規(guī)則還有其他一些重復(fù)的邏輯操作。

在引入Flutter之前閑魚(yú)的音視頻架構(gòu)與大部分音視頻邏輯一樣采用分層架構(gòu):

1:底層是一些獨(dú)立模塊

2:SDK層是對(duì)底層模塊的封裝

3:最上層是UI層。

引入Flutter之后,通過(guò)分析各個(gè)模塊的使用場(chǎng)景,我們可以得出一個(gè)假設(shè)或者說(shuō)是抽象:音視頻應(yīng)用在終端上可以歸納為視頻幀解碼之后視頻數(shù)據(jù)幀在各個(gè)模塊之間流動(dòng)的過(guò)程,基于這種假設(shè)去做Flutter音視頻框架的抽象。

咸魚(yú)Flutter多媒體開(kāi)源組件

整個(gè)Flutter音視頻框架抽象分為管線和數(shù)據(jù)的抽象、模塊的抽象、線程統(tǒng)一管理和上下文同一管理四部分。

管線,其實(shí)就是視頻幀流動(dòng)的管道。數(shù)據(jù),音視頻中涉及到的數(shù)據(jù)包括紋理、Bit Map以及時(shí)間戳等。結(jié)合現(xiàn)有的應(yīng)用場(chǎng)景我們定義了管線流通數(shù)據(jù)以Texture為主數(shù)據(jù),同時(shí)可以選擇性的添加Bit Map等作為輔助數(shù)據(jù)。這樣的數(shù)據(jù)定義方式,避免重復(fù)的創(chuàng)建和銷(xiāo)毀紋理帶來(lái)的性能開(kāi)銷(xiāo)以及多線程訪問(wèn)紋理帶來(lái)的一些問(wèn)題。也滿足一些特殊模塊對(duì)特殊數(shù)據(jù)的需求。同時(shí)也設(shè)計(jì)了紋理池來(lái)管理管線中的紋理數(shù)據(jù)。

模塊:如果把管線和數(shù)據(jù)比喻成血管和血液,那框架音視頻的場(chǎng)景就可以比喻成器官,我們根據(jù)模塊所在管線的位置抽象出采集、處理和輸出三個(gè)基類。這三個(gè)基類里實(shí)現(xiàn)了剛才說(shuō)的線程切換,上下文切換,格式轉(zhuǎn)換等等共同邏輯,各個(gè)功能模塊通過(guò)集成自這些基類,可以避免很多重復(fù)勞動(dòng)。

線程:每一個(gè)模塊初始化的時(shí)候,初始化函數(shù)就會(huì)去線程管理的模塊去獲取自己的線程,線程管理模塊可以決定給初始化函數(shù)分配新的線程或者已經(jīng)分配過(guò)其他模塊的線程。

這樣有三個(gè)好處:

一是可以根據(jù)需要去決定一個(gè)線程可以掛載多少模塊,做到線程間的負(fù)載均衡。第二,多線程并發(fā)式能夠保證模塊內(nèi)的OpenGL操作是在當(dāng)前線程內(nèi)而不會(huì)跑到主線程去,徹底避免Flutter的OpenGL 環(huán)境被破壞。第三,多線程并行可以充分利用CPU多核架構(gòu),提升處理速度。

從Flutter端修改Flutter引擎將Context取出后,根據(jù)Context創(chuàng)建上下文的統(tǒng)一管理模塊,每一個(gè)模塊在初始化的時(shí)候會(huì)獲取它的線程,獲取之后會(huì)調(diào)用上下文管理模塊獲取自己的上下文。這樣可以保證每一個(gè)模塊的上下文都是與Flutter的上下文進(jìn)行Share的,每個(gè)模塊之間資源都是共享可見(jiàn)的,F(xiàn)lutter和音視頻native之間也是互相共享可見(jiàn)的。

基于上述框架如果要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的場(chǎng)景,比如畫(huà)面實(shí)時(shí)預(yù)覽和濾鏡處理功能,

1:需要選擇功能模塊,功能模塊包括攝像頭模塊、濾鏡處理模塊和Flutter畫(huà)面渲染模塊,

2:需要配置模塊參數(shù),比如采集分辨率、濾鏡參數(shù)和前后攝像頭設(shè)置等,

3:在創(chuàng)建視頻管線后使用已配置的參數(shù)創(chuàng)建模塊

4:最后管線搭載模塊,開(kāi)啟管線就可以實(shí)現(xiàn)這樣簡(jiǎn)單的功能。

上圖為整個(gè)功能實(shí)現(xiàn)的代碼和結(jié)構(gòu)圖。

結(jié)合上述音視頻框架,閑魚(yú)實(shí)現(xiàn)了Flutter多媒體開(kāi)源組件。

組要包含四個(gè)基本組件分別是:

1:視頻圖像拍攝組件

2:播放器組件

3:視頻圖像編輯組件

4:相冊(cè)選擇組件

現(xiàn)在這些組件正在走內(nèi)部開(kāi)源流程。預(yù)計(jì)9月份,相冊(cè)和播放器會(huì)實(shí)現(xiàn)開(kāi)源。

后續(xù)展望和規(guī)劃

1:實(shí)現(xiàn)開(kāi)頭所說(shuō)的從底層SDK到UI的全鏈路的跨端開(kāi)發(fā)。目前底層框架層和模塊層都是各個(gè)平臺(tái)各自實(shí)現(xiàn),反而是Flutter的UI端進(jìn)行了跨平臺(tái)的統(tǒng)一,所以后續(xù)會(huì)將底層也按照音視頻常用做法把邏輯下沉到C++層,盡可能的實(shí)現(xiàn)全鏈路跨平臺(tái)。

2:第二部分內(nèi)容為開(kāi)源共建,閑魚(yú)開(kāi)源的內(nèi)容不僅包括拍攝、編輯組件,還包括了很多底層模塊,希望有開(kāi)發(fā)者在基于Flutter開(kāi)發(fā)音視頻應(yīng)用時(shí)可以充分利用閑魚(yú)開(kāi)源出的音視頻模塊能力,搭建APP框架,開(kāi)發(fā)者只要去負(fù)責(zé)實(shí)現(xiàn)特殊需求模塊就可以,盡可能的減少重復(fù)勞動(dòng)。


網(wǎng)頁(yè)標(biāo)題:flutter相機(jī)預(yù)覽,flutter 拍照
文章分享:http://weahome.cn/article/hodpsc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部