Flow 介绍使用

前言

如今android开发基本上从之前的Java语言转而使用Kotlin语言,MMVM模式中用于保存UI状态的工具LiveData也逐渐被Flow代替。下面将逐步介绍Kotlin的Flow相关知识,以及如何与Coroutine配合使用,写出漂亮的声明式,响应式代码,当然最重要的是性能强大,可读性强,易于维护!

Flow介绍

Flow 是 Kotlin 协程库中的一个概念和类,用于处理异步数据流。它提供了一种声明式的方式来处理连续的、异步的数据序列,并且与协程无缝集成。

以下是 Flow 的一些关键特性和优势

  1. 异步数据流:Flow 允许以异步的方式处理连续的数据流。它可以处理大量的数据或长时间运行的操作,而无需阻塞主线程。
  2. 声明式编程:Flow 提供了一种声明式的编程模型,通过操作符(operators)链式调用来处理数据流。这使得代码更简洁、易读和易于维护。
  3. 可组合性:Flow 的操作符可以组合在一起,构建复杂的数据转换和处理逻辑。您可以使用 mapfilterflatMapzip 等操作符来转换、过滤、合并和组合数据流。
  4. 挂起函数:Flow 的操作可以在挂起函数中执行,使其适用于与协程一起使用。这样可以方便地进行异步操作和并发编程,避免了回调地狱和复杂的线程管理。
  5. 取消支持:Flow 具有与协程一样的取消支持。可以使用 cancelcollect 中的 cancellable 参数或 withTimeout 等函数来取消数据流的收集和处理。

在介绍flow具体用法之前,先说明下flow的一些概念:

Flow组成
  • Producers(生产者):数据流的产生emit
  • Customers(消费者):数据流的收集collect
  • Operators(中间操作符):数据流的二次加工
flow的冷流&热流

在 Kotlin 的协程中,“冷流”(Cold Flow)和"热流"(Hot Flow)是用来描述 Flow 和 SharedFlow 两种不同的数据流的特性,还有一种特别的热流,StateFlow,它继承自SharedFlow

public interface StateFlow<out T> : SharedFlow<T> {
    /**
     * The current value of this state flow.
     */
    public val value: T
}

cold flow & hot flow区别
  1. 冷流(Cold Flow):

    • 冷流是指每次订阅都会重新开始并独立运行的数据流。
    • 当每个订阅者开始收集数据时,冷流会从头开始发射数据,每个订阅者都会独立地接收到完整的数据流。
    • 例如,通过调用 Flow 的 collectcollectLatest 函数,可以订阅冷流并收集数据。
  2. 热流(Hot Flow):

    • 热流是指已经开始发射数据并在订阅之前运行的数据流。
    • 热流在启动时就开始发射数据,无论是否有订阅者。
    • 如果订阅者在流已经开始发射数据后加入,它们可能会错过一些数据。
    • 例如,通过调用 SharedFlow 的 asSharedFlow 函数,可以创建热流,并可以通过 collect 函数订阅。

Flow使用

class SecondFragment : Fragment() {

    //……省略无关代码

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.buttonFlow.setOnClickListener {
            lifecycleScope.launch {
                val value = createFlow().first()
                Log.d("flow", "flow.first() = $value")

                val acc = createFlow().fold(0) { acc, item ->
                    acc + item
                }
                Log.d("flow", "flow.fold() = $acc")

                try {
                    val value = createFlow().single()
                    Log.d("flow", "flow.single() = $value")
                } catch (e: Exception) {
                    Log.d("flow", e.toString())
                }
            }
        }

        binding.collectLastBtn.setOnClickListener {
            lifecycleScope.launch {
                createFlow().collectLatest { value ->
                    println("Collecting $value")
                    delay(1000) // Emulate work
                    println("$value collected")
                }
            }
        }

    }

    private fun createFlow(): Flow<Int> {
        return flow {
            emit(100)
            delay(500)
            emit(200)
            emit(300)
        }
    }
}

flow创建

创建一个普通flow很简单,直接如上所述方法createFlow(),直接调用flow{},代码块中使用emit(value)发射数据;另外还有一些其他方式创建flow,例如T.asFlow()flowOf(value: T)等方法,本质都是调用了flow{},具体使用细节看后续Demo;

