一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳解Jetpack Compose布局流程

谷歌開發(fā)者 ? 來源:AndroidPub ? 2025-02-05 13:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

本文作者 / Android 谷歌開發(fā)者專家王鵬

前言 - 從 Compose 生命周期說起

ba236dbc-da36-11ef-9310-92fbcf53809c.png

Compose 繪制生命周期為三個階段:

Composition/組合: Composable 源碼經(jīng)過運行后生成 LayoutNode 的節(jié)點樹,這棵樹被稱為 Composition。

Layout/布局: 對節(jié)點樹深度遍歷測量子節(jié)點的尺寸,并將其在父容器內(nèi)擺放到合適的位置。

Drawing/繪制: 基于布局后拿到的尺寸和位置信息,繪制上屏。

我們與 Android 經(jīng)典視圖系統(tǒng)的生命周期 (Measure,Layout,Drawing) 做一個對比: 組合是 Compose 的特有階段,是其能夠通過函數(shù)調(diào)用實現(xiàn)聲明式 UI 的核心,想要深入理解 Compose 第一課就是理解這個過程。

繪制階段與傳統(tǒng)視圖大同小異,都是通過 Android Cavas API,底層調(diào)用 skia 實現(xiàn)。

本文討論的重點是布局階段。Compose 的 Layout 把 Measure 也囊括了進來,相對于 Android View 有相似性,但也有其獨有的特點和優(yōu)勢,接下來我們進入正題。

Compose 布局過程三步走

Compose 布局包括三個階段,從當(dāng)前 Node 出發(fā),需要依次經(jīng)歷:

Measure children: 深度遍歷子節(jié)點,并測量它們的尺寸

Decide own size: 根據(jù)收集到的子節(jié)點尺寸,決定當(dāng)前節(jié)點自己的尺寸

Place children: 將子節(jié)點擺放到合理的相對位置

wKgZO2ei-d-ASRvkAACju1W21oo095.png

上面代碼描述了一個卡片的布局,下面以這個布局的節(jié)點樹為例,看一下布局流程。

ba53930c-da36-11ef-9310-92fbcf53809c.png

Step1: 從 Row 開始發(fā)起測量,遵循三步走第一步,深度遍歷測量其子節(jié)點 Image 和 Column

Step2&3: Image 發(fā)起測量,因為沒有子節(jié)點需要測量了,所以只需要計算自己的尺寸,也因為沒有子節(jié)點需要擺放,空實現(xiàn)完成 place 即可

Step4: Column 發(fā)起測量,因其有子節(jié)點,繼續(xù)深度遍歷

Step5&6: 測量 Text,因為一個葉子節(jié)點,立即完成自己的 Size 和 Place 階段

Step7&8: 測量另一個 Text,同上

Step9: Column 拿到兩個子 Text 返回的 Size 后,計算出自己的 Size,不難猜到其計算邏輯應(yīng)該是 width = maxOf(child1.w, child2.w),height = sumOf(child1.h, child2.h)。設(shè)置自己的 width 和 height 后,對兩個子 Text 進行 Place,垂直線性擺放。

看一下代碼是如何實現(xiàn)這三步。

所有的 Composable 最終都會調(diào)用一個公共 Layout Composable 方法,這里面創(chuàng)建 LayoutNode 存儲在 Composition 節(jié)點樹。

ba6b6c02-da36-11ef-9310-92fbcf53809c.png

以 Column 的實現(xiàn)為例,可以看到調(diào)用 Layout 時,傳入了三個參數(shù):

@Composable
inline fun Column(
    modifier: Modifier = Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    content: @Composable ColumnScope.() -> Unit
) {
    val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
    Layout(
        content = { ColumnScopeInstance.content() },
        measurePolicy = measurePolicy,
        modifier = modifier
    )
}

content: 在這里定義子 Composable,組合過后形成當(dāng)前節(jié)點的子節(jié)點

measurePolicy: 這是定義了布局的三步走核心邏輯

modifier: 修飾符鏈,參與到布局或者繪制階段

