精华内容
下载资源
问答
  • app优化
    千次阅读
    2019-12-19 16:44:51

    引言

    互联网时代, App作为于用户交互的端, 可以说实际上是一个界面, 产品的业务, 服务都是由Server提供的. 而App与Server的交互依赖于网络, 故而网络优化, 也是我们的App优化中不可缺少的一个优化项.

    1, 网络连接对用户的影响

    App的网络连接对于用户来说, 影响很多, 且多数情况下都很直观, 直接影响用户对这个App的使用体验. 其中较为重要的几点:

    • 流量 App的流量消耗对用户来说是比较敏感的, 毕竟流量是花钱的嘛. 现在大部分人的手机上都有安装流量监控的工具App,
      用来监控App的流量使用. 如果我们的App这方面没有控制好, 会给用户不好的使用体验.
    • 电量 电量相对于用户来说, 没有那么明显. 一般用户可能不会太注意. 但是如前文电量优化中说的那样,
      网络连接(radio)是对电量影响很大的一个因素. 所以我们也要加以注意.
    • 用户等待 也就是用户体验, 良好的用户体验, 才是我们留住用户的第一步. 如果App请求等待时间长, 会给用户网络卡, 应用反应慢的感觉,
      如果有对比, 有替代品, 我们的App很可能就会被用户无情抛弃.

    2, 分析网络连接的工具

    2.1 Network Monitor

    Android Studio内置的Monitor工具中就有一个Network Monitor:
    在这里插入图片描述

    其中:

    • Rx — R(ecive) 表示下行流量, 即下载接收.
    • Tx — T(ransmit) 表示上行流量, 即上传发送.

    2.2 网络代理工具

    一般来说, 网络代理工具有两个作用:

    1. 截获网络请求响应包, 分析网络请求
    2. 设置代理网络, 移动App开发中一般用来做不同网络环境的测试, 例如Wifi/4G/3G/弱网等.

    代理工具很多, 诸如Wireshark, Fiddler, Charles等, 在此不一一细说了, 使用方法自行问谷歌度娘. 😃

    3, 哪些方面取优化网络连接

    简单来说, 两个方面:

    1. 减少Radio活跃时间

      1-1. 也就是减少网络数据获取的频次.
      1-2. 这就减少了radio的电量消耗, 控制电量使用.

    2. 减少获取数据包的大小

      2-1. 可以减少流量消耗
      2-2. 也可以让每次请求更快, 在网络情况不好的情况下也有良好表现, 提升用户体验.

    那么, 具体应该从哪些方面着手呢?

    3.1 接口设计

    API设计

    App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示.

    例如, 注册登录. 正常会有两个API, 注册和登录, 但是设计API时我们应该给注册接口包含一个隐式的登录. 来避免App在注册后还得请求一次登录接口(有可能失败, 从而导致业务流程失败).

    再例如, 上文提到的获取repo详情, 实际上请求了4个接口, 请求了repo的信息, forks列表, contributors列表, readme, 这是因为github提供的接口是尽量单一职责的. 然而在我们的实际开发中, 我们的Server除了提供这些单一职责的小接口外, 最好还能组合一个满足客户端业务需求的repo详情接口出来.

    Gzip压缩

    使用Gzip来压缩request和response, 减少传输数据量, 从而减少流量消耗.

    考虑使用Protocol Buffer代替JSON

    从前我们传输数据使用XML, 后来使用JSON代替了XML, 很大程度上也是为了可读性和减少数据量(当然还有映射成POJO的方便程度).

    Protocol Buffer是Google推出的一种数据交换格式.

    如果我们的接口每次传输的数据量很大的话, 可以考虑下protobuf, 会比JSON数据量小很多.

    当然相比来说, JSON也有其优势, 可读性更高.

    图片的Size

    上面Network Monitor中看到的22s到27s之间的有多次请求, 且数据量还很大. 就是在获取图片资源.

    图片相对于接口请求来说, 数据量要大得多. 故而也是我们需要优化的一个点.

    我们可以在获取图片时告知服务器需要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.

    我们现在很多公司的图片资源都是使用第三方的云存储服务的(七牛, 阿里云存储之类的).

    以七牛为例, 可以在请求图片的url中添加诸如质量, 格式, width, height等path来获取合适的图片资源:

    imageView2/<mode>/w/<LongEdge>
                     /h/<ShortEdge>
                     /format/<Format>
                     /interlace/<Interlace>
                     /q/<Quality>
                     /ignore-error/<ignoreError>
    

    3.2 网络缓存

    适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必要的流量消耗.

    3.3 打包网络请求

    当接口设计不能满足我们的业务需求时. 例如可能一个界面需要请求多个接口, 或是网络良好, 处于Wifi状态下时我们想获取更多的数据等.

    这时就可以打包一些网络请求, 例如请求列表的同时, 获取Header点击率较高的的item项的详情数据.

    可以通过一些统计数据来帮助我们定位用户接下来的操作是高概率的, 提前获取这部分的数据.

    3.4 监听相关状态

    通过监听设备的状态:

    • 休眠状态
    • 充电状态
    • 网络状态

    结合JobScheduler来根据实际情况做网络请求. 比方说Splash闪屏广告图片, 我们可以在连接到Wifi时下载缓存到本地; 新闻类的App可以在充电, Wifi状态下做离线缓存.

    3.5 弱网测试&优化

    除了正常的网络优化, 我们还需考虑到弱网情况下, App的表现.

    3.5.1 弱网测试

    有几种方式来模拟弱网进行测试.

    Android Emulator

    创建和启动Android模拟器可以设置网络速度和延迟:

    创建时:
    在这里插入图片描述

    启动时, 使用emulator命令:

    $emulator -netdelay gprs -netspeed gsm -avd Nexus_5_API_22
    

    使用网络代理工具

    Charles为例:

    保持手机和PC处于同一个局域网, 在手机端wifi设置高级设置中设置代理方式为手动, 代理ip填写PC端ip地址, 端口号默认8888.

    在这里插入图片描述
    在这里插入图片描述

    其他模拟弱网方式

    如果你恰好也是iOS的开发者, Apple提供了Network Link Conditioner, 非常好用.

    可以模拟的网络情况与上述类似:
    在这里插入图片描述

    如果你使用Linux环境开发, 还可以试下facebook出的ATC.

    3.5.2 弱网优化

    利用上述工具模拟弱网, 在弱网情况下体验我们的App. 一般来说, 网络延迟在60ms内, 是OK的, 超过200ms就比较糟糕了. 我们需要做的是在比较糟糕的网络环境下还能给用户较好的体验.

    弱网优化, 本质上是在弱网的情况下能让用户流畅的使用我们的App. 我们要做的就是结合上述的优化项:

    • 压缩/减少数据传输量

    • 利用缓存减少网络传输

    • 针对弱网(移动网络), 不自动加载图片

    • 界面先反馈, 请求延迟提交

      例如, 用户点赞操作, 可以直接给出界面的点赞成功的反馈, 使用JobScheduler在网络情况较好的时候打包请求.

    更多相关内容
  • 浅谈App优化
  • 混合APP优化加速方案.pdf
  • 通过仿真App优化轿车设计.pdf
  • 基于心理模型的生理期APP优化设计探索.pdf
  • 天津市民应用运动类APP优化传播路径研究.pdf
  • 第四章:原生App优化.pdf
  • BIM软件应用模式在翻转课堂教学APP优化研究中的应用与设计.pdf
  • BIM软件应用模式在翻转课堂教学APP优化研究中的应用与设计.docx
  • w3cschool App提供了优质、系统化的教程、经验文档、参考手册,为开发者节省时间,提高效率! 这个版本为优化版本
  • APP性能优化

    千次阅读 多人点赞 2022-05-24 00:08:12
    APP性能优化分:卡顿处理、耗电处理、安装包瘦身、APP启动四大方面。 文章目录1、卡顿处理1.1、卡顿分析1.2、卡顿优化1、CPU 优化2、GPU 优化离屏渲染1、离屏渲染消耗性能的原因2、哪些操作会触发离屏渲染?1.3、...

    APP性能优化分:卡顿处理、耗电处理、安装包瘦身、APP启动四大方面。

    1、卡顿处理

    1.1、卡顿分析

    APP导致卡顿,最终可以归结为:CPU和GPU处理不及时导致的:

    1、CPU(Central Processing Unit,中央处理器):对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制(Core Graphics)。
    2、GPU(Graphics Processing Unit,图形处理器):纹理的渲染。

    1、屏幕渲染逻辑:
    在这里插入图片描述
    在iOS中是双缓冲机制,有前帧缓存、后帧缓存。

    2、APP屏幕成像原理:
    在这里插入图片描述
    3、卡顿产生的原因:
    在这里插入图片描述
    卡顿解决的主要思路:

    1、尽可能减少CPU、GPU资源消耗。
    2、按照60FPS的刷帧率,每隔16ms就会有一次VSync信号。

    1.2、卡顿优化

    1、CPU 优化

    1、尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView。
    2、不要频繁地调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改。
    3、尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性。
    4、Autolayout会比直接设置frame消耗更多的CPU资源。
    5、图片的size最好刚好跟UIImageView的size保持一致。
    6、控制一下线程的最大并发数量。
    7、尽量把耗时的操作放到子线程。

    1、文本处理(尺寸计算、绘制)
    2、图片处理(解码、绘制)

    2、GPU 优化

    1、尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示。
    2、GPU能处理的最大纹理尺寸是4096x4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过这个尺寸。
    3、尽量减少视图数量和层次。
    4、减少透明的视图(alpha<1),不透明的就设置opaque为YES。
    5、尽量避免出现离屏渲染。

    离屏渲染

    在OpenGL中,GPU有2种渲染方式:

    1、On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作。
    2、Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

    1、离屏渲染消耗性能的原因

    1、需要创建新的缓冲区。
    2、离屏渲染的整个过程,需要多次切换上下文环境。

    1、先是从当前屏幕(On-Screen)切换到离屏(Off-Screen)。
    2、等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上。
    3、又需要将上下文环境从离屏切换到当前屏幕。

    2、哪些操作会触发离屏渲染?

    1、光栅化:layer.shouldRasterize = YES
    2、遮罩:layer.mask
    3、圆角:同时设置layer.masksToBounds = YESlayer.cornerRadius大于0,考虑通过CoreGraphics绘制裁剪圆角,或者叫美工提供圆角图片。
    4、阴影:layer.shadowXXX,如果设置了layer.shadowPath就不会产生离屏渲染。

    1.3、卡顿检测

    1、平时所说的“卡顿”主要是因为在主线程执行了比较耗时的操作。
    2、可以添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的。

    2、耗电处理

    2.1、好点主要来源

    在这里插入图片描述1、CPU处理,Processing
    2、网络,Networking
    3、定位,Location
    4、图像,Graphics

    2.2、耗电优化

    1、少用定时器。
    2、尽可能降低CPU、GPU功耗。
    3、网络优化

    1、减少、压缩网络数据。
    2、如果多次请求的结果是相同的,尽量使用缓存。
    3、使用断点续传,否则网络不稳定时可能多次传输相同的内容。
    4、网络不可用时,不要尝试执行网络请求。
    5、让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间。
    6、批量传输。比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块地下载。如果下载广告,一次性多下载一些,然后再慢慢展示。如果下载电子邮件,一次下载多封,不要一封一封地下载。

    4、定位优化

    1、如果只是需要快速确定用户位置,最好用CLLocationManager的requestLocation方法。定位完成后,会自动让定位硬件断电。
    2、如果不是导航应用,尽量不要实时更新位置,定位完毕就关掉定位服务。
    3、尽量降低定位精度,比如尽量不要使用精度最高的kCLLocationAccuracyBest
    4、需要后台定位时,尽量设置pausesLocationUpdatesAutomatically为YES,如果用户不太可能移动的时候系统会自动暂停位置更新。
    5、尽量不要使用startMonitoringSignificantLocationChanges,优先考虑startMonitoringForRegion:

    5、优化I/O操作

    1、尽量不要频繁写入小数据,最好批量一次性写入。
    2、读写大量重要数据时,考虑用dispatch_io,其提供了基于GCD的异步操作文件I/O的API。用dispatch_io系统会优化磁盘访问。
    3、数据量比较大的,建议使用数据库(比如SQLite、CoreData)。

    6、硬件检测优化
    用户移动、摇晃、倾斜设备时,会产生动作(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。在不需要检测的场合,应该及时关闭这些硬件。

    3、安装包瘦身

    1、安装包(IPA)主要由可执行文件、资源组成
    2、资源(图片、音频、视频等)

    1、采取无损压缩
    2、去除没有用到的资源: https://github.com/tinymind/LSUnusedResources

    3、可执行文件瘦身

    1、编译器优化

    1、Strip Linked ProductMake Strings Read-OnlySymbols Hidden by Default设置为YES
    2、去掉异常支持,Enable C++ ExceptionsEnable Objective-C Exceptions设置为NO, Other C Flags添加-fno-exceptions

    2、利用AppCodehttps://www.jetbrains.com/objc/)检测未使用的代码:菜单栏 -> Code -> Inspect Code。
    3、编写LLVM插件检测出重复代码、未被调用的代码。
    4、LinkMap:查看可执行文件的具体组成。可借助第三方工具解析LinkMap文件: https://github.com/huanxsd/LinkMap

    4、APP的启动

    4.1、APP启动分类

    APP的启动可以分为2种

    1、冷启动(Cold Launch):从零开始启动APP。
    2、热启动(Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP。

    4.2、APP启动时间分析

    注意:这里所说的APP启动时间的分析,主要是针对冷启动进行分析和优化。
    配置:通过添加环境变量可以打印出APP的启动时间分析(Edit scheme -> Run -> Arguments),DYLD_PRINT_STATISTICS设置为1,如果需要更详细的信息,那就将DYLD_PRINT_STATISTICS_DETAILS设置为1

    APP的冷启动可以概括为3大阶段

    1、dyld
    2、runtime
    3、main

    在这里插入图片描述

    4.2.1、dyld 阶段

    1、dyld(dynamic link editor):Apple的动态链接器,可以用来装载Mach-O文件(可执行文件、动态库等)。
    2、启动APP时,dyld所做的事情有:

    1、装载APP的可执行文件,同时会递归加载所有依赖的动态库。
    2、当dyld把可执行文件、动态库都装载完毕后,会通知Runtime进行下一步的处理。

    4.2.2、runtime 阶段

    启动APP时,runtime所做的事情有:

    1、调用map_images进行可执行文件内容的解析和处理。
    2、在load_images中调用call_load_methods,调用所有Class和Category的+load方法。
    3、进行各种objc结构的初始化(注册Objc类 、初始化类对象等等)
    调用C++静态初始化器__attribute__((constructor))修饰的函数

    到此为止,可执行文件和动态库中所有的符号(Class、Protocol、Selector、IMP、…)都已经按格式成功加载到内存中,被runtime 所管理。

    4.2.3、main

    1、APP的启动由dyld主导,将可执行文件加载到内存,顺便加载所有依赖的动态库。
    2、并由runtime负责加载成objc定义的结构。
    3、所有初始化工作结束后,dyld就会调用main函数。
    4、接下来就是UIApplicationMain函数,AppDelegate的application:didFinishLaunchingWithOptions:方法

    4.3、APP启动优化

    1、dyld

    1、减少动态库、合并一些动态库(定期清理不必要的动态库)。
    2、减少Objc类、分类的数量、减少Selector数量(定期清理不必要的类、分类)。
    3、减少C++虚函数数量。
    4、Swift尽量使用struct。

    2、runtime

    1、用+initialize方法和dispatch_once取代所有的__attribute__((constructor))C++静态构造器ObjC的+load

    3、main

    1、在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在finishLaunching方法中。
    2、按需加载。

    5、问答拓展

    1、你在项目中是怎么优化内存的?
    2、优化你是从哪几方面着手?
    3、列表卡顿的原因可能有哪些?你平时是怎么优化的?
    4、遇到tableView卡顿嘛?会造成卡顿的原因大致有哪些?

    展开全文
  • Serial1App优化界面 发送多行 到现在看到的界面就差不多了,调试发现在接受数据的窗口里当接收到的内容满了整个窗口后后来的数据并不会现在在窗口上,而是内容在下方,要拖动下拉调,为了避免这个缺陷,在下面函数...
  • 前言 ...通过DDMS的APP内存占用查看工具分析发现,APP中占用内存最多的是图片,每个Activity中图片占用内存占大半,本文重点分享对图片的内存优化。 不要将Button的背景设置为selector   在布局
  • AppStore搜索优化

    2018-04-18 19:06:46
    AppStore上架排名、用户搜索靠前等优化技巧,从APP瘦身到发布信息优化
  • 手机银行APP的改进和优化.pdf
  • iOSApp启动性能优化

    2021-01-27 16:32:36
    本文介绍了如何优化iOSApp的启动性能。本文分为四个部分:第一部分科普了一些和App启动性能相关的前置知识第二部分主要讲如何定制启动性能的优化目标第三部分通过在WiFi管家这个具体项目的优化过程,分享一些有用的...
  • App 启动方式 冷启动 App 没有启动过或 App 进程被杀,系统中不存在该 App 进程,此时启动即为冷启动。需要创建 App 进程,加载相关资源,启动 Main Thread,初始化首屏 Activity 等。在这个过程中,屏幕会显示一个...
  • Android App优化之网络优化

    千次阅读 2018-09-10 06:31:20
    而App与Server的交互依赖于网络, 故而网络优化, 也是我们的App优化中不可缺少的一个优化项. 1, 网络连接对用户的影响 App的网络连接对于用户来说, 影响很多, 且多数情况下都很直观, 直接影响用户对这个App的使用...

    互联网时代, App作为于用户交互的端, 可以说实际上是一个界面, 产品的业务, 服务都是由Server提供的. 而App与Server的交互依赖于网络, 故而网络优化, 也是我们的App优化中不可缺少的一个优化项.

    1, 网络连接对用户的影响

    App的网络连接对于用户来说, 影响很多, 且多数情况下都很直观, 直接影响用户对这个App的使用体验. 其中较为重要的几点:

    • 流量
      App的流量消耗对用户来说是比较敏感的, 毕竟流量是花钱的嘛. 现在大部分人的手机上都有安装流量监控的工具App, 用来监控App的流量使用. 如果我们的App这方面没有控制好, 会给用户不好的使用体验.

    • 电量
      电量相对于用户来说, 没有那么明显. 一般用户可能不会太注意. 但是如前文电量优化中说的那样, 网络连接(radio)是对电量影响很大的一个因素. 所以我们也要加以注意.

    • 用户等待
      也就是用户体验, 良好的用户体验, 才是我们留住用户的第一步. 如果App请求等待时间长, 会给用户网络卡, 应用反应慢的感觉, 如果有对比, 有替代品, 我们的App很可能就会被用户无情抛弃.

    2, 分析网络连接的工具

    2.1 Network Monitor

    Android Studio内置的Monitor工具中就有一个Network Monitor:

    其中:

    • Rx --- R(ecive) 表示下行流量, 即下载接收.
    • Tx --- T(ransmit) 表示上行流量, 即上传发送.

    怎么使用Network Monitor?

    Network monitor实时跟踪选定应用的数据请求情况. 我们可以连上手机, 选定调试应用进程, 然后在App上操作我们需要分析的页面请求.

    例如, 上图就是以CoderPub为例, 针对从repo列表界面进入repo详情界面的监控数据.

    可以看到从10s到30s之间, 20s时间内发生了多次数据请求, 且22s到27s之间的请求数据量还很大.

    分析代码可以看到, 在请求repo详情的时候是打包了很多请求的:

    @Override
    public Observable<RepoDetail> getRepoDetail(String owner, String name) {
        return Observable.zip(mRepoService.get(owner, name),
                mRepoService.contributors(owner, name),
                mRepoService.listForks(owner, name, "newest"),
                mRepoService.readme(owner, name),
                isStarred(owner, name),
                new Func5<Repo, ArrayList<User>, ArrayList<Repo>, Content, Boolean, RepoDetail>() {
                    @Override
                    public RepoDetail call(Repo repo, ArrayList<User> users, ArrayList<Repo> forks, Content readme, Boolean isStarred) {
                        RepoDetail detail = new RepoDetail();
    
                        repo.setStarred(isStarred);
                        detail.setBaseRepo(repo);
                        detail.setForks(forks);
    
                        // because the readme content is encode with Base64 by github.
                        readme.content = StringUtil.base64Decode(readme.content);
                        detail.setReadme(readme);
    
                        detail.setContributors(users);
                        return detail;
                    }
                });
    }

    这也验证了14s到20s间的四次数据请求, 另外由于repo详情界面会显示作者以及贡献者的图片, 而图片的数据量相对大, 故而23s到27s间有多次数据量很大的请求发生.

    2.2 网络代理工具

    一般来说, 网络代理工具有两个作用:

    1. 截获网络请求响应包, 分析网络请求
    2. 设置代理网络, 移动App开发中一般用来做不同网络环境的测试, 例如Wifi/4G/3G/弱网等.

    代理工具很多, 诸如Wireshark, Fiddler, Charles等, 在此不一一细说了, 使用方法自行问谷歌度娘. :)

    3, 哪些方面取优化网络连接

    第一节说到了网络请求对App和用户的影响, 那么我们怎么从哪些方面去优化网络进而减少甚至消灭这些影响呢?

    简单来说, 两个方面:

    • 减少Radio活跃时间

      • 也就是减少网络数据获取的频次.
      • 这就减少了radio的电量消耗, 控制电量使用.
    • 减少获取数据包的大小

      • 可以减少流量消耗
      • 也可以让每次请求更快, 在网络情况不好的情况下也有良好表现, 提升用户体验.

    那么, 具体应该从哪些方面着手呢?

    3.1 接口设计

    API设计

    App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示.

    例如, 注册登录. 正常会有两个API, 注册和登录, 但是设计API时我们应该给注册接口包含一个隐式的登录. 来避免App在注册后还得请求一次登录接口(有可能失败, 从而导致业务流程失败).

    再例如, 上文提到的获取repo详情, 实际上请求了4个接口, 请求了repo的信息, forks列表, contributors列表, readme, 这是因为github提供的接口是尽量单一职责的. 然而在我们的实际开发中, 我们的Server除了提供这些单一职责的小接口外, 最好还能组合一个满足客户端业务需求的repo详情接口出来.

    Gzip压缩

    使用Gzip来压缩request和response, 减少传输数据量, 从而减少流量消耗.

    考虑使用Protocol Buffer代替JSON

    从前我们传输数据使用XML, 后来使用JSON代替了XML, 很大程度上也是为了可读性和减少数据量(当然还有映射成POJO的方便程度).

    Protocol Buffer是Google推出的一种数据交换格式.

    如果我们的接口每次传输的数据量很大的话, 可以考虑下protobuf, 会比JSON数据量小很多.

    当然相比来说, JSON也有其优势, 可读性更高.

    本文以网络流量优化的角度推荐protobuf作为一个选择, 具体还需更具实际情况考虑.

    图片的Size

    上面Network Monitor中看到的22s到27s之间的有多次请求, 且数据量还很大. 就是在获取图片资源.

    图片相对于接口请求来说, 数据量要大得多. 故而也是我们需要优化的一个点.

    我们可以在获取图片时告知服务器需要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.

    我们现在很多公司的图片资源都是使用第三方的云存储服务的(七牛, 阿里云存储之类的).

    以七牛为例, 可以在请求图片的url中添加诸如质量, 格式, width, height等path来获取合适的图片资源:

    imageView2/<mode>/w/<LongEdge>
                     /h/<ShortEdge>
                     /format/<Format>
                     /interlace/<Interlace>
                     /q/<Quality>
                     /ignore-error/<ignoreError>
    
    

    3.2 网络缓存

    适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必要的流量消耗.

    关于Android App的网络缓存, 请参考MVP架构实现的Github客户端(4-加入网络缓存)一文.

    3.3 打包网络请求

    当接口设计不能满足我们的业务需求时. 例如可能一个界面需要请求多个接口, 或是网络良好, 处于Wifi状态下时我们想获取更多的数据等.

    这时就可以打包一些网络请求, 例如请求列表的同时, 获取Header点击率较高的的item项的详情数据.

    可以通过一些统计数据来帮助我们定位用户接下来的操作是高概率的, 提前获取这部分的数据.

    3.4 监听相关状态

    通过监听设备的状态:

    • 休眠状态
    • 充电状态
    • 网络状态

    结合JobScheduler来根据实际情况做网络请求. 比方说Splash闪屏广告图片, 我们可以在连接到Wifi时下载缓存到本地; 新闻类的App可以在充电, Wifi状态下做离线缓存.

    3.5 弱网测试&优化

    除了正常的网络优化, 我们还需考虑到弱网情况下, App的表现.

    3.5.1 弱网测试

    有几种方式来模拟弱网进行测试.

    Android Emulator

    创建和启动Android模拟器可以设置网络速度和延迟:

    创建时:

    启动时, 使用emulator命令:

    $emulator -netdelay gprs -netspeed gsm -avd Nexus_5_API_22

    具体参数参考这里这里, 需要翻墙.

    使用网络代理工具

    Charles为例:
    保持手机和PC处于同一个局域网, 在手机端wifi设置高级设置中设置代理方式为手动, 代理ip填写PC端ip地址, 端口号默认8888.

    其他模拟弱网方式

    如果你恰好也是iOS的开发者, Apple提供了Network Link Conditioner, 非常好用.

    可以模拟的网络情况与上述类似:

                                                            

    如果你使用Linux环境开发, 还可以试下facebook出的ATC.

    3.5.2 弱网优化

    利用上述工具模拟弱网, 在弱网情况下体验我们的App. 一般来说, 网络延迟在60ms内, 是OK的, 超过200ms就比较糟糕了. 我们需要做的是在比较糟糕的网络环境下还能给用户较好的体验.

    弱网优化, 本质上是在弱网的情况下能让用户流畅的使用我们的App. 我们要做的就是结合上述的优化项:

    • 压缩/减少数据传输量
    • 利用缓存减少网络传输
    • 针对弱网(移动网络), 不自动加载图片
    • 界面先反馈, 请求延迟提交
      例如, 用户点赞操作, 可以直接给出界面的点赞成功的反馈, 使用JobScheduler在网络情况较好的时候打包请求.

    结语

    网络优化, 是App优化中相当重要的一项优化. 除了客户端, 接口的优化外, 很多一部分优化还依赖于服务器端, 包括服务器端的代码开发, 部署方式等. 跟你的服务器开发/运维工程师一起聊聊这个话题吧:)



    作者:anly_jun
    链接:https://www.jianshu.com/p/d4c2c62ffc35
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • App性能优化:内存优化

    千次阅读 2020-01-03 14:22:41
    App性能优化:内存优化 本篇主要探讨app性能优化相关的知识点,预计20年2月底前完成 内存优化工具 内存管理机制 内存都懂解决 内存泄漏解决 MAT详解 小结 ...

    App性能优化:内存优化

    目录:

    1. 内存优化工具
    2. 内存管理机制
    3. 内存抖动解决
    4. 内存泄漏解决
    5. MAT详解
    6. 小结
    背景介绍
    • 内存是大问题但缺乏关注
    • 压死骆驼的最后一根稻草
    表现形式
    • 内存抖动:锯齿状,GC导致卡顿
    • 内存泄漏:可用内存减少、频繁GC
    • 内存溢出:OOM、程序异常

    1、工具选择

    • Memory Profiler
    • Memory Analyzer
    • LeakCanary
    Memory Profiler
    1. 实时图标展示内存使用量
    2. 识别内存泄漏、抖动
    3. 提供捕获堆转储、强制GC以及跟踪内存分配的能力
    Memory Profiler的使用
    1. 非常直观
    2. 线下平时使用
    Memory Analyzer(MAT)
    1. 强大的Java heap 分析工具,帮助查找内存泄漏和内存占用
    2. 生成整体报告,分析问题
    3. 线下深入使用
    LeakCanary
    1. 自动内存泄漏检测
    2. 线下集成

    2、android内存管理机制

    Java内存管理机制

    在这里插入图片描述

    Java内存回收算法-标记清除算法
    • 标记出所有需要回收的对象
    • 统一回收所有被标记的对象
      在这里插入图片描述
    标记回收算法存在的问题
    • 标记和清除的效率不高
    • 产生大量的内存碎片
    Java内存回收算法之 复制算法
    • 将内存分成两份,只将数据存储在其中一块上。
    • 当需要垃圾回收时,也是标记出废弃的数据,然后将有用数据复制到另一块内存上,最后将第一块内存全部清除
      在这里插入图片描述
    复制算法的问题
    • 实现简单,运行高效
    • 浪费一半空间,代价大
    Java内存回收算法之 标记整理算法
    1. 标记过程与“标记-清除算法”一样
    2. 存活对象往一端移动
    3. 清理其余内存
      在这里插入图片描述
    标记整理算法的特点
    1. 避免标记-清理导致的内存碎片
    2. 避免复制算法的空间浪费
    Java内存回收算法之 分代收集算法
    1. 结合多种收集算法优势
    2. 新生带对象存活率低:复制算法
    3. 老年代对象存活率高:标记-整理算法
    Android内存管理机制
    • 内存弹性分配,分配值和最大值受具体设备影响
    • OOM场景:内存真正不足,可用内存不足
    Dalvik 与Art区别
    • Dalvik仅固定一种回收算法
    • Art回收算法可运行期选择
    • Art具备内存整理能力,减少内存空洞
    Low Memory killer
    • 进程分类:前端、可见、服务、后台、空进程,优先级依次降低
    • 回收收益

    内存抖动案例

    ######制造内存抖动

        companion object {
            var datas: ArrayList<TestClass>? = null
            val handler = object : Handler() {
                override fun handleMessage(msg: Message) {
                    //创造内存抖动
                    for (i in 0..100) {
                        datas = ArrayList<TestClass>(100000)
                    }
                    sendEmptyMessageDelayed(0, 1000)
                }
            }
        }
    

    在这里插入图片描述

    内存抖动解决技巧
    1. 找循环或者频繁调用的地方
    2. 通过Profiler定位,锯齿状或者频繁的GC

    内存泄漏

    • 定义:内存中存在没有用的对象,又无法回收
    • 表现:内存抖动、可用内存逐渐减少

    内存泄漏案例

    1. 静态变量持有Activity引用导致Activity无法被回收
    //定义一个接口
    public interface Callback {
    
        void doOperation();
    }
    //定义持有Activity引用的类
    public class CallbackMananger {
        public static ArrayList<Callback> sCallbacks = new ArrayList();
    
        public static void addCallback(Callback callback) {
            sCallbacks.add(callback);
        }
    
        public static void removeCallBack(Callback callback) {
            sCallbacks.remove(callback);
        }
    }
    
    
    1. 在生成LeakCanaryActivity,显示一张图片
    
    class MemoryLeakActivity : AppCompatActivity(), Callback {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_memory_leak)
            val bitmap = BitmapFactory.decodeResource(resources, R.drawable.icon_leaktest)
            iv.setImageBitmap(bitmap)
            //保存Activity引用
            CallbackMananger.addCallback(this)
        }
    
        override fun doOperation() {
    
        }
    }
    
    
    1. 重复打开关闭 页面,即可在Profiler中看到内存成阶梯状上升,如下图所示:
      在这里插入图片描述
      显然:这里每次GC的的时候并没有导致MemoryLeakActivity被回收,内存图形呈现阶梯状显示。

    2. 使用MAT分析内存泄漏
      1. 进入官网下载MAT工具:MAT下载地址
      2. 下载对应系统版本
      在这里插入图片描述

    3. 安装MAT工具,双击zip文件解压后得到mat.app
      在这里插入图片描述

    4. 获取堆文件 Heap Dump
      在这里插入图片描述

    5. 将文件存到本地
      在这里插入图片描述
      在这里插入图片描述

    6. 注意这里是Android的hprof文件,需要使用android 的platform-tool里面的hprof-conv工具对文件进行一次格式转化,转化命令如下:
      ./hprof-conv /Users/hudingpeng/Desktop/memory-20200221T114049.hprof 2.hprof
      在这里插入图片描述

    7. 这样在platform-tools目录下会生成一个2.hprof文件,如下图所示:
      在这里插入图片描述

    8. 打开MAT工具:

      1. 直接点击mat.app会报错,按照以下步骤运行
      2. 右键mat.app => 显示包内容 =>进入 mat.app/Contents/MacOS ,此目录下就有工具MemoryAnalyzer =>双击直接打开工具就行了
        在这里插入图片描述
    9. 在这里插入图片描述
      10.点击open a Heap Dump选择我们的转化后的文件2.hprof 文件即可,下面分析MAT工具的一些常用用法

    MAT工具分析内存泄漏

    1. 打开hprot文件,选择Histogram
      在这里插入图片描述

    2. 搜索我们的泄漏的MemoryLeakActivity,可以看到有4个MemoryLeakActivity对象,表示已经泄漏了
      在这里插入图片描述

    3. 右键选择查看with incoming references
      在这里插入图片描述

    4. 选择一个,点击查看到GC Root的路径,看到具体引用的地方
      在这里插入图片描述
      在这里插入图片描述
      这样我们就看到了具体泄漏的地方就是,CallbackManager类里面的静态变量sCallbacks

    5. 点击Group by package 可以按包名排序
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      这样也可以很方便看到我们的包名下的类对象生成的情况,这里也可以看到MemoryLeakActivity在内存里有4个对象

    6. 第三个菜单项:dominator_tree 视图,显示对象占用内存的百分比
      在这里插入图片描述
      可以看到对象占用内存的百分比,给我们的内存优化提供一定的参考

    7. 第四个菜单项:OQL,相当于一种数据查询语言,我们直接搜索我们的类,点击感叹号查询,如下图所示
      在这里插入图片描述

    8. Top Consumer条目:通过图表的形式显示占用内存最多的对象
      在这里插入图片描述
      在这里插入图片描述
      这对我们的内存占用优化也是一个不错的参考

    关于BitMap的优化

    Btimap的内存模型
    1. 获取Bitmap占用的内存

      1. getByteCount()方法
      2. 宽 x 高 x 一像素占用的内存
    2. 常规方式:
      背景:图片对内存大小至关重要、图片宽高大于控件宽高

    3. 通过Epic ARTHook优雅检测不合理的图片
      Epic:Epic 是一个在虚拟机层面、以 Java Method 为粒度的 运行时 AOP Hook 框架。简单来说,Epic 就是 ART 上的 Dexposed(支持 Android 4.0 ~ 10.0)。它可以拦截本进程内部几乎任意的 Java 方法调用,可用于实现 AOP 编程、运行时插桩、性能分析、安全审计等。
      Epic 被 VirtualXposed 以及 太极 使用,用来实现非 Root 场景下的 Xposed 功能,已经经过了相当广泛的验证。
      非常厉害的AOP框架,参考连接:Epic AOP框架
      这里我们Hook setImageBitmap方法:

    import android.graphics.Bitmap;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.widget.ImageView;
    
    import com.optimize.performance.utils.LogUtils;
    import com.taobao.android.dexposed.XC_MethodHook;
    
    public class ImageHook extends XC_MethodHook {
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            // 实现我们的逻辑
            ImageView imageView = (ImageView) param.thisObject;
            checkBitmap(imageView,((ImageView) param.thisObject).getDrawable());
        }
    
    
        private static void checkBitmap(Object thiz, Drawable drawable) {
            if (drawable instanceof BitmapDrawable && thiz instanceof View) {
                final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
                if (bitmap != null) {
                    final View view = (View) thiz;
                    int width = view.getWidth();
                    int height = view.getHeight();
                    if (width > 0 && height > 0) {
                        // 图标宽高都大于view带下的2倍以上,则警告
                        if (bitmap.getWidth() >= (width << 1)
                                && bitmap.getHeight() >= (height << 1)) {
                            warn(bitmap.getWidth(), bitmap.getHeight(), width, height, new RuntimeException("Bitmap size too large"));
                        }
                    } else {
                        final Throwable stackTrace = new RuntimeException();
                        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                            @Override
                            public boolean onPreDraw() {
                                int w = view.getWidth();
                                int h = view.getHeight();
                                if (w > 0 && h > 0) {
                                    if (bitmap.getWidth() >= (w << 1)
                                            && bitmap.getHeight() >= (h << 1)) {
                                        warn(bitmap.getWidth(), bitmap.getHeight(), w, h, stackTrace);
                                    }
                                    view.getViewTreeObserver().removeOnPreDrawListener(this);
                                }
                                return true;
                            }
                        });
                    }
                }
            }
        }
    
    
        private static void warn(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight, Throwable t) {
            String warnInfo = new StringBuilder("Bitmap size too large: ")
                    .append("\n real size: (").append(bitmapWidth).append(',').append(bitmapHeight).append(')')
                    .append("\n desired size: (").append(viewWidth).append(',').append(viewHeight).append(')')
                    .append("\n call stack trace: \n").append(Log.getStackTraceString(t)).append('\n')
                    .toString();
    
            LogUtils.i(warnInfo);
        }
    
    }
    
    

    在App onCreate方法里注册要Hook的方法,传入ImageHook

     DexposedBridge.hookAllConstructors(ImageView.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    DexposedBridge.findAndHookMethod(ImageView.class, "setImageBitmap", Bitmap.class, new ImageHook());
                }
            });
    

    more:LeakCanary 监控内存泄漏

    内存优化总结

    优化大方向
    1. 内存泄漏
    2. 内存抖动
    3. Btimap
    优化细节
    1. LargeHeap属性 (建议开启,大概率能申请到更多内存)
    2. onTrimMemory (系统块干掉app了,可以手动清理界面,跳转到主界面)
    3. 使用系统优化过的集合:SparseArray
    4. 谨慎使用SharedPreferences
    5. 谨慎使用外部库
    6. 业务架构设计合理
    展开全文
  • Android--App优化之性能分析工具

    千次阅读 2016-09-20 14:15:23
    App优化之性能分析工具App优化之提升你的App启动速度之理论基础App优化之提升你的App启动速度之实例挑战App优化之Layout怎么摆App优化之ANR详解App优化之消除卡顿App优化之内存分析工具App优化之内存泄露怎么解App...
  • Android App优化之高效网络请求

    千次阅读 2016-10-11 09:20:35
    背景:Android App优化, 要怎么做? App优化之性能分析工具 App优化之提升你的App启动速度之理论基础 App优化之提升你的App启动速度之实例挑战 App优化之Layout怎么摆 App优化之ANR详解 App优化之消除卡顿 App优化之...
  • 优化APP性能的三大方法

    千次阅读 2022-04-06 17:13:57
    对于开发人员来说“性能优化”是再熟悉不过了,因为一个合格的APP操作是流畅的,性能是稳定的,所以开发人员的工作除了编写代码之外,就是检测分析APP的性能,然后找出原因,进而优化APP性能。另外,除了人为检测...
  • Android App优化方案梳理

    千次阅读 2015-09-16 20:03:56
    1,内存优化: 1.1 使用android:largeHeap属性扩大app内存上限 1.2 一个ui界面有较多的、规律的、相对固定的图片时,将图片合并加载和绘制 1.3 使用线程池统一处理图片的加载,线程池数量根据cpu核数确定 1.4 ...
  • App启动时间优化 一、首先我们需要清楚App的主题加载 你的App的主题位于 res/values/styles 我们点击Light主题进去,会发现此主题位于 app/build/intermediates/exploded-oar/...
  • 2022千月影视全新改版影视app系统-已经优化全屏功能,支持投屏,已自测 可控性强,前端90%的界面功能都可以在后台设置 源码仅供个人学习交流
  • APP优化 布局优化

    千次阅读 2017-07-26 18:02:35
    本章节讲述布局优化时三种标签的详解 一.include标签 include标签常用于将布局中的公共部分提取出来供其他layout使用,以实现布局模块化。 代码 1.公共Layout 2.引入使用页面的Layout ...... 即: 3.引入使用的...
  • APP优化篇——优化关键评估指标

    千次阅读 2018-09-15 22:37:16
    目前,随着APP行业的竞争越来越激烈,功能也越发丰富,人们评价一款产品的优秀程度,已经不能单纯通过 ”是否具备某些功能“ 来评价某个产品了,纯技术壁垒的产品已经是凤毛麟角,从用户角度,客户端不仅仅需要具备...
  • Android App 优化之消除卡顿

    万次阅读 2018-03-06 09:50:26
    App优化之提升你的App启动速度之理论基础 和 App优化之提升你的App启动速度之实例挑战 . 在这里需要提下我们在 性能分析工具 中提到的StrictMode. 2.3.1 StrictMode的使用 StrictMode用来基于线程或VM设置一些策略, ...
  • 会展App应用优化研究.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 381,908
精华内容 152,763
关键字:

app优化