public fun <T> Iterable<T>.asFlow(): Flow<T> = flow {
    forEach { value ->
        emit(value)
    }
}

flow的常用操作符

first

顾名思义获取到flow数据流中的第一个元素,与之对应的是last()

fold

这个方法源码如下:需要一个参数初始值,用于后续(acc: R, value: T) -> R函数的入参acc,通过collect得到flow发射的每一个值,调用operation,返回最终得到的计算结果;

public suspend inline fun <T, R> Flow<T>.fold(
    initial: R,
    crossinline operation: suspend (acc: R, value: T) -> R
): R {
    var accumulator = initial
    collect { value ->
        accumulator = operation(accumulator, value)
    }
    return accumulator
}

例如:得到的计算结果就是100+200+300 = 600,最终打印flow.fold() = 600

val acc = createFlow().fold(0) { acc, item ->
                    acc + item
                }
Log.d("flow", "flow.fold() = $acc")

single

上述例子中有这样一段code:

try {
    val value = createFlow().single()
    Log.d("flow", "flow.single() = $value")
} catch (e: Exception) {
    Log.d("flow", e.toString())
}

这里的single()操作符作用如下:

  1. 获取单个元素single() 操作符用于获取 Flow 中的单个元素。如果 Flow 中只包含一个元素,它将返回该元素;如果 Flow 中包含多个元素或没有元素,它将抛出 IllegalArgumentException 异常。
  2. 用于确保 Flow 只包含一个元素single() 可以用作 Flow 的检查机制,确保 Flow 中只包含一个元素。如果 Flow 中的元素数量不符合预期,single() 将抛出异常,提供了一种简单的验证和安全性检查。
  3. 简化处理单个元素的情况:当你只关心 Flow 中的单个元素,并希望在处理该元素时终止流的收集时,可以使用 single()。它能够简化对单个元素的处理逻辑。

distinctUntilChanged

数据去重

createFlow().distinctUntilChanged().collectLatest {
    println("emit value = $it")
}

StateFlow

创建

stateFlow初始化的时候必须要有一个初始值

public fun <T> MutableStateFlow(value: T): MutableStateFlow<T> = StateFlowImpl(value ?: NULL)

用法也很简单,几乎和LiveData一样,都有一个value属性,赋值都是给value赋值

private val _stateFlow = MutableStateFlow("Hello world")
val stateFlow: StateFlow<String> = _stateFlow.asStateFlow()

fun triggerStateFlow() {
    _stateFlow.value = "StateFlow"
}

使用

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        launch {
            viewModel.stateFlow.collectLatest {
                binding.stateText.text = it
                Snackbar.make(
                    binding.root,
                    it,
                    Snackbar.LENGTH_LONG
                ).show()
            }
        }
     }
 }

每次给stateflow.value赋值,都会触发collect方法,类似livedata.observe(this), 只不过collect是协程挂起函数,需要在Coroutine.Scope中执行代码块。

如何与LifecycleScope协作

image.png

这里Lifecycle.repeatOnLifecycle用法如上图所示,顺便说下该repeatOnLifecycle是基于lifecycte-runtime-ktx:2.4.0版本才有的新接口,如果你的没有找到该api,请检查你的库版本。

要解释这里为什么要这么使用需要了解activity/fragment生命周期

当我们直接使用:

lifecycleScope.launch {
    viewModel.triggerFlow().collectLatest {
        binding.flowText.text = it
    }
}

这种方式是不安全的,当app进入后台的时候,生命周期函数是走到onStop,但是此刻flow所在的协程还是处在活跃状态,可以正常收集数据,这就造成了数据的浪费,甚至产生内存泄漏现象如下图所示;

image.png

当我们使用repeatOnLifecycle(Lifecycle.State.STARTED)的时候,看下图:

image.png

当app进入后台的时候我们的协程挂起函数会处于挂起状态,此时会停止收集flow;重新进入前台后,挂起函数会重新运行;

数据防抖动

StateFlowLiveData一个重要的区别在于,LiveData在重复设置value为相同值的情况下,会重复触发observe回调, 它是不防抖的;

