Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

2024-07-04 1219阅读

emit(“value2”)

delay(1000)

emit(“value3”)

}

val flow = flowOf(“value”)

val flow = listOf(1, 2, 3).asFlow()

  • 收集Flow----collect()

    由于 collect 是挂起函数,因此需要在协程中执行

    scope.launch {

    flow.collect {

    LogUtil.e(it)

    }

    }

    • 转换Flow----map()

      flowOf(1, 2, 3).map {

      “第$it 个”

      }.collect {

      LogUtil.e(it)

      }

      • 过滤Flow----filter()

        flowOf(1, 2, 3).filter {

        it > 1

        }.collect {

        LogUtil.e(it)

        }

        • 合并Flow

          zip操作符会把 flow1 中的一个 item 和 flow2 中对应的一个 item 进行合并,如果 flow1 中 item 个数大于 flow2 中 item 个数,合并后新的 flow 的 item 个数 = 较小的 flow 的 item 个数

          val flow1 = flowOf(1, 2, 3, 4, 5)

          val flow2 = flowOf(“一”, “二”, “三”, “四”, “五”, “六”)

          flow1.zip(flow2) { a, b ->

          “ a − − − a--- a−−−b”

          }.collect {

          LogUtil.e(it)

          }

          combine合并时,每次从 flow1 发出新的 item ,会将其与 flow2 的最新的 item 合并

          val flow1 = flowOf(1, 2, 3, 4, 5).onEach { delay(1000) }

          val flow2 = flowOf(“一”, “二”, “三”, “四”, “五”, “六”).onEach { delay(500) }

          flow1.combine(flow2) { a, b ->

          “ a − − − a--- a−−−b”

          }.collect {

          LogUtil.e(it)

          }

          • 捕获异常----catch()

            flow {

            emit(1)

            emit(1 / 0)

            emit(2)

            }.catch {

            it.printStackTrace()

            }.collect {

            LogUtil.e(it)

            }

            • 线程切换----flowOn()

              withContext(Dispatchers.IO){

              flowOf(1, 2, 3, 4).onEach {

              //受到下面最近的flowOn控制-Main

              LogUtil.e(“init—KaTeX parse error: Expected 'EOF', got '}' at position 33: …read().name}") }̲.filter { //受到下…{Thread.currentThread().name}”)

              it > 1

              }.flowOn(Dispatchers.Main).map {

              //受到下面最近的flowOn控制-IO

              LogUtil.e(“map— T h r e a d . c u r r e n t T h r e a d ( ) . n a m e " ) " 第 {Thread.currentThread().name}") "第 Thread.currentThread().name")"第it”

              }.flowOn(Dispatchers.IO).map {

              //受到下面最近的flowOn控制-Main

              LogUtil.e(“第二次map— T h r e a d . c u r r e n t T h r e a d ( ) . n a m e " ) " {Thread.currentThread().name}") " Thread.currentThread().name")"it 个结果”

              }.flowOn(Dispatchers.Main).collect {

              //collect要看整个flow处于哪个线程,此处为IO

              LogUtil.e(“collect—${Thread.currentThread().name}”)

              LogUtil.e(it)

              }

              }

              • 转为liveData----asLiveData()

                添加依赖

                “androidx.lifecycle:lifecycle-livedata-ktx:${LibraryVersion.LIVEDATA_KTX}”

                flowOf(1, 2, 3, 4).asLiveData().observe(viewLifecycleOwner, Observer {

                LogUtil.e(it)

                })

                更多操作符

                本地保存 DataStore

                DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。 参考鸿洋的公众号内容

                SharedPreferences存在的问题
                • 通过 getXXX() 方法获取数据,可能会导致主线程阻塞
                • SharedPreference 不能保证类型安全
                • SharedPreference 加载的数据会一直留在内存中,浪费内存
                • apply() 方法虽然是异步的,可能会发生 ANR,在 8.0 之前和 8.0 之后实现各不相同
                • apply() 方法无法获取到操作成功或者失败的结果
                  DataStore 解决了什么问题
                  • DataStore 是基于 Flow 实现的,所以保证了在主线程的安全性
                  • 以事务方式处理更新数据,事务有四大特性(原子性、一致性、 隔离性、持久性)
                  • 没有 apply() 和 commit() 等等数据持久的方法
                  • 自动完成 SharedPreferences 迁移到 DataStore,保证数据一致性,不会造成数据损坏
                  • 可以监听到操作成功或者失败结果
                  • 另外 Jetpack DataStore 提供了 Proto DataStore 方式,用于存储类的对象(typed objects ),通过 protocol buffers 将对象序列化存储在本地,protocol buffers 现在已经应用的非常广泛,无论是微信还是阿里等等大厂都在使用
                    DataStore使用

                    添加依赖

                    const val DATA_STORE = “1.0.0-alpha05”

                    const val PROTOBUF = “3.11.0”

                    “androidx.datastore:datastore-preferences: L i b r a r y V e r s i o n . D A T A S T O R E " / / p r o t o b u f 需下面的依赖 " a n d r o i d x . d a t a s t o r e : : d a t a s t o r e − c o r e : {LibraryVersion.DATA_STORE}" //protobuf需下面的依赖 "androidx.datastore::datastore-core: LibraryVersion.DATAS​TORE"//protobuf需下面的依赖"androidx.datastore::datastore−core:{LibraryVersion.DATA_STORE}”

                    “com.google.protobuf:protobuf-java:${LibraryVersion.PROTOBUF}”

                    保存键值对

                    object DataStore {

                    private const val APP_DATA_STORE_NAME = “APP_DATA_STORE_NAME”

                    private lateinit var dataStore: DataStore

                    fun init(context: Context) {

                    dataStore = context.createDataStore(APP_DATA_STORE_NAME)

                    }

                    suspend fun save(key: Preferences.Key, value: T) {

                    dataStore.edit {

                    it[key] = value

                    }

                    }

                    suspend fun get(key: Preferences.Key): T? {

                    val value = dataStore.data.map {

                    it[key]

                    }

                    return value.first()

                    }

                    }

                    保存

                    CoroutineScope(scope).launch {

                    DataStore.save(preferencesKey(“key1”), “aa”)

                    }

                    读取

                    CoroutineScope(scope).launch {

                    val get = DataStore.get(preferencesKey(“key1”))

                    }

                    保存protobuf

                    protobuf相关知识不在这里展开叙述

                    • 定义.proto文件

                      syntax = “proto3”;

                      option java_package = “com.haikun.jetpackapp.home.ui.demo.datastore.bean”;

                      option java_multiple_files = true;

                      message MessageEvent {

                      int32 type = 1;

                      string message = 2;

                      }

                      • 编译文件

                        编译后得到下图三个文件

                        Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                        • 定义Serializer

                          object MessageSerializer : Serializer {

                          override val defaultValue: MessageEvent

                          get() = MessageEvent.getDefaultInstance()

                          override fun readFrom(input: InputStream): MessageEvent {

                          return MessageEvent.parseFrom(input)

                          }

                          override fun writeTo(t: MessageEvent, output: OutputStream) {

                          t.writeTo(output)

                          }

                          }

                          • 保存

                            val createDataStore = context?.createDataStore(“data”, MessageSerializer)

                            createDataStore?.updateData {

                            it.toBuilder().setType(12).setMessage(“消息”).build()

                            }

                            • 读取

                              CoroutineScope(scope).launch {

                              context?.createDataStore(“data”, MessageSerializer)?.data?.first()?.let {

                              LogUtil.e(“ i t . t y p e − − − {it.type}--- it.type−−−{it.message}”)

                              }

                              }

                              声明式UI DataBinding

                              数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源,可以使用 LiveData 对象作为数据绑定来源,自动将数据变化通知给界面

                              声明式UI VS 命令式UI
                              • 声明式UI 只需要把界面给「声明」出来,而不需要手动更新,只要声明的数据发生了变化,UI就跟着变化

                              • 命令式UI 需要主动让UI更新,比如setText()

                                DataBinding使用
                                开启DataBinding

                                android {

                                dataBinding {

                                enabled = true

                                }

                                }

                                基本用法
                                • 在ViewModel中定义数据和方法

                                  class DataBindingViewModel : ViewModel() {

                                  val userName = MutableLiveData()

                                  val clickTimes = MutableLiveData()

                                  val sexCheckId = MutableLiveData()

                                  val love = MutableLiveData()

                                  fun save(){

                                  LogUtil.e(“ u s e r N a m e . v a l u e − − − {userName.value}--- userName.value−−−{sex.value}—${love.value}”)

                                  }

                                  }

                                  • xml中引用和调用

                                    • Fragment

                                      class DataBindingFragment : Fragment() {

                                      private val mViewModel: DataBindingViewModel by viewModels()

                                      override fun onCreateView(

                                      inflater: LayoutInflater,

                                      container: ViewGroup?,

                                      savedInstanceState: Bundle?

                                      ): View {

                                      val dataBinding = DataBindingUtil.inflate(

                                      inflater,

                                      R.layout.fragment_data_binding,

                                      container,

                                      false

                                      )

                                      //使用liveData必须要设置lifecycleOwner,否则无法更新数据

                                      dataBinding.lifecycleOwner = viewLifecycleOwner

                                      dataBinding.viewModel = mViewModel

                                      return dataBinding.root

                                      }

                                      }

                                      进阶用法
                                      • BindingMethods 绑定方法名

                                        @BindingMethods(value = [BindingMethod(type = MyButton::class, attribute = “maxTimes”, method = “setMaxTimes”)])

                                        xml中使用

                                        app:maxTimes=“@{15}”

                                        • BindingAdapter 提供自定义逻辑

                                          一些属性需要自定义绑定逻辑。例如,android:paddingLeft 特性没有关联的 setter,而是提供了 setPadding(left, top, right, bottom) 方法。使用 BindingAdapter 注释的静态绑定适配器方法支持自定义特性 setter 的调用方式。

                                          object ViewAdapter {

                                          @BindingAdapter(“minTimes”)

                                          @JvmStatic

                                          fun setMinTimes(view: MyButton, minTimes: Int) {

                                          view.setMin(minTimes)

                                          }

                                          }

                                          xml中使用

                                          app:minTimes=“@{8}”

                                          • 自定义双向绑定

                                            @InverseBindingAdapter(attribute = “clickTimes”)

                                            @JvmStatic

                                            fun getClickTimes(view: MyButton): Int {

                                            return view.clickTimes

                                            }

                                            @BindingAdapter(“clickTimesAttrChanged”)

                                            @JvmStatic

                                            fun setListener(view: MyButton, listener: InverseBindingListener?) {

                                            view.onTimesChangeListener = {

                                            listener?.onChange()

                                            }

                                            }

                                            xml使用

                                            app:clickTimes=“@={viewModel.clickTimes}”

                                            Compose----android声明式UI未来的趋势
                                            • 2019 年中,Google 在 I/O 大会上公布了 Android 最新的 UI 框架:Jetpack Compose。Compose 可以说是 Android 官方有史以来动作最大的一个库了。它在 2019 年中就公布了,但要到今年也就是 2021 年才会正式发布。这两年的时间 Android 团队在干嘛?在开发这个库,在开发 Compose。一个 UI 框架而已,为什么要花两年来打造呢?因为 Compose 并不是像 RecyclerView、ConstraintLayout 这种做了一个或者几个高级的 UI 控件,而是直接抛弃了我们写了 N 年的 View 和 ViewGroup 那一套东西,从上到下撸了一整套全新的 UI 框架。直白点说就是,它的渲染机制、布局机制、触摸算法以及 UI 的具体写法,全都是新的。
                                            • 第一眼看到Compose,第一感觉就是觉得和Flutter的写法惊人的相似,Compose需要系统的学习,而且需要较高的学习成本,不在这里展开叙述
                                            • Compose只支持kotlin,并且目前需要用Canary版本的android studio进行开发

                                              数据库 Room

                                              Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库 Room可以和kotlin协程/flow结合使用 Room可以和LiveData结合使用

                                              Room 包含 3 个主要组件:

                                              • 数据库:包含数据库持有者,并作为应用已保留的持久关系型数据的底层连接的主要接入点。
                                              • Entity:表示数据库中的表。
                                              • DAO:包含用于访问数据库的方法。
                                                添加依赖

                                                implementation “androidx.room:room-runtime: r o o m v e r s i o n " k a p t " a n d r o i d x . r o o m : r o o m − c o m p i l e r : room_version" kapt "androidx.room:room-compiler: roomv​ersion"kapt"androidx.room:room−compiler:room_version”

                                                implementation “androidx.room:room-ktx:$room_version”

                                                基本用法
                                                • 定义Entity

                                                  @Entity

                                                  data class Car(

                                                  @PrimaryKey(autoGenerate = true) val id: Long,

                                                  var name: String,

                                                  val color: String,

                                                  )

                                                  @PrimaryKey 主键 类名就是表名,也可以在@Entity(table=)设置表名 可以使用@Ignore忽略某个字段

                                                  • 定义Dao

                                                    @Dao

                                                    interface CarDao {

                                                    @Insert(onConflict = OnConflictStrategy.REPLACE)

                                                    fun insertCar(car: Car):Long

                                                    @Delete

                                                    fun deleteCar(car: Car)

                                                    @Update

                                                    fun updateCar(car: Car)

                                                    @Query(“SELECT * From Car”)

                                                    fun queryCarList(): MutableList

                                                    @Query(“Select * from Car where id=:id”)

                                                    fun queryCarById(id: Long): Car?

                                                    }

                                                    • 定义Database

                                                      @Database(entities = [Car::class], version = 1,exportSchema = false)

                                                      abstract class DemoDatabase : RoomDatabase() {

                                                      abstract fun carDao(): CarDao

                                                      }

                                                      • 创建Database和获取Dao

                                                        private val db: DemoDatabase by lazy {

                                                        Room.databaseBuilder(

                                                        JetpackApp.getContext(),

                                                        DemoDatabase::class.java, “demo-database”

                                                        ).build()

                                                        }

                                                        private val carDao: CarDao by lazy {

                                                        db.carDao()

                                                        }

                                                        • 增删改查

                                                          carDao.insertCar(car)

                                                          carDao.delete(car)

                                                          carDao.updateCar(car)

                                                          val car = carDao.queryCarById(mUpdateId)

                                                          Room并不支持在主线程访问数据库, 除非在Builder调用allowMainThreadQueries()方法, 因为它很可能将UI锁上较长一段时间. 但是, 异步查询–返回LiveData/Flowable实例的查询–则从此规则中免除, 因为它们在需要的时候会在后台线程异步地运行查询.

                                                          • 使用Flow流进行响应式查询

                                                            只要表中的任何数据发生变化,返回的 Flow 对象就会再次触发查询并重新发出整个结果集。

                                                            使用 Flow 的响应式查询有一个重要限制:只要对表中的任何行进行更新(无论该行是否在结果集中),Flow 对象就会重新运行查询。通过将 distinctUntilChanged() 运算符应用于返回的 Flow 对象,可以确保仅在实际查询结果发生更改时通知界面:

                                                            @Query(“Select * From Car where id = :id”)

                                                            fun queryCarAsFlowById(id: Long): Flow

                                                            fun queryCarAsFlowByIdDistinctUntilChanged(id: Long): Flow =

                                                            queryCarAsFlowById(id).distinctUntilChanged()

                                                            • 使用 Kotlin 协程进行异步查询

                                                              将 suspend Kotlin 关键字添加到 DAO 方法中,以使用 Kotlin 协程功能使这些方法成为异步方法。这样可确保不会在主线程上执行这些方法。

                                                              • 使用 LiveData 进行可观察查询

                                                                @Query(“Select * From Car where id = :id”)

                                                                fun queryCarAsLiveDataById(id: Long): LiveData

                                                                对象之间的关系
                                                                嵌套关系
                                                                一对一
                                                                一对多
                                                                多对多

                                                                以一对多为例

                                                                • 定义Entity和关系

                                                                  @Entity

                                                                  data class One(@PrimaryKey(autoGenerate = true) val id: Long, val name: String)

                                                                  @Entity

                                                                  data class More(@PrimaryKey(autoGenerate = true) val id: Long, val oneId: Long, val name: String)

                                                                  data class OneAndMore(

                                                                  @Embedded val one: One,

                                                                  @Relation(

                                                                  parentColumn = “id”,

                                                                  entityColumn = “oneId”

                                                                  ) val moreList: MutableList

                                                                  )

                                                                  • 定义Dao

                                                                    添加 @Transaction 注释,以确保整个操作以原子方式执行。

                                                                    @Transaction

                                                                    open fun insertOneAndMore(){

                                                                    val one = One(0, “OneName”)

                                                                    val insertOneId = insertOne(one)

                                                                    val more = More(0, insertOneId, “moreName1”)

                                                                    val more1 = More(0, insertOneId, “moreName2”)

                                                                    insertMore(more)

                                                                    insertMore(more1)

                                                                    }

                                                                    @Transaction

                                                                    @Query(“Select * from One”)

                                                                    abstract fun queryOneAndMore():MutableList

                                                                    使用类型转换器处理复杂数据

                                                                    有时需要使用自定义数据类型,其中包含想要存储到单个数据库列中的值。TypeConverter可以在自定义类与 Room 可以保留的已知类型之间来回转换。

                                                                    例如需要把一个包含List的对象保存到数据库

                                                                    • 定义Entity

                                                                      @Entity

                                                                      data class ComplexEntity(

                                                                      @PrimaryKey val id: Long,

                                                                      val list: MutableList

                                                                      )

                                                                      • 定义Converter

                                                                        class Converters {

                                                                        @TypeConverter

                                                                        fun fromJson(value: String): MutableList? {

                                                                        val types =

                                                                        Types.newParameterizedType(MutableList::class.java, OneAndMore::class.java)

                                                                        return MoshiInstance.moshi.adapter(types).fromJson(value)

                                                                        }

                                                                        @TypeConverter

                                                                        fun toJson(list: MutableList): String {

                                                                        val types =

                                                                        Types.newParameterizedType(MutableList::class.java, OneAndMore::class.java)

                                                                        return MoshiInstance.moshi.adapter(types).toJson(list)

                                                                        }

                                                                        }

                                                                        • 添加Converter到Database

                                                                          @TypeConverters(Converters::class)

                                                                          abstract class DemoDatabase : RoomDatabase()

                                                                          • Dao

                                                                            @Insert

                                                                            abstract fun insertComplexEntity(complexEntity: ComplexEntity)

                                                                            @Query(“Select * from ComplexEntity”)

                                                                            abstract fun queryComplexEntity():MutableList

                                                                            依赖注入 Koin

                                                                            参考 依赖项注入 (DI) 是一种广泛用于编程的技术,Hilt、Dagger、Koin 等等都是依赖注入库,依赖注入是面向对象设计中最好的架构模式之一,使用依赖注入库有以下优点:

                                                                            自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

                                                                            深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

                                                                            因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

                                                                            由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

                                                                            如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            要如何成为Android架构师?

                                                                            搭建自己的知识框架,全面提升自己的技术体系,并且往底层源码方向深入钻研。

                                                                            大多数技术人喜欢用思维脑图来构建自己的知识体系,一目了然。这里给大家分享一份大厂主流的Android架构师技术体系,可以用来搭建自己的知识框架,或者查漏补缺;

                                                                            Android kotlin Jetpack mvvm 项目,Android插件化主流框架和实现原理

                                                                            对应这份技术大纲,我也整理了一套Android高级架构师完整系列的视频教程,主要针对3-5年Android开发经验以上,需要往高级架构师层次学习提升的同学,希望能帮你突破瓶颈,跳槽进大厂;

                                                                            最后我必须强调几点:

                                                                            1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。

                                                                            2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识

                                                                            3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。

                                                                            你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境

                                                                            本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

                                                                            一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

                                                                            AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

                                                                            ndroid高级架构师完整系列的视频教程,主要针对3-5年Android开发经验以上,需要往高级架构师层次学习提升的同学,希望能帮你突破瓶颈,跳槽进大厂;

                                                                            最后我必须强调几点:

                                                                            1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。

                                                                            2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识

                                                                            3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。

                                                                            你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境

                                                                            本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

                                                                            一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

                                                                            AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]