关于segmentfault:移动应用性能优化

11次阅读

共计 4937 个字符,预计需要花费 13 分钟才能阅读完成。

前言

间隔我的 GoodWeather 开发曾经过来一年多的工夫了,这个 App 我是齐全开源,并且把开发的步骤都颁布了进去,在开发过程中我遇到过很多问题,刚好借着这个机会来说一下。

注释

GoodWeather App 是一个天气的 App,能够实时定位你以后的所在位置,查问到当地的天气,并且提供地图定位模式和语音输入疾速查问的形式,我的项目的源码地址如下:GoodWeather,不不便下载源码的能够间接通过二维码下载安装体验一下:

这个我的项目我利用工作之余劳动的工夫陆陆续续的写完了,写的过程中一直的在欠缺和批改,也会听取读者的倡议减少相应的性能,这个过程中也遇到了一些问题,例如:ANR(程序无响应)、NullPointerException(空指针异样)、RunningTimeException(运行时异样)、ArrayIndexOutOfBoundsException(数组索引越界异样)、IllegalArgumentException(非法参数)、NumberFormatException(数字格局异样)等等。

一、问题

就上述的这些异样你在日常开发中必定会遇到的,大体说一下。

① ANR

ANR(全称:Application Not Responding)程序无响应,要解决问题首先要晓得问题呈现有哪些可能性,而后在联合你以后利用的理论状况去排查,最终找到解决办法。这是我的思路,那么造成 ANR 有哪些可能呢?

可能性一:主线程阻塞,在主线程中进行耗时操作过多(数据库读写、文件读写、网络申请、大数据计算等)。可能性二:内存透露,列如 App 的启动页是一个高清的图片,在有的手机上能够失常运行,有的手机机会闪退。可能性三:适度绘制,这个说法就是下面两种可能的相结合,首先你在主线程中绘制 UI,其次绘制的图比拟大或者反复绘制都会有 ANR 可能。

理论中的可能性可不止这三点,说说怎么解决的,第一个可能性,主线程阻塞,因为执行了大量的耗时操作造成的,那么这个时候就要应用子线程去进行耗时操作的解决。例如网络申请、数据库读写、文件读写都应该开一个子线程去执行,而不应该在主线程中解决,对于 Activity 来说 UI 线程就是主线程,UI 线程要负责页面 UI 的绘制,这里又会引发另一个问题,那就是当你的 view 由主线程绘制时,在子线程中进行扭转时会报错,所以子线程可不可以刷新 view 呢?是能够的,只不过有一个前提,那就是你的子线程创立了这个 view,此时这个子线程就是这个 view 的 UI 线程。

而对于内存透露来说,惯例状况下是资源处理不当造成的。举个艰深的例子,有两座桥,A 和 B,A 最大承重 2 吨,B 最大承重 6 吨,有 100 辆车要过桥,车上载重 1 吨到 6 吨不等,失常的调配就是小分量走小桥,大分量走大桥,当资源分配不合理就会呈现 1 吨的车走承重 6 吨的桥,而后 6 吨的车走承重 2 吨的桥,那怕桥品质再好终究会塌,可能例子不是很失当,然而意思应该说的很分明了,就是资源正当应用,不必就要回收,回到一个我之前遇到的问题,就是高清图片,国产手机的定制化是很多的,各个厂商都更改了 Google 的源码变成了定制化零碎,这对用户来说没啥,然而对开发者来说就很好受了,因为一个问题你是躲不开的,那就是适配。

我之前遇到的问题就是我在启动页用了一个高清图,而后在我的手机上失常运行,而后在一个读者的手机上就间接闪退了。报错的图如下:

从这个图能看出什么内容呢?
首先这是一个运行时异样,其次和图片的绘制有关系,那么这么一联合就是适度绘制的问题。
过后这个读者就找到我,而后我就开始排查,首先是启动 App 的时候做了什么,这里还会波及到一个点,那就是 App 的启动优化,这个点很要害。不过首先要解决 bug,通过排查最终定位到是图片的问题,这里就阐明了国内厂商对于手机屏幕及本身零碎的定制是千差万别的,最终的解决办法就是针对于高清图的文件批改到大分辨率文件夹下,这属于一个比拟低级的谬误,我之前搁置的都是惯例的文件夹,吃一堑长一智。

② NullPointerException

NullPointerException(空指针异样),我置信用 Java 写 Android 的敌人必定遇到过找个问题,那就是 null,常说的空对象。这个问题一般来说在开发的时候做得好能够防止 90% 的呈现概率。最大的呈现状况就是赋值的时候,只有呈现这个,那么对应的就是你的程序闪退了,哦豁!这个月奖金又没了,打工人的辛酸,留下了懊悔的泪水。所以应用 Java 开发 Android 的时候要特地留神这一点,留神 null。这一点 Kotlin 就做的很好,因为空平安这个个性。那么如果呈现问题了,线上的我的项目,用户就说会闪退,甚至都不说是什么时候闪退的,你要怎么办呢?怎么去解决呢?通过第三方 SDK,例如友盟,你对接 SDK 之后,公布之后,报错时,平台上会有报错的信息与日志,这样开发者就能够疾速定位问题,而后解决问题了,而后对 App 做一个更新,这就完满化解了,尽管扣的钱回不来了,然而你及时止损了。至于其余的一些异样都是惯例的,发现了就能解决,在开发过程中。最麻烦的就是上线之后的问题要怎么去定位和解决。

其实在理论的 App 开发中,大部分的问题都能在开发和测试阶段发现并且解决,然而巧的就是在上线之后到了用户手里,就呈现了之前没有发现到的问题,这个时候开发和测试就要相互甩锅了,扯皮是常事。扯完之后还是要想方法解决才行,因而对于当初的线上我的项目来说,上线之前对接一款性能检测,谬误收集的 SDK 是很有必要的,上面我将针对于我的这个 GoodWeather 进行这个 SDK 的对接与应用。