StateFlow 防抖,它天生有去重的功能!效果类似Flow.distinctUntilChanged()这是因为它的源码中有这段逻辑:

private fun updateState(expectedState: Any?, newState: Any): Boolean {
    var curSequence = 0
    var curSlots: Array<StateFlowSlot?>? = this.slots // benign race, we will not use it
    synchronized(this) {
        val oldState = _state.value
        if (expectedState != null && oldState != expectedState) return false // CAS support
        if (oldState == newState) return true
    

stateflow调用distinctUntilChanged会报错如下

@Deprecated(
    level = DeprecationLevel.ERROR,
    message = "Applying 'distinctUntilChanged' to StateFlow has no effect. See the StateFlow documentation on Operator Fusion.",
    replaceWith = ReplaceWith("this")
)
public fun <T> StateFlow<T>.distinctUntilChanged(): Flow<T> = noImpl()

粘性数据(数据倒灌)

当屏幕翻转或跳转返回,或者弹Dialog的时候,stateFlow会发生数据倒灌,stateflow的value会重新发送给消费者,触发collect代码块; 这与LiveData是一致的,后面ShareFlow会讲到如何避免这种情况!

SharedFlow

创建

SharedFlow和StateFlow一样,SharedFlow 也有两个版本:SharedFlowMutableSharedFlow

private val _sharedFlow = MutableSharedFlow<String>()
val sharedFlow = _sharedFlow.asSharedFlow()

fun triggerSharedFlow() {
    viewModelScope.launch {
        _sharedFlow.emit("SharedFlow")
    }
}


初始化方法:

public fun <T> MutableSharedFlow(
    replay: Int = 0,
    extraBufferCapacity: Int = 0,
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
)

它和StateFlow区别在于

  1. 没有初始值;
  2. SharedFlow可以保留历史数据,stateFlow只会保存最新的值;
  3. SharedFlow发射数据用emit,没有setValue方法;

stateFlow继承自SharedFlow

StateFlow是SharedFlow的一种特殊用途、高性能且高效的实现,用于狭窄但广泛使用的共享状态的情况。有关适用于所有共享流的基本规则、约束和运算符,请参阅 SharedFlow文档。

StateFlow始终有一个初始值,向新订阅者重播一个最新值,不再缓冲任何其他值,但保留最后发出的值,并且不支持 ResetReplayCache。当使用以下参数创建StateFlow并对其应用distinctUntilChanged运算符时,StateFlow的行为与共享流相同:

// MutableStateFlow(initialValue) is a shared flow with the following parameters:
val shared = MutableSharedFlow(
    replay = 1,
    onBufferOverflow = BufferOverflow.DROP_OLDEST
)
shared.tryEmit(initialValue) // emit the initial value
val state = shared.distinctUntilChanged() // get StateFlow-like behavior

当您需要对 StateFlow的行为进行调整(例如额外缓冲、重播更多值或省略初始值)时,请使用 SharedFlow 。

使用

使用和StateFlow 类似


lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        launch {
            viewModel.sharedFlow.collectLatest {
                binding.shareText.text = it
            }
        }
    }
}

默认情况下,replay = 0,当有新的订阅者的时候,SharedFlow不会向它发送数据。这里有点像通知的感觉。

正因为默认情况下 replay = 0,SharedFlow不会有数据倒灌的情况发生。 具体查看 Demo演示。

总结

Flow 提供了一种简洁、强大且可组合的方式来处理异步数据流。它可以与 Kotlin 协程一起使用,为异步编程提供了更优雅的解决方案,并提供了更好的可读性和维护性。Flow 的设计使得处理数据流变得更加直观和简单,同时具备高效和可扩展的特性。