measurePolicy 和 modifier 會存儲在當(dāng)前 LayoutNode 上,等待 measure 的開始參與其中。下面重點分析 MeasurePolicy 了解三步走如何實現(xiàn)。

MeasurePolicy - 測量策略

fun interface MeasurePolicy {


    fun MeasureScope.measure(
        measurables: List,
        constraints: Constraints
    ): MeasureResult


}

MeasurePolicy 通過 measure 方法完成測量。這里有兩個重要參數(shù):

measurables: 等待測量的對象,其實就是當(dāng)前節(jié)點的子節(jié)點

constraints: 測量約束。節(jié)點需要基于當(dāng)前的 Constaints 進行測量,它規(guī)定了節(jié)點尺寸的上限和下限,如下:

class Constraints {
    val minWidth: Int
    val maxWidth: Int
    val minHeight: Int
    val maxHeight: Int
    ...
}

Constraints - 測量約束

父節(jié)點通過 Constraints 約束子節(jié)點的測量。Constraints 非常重要,我們常說 Compose 不怕布局嵌套正是得益于它。反觀 Android 原生視圖,由于測量階段的約束不明確,子 View 需要再次請求父 View 給出清楚的 View.MeasureSpec,導(dǎo)致出現(xiàn)多次繪制。

舉幾個例子理解一下 Constraints 如何設(shè)置:

ba8aefbe-da36-11ef-9310-92fbcf53809c.png

對于頁面的根節(jié)點, Activity 的 Window 的長寬就是其 Constraints 的最大長寬。如果是一個垂直可滾動容器的節(jié)點,那么它的 Constraints 的 height 應(yīng)該是 Infinity,因為它可以跨多個屏幕存在。

此外, Modifier 的裝飾能力本質(zhì)也是通過修改 Constraints 完成的。例如 fillMaxWidth 要求被修飾的節(jié)點填充整個父容器,所以 Modifier 會在布局階段將 minHeight/minWidth 對齊 max 組值。關(guān)于 Modifier 參與布局的流程,稍后介紹。

三步走實現(xiàn) - Kotlin 語法優(yōu)勢的體現(xiàn)

舉例看一下三步走代碼如何實現(xiàn)。

baa449f0-da36-11ef-9310-92fbcf53809c.png

我們實現(xiàn)一個類似 Column 的布局效果,在 measurePolicy#measure 中實現(xiàn)三步走邏輯。

measurePolicy = { // this: MeasureScope
    // Step1:Measure each children
    val placeables = measurables.map { measurable ->
        measurable.measure(constraints)
    }


    // Step2: Deciee own size
    val height = placeables.sumOf { it.height }
    val width = placeables.maxOf { it.width }


    layout(width, height) { //this: Placeable.PlacementScope


        // Step3: Place children by changing the offset of y co-ord    
        var yPosition = 0


        placeables.forEach { placeable ->
            // Position item on the screen
            placeable.placeRelative(x = 0, y = yPosition)


            // Record the y co-ord placed up to
            yPosition += placeable.height
        }
    }
}

每個 measuable 提供了參與測量的 measure 方法,此處會傳入 Constraints,返回的 placeable 中已經(jīng)存儲了測量后的 widht 和 height,等待 place

基于各個 placeable 的 w 和 h 計算當(dāng)前節(jié)點的 Size,并通過 layout 方法設(shè)置。layout 方法內(nèi)會真正的創(chuàng)建 LayoutNode

layout 方法的末參是一個 lambda,這里是第三步擺放子節(jié)點的邏輯,通過設(shè)置 y 軸的偏移量實現(xiàn)縱向布局,非常簡單

特別值得一提的是,通過 meause 一個方法就完成三步走,布局邏輯相對傳統(tǒng)的 View 系統(tǒng)更加高效,回想傳統(tǒng)自定義 View 你需要分別實現(xiàn) onMeasure,onLayout,onDraw 等,邏輯分散,可讀性差。

但是這種集中式的寫法有一個弊端,需要人為保證代碼順序。試想如果把 layout 寫在 measure 前面怎么辦?幸好 Kotlin 強大的編譯期檢查能力,很好地指導(dǎo)大家寫出正確代碼:

