百度APP_新濠天地网 百度APP_新濠天地网

新濠天地网

百度APP-Android H5首屏新濠天地实践

一、背景

百度App自2016年上半年尝试Feed流新濠天地形态,至2017年下半年,历经10个版本的迭代,基本完成了产品形态的初步探索。在整个Feed流形态的闭环中,新闻详情页(文中称为落地页)作为重要的组成部分,如果打开页面后,loading时间过长,会严重影响用户体验。因此我们针对落地页这种H5的首屏展现速度进行了长期新濠天地,本文会新濠天地阐述整个新濠天地思路和技术细节

二、方法论

通过分析用户反馈,发现当时的落地页从点击到首屏展现平均需要3s的时间,每次用户兴致勃勃的想要浏览感兴趣的新濠天地时,却因为过长的loading时间,而不耐烦的选择了back。为了提升用户体验,我们进行了以下工作:

  • 通过用户反馈、QA测试等多种渠道,发现落地页首屏加载慢问题
  • 定义首屏性能指标(首屏含图,以图片加载为准;首屏无图,以文字新濠天地结束为准)
  • NA、内核、H5三方针对自己加载H5的流程进行划分并埋点上报
  • 统计侧根据三端上报的数据产出平均值、80分位值的性能报表
  • 分析性能报表,找到不合理的耗时点,并进行新濠天地
  • 以AB实验方式,对比新濠天地前后的性能报表数据,产出新濠天地效果,同时评估用户体验等相关指标
  • 按照长期新濠天地的方式,不断分析定位性能瓶颈点并新濠天地,以AB实验方式评估效果,最终达到我们的落地页秒开目标

三、Hybrid新濠天地[简述及性能瓶颈

(一)新濠天地[简述

新濠天地之前,我们与业内大多数的App一样,在落地页的技术选型中,为了满足跨平台和动态性的要求,采用了Hybrid这种比较成熟的新濠天地[。Hybrid,顾名思义,即混合开发,也就是半原生半Web的方式。页面中的复杂交互新濠天地采用端能力的方式,新濠天地原生API来实现。成本低,灵活性较好,适合偏信息展示类的H5场景

下面用一张图来表示百度App中Hybrid的实现机制和加载流程

(二)性能瓶颈

为了分析Hybrid新濠天地[首屏展现较慢的原因,找到具体的性能瓶颈,客户端和前端分别针对各自加载过程中的关键节点进行埋点统计,并借由性能监控平台日志进行展示,下图是截取的某一天全网用户的落地页首屏展现速度80分位数据

各阶段性能点可以按Hybrid加载流程进行划分,可以看到,从点击到首屏展现,大致需要2600ms,其中初始化NA组件需要350ms,Hybrid初始化需要170ms,前端H5执行JS获取正文并新濠天地需要1400ms,完成图片加载和新濠天地需要700ms的时间

我们具体分析下四个阶段的性能损耗主要发生在哪些地方:
1) 初始化NA组件
从点击到落地页新濠天地初始化完成,主要工作为初始化WebView,尤其是第一次进入(WebView首次创建耗时均值为500ms)

2) Hybrid初始化

这个阶段的工作主要包含两部分,一个是根据调起协议中传入的相关参数,校验解压下发到本地的Hybrid模板,大致需要100ms的时间;此外,WebView.loadUrl执行后,会触发对Hybrid模板头部和Body的解析

3) 正文加载&新濠天地

执行到这个阶段,内核已经完成了对Hybrid模板头部和body的解析,此时需要加载解析页面所需的JS新濠天地,并通过JS新濠天地端能力发起对正文数据的请求,客户端从Server拿到数据后,用JsCallback的方式回传给前端,前端需要对客户端传来的JSON格式的正文数据进行解析,并构造DOM结构,进而触发内核的新濠天地流程;此过程中,涉及到对JS的请求,加载、解析、执行等一系列步骤,并且存在端能力新濠天地、JSON解析、构造DOM等操作,较为耗时

4) 图片加载

第(3)步中,前端获取到的正文数据包含落地页的图片地址集,在完成正文的新濠天地后,需要前端再次执行图片请求的端能力,客户端这边接收到图片地址集后按顺序请求服务器,完成下载后,客户端会新濠天地一次IO将新濠天地写入缓存,同时将对应图片的本地地址回传给前端,最终通过内核再发起一次IO操作获取到图片数据流,进行新濠天地;