Flow、StateFlow和SharedFlow是Kotlin协程库中用于处理异步数据流的不同类型。它们适用于不同的使用场景:

  1. Flow:

    • Flow适用于一次性的、连续的异步数据流。
    • 使用Flow可以处理潜在的无限数据流,并在每次订阅时重新开始。
    • Flow是冷流,每个订阅者都会独立地接收到完整的数据流。
    • 适合处理单个值、集合、网络请求、数据库查询等异步操作的结果。
    • 操作符链式调用的声明式编程风格使代码易于理解和组合。
  2. StateFlow:

    • StateFlow适用于具有状态的异步数据流。
    • 它是SharedFlow的一个特化版本,用于表示具有可变状态的数据流。
    • StateFlow维护当前的状态值,并将状态变化通过Flow的方式进行广播。
    • 适合在UI层面中使用,可以实现简单的状态管理,例如表示UI组件的可见性、文本内容等。
  3. SharedFlow:

    • SharedFlow适用于多个订阅者共享的异步数据流。
    • 它是一种热流,即在开始发射数据后,无论是否有订阅者,都会持续发射数据。
    • SharedFlow允许多个订阅者同时收到相同的数据流,而不是每个订阅者都重新开始数据流。
    • 适合实现事件总线、实时更新、广播消息等场景,可以让多个订阅者观察和响应相同的数据。
  4. StateFlow在遇到数据倒灌的情况下,数据倒灌不是问题,在某些场景下我们不需要数据倒灌,可以采用SharedFlow代替;

根据您的使用需求,可以选择适合的数据流类型。如果只需要一次性的连续数据流,可以使用Flow。如果需要具有可变状态的数据流,可以使用StateFlow。如果需要多个订阅者共享相同的数据流,可以使用SharedFlow。

注意,Flow、StateFlow和SharedFlow都需要在协程作用域内进行收集和处理,以确保正确的协程上下文和取消支持。

参考

官方文档 StateFlow& SharedFlow

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

