StrictMode检测Android中的违规代码 (一)(内存泄露,IO操作,网络操作)

1、最近看到一篇关于Android性能调优的文章,里面提到了一个性能调优利器StrictMode,并且还是系统自带,不需要第三方引入。(之前一直没发现,惭愧)试着用它去检测了一下之前的代码,确实发现不少问题,特此记录分享下。

2.关于使用比较简单,建议在Applicaiton的oncreate方法中调用。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());

ps:第一行setThreadPolicy()这个方法顾名思义是开启线程策略检测(detectAll就是开启下面的所有检测)

  • 自定义的耗时调用 使用detectCustomSlowCalls()开启
  • 磁盘读取操作 使用detectDiskReads()开启
  • 磁盘写入操作 使用detectDiskWrites()开启
  • 网络操作 使用detectNetwork()开启

    第二行setVmPolicy()方法是开启虚拟机策略检测,就是各种泄露问题。

  • Activity泄露 使用detectActivityLeaks()开启
  • 未关闭的Closable对象泄露 使用detectLeakedClosableObjects()开启
  • 泄露的Sqlite对象 使用detectLeakedSqlLiteObjects()开启
  • 检测实例数量 使用setClassInstanceLimit()开启

3.下面有这样一行代码,拿到外部sd卡的路径,这行代码放在主线程执行,正常情况下,是不会报错的。但是实际上也属于违规代码。

    @Override
    public void onCreate() {
        super.onCreate();
        String path = Environment.getExternalStorageDirectory().getPath();

    }

我们来看看报了什么提示:

大概能知道什么意思,就是说这句代码属于io操作,在主线程执行了,给出警告了。我相信很多人写着行代码都随手在主线程写了,当然这只是一个小例子,为了说明一下io操作在主线程执行的隐患。

解决办法:把这段代码放在子线程执行就不会报警告了,至于结果回调处理,就不多说了。

4.一个关于activity实例导致内存泄露的问题,有个需求是token失效的时候,app请求网络,后台会返回失效码,app这边需要从A页面跳转到登陆页面B,引导用户重新登陆进入C页面,所以,我在BaseActivity里面把当前activity用一个list维护起来,当token跳转到登陆页面的时候,把list里面的activity全部remove掉,确保当前list里面只有登陆页面的实例,(这里面有个小问题就是,用户不手动按返回键,而只是通过startactivity()跳转到另一个页面的时候,若没有finish,上一个activity是不会走ondestory的,所以这个实例实际上应该是在的),所以,当A页面跳转到登陆页面B的时候,需要手动调一下remove移除掉A,否则可能会导致A页面没有走ondestory方法,实例会一直存在。我用StrictMode打印日志的时候发现,从C主页跳转到A DataActivity时,A的实例一直增加,仔细查了下代码,发现,基类里面添加了A进去,但是,ondestory的时候没有调用remove当前activity的方法,导致,A实例一直增加。(即使用户是手动按返回键退出A页面,但因为A已经被List引用了,所以,A的资源还是无法全部释放,)

11-22 19:11:13.523 23937-23937/com.mzj.bd E/StrictMode: class com.mzj.bd.view.question.WebViewActivity; instances=2; limit=1
    android.os.StrictMode$InstanceCountViolation: class com.mzj.bd.view.question.WebViewActivity; instances=2; limit=1

我们再来看看,Android studio自带的内存分析工具,分析的结果。下图右边可以看到,点了6次,就有6个实例了,明显的泄露了。

解决办法也很简单:

只需要在A的基类activity的ondestory方法里面remove掉list里面的实例就OK。

解决后无论跳转多少次,都不会出现多个实例的情况了。

5.关于百度地图mapview没有及时销毁导致的内存泄露问题。

(1)假如有一个加载百度地图的SignLocationActivity,销毁后必须伴随mapview的onDestroy()方法,否则,会造成LocationActivity的泄露,一直回收不了。即使SignLocationActivity已经走了生命周期的ondestory方法。我们先看下StrictMode替我们打出的信息。

11-23 10:13:21.864 16150-16150 E/StrictMode: class com.location.SignLocationActivity; instances=2; limit=1
    android.os.StrictMode$InstanceCountViolation: class com.location.SignLocationActivity; instances=2; limit=1
        at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

很明显,这是说SignLocationActivity的实例已经存在2个了,限制最多只能存在一个。查找下代码,发现SignLocationActivity的ondestory方法没有及时调用mapview的ondestory方法。导致mapview引用到SignLocationActivity的资源无法销毁。再看下此时的as打印的内存信息。(点了2次,并且手动gc一次,已经存在2个SignLocationActivity实例了,明显的泄露了)

再看看这个,Shallow Size指的是该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收器能回收的内存总和。如果改实例能正常回收,理论上Shallow Size和Retained Size大小基本一致,这里的Retained Size 明显大于Shallow Size,说明,有很多其他地方引用的资源,得不到释放。原因也写的很清楚,是SignLocationActivity的mcontext上下文,被mapview引用,mapview没有销毁掉,SignLocationActivity资源得不到释放。

解决办法:在SignLocationActivity的ondestory方法调用mapview的ondestory方法。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mBaiduMap!=null){
            mBaiduMap.clear();
        }
        if(signMapView!=null){
            signMapView.onDestroy();
        }

    }

6.还有一个关于百度地图的内存泄露问题,在初始化LocationClient的时候,mLocationClient = new LocationClient(context);切记不要用当前activity的context,要用applicationContext,否则会出现下面的警告。

android.app.ServiceConnectionLeaked: Activity com.location.LocationActivity has leaked ServiceConnection com.baidu.location.b@fa723f1 that was originally bound here
        at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1344)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值