当前位置: 首页 > news >正文

网站备案要邮寄资料吗中国建设银行西平支行网站

网站备案要邮寄资料吗,中国建设银行西平支行网站,网站无障碍建设报告,php网站开发和部署由于安卓已经诞生快二十载#xff0c;其最初的开发思想与现代的开发思想已经大相径庭#xff0c;特别是Jetpack库诞生之后#xff0c;项目中存在着新老思想混杂的情况#xff0c;让许多的新手老手都措手不及#xff0c;项目大步向屎山迈进。为了解决这个问题#xff0c;开…由于安卓已经诞生快二十载其最初的开发思想与现代的开发思想已经大相径庭特别是Jetpack库诞生之后项目中存在着新老思想混杂的情况让许多的新手老手都措手不及项目大步向屎山迈进。为了解决这个问题开发者必须弄懂新旧两种开发模式这就是《安卓现代化开发系列》诞生的意义本系列并不会包含隐晦难懂的代码一切的文字都是以理解本质为主起到一个抛钻引玉的作用。 生命周期的前世今生 1.1、前世——初识篇 天地初开一切皆为混沌的时代安卓宇宙中诞生了名为Activity活动的组件Activity 是Android应用中最关键的组件一个Activity 通常对应的是App的一个页面当手机使用者在不同的页面之间导航的时候新的Activity 会诞生同时也会在特定的时候销毁。一个页面的诞生之初到它销毁的这段时间名为「生命周期」。 理解并掌握生命周期是每一个Android修炼者的必修功力因为生命周期的每一个阶段均代表Activity 处于不同的状态之中一旦错误处理生命周期周期修炼者轻则内伤残疾手机耗电过多丢失信息重则走火入魔程序崩溃。 关于生命周期江湖中一直流传着一张「Activity生命周期总览图」但个中奥秘却鲜为人知因此少有人能够修炼到最高境界 由图可见Activity的生命周期中提供了6种回调onCreate()、onStart()、onResume()、onPause()、onStop()、onDestroy() 需要特别注意的是这仅仅是一种回调与我们通常的认识不同都是生命周期的某个阶段是指一个时间段 而回调或者说事件只是一个瞬间换句话来说onCreate并不是指生命周期中存在一个阶段名为onCreate而是Activity 触发了onCreate事件即将进入已创建阶段。 然而可惜的是在远古Android的设计中Android的创世神并没有为开发者提供具体的生命周期阶段的概念仅仅是提供了进入某个生命周期阶段的回调因此上述提到的“已创建”这个状态在原生安卓的概念中并不存在。然而在后人的努力中生命周期阶段这一概念最终得到确定与落实不过这都是后话了。 1.2、前世——详解篇 1.2.1、onCreate()、onDestroy() onCreate() Activity 生命周期的起点首次被系统创建时触发整个生命周期只会触发一次。此回调通常用于执行页面View的设置例如setContentView()。onDestroy() Activity生命周期的终点在Activity被销毁前触发此回调的有两种情况被调用 用户手动关闭Activity按返回键或者系统主动关闭Activity一般是App进程因内存不足被销毁导致Activity也被销毁。配置变更设备旋转、语言切换等。 简单来说onCreate()是Activity被创建的时刻onDestroy()是Activity即将被销毁的时刻。 一个Activity进入onDestroy() 之后理应被GC回收但是如果此时它仍然被引用例如被某些网络请求的回调中被引用那么此Activity就会导致内存泄漏 这也是所有Android开发者需要关注其生命周期的原因。 1.2.2、onStart()、onStop() onStart() 当Activity在onCreate()之后不久就会触发此回调说明了Activity 此刻进入了“已开始”的状态但是此刻的Activity仍然未获取焦点。 很多Android开发者一直搞不懂Activity为什么会存在一个可见但是没有获取焦点的状态会存在这种疑惑的原因是因为Android通常作为一种移动设备的系统而存在而移动设备由于其特殊性通常也只会同屏存在一个页面因此可见但是没有获取焦点这种状态几乎只存在一瞬间它马上就会遮住之前正在交互的页面然而我们以电脑系统的角度来看电脑系统的桌面上基本都是多窗口并存的然而即使存在了多窗口用户能交互的也仅仅只有获取焦点的那个窗口。 因此可见但是没有获取焦点的窗口就像是电脑上那些打开着、但被用户正在交互的窗口挡住的那些窗口假如电脑桌面上存在着一个QQ窗口然而用户正在编写一个Word文档那么被Word挡住的那个QQ窗口就是可见但未获取焦点的窗口。 onStop() 当一个Activity从可见但是没有获取到焦点的状态变为完全不可见的状态时就会触发此回调按照上文类比这种情况通常可以理解为电脑桌面上的一个被遮挡的窗口被最小化了。 1.2.3、onResume()、onPause() onResume() 当Activity从可见但是没有获取焦点的状态变成可见同时获取焦点的状态时触发此回调同样按照电脑系统的角度来理解这种情况通常可以理解为电脑桌面上的一个被遮挡的窗口此刻被用户交互了。onPause() 当Activity从“可见同时获取焦点”的状态变成可见但是没有获取焦点的状态时触发此回调同样同样按照电脑系统的角度来理解这种情况通常可以理解为电脑桌面上的一个正在被用户交互的窗口由于用户操作了其他窗口导致当前的窗口被遮挡了也因此失去了焦点。 1.3、前世——总结篇 我们从电脑系统的窗口去理解Activity的生命周期 启动一个程序的时候程序就会在电脑桌面上创建一个窗口创建的那一瞬间通常会很快可能不需要1秒就相当于Activity的onCreate()。创建完成后窗口就可以被用户所看见了被用户看到的那一瞬间就相当于Activity的onStart()。通常来说一个新启动的程序会自动获得焦点并可被用户交互因此onStart()之后窗口会被置顶到顶层这一瞬间就相当于Activity的onResume()。当用户选择其他窗口时之前交互的窗口并不会消失而是会失去焦点并被用户最新交互的窗口所遮挡这一瞬间就相当于Activity的onPause()。当用户最小化窗口时窗口就会进入后台并不是销毁而且并不能被用户所看见这一瞬间就相当于进入了Activity的onStop()。当用户关闭程序亦或者电脑内存不足时程序被销毁窗口同时也被销毁了这一瞬间就相当于进入了Activity的onDestroy()。 一个窗口当然可以失去焦点后重新获取焦点因此onPause()和onResume()可能在生命周期中多次被执行同理窗口也可以最小化之后重新最大化onStart()和onStop()也可能在生命周期中多次被执行。只不过对于移动设备来说几乎不存在页面失去焦点后又重新获得焦点的情况因为移动设备的页面绝大多数情况都是一个页面可被用户交互被挡住的页面完全不可见即等价于电脑系统中只存在一个最大化的页面所以移动设备的Activity的生命周期通常只会在onStart()和onStop()两者之间流转当然仍然会遵循onStart()-onResumt()-onPause()-onStop()的顺序。 而一个窗口只能被创建和销毁一次因此在Activity的生命周期中onCreate()和onDestroy()只会被调用一次。 上文中提到原生的Android生命周期设计中只提供了进入某个生命周期状态的回调并没有提供具体的状态的定义例如onCreate() 与onStart()之间的状态叫什么呢官方的文档提到了这个叫“已创建”的状态然而这只存在于文本性的文档中这在代码中并不存在只能作为一种“共识”的定义。这也为开发者之间沟通生命周期带来了极大的困扰。 2.1、今生——初识篇 经历漫长的混沌时代之后Jetpack携带着「Lifecycle」正式进入到了Android的世界中「Lifecycle」为千千万万的Android修炼者带来了福音因为它比起传统的基于回调的方式来感知生命周期的方式有以下的优点 提出了「生命周期状态」的概念弥补了安卓传统的生命周期只有事件没有状态的缺陷将生命周期管理从页面如Activity和Fragment脱离将生命周期监听的职责转移到组件中降低页面与组件的耦合度。 为了让读者更加清晰使用「Lifecycle」与不使用它之间的区别这里使用两个代码案例来对比 首先定义一个常见的基于回调的监听类每秒钟会对外广播一次字符串。 在Activity中的onCreate()阶段初始化监听然后在onStart()中开启监听在onStop()中关闭监听这样的好处是当页面不可见的时候不会浪费手机性能。 以上便是传统安卓开发中最直接也是最常见的一种根据生命周期来实现监听的方式让我们分析一下这种方式的缺点 真实业务开发中同一页面中往往存在大量的生命周期监听需求Activity等生命周期组件会同时管理大量的组件让代码难以维护。代码缺乏一致性需要监听生命周期的组件存在许多模板代码。试想一下一个需要在onStart()启动在onStop()关闭的、同时在项目中大量存在的组件某天需要它在onResume()做一些操作那将会导致灾难因为需要每一处使用它的代码中增加onResume()的修改一旦遗漏这个修改将会导致不可预知的bug。无法获取实时的生命周期状态。假设在onStart()的阶段需要执行一个网络请求或者其他耗时操作之后再调用listener.start()的场景下无法保证此刻页面仍然处于可见的状态开发者也无法获取「当前所处状态」来避免不可见的时候仍然调用listener.start()这个缺陷上文已经提到原生安卓生命周期只提供了生命周期事件而没有生命周期状态。 让我们看一看使用了「Lifecycle」库之后的生命周期是如何实现监听的 我们让需要监听Activity生命周期的MyListener组件实现DefaultLifecycleObserver接口然后重写onStart()、onStop()方法然后直接在Activity中获取lifecycle然后调用其addObserver()即可。 我们会发现「生命周期管理」的责任从Activity转移到了组件中Activity本身只负责对外广播自身的生命周期这样极大减少了Activity的维护负担。 2.2、今生——详解篇 2.2.1、Lifecycle(opens new window) Lifecycle包含两个定义一个指的是Jetpack库中的Lifecycle组件库一个指的是Lifecycle组件库中的一个核心类后文中如果没有特指情况下文章中描述的默认为类 上文中提到安卓原生中只有描述生命周期的事件缺乏一种描述当前生命周期所处的状态但是「Lifecycle」库中补全了状态下图中阐述了事件与状态的关系 根据「Lifecycle」库的定义一个生命周期状态的起点是「Initialized」终点是「Destroyed」当发生生命周期事件时生命周期状态就会发生移动包括状态提升和状态下降。 我们把状态从Initialized到Resumed当做一个从小到大的状态如果状态值变小了则称为状态下降反之则为状态提升。 初步的定义有了让我们把视角聚焦于Lifecycle类的源码 可以看到Lifecycle类的设计基本遵循生命周期事件与状态图例一个Lifecycle只有2个核心功能 缓存当前的生命周期状态currentState。添加与移除生命周期观察者。 上述代码中对Event和State的部分代码进行了省略下面展开讲解 首先是Event类Event类对应的是生命周期事件也就是原生安卓生命周期的事件即onCreate()、onPause()等。 该类提供了一个targetState的属性指的是发生了该事件之后生命周期状态发生改变的状态目标。 例如发生了ON_CREATE事件这是状态从「Initialized」向「Created」转移的瞬间那么targetState自然就是「State.CREATED」了同理发生ON_STOP事件时是状态从「Started」向「Created」转移的瞬间targetState也是「State.CREATED」。 此处不必死记硬背只需要配合状态与事件图理解其意义即可。 该类还提供了四个方法downFrom()、downTo()、upFrom()、upTo()这些都是当状态发生提升或者降级的时候方便获取对应的事件的便捷方法以downFrom()举例 downFrom(state:State)的含义是获取会导致state发生状态下降的事件假如State.Created发生什么事件会导致状态从State.Created下降呢我们回去查看状态与事件图发现是发生了ON_DESTROY事件那么该方法就会返回ON_DESTROY。 此处不必死记硬背只需要配合状态与事件图理解其意义即可。 看完了Event我们把视角转向State State的代码非常简单甚至不用一丝的省略除了枚举值外仅有一个方法isAtLeast(state:State) 此方法的含义是用于判断当前的状态是否大于或等于目标值的状态。 如何理解呢还记得上文提到的吗状态是有大小的 我们把状态从Initialized到Resumed当做一个从小到大的状态如果状态值变小了则称为状态下降反之则为状态提升。 因此对于生命周期的状态而言Created是比Initialized大的isAtLeast(state:State)的含义就是判断生命周期是否比某个预期值“走的更远”了如果一个行为可以在组件创建后被执行那么换句话说只要生命周期的状态大于或者等于Created即可。 上文中提到原生的生命周期回调无法实时获取生命周期所处的状态一旦在生命周期回调方法中执行一些耗时操作就无法耗时操作结束后仍处于安全的生命周期区间例如下面的代码 我们尝试在onStart()中执行一段耗时操作再开启监听但是执行耗时操作期间无法Activity是否已经处于onStop()了此刻我们就可以使用isAtLeast(state:State)来判断耗时操作结束后的生命周期状态 可见「Lifecycle」库确实解决了生命周期只有事件没有状态的问题开发者可以轻易获取当前的生命周期所处的阶段。 2.2.2、LifecycleOwner(opens new window) 首先我们看看它的源码 非常的简单只是给实现者对外提供一个获取Lifecycle的入口为什么要这样设计呢还记得Lifecycle吗它并不是一个接口而是一个抽象类在Jvm中是单继承的因此不太可能会让带有生命周期的组件直接继承Lifecycle抽象类。 因此在实际使用中带有生命周期的组件和Lifecycle是包含的关系即下图的情况 为什么谷歌的开发人员要如此奇怪呢让Lifecycle变成接口让Activity实现接口不一样能让组件访问到Lifecycle吗先别急Lifecycle的具体实现我们还没看等到那一节将会解答这个疑问。 总结LifecycleOwner只是一个简单的对外提供访问Lifecycle的接口。 2.2.3、LifecycleObserver(opens new window) 此处就不放代码了因为这是一个空接口作用是将其实现者变成一个生命周期的观察者。 其本身不起作用业务中我们通常使用其子接口例如DefaultLifecycleObserver、LifecycleEventObserver等可以回去查看2.1节的MyListener实现了DefaultLifecycleObserver之后是如何感知Activity的生命周期的。 2.2.4、LifecycleRegistry(opens new window) 此类是「Lifecycle」库的核心类也是Lifecycle抽象类的直接实现它的作用是管理生命周期事件的派发但是其做了非常多的优化例如解决了产生事件时迭代观察者过程中可能会新增或者移除观察者用ArrayList遍历会崩的问题、新加入的观察者如何派发事件的问题移除观察者如何更新状态的问题等等。 这些谷歌的开发人员都帮我们解决了只需要按下图简单配置一下即可使用 可见我们只需要按照上文提到的结构在Activity中实例化一个LifecycleRegistry然后在合适的生命周期回调中派发响应的事件所有监听当前Activity生命周期的组件就可以获取到当前Activity的生命周期了。 需要注意的是上述代码仅仅是为了为你展示Lifecycle是如何实现生命周期事件派发的实际使用中并不需要为Activity手动派发事件ComponentActivity、AppcompatActivity实际上已经配置好了派发逻辑开发中直接获取Lifecycle即可。 下面即将深入LifecycleRegistry的源码层面探究一下它的原理但是需要注意的是本文章的目的并不是让读者100%搞懂源码中每一行代码的运行逻辑因为这违背了本系列文章的初衷——让读者能够在对库有足够充足的了解下开发同时笔者也没有100%搞懂源码每一行的逻辑。 如果读者非常有钻研精神可以看一下这个博主的文章他对LifecycleRegistry的源码做了非常详细的讲解 下面我们看看LifecycleRegistry的代码脉络 笔者省去了绝大部分和业务无关的代码只保留了最核心最精华的代码其实被移除掉的代码都是为了解决前文中提到的“遍历过程中增删列表”、”新加入的观察者如何派发事件“等细枝末节的问题与本文主题关系不大。 可以看到LifecycleRegistry本质上就是一个强化版的观察者模式的设计添加观察者observer、遍历派发事件的模式。 还记得上文提到的一个小问题吗为什么LifecycleOwner不直接设计成接口而是以成员变量的方式挂载在对应的生命周期组件里面呢通过LifecycleRegistry的源码我们可以看到LifecycleOwner被以弱引用的方式存放着的也就是说处理生命周期事件派发的LifecycleRegistry并不会直接引用LifecycleOwner可以认为是谷歌的开发人员是为了防止产生内存泄漏而故意设计的。 2.2.5、小总结 我们已经依次浏览了「Lifecycle」库中的四个最核心的组件他们的关系如果你已经搞混了笔者再次通过一段极简的代码的方式来强化读者对他们的理解 关于四个核心组件的总结 Lifecycle描述的是存放和管理生命周期的容器LifecycleRegistry是Lifecycle的实现类LifecycleObserver是观察生命周期变化的监听器LifecycleOwner是对外提供Lifecycle的提供者。 3、谷歌眼中的Lifecycle 3.1、ComponentActivity 此类是谷歌官方基于Activity开发的子类其集成了许多Jetpack库的核心功能其中就包括了「Lifecycle」库该类因此也实现了LifecycleOwner接口开发者常用的AppcompatActvity也是该类的子类。 但是细读源码会发现该类并没有像笔者之前展示的源码那样直接调用LifecycleRegistry在特定的Activity生命周期回调中派发事件那么该类是如何实现生命周期事件的派发的呢下面介绍「Lifecycle」库中的另外一个关键类ReportFragment。 3.1.1、ReportFragment与LifecycleCallbacks 在ComponentActivity的onCreate()中有一段ReportFragment.injectIfNeededIn(this)的代码这个就是实现了生命周期事件派发的核心类。 接下来让我们走进ReportFragment的源码正如前文所述文章并不会阐述每一行代码的原理而是抓住主要的脉络隐藏了和主脉络无关的代码但是剩余的代码量仍然挺多读者不必对大量的代码感到恐慌因为文章会逐一解释 可见ReportFragment做的事非常简单就是在其生命周期的各个阶段上报生命周期事件因为Fragment的生命周期和Activity在绝大部分是保持一致的特殊的如onCreate()除外不过也有onActivityCreated()、onActivityPostCreated()等可以感知Activity生命周期的函数谷歌的开发人员于是就利用ReportFragment作为监听Activity生命周期的工具你可以看到这个Fragment是没有UI的这也间接证明了它的任务并不是展示一个UI而仅仅是为了监听生命周期。 让我们回到injectIfNeedIn() 可以清楚的看到这里做了一个版本判断如果大于api版本大于29则使用LifecycleCallbacks做一个注册的逻辑这是怎么回事呢 在我提到ReportFragment是作为一个生命周期监听者而不是一个展示UI的模块的时候你也许就已经隐隐约约闻到一种非常奇怪的味道。由于安卓源码设计的缺陷只对外提供了回调方法而没有提供回调监听注册开发者对待这一问题必须考虑向下兼容因此他们选择了源码中已经存在的、可以监听Activity的生命周期的Fragment但是在api 29之后Activity原生自带了生命周期的回调监听注册因此一旦检测到api大于或者等于29ReportFragment的作用就形同虚设了因为广播生命周期的事件的任务已经转移给Activity自带的生命周期回调来实现了。 你也许还会担心现在有ReportFragment和Activity自带的生命周期回调两种方式了会不会导致一个事件被广播两次呢其实不用担心广播的时候已经做了排除了只有api小于29的情况下ReportFragment才会生效。 3.2、Fragment Fragment本身的生命周期和Activity没有很大的差异依然是内置LifecycleRegistry然后在合适的生命周期回调中广播生命周期事件的一套但是值得注意的是 当Fragment被FragmentManager管理时例如执行replace()事务中逻辑上当前的Fragment只是被另外一个同类所替换了它并没有真的被销毁因为待会还有重新回来的机会因此该Fragment并不会执行onDestroy()然而由于内存上的考量不可见的Fragment的View理应被回收因此View会被销毁。 换句话说Fragment不可见之后它的状态会保存起来但是其View会被销毁待会再次可见的时候会根据其状态再一次执行onCreateView() 。 上述机制导致了一个问题Fragment的生命周期和其对应的View的生命周期在实质上是不对等的然而实际开发中感知生命周期大多数是为了与UI进行互动这也导致了开发者单纯监听Fragment的生命周期已经不能够满足开发上的需求了。 下面这张来源于谷歌官方开发者文档的图片很好的诠释了Fragment和它的View的生命周期关系 假如一个Fragment正在栈顶他会处于Resumed的阶段但是被replace之后它会进入Created阶段此刻View被销毁View会进入Destroyed阶段但是Fragment重回栈顶的时候Fragment会从Created再次回归到Resume而View会从Destroyed重回Resumed状态。 换句话说在Fragment的生命周期中它的View可能会反复的从Destroyed到Resumed之间移动即不断地销毁与创建 谷歌为了缓解这个问题给Fragment的View单独添加了一套生命周期我们可以通过代码看到端倪 可以看到在Fragment执行performCreateView()的时候会初始化View的Lifecycle两者的生命周期事件是单独通知的。 如果开发者想访问Fragment的生命周期在Fragment中访问lifecycleOwner即可。如果开发者想访问Fragment的View的生命周期在Fragment中访问viewLifecycleOwner即可。 3.3、ViewTreeLifecycleOwner 在上述的代码中能够直接访问Activity、Fragment的Lifecycle的只能是它们的类中而很多需要访问生命周期的地方往往是一些View中例如要在View中监听其父组件生命周期然而View的父控件有非常多包括了Activity、Fragment甚至是Dialog乃至更多要想获取父组件的生命周期只能做类型判断类型强转的工作这样就极大的限制了View的使用范围 为了缓解谷歌的开发人员提出了一种叫ViewTreeLifecycleOwner的设计其实这个东西并没有什么神秘的让我们直接看看源码 通篇只有两个View的扩展函数第一个函数的意义是给对应的View绑上一个LifecycleOwner第二个函数的意义是不断往上查找父控件直到查出之前绑定的LifecycleOwner。 这段源码的作用挺简单的也就是说只要给某个顶层的控件提前绑好了LifecycleOwner那么他下辖的所有子View都可以通过往上查找的方式来找到LifecycleOwner不得不说谷歌的开发人员真的是太厉害了在简陋的基础下做出了非常强大的功能。 那么下面的问题是LifecycleOwner的绑定发生在哪里呢 3.3.1、Activity中的绑定 ​ Activity的直接子类ComponentActivity、AppcompatActivity均自动完成了绑定的工作我们以ComponentActivity为例看看相关的绑定代码 可见在ComponentActivity的setContentView被执行时会将Activity的ViewLifecycleOwner绑定其所在的Window的DecorView中我们都知道Activity下面的所有View都是DecorView的子View因此它们都可以直接通过谷歌开发人员提供的扩展函数直接访问到最顶层的Activity的Lifecycle。 3.3.2、Fragment中的绑定 和Activity类似Fragment也采用了几乎一致的绑定方式只不过是将Lifecycle绑定在了Fragment的View之上 3.3.3、Dialog中的绑定 默认的Dialog和Activity是不支持ViewTreeLifecycleOwner的因此谷歌的开发人员重新继承实现了一个新的Dialog子类ComponentDialog其中的绑定大同小异简单看下源码即可了解 看来和Activity一样把LifecycleOwner绑定在了DecorView中。 3.3.4、意义与总结 那么谷歌的开发人员费尽心思的为以上的组件绑定ViewTreeLifecycleOwner有何用意呢意义可大了由于消除了组件之间的差异均是通过View往上查找父控件直到找到LifecycleOwner的模式我们不用在乎当前的View是在哪个控件中都是统一通过findViewTreeLifecycleOwner()来获取最顶层控件的生命周期。 例如下面的自定义View的代码无论在上述哪个控件中都可以用 可见开发者只需要关注生命周期本身不再需要担心不同组件之间的差异了。 4、结语 安卓原生的生命周期设计只能说是毛坯房都算不上的水平然而通过「Lifecycle」库的加持之后开发者可以轻松访问组件的生命周期让开发业务更加的合理与安全。 作为开发者的你应该逐渐将重写生命周期函数的方式逐渐过渡到「Lifecycle」的开发方式中来在一些工具类亦或者其他业务类中你也可以使用「Lifecycle」辅助强化与生命周期相关的业务。 Android 学习笔录 Jetpack全家桶篇内含Composehttps://qr18.cn/A0gajp Android 性能优化篇https://qr18.cn/FVlo89 Android Framework底层原理篇https://qr18.cn/AQpN4J Android 车载篇https://qr18.cn/F05ZCM Android 逆向安全学习笔记https://qr18.cn/CQ5TcL Android 音视频篇https://qr18.cn/Ei3VPD OkHttp 源码解析笔记https://qr18.cn/Cw0pBD Gradle 篇https://qr18.cn/DzrmMB Kotlin 篇https://qr18.cn/CdjtAF Flutter 篇https://qr18.cn/DIvKma Android 八大知识体https://qr18.cn/CyxarU Android 核心笔记https://qr21.cn/CaZQLo Android 往年面试题锦https://qr18.cn/CKV8OZ 2023年最新Android 面试题集https://qr18.cn/CgxrRy Android 车载开发岗位面试习题https://qr18.cn/FTlyCJ 音视频面试题锦https://qr18.cn/AcV6Ap
http://www.zqtcl.cn/news/650469/