measure 方法的返回值是 MeasureResult 類型,layout 方法也返回此類型,所以保證了尾部一定是調(diào)用 layout 完成三步走

Measuable#measure 調(diào)用后返回 Placeable 類型,然后才能調(diào)用 Placeable#place,這保證了 place 和 measure 的先后關(guān)系

Measuable#measure 只能在 MeasureScope 中調(diào)用,Placeable#place 只能在 Placeable.PlacementScope 中調(diào)用,這確保了 place 需要在 layout 的 lambda 中調(diào)用

通過各種返回值類型、作用域類型的約束,大家可以寫出安全又一氣呵成的代碼,這種 API 設(shè)計理念值得推崇。

Modifier Node

接下來介紹一下 Modifier 如何參與布局的。

bab8a40e-da36-11ef-9310-92fbcf53809c.png

Modifier 在組合之后也會成為 Node 存儲在節(jié)點樹上,Modifier 的調(diào)用鏈生成一條單向繼承的子節(jié)點樹,而被修飾的 Composable 會成為這條樹枝的葉子結(jié)點。

比如上面例子中,Image 最終成為 clip->size 的子節(jié)點。實際上 Image 內(nèi)部有一些內(nèi)置的 Modifier,所以全部展開后 Image 所在的樹枝上有一連串 ModifierNode。

掛在節(jié)點樹上的 ModifierNode 可以參與到深度遍歷的繪制流程中,在 Image 之前對 Constraints 做出調(diào)整,完成對末端 Image 的裝飾。

以 Padding 修飾符為例,看一下源碼:

//組合中調(diào)用 paddiung 會
fun Modifier.padding(
    start: Dp = 0.dp,
    top: Dp = 0.dp,
    end: Dp = 0.dp,
    bottom: Dp = 0.dp
) = this then PaddingElement(
    start = start,
    top = top,
    end = end,
    bottom = bottom
)


//Element 存儲到鏈上,創(chuàng)建 PaddingNode
private class PaddingElement(
    ...
) : ModifierNodeElement() 




//PaddingNode 定義 measure 邏輯
private class PaddingNode(


    overide fun MeasureScope.measure(
        measurable: Measurable, // 注意不是list
        constraints: Constraints
    ): MeasureResult {
        ...
    }


):LayoutModifierNode,Modifier.Node()

組合階段,Modifier#then 創(chuàng)建 Element 加入 Modifier chain 中。Element 是無狀態(tài)的,重組中會重新生成,Element 會在組合中創(chuàng)建有狀態(tài)的 ModifierNode。ModifierNode 有狀態(tài),重組中僅當(dāng)狀態(tài)發(fā)生變化時被更新,否則不會重新生成。Modifier Node 是 Compose 1.5 引入的新優(yōu)化,目的就是通過存儲 Modifier 狀態(tài)參與比較,提升重組性能。

ModifierNode 按照參與的階段不同,分為 LayoutModifierNode 和 DrawModifierNode。對于前者,布局邏輯就是現(xiàn)在 LayoutModifierNode#measure 中,和 MeasurePolicy#measure 的功能一樣,唯一的區(qū)別是接受單個 measurable 參數(shù)而不是 List。因為我們知道了 ModifierNode 是單向繼承,所以只會有一個后續(xù)子節(jié)點。如果把LayoutNode 的 measure 看做是自定義 ViewGroup 需要針對多個子 View 布局,那么 LayoutModifierNode 的 measure 更像是自定義 View,只對自身負(fù)責(zé)。

Modifier.layout {}

除了自定義一個 Modifier 來改變當(dāng)前節(jié)點的布局,還有一個簡單的方法就是使用 Modifier.layout {} 方法。

fun Modifier.layout(
    measure: MeasureScope.(Measurable, Constraints) -> MeasureResult
)
我們可以在 Modifier 調(diào)用鏈的任意位置插入 measure 自定義代碼,對當(dāng)前節(jié)點做裝飾。例如下面代碼中添加了一個自定義 50px 的 padding。
Box(Modifier
    .background(Color.Gray)
    .layout { measurable, constraints ->
        // an example modifier that adds 50 pixels of vertical padding
        val padding = 50
        val placeable = measurable.measure(constraints.offset(vertical = -padding))
        layout(placeable.width, placeable.height + padding) {
            placeable.placeRelative(0, padding)
        }
    }){ ... }