Android-海绵
关注 关注
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android使用Flow获取网络连接信息
虎哥LoveDroid
12-25 1964
如果你是一名Android开发者,你可能会对这个主题感到有趣。考虑到几乎每个应用程序都需要数据交换,例如刷新动态或上传/下载内容。而互联网连接对此至关重要。但是,当用户的设备离线时,数据如何进行交换呢?我们如何确定设备重新连接到互联网,以便我们可以提供他们请求的数据?本文将指导您了解如何读取和监听用户的网络状态。
Android-Flow 使用和源码解析
ShiShouFeng
12-07 1463
数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。例如,Flow 是发出整数值的数据流。在协程中,与仅返回单个值的挂起函数相反,数据流可按顺序发出多个值。数据流包含三个实体:创建数据流有两种常用方式: 第一就是试用数据流构建函数, 第二就是利用扩展方法将原有类型转换成Flow这里比较常用的函数是 和 其实 是简化版的 函数,内部帮我们调用了 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JE
[Android][kotlin]Flow数据流
qq_27871511的博客
08-19 847
Flow 是一个异步数据流,它可以顺序地发出数据,通过流上的一些中间操作得出结果;若出错可抛出异常。这些 “流上的中间操作” 包括但不限于mapfiltertakezip等等方法。这些中间操作是链式的,可以在后面再次添加其他操作方法,并且也不是挂起函数,它们只是构建了一条链式的操作并实时返回结果给后面的操作步骤。流上的终端操作符要么是挂起函数,例如collectsingletoList等等,要么是在给定作用域内开始收集流的launchIn操作符。前半句好理解,后半句啥意思?这就得看一下launchIn。
FlowAndroid UI 状态管理和导航框架
最新发布
Unity打怪升级
09-10 1948
在构建复杂的移动应用时,管理 UI 状态和导航逻辑可能会变得非常复杂。Flow 是 Square 开源的一个框架,它旨在简化这一过程,让开发者能够更容易地命名、导航和管理 UI 状态。
Flow使用
csz_12345的博客
11-17 1161
flow 是 Facebook 推出的 js 静态类型检查工具。 flow可以在代码运行前对类型错误进行检查,包括: 类型错误 对 null 的引用 以及可怕的 “undefined is not a function” flow 允许我们给变量添加类型 快速上手 //初始化项目配置(我这是用yarn,npm之后补充) yarn init -yes //安装flow yarn add flow-bin -dev //初始化flow 获取初始化flow配置文件 yarn flow init 在用vs c
Flow 简单使用
mikechenmj的博客
11-14 1979
Flow 简单使用
Android】之 Flow使用和浅析
热门推荐
yang553566463的博客
06-01 1万+
Google 推荐在 MVVM 架构中使用 Kotlin Flow,可见其发展前景是相当好的。Kotlin Flow 可以用于替换 Rxjava,也可以用于替换 LiveData,功能十分强大,它是 Kotlin 协程库提供的一部分功能,因此,如果我们项目中已经引用了 Kotlin 协程,则不需要额外引入 Flow 相关的依赖。在协程中,挂起函数最多仅能返回一个值,而数据流 Flow 可按顺序发出多个值,例如,我们可以通过数据流从数据库中实时接收更新。数据流使用挂起函数通过异步方式生成和使用值,也就是说,数
flow 使用详解 + 小结
GoldenaArcher的博客
06-27 4183
出现 flow 这种静态检查的工具是与 JavaScript 的使用有些关系的——这是一种弱类型同事是动态类型的语言。这就造成了 JavaScript 会有一些比较哪恼人的特性,如可以不声明直接使用,又比如在运行时动态的决定变量的类型,如: // 未声明就是用 a = 10; // 可以运行,不会有问题 a = 'hello world'; // 修改了 a 的类型,但是也没有问题,不会报错 这种特性在个人项目中可能不是问题,还是写起来会很方便的一个特点。但是一旦项目体量比较大了,那么实现起来就会有不便之
PX4FLOW-光流传感器入门说明 详细介绍怎么使用 驱动的安装等等
07-06
PX4FLOW-光流传感器入门说明 详细介绍怎么使用 驱动的安装等等 X4FLOW驱动的安装 PX4 FLOW的 Windows驱动下载:px4 win drivers.zip,下载后解压备用 安装步骤:PX4FLW光流传感器插到WN7系统电脑上,会显小两个未知的PX4...
vue项目配置使用flow类型检查的步骤
11-21
下面将详细介绍 Vue 项目中使用 Flow 的配置步骤和使用方法。 首先,安装 Flow。在终端中使用 npm 或 yarn 命令安装 Flow: ```bash npm install --save-dev flow-bin ``` 同时,由于 Flow 的类型注解需要被 ...
FLOW-3D-v11-1-user-manual_难得的FLOW-3D原版手册_flow_flow3dv11user_flow
09-11
FLOW-3D v11.1 用户手册》是一份非常珍贵的资源,它详尽地介绍FLOW-3D软件的使用方法和技术细节。FLOW-3D是一款强大的三维流体动力学模拟软件,广泛应用于水利、环境工程、海洋工程、航空航天、能源等领域,通过...
Stateflow使用C语言结构体,关于使用Stateflow调用外部C代码的教程介绍
weixin_34947914的博客
05-25 2273
无论是Simulink仿真,还是对模型做代码生成,已有C代码的调用都是我们经常会遇到的情形:如何调用现有的外部C代码?很多人首先想到的是S-Function。的确,S-Function提供了一种途径,可以让我们把C函数封装成Simulink模块在Simulink环境下运行。另外还有一种方式,叫做Legacy Code Tool,说白了也是S-Function,只是MATLAB提供了这样的接口便于用...
flow的简单使用
linshaolie
03-30 1338
Flow 是 Facebook 旗下一个为 JavaScript 进行静态类型检测的检测工具。它可以在 JavaScript 的项目中用来捕获常见的 bugs,比如隐式类型转换,空引用等等。
协程三部曲之③:Flow使用
承香墨影的博客
07-02 2438
Hi,大家好,这里是承香墨影!今天继续给大家分享来自作者「九心」 Kotlin 的协程系列的第三篇。Google 一直在推 Kotlin,在 Android Jetpack 中也是使用 K...
Spring Web Flow 入门demo(一)简单页面跳转 附源码
kevin_xiang的专栏
10-22 700
Spring Web Flow 入门demo(一)简单页面跳转 附源码 Spring Web Flow (SWF)是Spring Framework的一个脱离模块。这个模块是Spring Web应用开发模块栈的一部分,Spring Web包含Spring MVC。 Spring Web Flow的目标是成为管理Web应用页面流程的最佳方案。当你的应用需要复杂的导航控制,例如向导,在
Android—Kotlin-Flow异步流超详细讲解
qq_30382601的博客
12-10 5482
前言 本来这一篇准备写Jetpack对应的paging的,但在整理资料的时候,发现Kotlin还有Flow未讲解,这个也是一大重点,因此本篇将对Flow进行详解!
(原创)Flow数据流的使用
Android_xiong_st的博客
01-05 2018
Flow翻译过来,是“流”的意思
stateflow介绍
05-15
Stateflow提供了一个图形化界面,允许用户使用状态图和状态转换来描述系统的行为,然后自动生成对应的代码。这些状态图和状态转换可以用来描述系统的状态,事件和行为,并且可以与Simulink模型集成,实现系统的模拟...
写文章