二、友盟应用

点击友盟进入官网,而后注册和登录。

1、创立平台利用

登录后点击 进入工作台,这里能够查看利用信息,如果还没有创立过利用就增加新利用。

在友盟上创立利用,获取 AppKey

注册利用。此时 AppKey 曾经生成了,而后抉择须要开明的产品,这里抉择利用性能监控 U -APM。

确认开明。

复制这个 App Key 到本人的我的项目中,一会儿会用到。关上我的项目的 build.gradle,增加 maven 库。两处中央,同一句代码:
groovy

maven {url 'https://repo1.maven.org/maven2/'}


而后关上 app 模块的 build.gradle,在 dependencies 中增加如下代码:
groovy
// 友盟根底组件库(所有友盟业务 SDK 都依赖根底组件库)

implementation "com.umeng.umsdk:common:9.4.2" //(必选)implementation "com.umeng.umsdk:asms:1.4.1" // asms 包依赖(必选)
implementation "com.umeng.umsdk:apm:1.4.2" // U-APM 包依赖(必选)

而后 Sync Now,同步一下我的项目。
因为友盟的 SDK 须要获取手机的设施信息和网络状态,因而须要在 AndroidManifest.xml 中配置相应的权限
xml

<uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>
<uses-permissionandroid:name="android.permission.INTERNET"/>

其中 READ_PHONE_STATE 须要动静申请。

而后就是初始化了,这里要留神一点就是须要在在《隐衷政策》中向用户告知应用友盟 SDK,参考条款如下:应用 SDK 名称:友盟 SDK 服务类型:请按 SDK 性能填写,如利用性能监控平台 U-APM 收集个人信息类型:设施信息(IMEI/MAC/Android ID/IDFA/OpenUDID/GUID/SIM 卡 IMSI 地理位置信息等)隐私权政策链接:https://www.umeng.com/page/po… 这个隐衷协定的弹窗理当做成相似这样的成果。假如这是你之前的隐衷政策,

那么你须要在这个外面加上对于友盟 +SDK 的应用阐明。而后用户批准后能力进行这个初始化的操作,在 Application 的 onCreate 中进行。这里有一个预初始化和一个正式初始化,预初始化在程序第一次装置运行时应用。在用户批准了隐衷政策之后调用正式的初始化,比方上面这个图这样

好了,当初基本上就实现了对接的工作,上面就来应用它。

二、应用

① 日志应用
当对接了友盟 SDK 之后,就会打印友盟的相干日志,而上线的时候就不必再打印了。

能够通过上面这行代码设置敞开。
java
UMConfigure.setLogEnabled(boolean)

② 解体剖析
实现了 SDK 对接之后,即可应用 Java、Native 解体剖析、ANR 剖析性能,无需额定其余接入操作。如果须要对 Native 进行采集能够这样写:
java

      // 针对于 Native 解体信息采集
        final Bundle customInfo = new Bundle();
        customInfo.putBoolean("mCallNativeDefaultHandler",true);
        CrashApi.getInstance().updateCustomInfo(customInfo);

解体回调(自定义字段)
java

// 解体回调
        UMCrash.registerUMCrashCallback(new UMCrashCallback(){
            @Override
            public String onCallback(){return "App 程序解体了";}
        });

自定义异样接口
在开发中通常有本人异样 try catch,那么也能够将 catch 中的异样通过友盟的接口传到后盾去,而后开发者去查看。
java

try {// 抛出异样的代码} catch (Exception e){UMCrash.generateCustomLog(e,"UmengException");
        }

应用

③ 自定义版本号
有时候线上可能有多个版本那么,能够通过自定义版本号 API,使 SDK 所上报数据绑定您指定的 App 版本信息。
java

UMCrash.setAppVersion("1.0.0", "release", "0001");

应用

有了这些,你就能够等着程序报错的日志上传到友盟上了,首先找到友盟上查看日志信息的中央。这个中央的确不太好找

点击稳定性。

立刻应用。

上面就能够进行相干的日志查看了,那么先来写一个 bug 吧。

比方我在 App 的启动页的 onCreate 中写下这样的代码。
java

 try {Thread.sleep(1000000);
        } catch (InterruptedException e) {e.printStackTrace();
        }

而后运行,看 AS 的控制台日志

这个日志就很全面了,不过这是友盟 SDK 的日志打印,本地调试的确能够应用,那么它有没有传到平台上呢? 毕竟线上我的项目的错误信息日志才是要害。

很显著,上传了这个谬误,再向下滑动去查看这个谬误的详情。


点击右边的蓝色报错处

这里通知你报错的具体代码行,以及下方这里有你报错设施的信息,不便你去排查起因,再往下看。

这里通知你报错的起因是什么?主线程睡眠工夫过长,导致的线程阻塞,程序无响应,ANR。
这里左边的行为日志,也很不错,能够让你晓得你在以后这个页面是在做什么。

这里对应的是页面浏览,正当,因为我的确还没有做什么。

而这个内存快照,就是不便你查看报错时的内存应用状况,能够酌情进行优化。

最初这个自定义字段,很显著就是在代码中写的一个解体的回调。

这阐明我自定义字段的日志也上传了。

通过介绍、接入、应用和日志剖析理解到友盟的弱小,这对于线上我的项目来说是一个福音,提交的错误信息可能疾速上传,定位到,疾速解决问题。

更多的性能应用须要开发者自行去摸索,这里只是起到一个抛砖引玉的成果,山高水长,后会有期~

作者:李龙威

正文完
 0