相关文章:

  • 建设企业网站公司价格page做网站
  • 直播网站建设模板跨境电商选品
  • 购物网站有哪些shop++是什么
  • 自动化优化系统网站建设网站建设类文章
  • 网站建设以及推广提案书支付通道网站怎么做
  • 上海兼职做网站凤凰军事新闻
  • 青田建设局网站ui培训哪好
  • 佛山网站seo哪家好全返网站建设
  • 快速建站哪个平台好常见网页设计
  • 织梦网站地图模板网站服务费
  • 织梦建设两个网站 视频互联网公司排名1000
  • 广州企业网站设计西昌手机网
  • 一个工厂做网站有用吗wordpress重写登录页面
  • 网站服务器如何搭建网站分页设计
  • 可以直接进入网站的正能量连接温州注册网络公司
  • 清丰网站建设价格福州绿光网站建设工作室
  • 武城网站建设价格东莞容桂网站制作
  • 工作室网站需要备案吗wordpress群发工具
  • 官方网站娱乐游戏城自己做网站的好处
  • 查询建设规范的网站1元网站建设精品网站制作
  • 社交网站的优点和缺点个人网页制作软件
  • 做一家算命的网站有没有专门做淘宝客的网站
  • 网站站点管理在哪里建筑施工图设计
  • 众筹网站开发周期网页云原神
  • 哪些网站可以免费做h5东莞制作企业网站
  • 帝国cms 网站地址设置深圳住房和建设部网站
  • 专业网站建设价格最优网页游戏大全电脑版在线玩
  • 建设租车网站wordpress+js插件开发
  • 定制网站开发与模板商务酒店设计网站建设
  • php 网站部署后乱码wordpress禁止调用头部