Modifier 布局流程

bade81ec-da36-11ef-9310-92fbcf53809c.png

上面代碼繪制一個居中擺放 50*50 的矩形。我們通常不會同時設(shè)置這么多 size 相關(guān)的 modifier,這個例子只是為了展示 Modifier 的布局流程:

bafa741a-da36-11ef-9310-92fbcf53809c.png

先看一下自頂向下的測量流程: 從 fillMaxSize 對應(yīng)的 LayoutModifierNode 出發(fā),假設(shè)當(dāng)前的 Constraints 是 w:0-200,h:0-300。fillMaxSize 的功能是讓子節(jié)點填滿當(dāng)前全部剩余空間,會為子節(jié)點創(chuàng)建以下 childConstraints:

val childConstraints = Constraints (
    minWidth = outerConstraints.maxWidth,
    maxWidth = outerConstraints.maxWidth,
    minHeight = outerConstraints.maxHeight,
    maxHeight = outerConstraints.maxHeight,
)
來到 warpContentSize,它會讓子自己決定 size 不設(shè)限,min 值再次回歸 0,childConstraints 如下:
val childConstraints = Constraints (
    minWidth = 0,
    maxWidth = outerConstraints.maxWidth,
    minHeight = 0,
    maxHeight = outerConstraints.maxHeight,
)
來到 size(50),這里自然要給一個具體的 size 約束,如下:
val childConstraints = Constraints (
    minWidth = 50,
    maxWidth = 50,
    minHeight = 50,
    maxHeight = 50,
)
以此類推 Constraints 經(jīng)過不斷調(diào)整傳入到葉子節(jié)點 Box 對應(yīng)的 LayoutNode,完成三步走。 第一步測量

bb16c8cc-da36-11ef-9310-92fbcf53809c.png

葉子節(jié)點測量完后,再自底向上進行第二三步,整個流程不做贅述了,只提一點: wrapContentSize 從語義上是應(yīng)該跟隨子節(jié)點的大小,即 5050,為什么實際尺寸設(shè)置了 200300 呢?

因為其父節(jié)點 fillMaxSize 傳入的 Constraints 是 200300,rwapContentSize 必須填滿這個空間,而由于它有一個默認(rèn)參數(shù) align = Alignment.Center,所以才能出現(xiàn) 5050 矩形塊居中的效果。

Intrinsic Measurements - 固有特性測量

中文將其翻譯成 "固有特性",很多人不理解 "固有" 到底指什么?所以放在本文最后討論一下。

Compose 要求布局過程中每個節(jié)點只被測量一次,測量總耗時只與節(jié)點數(shù)正相關(guān),與層級無關(guān),所以 ComopseUI 不怕嵌套過深,而傳統(tǒng) Android 視圖系統(tǒng)中,某個 View 存在多次測量的情況,隨著層級變多測量次數(shù)會指數(shù)級增長,所以傳圖視圖下我們需要通過優(yōu)化 View 的層級提升性能。

Compose 為了保證 "每個節(jié)點只測量一次" 的原則,甚至增加了編譯期檢查:

val constraints1 = ...
val constraints2 = ...
val placeable1 = measurable.measure(constraints1
val placeable2 = measurable.measure(constraints2)

bb280286-da36-11ef-9310-92fbcf53809c.png

"每個節(jié)點只測量一次"在提升性能的同時也帶來了問題。來自官方文檔的例子:

@Composable
fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) {
    Row(modifier = modifier) {
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(start = 4.dp)
                .wrapContentWidth(Alignment.Start),
            text = text1
        )
        Divider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),


            text = text2
        )
    }
}
上面代碼的本意是希望打造以下的布局效果:

但發(fā)現(xiàn)實際效果不符合預(yù)期: Divider 的高度沒有對齊左右的 Text,而是撐滿了容器高度:

Row 為測量 Divider 傳入Constraints 時,不知道對齊 Text 高度應(yīng)該設(shè)置怎樣的 maxHeight。傳入的 maxHeight 值比較大導(dǎo)致 Divider 的 fillMaxSize 撐滿了整個容器。 傳統(tǒng)視圖體系中類似的情況,Row 在測量了 Text 的高度后,會再測量一次 Divider 并給出更合適的 View.MeasureSpec,但 Compose 中不可以,因為這樣違反了 "每個節(jié)點只測量一次"的原則。

為此, Compose 引入了 "固有特性測量" 的機制。在當(dāng)前節(jié)點正式發(fā)起深度遍歷子測量節(jié)點之前的一次 "預(yù)處理",從子節(jié)點提前獲取必要信息,設(shè)置更合理的 Constraints,然后再發(fā)起正式測量。 MeasurePolicy 中提供了獲取 "固有特性" 尺寸的方法: IntrinsicMeasureScope.minIntrinsicXXX

fun interface MeasurePolicy {


   fun IntrinsicMeasureScope.minIntrinsicWidth(
        measurables: List,
        height: Int
    ): Int


   fun IntrinsicMeasureScope.minIntrinsicHeight
   fun IntrinsicMeasureScope.maxIntrinsicWidth
   fun IntrinsicMeasureScope.maxIntrinsicHeight


}
Text 的固有特性的 minIntrinsicHeight 是文本內(nèi)容單行展示的高度;Divider 的 minIntrinsicHeight 是 0,當(dāng)我們改一下例子中的代碼,在 Row 的Modifier.height 增加 IntrinsicSize.Min。
Row(modifier = modifier.height(IntrinsicSize.Min)) {...}
Row 在發(fā)起子節(jié)點測量前,通過 MeasurePolicy 提供的固有特性相關(guān)方法,獲取所有子節(jié)點的minIntrinsicHeight,取最大的一個設(shè)為 Constraints.maxHeight 后發(fā)起正式測量。這樣,Divider 的 fillMaxSize 就會跟 Text 兩邊高度對齊了。

看到這里相信大家理解 "固有"的含義了,其本質(zhì)代表 "不依賴 Constraints"就可以獲取的值,基于這些值更新 Constraints,后續(xù)測量只有一次也能正確約束。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Android
    +關(guān)注

    關(guān)注

    12

    文章

    3973

    瀏覽量

    130291
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4381

    瀏覽量

    64926
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4900

    瀏覽量

    70779

原文標(biāo)題:【GDE 分享】一文看懂 Jetpack Compose 布局流程