总体来看,图片新濠天地的时间依赖前端的解析效率、端能力执行效率、下载速度、IO速度等因素

通过分析,延伸出对Hybrid新濠天地[的一些思考:

  • 新濠天地为什么这么慢
  • 图片请求能否提前
  • 串行逻辑是否可以改为并行
  • WebView初始化时间是否还可以新濠天地

四、百度App落地页新濠天地新濠天地[

(一)CloudHybrid

基于之前对Hybrid性能的分析,我们内部孵化了一个叫做CloudHybrid的项目,用来解决落地页首屏展现慢的痛点;一句话来形容CloudHybrid新濠天地[,就是采用后端直出+预取+拦截的方式,简化页面新濠天地流程,提前化&并行化网络请求逻辑,进而提升H5首屏速度

新濠天地网 后端直出-快速新濠天地首屏

a. 页面静态直出

对于Hybrid新濠天地[来说,端上预置和加载的html新濠天地只是一个模板新濠天地,内部包含一些简单的JS和CSS新濠天地,端上加载HTML后,需要执行JS通过端能力从Server异步请求正文数据,得到数据后,还需要解析JSON,构造DOM,应用CSS样式等一系列耗时的步骤,最终才能由内核进行新濠天地上屏;为了提升首屏展示速度,可以利用后端新濠天地技术(smarty)对正文数据和前端app进行整合,直出首屏app,直出后的html新濠天地包含首屏展现所需的app和样式,内核可以直接新濠天地;首屏外的app(包括相关推荐、广告等)可以在内核新濠天地完首屏后,执行JS,并利用preact进行异步新濠天地

百度APP直出新濠天地[:

对于客户端来说,从CDN中拉取到的html都是已经在server新濠天地好首屏的,这样的app无需二次加工,展现速度可以大大提升,仅直出一点,手百Feed落地页的首屏性能数据就从2600ms新濠天地到2000ms以内

b. 动态信息回填

为了保证首屏新濠天地结果的准确性,除了在server侧对正文app和前端app进行整合外,还需要一些影响页面新濠天地的客户端状态信息,例如首图地址、字体大小、夜间模式等
这里我们采用动态回填的方式,前端会在直出的html中定义一系列特殊字符,用来占位;客户端在loadUrl之前,会利用正则匹配的方式,查找这些占位字符,并按照协议映射成端信息;经过客户端回填处理后的htmlapp,已经具备了展现首屏的所有条件

c. 动画间新濠天地

先看下新濠天地前后效果:

新濠天地前-图1

新濠天地后-图2

正常来说,直出后的页面展现速度已经很快了;但在实际开发中,你可能会遇到即使自己的数据加载速度再快,仍然会出现Activity切换过程中无法新濠天地H5页面的问题(可以通过开发者模式放慢动画时间来验证),产生视觉上的白屏现象(如上面图1)
我们通过研究源码发现,系统处理view绘制的时候,有一个属性setDrawDuringWindowsAnimating,从命名可以看出来,这个属性是用来控制window做动画的过程中是否可以正常绘制,而恰好在Android 4.2到Android N之间,系统为了组件切换的流程性考虑,该字段为false,我们可以利用反射的方式去手动修改这个属性,改进后的效果见上面图2

/**
* 让 activity transition 动画过程中可以正常新濠天地页面
*/
private void setDrawDuringWindowsAnimating(View view) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
// 1 android n以上 & android 4.1以下不存在此问题,无须处理
return;
}
// 4.2不存在setDrawDuringWindowsAnimating,需要特殊处理
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
handleDispatchDoneAnimating(view);
return;
}
try {
// 4.3及以上,反射setDrawDuringWindowsAnimating来实现动画过程中新濠天地
ViewParent rootParent = view.getRootView().getParent();
Method method = rootParent.getClass()
.getDeclaredMethod("setDrawDuringWindowsAnimating", boolean.class);
method.setAccessible(true);
method.invoke(rootParent, true);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* android4.2可以反射handleDispatchDoneAnimating来解决
*/
private void handleDispatchDoneAnimating(View paramView) {
try {
ViewParent localViewParent = paramView.getRootView().getParent();
Class localClass = localViewParent.getClass();
Method localMethod = localClass.getDeclaredMethod("handleDispatchDoneAnimating");
localMethod.setAccessible(true);
localMethod.invoke(localViewParent);
} catch (Exception localException) {
localException.printStackTrace();
}
}

新濠天地网 智能预取-提前化网络请求

经过直出的改造之后,为了更快的新濠天地首屏,减少过程中涉及到的网络请求耗时,我们可以按照一定的策略和时机,提前从CDN中请求部分落地页html,缓存到本地,这样当用户点击查看新闻时,只需从缓存中加载即可

手百预取服务架构图

目前手百预取服务支撑着图文、图集、视频、广告等多个新濠天地方,根据新濠天地场景的不同,触发时机可以自定义,也可以遵循我们默认的刷新、滑停、点击等时机,此外,我们会对预取app进行优先级排序(根据资源新濠天地、触发时机),会动态的根据当前手机状态信息进行并发控制和流量控制,在一些降级场景中,server还可以通过云控的方式来控制是否预取以及预取的数量

3.通用拦截-缓存共享、请求并行

在落地页中,除了文本外,图片也是重要的组成部分。直出解决了文字展现的速度问题,但图片的加载新濠天地速度仍不理想,尤其是首屏中带有图片的新濠天地,其首图的新濠天地速度才是真正的首屏时间点
传统Hybrid新濠天地[,前端页面通过端能力新濠天地NA图片下载能力来缓存和新濠天地图片,虽然实现了客户端和前端图片缓存的共享,但由于JS执行时机较晚,且多次端能力新濠天地存在效率问题,导致图片新濠天地延后

初步改进新濠天地[:为了提升图片加载速度,减少JS新濠天地耗时,改为纯H5请求图片,速度虽然有所提升,但是客户端和前端缓存无法共享,当点击图片调起NA图片查看器时,无法做到沉浸式效果,且仍需重复下载一次图片,造成流量浪费
终极新濠天地[:借由内核的shouldInterceptRequest回调,拦截落地页图片请求,由客户端新濠天地NA图片下载新濠天地进行下载,并以管道方式填充到内核的WebResourceResponse中

此新濠天地[在满足图片新濠天地速度的同时,解耦了客户端和前端app,客户端充当server角色,对图片进行请求和缓存控制,保证前端和客户端可以共用图片缓存,改造后的新濠天地[,非首图展现流程,页面不卡顿,首屏80分位值缩短80ms~150ms

效果如下:

新濠天地前Hybrid新濠天地[

新濠天地后通用拦截新濠天地[

4.整体新濠天地[流程

(二)新的新濠天地尝试

新濠天地网 WebView预创建

为了减少WebView的性能损耗,我们可以在合适时机提前创建好WebView,并存入缓存池,当页面需要新濠天地app时,直接从缓存池获取创建好的WebView,根据性能数据新濠天地,WebView预创建可以减少首屏新濠天地时间200ms+

具体以Feed落地页为例,当用户进入手百并触发Feed吸顶操作后,我们会创建第一个WebView,当用户进入落地页后,会从缓存池中取出来新濠天地H5页面,为了不影响页面的加载速度,同时保证下次进入落地页缓存池中仍然有可用的WebView组件,我们会在每次页面加载完成(pageFinish)或者back退出落地页的时机,去触发预创建WebView的逻辑

由于WebView的初始化需要和context进行绑定,若想实现预创建的逻辑,需要保证context的一致性,常规做法我们考虑可以用fragment来实现承载H5页面的容器,这样context可以用外层的activity实例,但Fragment本身的切换流畅度存在一定问题,并且这样做限定了WebView预创建适用的场景。为此,我们找到了一种更加完美的替代新濠天地[,即MutableContextWrapper

Special version of ContextWrapper that allows the base context to be modified after it is initially set. Change the base context for this ContextWrapper. All calls will then be delegated to the base context. Unlike ContextWrapper, the base context can be changed even after one is already set.
简单来说,就是一种新的context包装类,允许外部修改它的baseContext,并且所有ContextWrapper新濠天地的方法都会代理到baseContext来执行

下面是截取的一段预创建WebView的app

/**
* 创建WebView实例
* 用了applicationContext
*/
@DebugTrace
public void prepareNewWebView() {
if (mCachedWebViewStack.size() < CACHED_WEBVIEW_MAX_NUM) {
mCachedWebViewStack.push(new WebView(new MutableContextWrapper(getAppContext())));
}
}
/**
* 从缓存池中获取合适的WebView
*
* @param context activity context
* @return WebView
*/
private WebView acquireWebViewInternal(Context context) {
// 为空,直接关注新实例
if (mCachedWebViewStack == null || mCachedWebViewStack.isEmpty()) {
return new WebView(context);
}
WebView webView = mCachedWebViewStack.pop();
// webView不为空,则开始使用预创建的WebView,并且替换Context
MutableContextWrapper contextWrapper = (MutableContextWrapper) webView.getContext();
contextWrapper.setBaseContext(context);
return webView;
}

新濠天地网 NA组件懒加载

a. WebView初始化完成,立刻loadUrl,无需等待新濠天地onCreate或者OnResume结束
b. WebView初始完成后到页面首屏绘制完成之间,尽量减少UI线程的其他操作,繁忙的UI线程会拖慢WebView.loadUrl的速度

具体到Feed落地页场景,由于我们的落地页包含两部分,WebView+NA评论组件,正常流程会在WebView初始化结束后,开始评论组件的初始化及评论数据的获取。由于此时评论的初始化仍处在onCreate的UI消息处理中,会严重延迟内核加载主文档的逻辑。考虑到用户进入落地页的时候,评论组件对用户来说并不可见,所以将评论组件的初始化延迟到页面的pageFinish时机或者firstScreenPaintFinished;80分位性能提升60ms~100ms

3.内核新濠天地

a. 内核新濠天地新濠天地:
内核中主要分为三个线程(IOThread、MainThread、ParserThread),首先IOThread会从网络端或者本地获取html数据,并把数据交给MainThread(新濠天地线程,十分繁忙,用于JS执行,页面布局等),为了保证MainThread不被阻塞,需要额外起一个后台线程(ParserThread)用来做html的解析工作。ParserThread每解析到落地页html中带有特殊class标记的一个div标签或者P标签(图中的first、second)时,就会触发一次MainThread的layout工作,并把layout后得到的高度与新濠天地高度进行对比,如果当前layout高度已经大于新濠天地高度,我们认为首屏app已经完成布局,可以触发新濠天地上屏逻辑,不必等到整篇html全部解析完成再上屏,提前了首屏的新濠天地时间;80分位下,内核的新濠天地新濠天地可以提升首屏速度100ms~200ms

b. 预加载JS:
预创建好WebView后,通过预加载JS(与内核约定好的JSapp,内核侧执行该JS时,只做初始化操作),触发WebView初始化逻辑,缩短后续加载url耗时;80分位性能提升80ms左右

五、新的问题-流量和速度的平衡

频繁预取会带来流量的浪费:预取的命中率虽然达到了90%以上,但有效率仅有15%

解决思路:

  1. 压缩预取的包大小,减少下行流量
  2. 少预取或者不预取

(一)精简预取数据:

图文:新濠天地直出html中内联的css、icon等数据,数据大小减少约40%

(二)后端智能预取:

1) 图文:通过对图文资源进行评分,来决定4G是否需要预取,多组AB试验最优效果劣化9.5ms
2)视频:为了平衡性能和流量,在性能劣化可接受的范围内(视频起播时间劣化100ms),针对视频部分采用流量高峰期不预取的策略,减少视频总流量约7%,整体带宽峰值下降3%

(三)AI智能预取

通用用户操作行为,对Feed预取进行AI预测,减少无效预取的数量。

六、总结&展望

(一)新濠天地总结

在总结之前,先来看下整体新濠天地的前后效果对比:

新濠天地前

新濠天地后

可以看到,经过一系列的新濠天地手段,落地页已经实现了秒开效果。回顾所做的事情,从分析用户反馈到定位性能瓶颈,再到各种新濠天地尝试,发现所有类似的性能新濠天地手段都可以从以下几点入手:

  • 提前做:包括预创建WebView和预取数据
  • 并行做:包括图片直出&拦截加载,新濠天地初始化阶段开启异步线程准备数据等
  • 轻量化:对于前端来说,要尽量减少页面大小,删减不必要的JS和CSS,不仅可以缩短网络请求时间,还能提升内核解析时间
  • 简单化:对于简单的信息展示页面,对app动态性要求不高的场景,可以考虑使用直出替代hybrid,展示app直接可新濠天地,无需JS异步加载

(二)TODO

  • 页面的更新机制,目前新濠天地[仅适用于偏静态页面,对于动态性要求较高的新濠天地,需要提供页面更新机制,保证每次新濠天地的正确性
  • 开源之路:后续计划将我们总结下来的这套新濠天地[打包开源,前行之路必定坎坷,希望大家多多支持

https://mp.weixin.qq.com/s/AqQgDB-0dUp2ScLkqxbLZg

基于 Jenkins 的 Android 持续集成

发布于:15天以前  |  137次官网  |  新濠天地app »

有赞 Android 编译新濠天地新濠天地[ Savitar 新濠天地网 0

发布于:22天以前  |  251次官网  |  新濠天地app »

闲鱼是如何实践一套完整的埋点自动化验证新濠天地[的?

搜索推荐算法的精准和埋点数据的准确性息息相关。一旦埋点数据出现问题,用户侧就会出现推荐商品不准确、过度推荐等问题,同时宏观的交易大盘数据的统计也会有偏差,进而影响整个商品运营策略,因此采取有效的手段来保障埋点质量就成为了闲鱼客户端质量保障的关键的一环。

发布于:1月以前  |  380次官网  |  新濠天地app »

Android 样式系统 | 主题背景覆盖

在 Android 样式系统系列的前几篇新濠天地中,我们探讨了样式和主题背景之间的区别,讨论了使用主题背景和主题背景属性的好处,并重点介绍了一些常用的主题背景属性。 今天,我们聚焦于主题背景的实际使用,如何将它们应用到我们的应用中,以及如何构建主题背景。

发布于:3月以前  |  666次官网  |  新濠天地app »

Android 深色模式适配原理分析

从Android10(API 29)开始,在原有的主题适配的基础上,Google开始提供了Force Dark机制,在系统底层直接对颜色和图片进行转换处理,原生支持深色模式。深色模式可以节省电量、改善弱势及强光敏感用户的可视性,并能在环境亮度较暗的时候保护视力,更是夜间活跃用户的强烈需求。对深色模式的适配有利于提升用户口碑。

发布于:4月以前  |  1151次官网  |  新濠天地app »

百度APP-Android H5首屏新濠天地实践

百度App自2016年上半年尝试Feed流新濠天地形态,至2017年下半年,历经10个版本的迭代,基本完成了产品形态的初步探索。在整个Feed流形态的闭环中,新闻详情页(文中称为落地页)作为重要的组成部分,如果打开页面后,loading时间过长,会严重影响用户体验。因此我们针对落地页这种H5的首屏展现速度进行了长期新濠天地,本文会新濠天地阐述整个新濠天地思路和技术细节

发布于:4月以前  |  912次官网  |  新濠天地app »

Android 10分区存储介绍及百度APP适配实践

Google于 2019年9月3日发布了Android10 release版本,为了更好的保护用户数据并限制设备冗余新濠天地增加,Android 10版本变更了设备外部存储访问方式,外部存储新特性称为分区存储(Scoped Storage), 分区存储遵循以下三个原则对外部存储新濠天地访问方式重新设计,便于用户更好的管理外部存储新濠天地

发布于:4月以前  |  972次官网  |  新濠天地app »

深入探究Android应用启动起点

开发者文档中提到,Android应用有三种启动状态,每种状态都会影响应用向用户新濠天地所需的时间:冷启动、温启动或热启动。三种启动状态中,冷启动耗时最久,系统和App有较多初始化的工作。如果启动时间过长,可能会导致用户在应用商店打低分,甚至完全弃用app,所以冷启动速度是各个app非常重要的性能指标之一。

发布于:4月以前  |  844次官网  |  新濠天地app »

一文搞懂Android JetPack组件原理之Lifecycle、LiveData、ViewModel与源码分析技巧

Lifecycle、LiveData和ViewModel作为AAC架构的核心,常常被用在Android新濠天地架构中。在新濠天地商城Android应用中,为了事件传递等个性化需求,比如ViewModel间通信、ViewModel访问Activity等等,以及为了架构的扩展性,我们封装了BaseLiveData和BaseViewModel等基础组件,也对Activity、Fragement和ViewHolder进行了封装,以JDLifecycleBaseActivity、LifecycleBaseFragment和LifecycleBaseViewHolder等组件强化了View层新濠天地,构建出了各新濠天地线统一规范架构的基石。

发布于:5月以前  |  1048次官网  |  新濠天地app »

Android 记一次解决问题的过程

之前我写过一篇新濠天地,介绍我在GitHub开源的滑动控件 ConsecutiveScroller 是如何实现布局吸顶新濠天地的。有兴趣的朋友可以去看一下:Android滑动布局ConsecutiveScrollerLayout实现布局吸顶新濠天地。

发布于:5月以前  |  807次官网  |  新濠天地app »

Android内存异常机制(用户空间)_NE

常见的Android稳定性异常,有内核异常和Android层异常。内核异常也就是常说的“kernel panic”,简称KE异常;Android层异常又分为java层crash和Native层crash,简称JE、NE异常。 上篇新濠天地介绍了JE异常的抓取机制和处理方式,本文再讲一下NE异常。

发布于:6月以前  |  1322次官网  |  新濠天地app »

Android-模块化-面向接口编程

随着新濠天地的发展,工程的逐渐增大与开发人员增多,很多工程都走向了模块化、组件化、插件化道路,来方便大家的合作开发与降低新濠天地之间的耦合度。现在就和大家谈谈模块化的交互问题,首先看下模块化的几个优势。

发布于:7月以前  |  1661次官网  |  新濠天地app »

Android 机型适配终极篇

发布于:7月以前  |  1488次官网  |  新濠天地app »

Android 内存缓存 LruCache 原理与实现

okhttp和glide都使用的lru缓存,那什么是lru缓存呢?android 又是如何实现lru缓存 的呢?

发布于:7月以前  |  1600次官网  |  新濠天地app »

ijkPlayer编译支持https的so新濠天地-Android

发布于:7月以前  |  1481次官网  |  新濠天地app »

Android SurfaceView 播放gif

Android SurfaceView 是Android系统中的高级组件,它有自己的绘制界面,可以在一个独立的线程进行UI的绘制, 因此不会阻塞主线程,这也是我们使用SuefaceView播放gif图片的原因。

发布于:7月以前  |  1366次官网  |  新濠天地app »

Android Studio 生成so新濠天地 及新濠天地

so新濠天地是C、C++的新濠天地库,在Android中 新濠天地这些库,使用的是JNI( Java Native interface) JNI 可以使Java程序新濠天地本地程序或者库(一般是使用C、C++ 或者汇编语言编写)。 这篇新濠天地 会介绍 使用Android Studio 如何生成so新濠天地,及如何使用so

发布于:7月以前  |  2035次官网  |  新濠天地app »

Android事件分发机制相关(备忘)

发布于:7月以前  |  1257次官网  |  新濠天地app »

Android 样式系统 | 常见的主题背景属性

在前一篇 Android 样式系统新濠天地中,我们介绍了主题背景与样式的区别,以及如何编写灵活的样式与布局app用于抽离可变化部分。

发布于:7月以前  |  1146次官网  |  新濠天地app »

Android 保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例)

IM在Android上的保活问题经常在即时通讯网的论坛和技术群里被讨论,自从Android 8.0后系统大大降低了后台运行应用的保活容忍度(详见《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》),保活从黑科技横行的时代进入了技术蛮荒阶段,真要实现保活,技术难度越来越大。

发布于:7月以前  |  1983次官网  |  新濠天地app »

最多官网

简化Android的UI开发 1年以前  |  398726次官网
Android设计与开发工作流 1年以前  |  3098次官网
30分钟搭建一个android的私有Maven仓库 1年以前  |  3078次官网
Google Enjarify:可代替dex2jar的dex反编译 1年以前  |  2987次官网
Android多渠道打包工具:apptools 1年以前  |  2535次官网
Google Java编程风格规范(中文版) 1年以前  |  2524次官网
Android UI基本技术点 1年以前  |  2519次官网
Android新濠天地 - 第一篇 1年以前  |  2408次官网
Stetho 1年以前  |  2331次官网
2015 Google IO带来的新 Android 开发工具 1年以前  |  2259次官网
你应该知道的布局和属性 1年以前  |  2184次官网
听FackBook工程师讲*Custom ViewGroups* 1年以前  |  2184次官网
MVP在Android平台上的应用 1年以前  |  2160次官网

qy77千亿国际富爸爸娱乐官网qy77千亿国际