热门文章

  • Android面试:整理了Android面试官最常问的26道面试题 ,教你吊打面试官 35367
  • 全网最全最通俗易懂的Android Framework知识点汇总,入门到精通,完全学会 9334
  • Android程序员掌握音视频开发,再冷的寒冬也不怕 6187
  • Android音视频开发这么吃香吗?一个悄然兴起的高收入职业 4785
  • 腾讯资深架构师分享Android程序员初中级到高级进阶宝典 4679

分类专栏

  • Android 148篇
  • Android面试 118篇
  • Android开发 102篇
  • 程序员 86篇
  • 技术提升 16篇
  • 面试准备 12篇
  • 面试 32篇
  • flutter 2篇
  • 性能优化 3篇
  • Kotlin 7篇
  • 网易 1篇
  • 抖音 1篇
  • Tencent 1篇
  • 源码 2篇

最新评论

  • Android面试:整理了Android面试官最常问的26道面试题 ,教你吊打面试官

    qq_27426639: RGB_565不是RBG

  • 全网最全最通俗易懂的Android Framework知识点汇总,入门到精通,完全学会

    用心学习,学无止境: 你的回答很重要,预防了后面的中招;表情包

  • 全网最全最通俗易懂的Android Framework知识点汇总,入门到精通,完全学会

    dec_AS: 骗人的,加了微信之后说要vip才能领取,骗人充会员不是免费领取的

  • Jetpack Compose - 一文了解清楚神秘的CompositionLocal

    雨人来: 讲得很明了

  • Android面试:整理了Android面试官最常问的26道面试题 ,教你吊打面试官

    haijunhaijun1987: 表情包

大家在看

  • python内置函数大全 731
  • vue-springboot基于JavaWeb的智慧养老院管理系统的设计与实现 附源码
  • 浏览器和服务端的通信协议 643
  • 迷宫的路径? 38
  • 【AI声音】曼波音效,心月AI变声器简易教程 533

最新文章

  • Android开发者如何积累和利用经验,以应对技术的半衰期呢?
  • 在Android开发领域,如何通过不断学习与技能提升,保持职业竞争力?
  • 趋近饱和的移动App市场下Android开发的发展路径
2024
07月 5篇
06月 4篇
05月 11篇
04月 12篇
03月 14篇
02月 10篇
2023年95篇
2022年171篇
2021年31篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家江苏景观灯玻璃钢花盆北京节庆商场美陈订购玻璃钢佛像雕塑供应浙江商业商场美陈哪家好玻璃钢雕塑设计价格表呈贡玻璃钢大型雕塑设计哪里有卖重庆玻璃钢雕塑考拉批发白银景区玻璃钢雕塑价格贵港商场美陈雕塑江苏装饰商场美陈订购上海商场美陈市场报价朝阳动物玻璃钢雕塑厂家曲阳玻璃钢花盆厂家玻璃钢花盆结实吗厦门玻璃钢雕塑销售丽水玻璃钢景观雕塑邵阳仿铜玻璃钢雕塑生产厂家杭州夏季商场美陈惠州发光小品玻璃钢雕塑摆件青岛景区玻璃钢雕塑公司阳江玻璃钢动物雕塑商家通州区商场大门圣诞美陈上海室内商场美陈供应新乡玻璃钢花盆花器信阳玻璃钢浮雕雕塑厂家玻璃钢雕塑定制吉祥物摆件大型卡苏州商场开业美陈金华小区玻璃钢雕塑制作湖北公园玻璃钢雕塑联系方式玻璃钢雕塑是什么香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化