文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    Jetpack Compose 的基本布局

    mcu
    橙群微電子
    發(fā)布于 :2024年05月21日 15:48:29

    PCB工藝流程詳解

    PCB工藝流程詳解PCB工藝流程詳解
    發(fā)表于 05-22 14:46

    compose的使用技巧是什么?

    compose的使用技巧是什么?
    發(fā)表于 11-15 07:27

    詳解Jetpack Compose 1.1版本的新功能

    我們一如既往地搭建產(chǎn)品路線圖,現(xiàn)在已經(jīng)發(fā)布了 Jetpack Compose 的 1.1 版本,這是 Android 的現(xiàn)代原生界面工具包。此版本新增了一些功能,比如經(jīng)過優(yōu)化的焦點處理、觸摸目標(biāo)值
    的頭像 發(fā)表于 03-11 10:14 ?1672次閱讀

    如何使用 Compose 進行構(gòu)建

    適用于 Wear OS 的 Compose 已推出了開發(fā)者預(yù)覽版,使用 Compose 構(gòu)建 Wear OS 應(yīng)用,不僅可以輕松遵循 Material You 指南,同時可以將 Compose 的優(yōu)點發(fā)揮出來。
    的頭像 發(fā)表于 03-17 13:44 ?2058次閱讀

    Jetpack Compose基礎(chǔ)知識科普

    Jetpack Compose 是用于構(gòu)建原生 Android 界面的新工具包。它可簡化并加快 Android 上的界面開發(fā),使用更少的代碼、強大的工具和直觀的 Kotlin API,快速讓應(yīng)用生動
    的頭像 發(fā)表于 04-02 13:38 ?3370次閱讀

    Android Studio Dolphin穩(wěn)定版正式發(fā)布

    預(yù)覽動畫。此外,針對應(yīng)用界面調(diào)試,我們還在布局檢查器 (Layout Inspector) 中引入了一個很好用的 Compose 界面計數(shù)工具,用以跟蹤界面重新組合的次數(shù)。 Jetpack C
    的頭像 發(fā)表于 10-12 19:37 ?2863次閱讀

    Compose Material 3 穩(wěn)定版現(xiàn)已發(fā)布 | 2022 Android 開發(fā)者峰會

    (新一代 Material Design ) 構(gòu)建 Jetpack Compose 界面。立即開始在應(yīng)用中使用 Material Design 3 吧! Compose Material 3
    的頭像 發(fā)表于 11-21 18:10 ?1582次閱讀

    Jetpack Compose 更新一覽 | 2022 Android 開發(fā)者峰會

    作者 /?Android 開發(fā)者關(guān)系工程師 Jolanda Verhoef 去年我們發(fā)布了 Jetpack Compose ,此后一直在進行優(yōu)化。我們已添加了新的功能并創(chuàng)造出功能更強大的工具,幫助
    的頭像 發(fā)表于 11-23 17:55 ?1506次閱讀

    Google計劃用Jetpack Compose來重建Android系統(tǒng)中的設(shè)置應(yīng)用

    上周,Google 發(fā)布了 Android 14 的首個開發(fā)者預(yù)覽版,除了那些最新的功能以外,Google 似乎還正在默默醞釀一個新的計劃 —— 用更現(xiàn)代的 Jetpack Compose 來逐步
    的頭像 發(fā)表于 02-18 11:16 ?1897次閱讀

    Compose for Wear OS 1.1 推出穩(wěn)定版: 了解新功能!

    為 Wear OS 構(gòu)建出色的響應(yīng)式應(yīng)用。 ? Compose for Wear OS?1.1 版本 https://developer.android.google.cn/jetpack
    的頭像 發(fā)表于 02-22 01:30 ?1273次閱讀

    Kotlin聲明式UI框架Compose Multiplatform支持iOS

    ,基于 Kotlin 和?Jetpack Compose?打造,由 JetBrains 和開源貢獻(xiàn)者開發(fā)。 Jetpack Compose 是 Google 為構(gòu)建原生 UI 打造的
    的頭像 發(fā)表于 04-24 09:12 ?1690次閱讀
    Kotlin聲明式UI框架<b class='flag-5'>Compose</b> Multiplatform支持iOS

    Jetpack Compose和設(shè)備類型的三大重要更新

    2024 年 Google I/O 大會上我們分享了大量更新和公告,幫助開發(fā)者提升工作效率。了解 2024 年 Google I/O 大會上有關(guān) Jetpack Compose 和設(shè)備類型的三大重要更新。
    的頭像 發(fā)表于 08-09 17:07 ?1010次閱讀

    docker-compose配置文件內(nèi)容詳解以及常用命令介紹

    一、Docker Compose 簡介 Docker Compose是一種用于定義和運行多容器Docker應(yīng)用程序的工具。通過一個? docker-compose.yml ?文件,您可以配置應(yīng)用程序
    的頭像 發(fā)表于 12-02 09:29 ?4454次閱讀
    docker-<b class='flag-5'>compose</b>配置文件內(nèi)容<b class='flag-5'>詳解</b>以及常用命令介紹

    Docker Compose的常用命令

    。它通過一個配置文件(docker-compose.yml)來詳細(xì)定義多個容器之間的關(guān)聯(lián)、網(wǎng)絡(luò)設(shè)置、服務(wù)端口等信息。使用一條簡單的命令,就可以輕松啟動、停止和管理這些容器,極大地簡化了多容器應(yīng)用的部署與管理流程,方便實現(xiàn)應(yīng)用的快速構(gòu)建、開發(fā)、測試以及部署。
    的頭像 發(fā)表于 04-30 13:40 ?459次閱讀