导致内存泄露的常见错误 - Android 外文翻译专区 - 安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户 - Powered by Discuz!
登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 247|回复: 6

导致内存泄露的常见错误

[复制链接]

2

主题

16

帖子

2

安币

初级码农

Rank: 1

发表于 2016-12-23 11:42:43 | 显示全部楼层 |阅读模式
本帖最后由 追击的树袋熊 于 2016-12-23 16:43 编辑

原文地址:http://stackoverflow.com/documentation/android/2687/memory-leaks#t=201612230215584380561

原文作者:Daniel Nugent

译文出自:安卓巴士

译者:李海洲


1. AsyncTask使用
一个常见的错误就是AsyncTask 持有所在的宿主Activity (或者 Fragment)的强引用

   class MyActivity extends Activity {  
           private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {   
           // Don't do this! Inner classes implicitly keep a pointer to their   
           // parent, which in this case is the Activity!
          }   }

这个问题很容易发生在当 AsyncTask 超出了它所在的宿主Activity的生命周期
典型的情况是配置发生变化时(比如横竖屏切换),线程任务没有执行结束
解决方法:
将你的AsyncTask设置为静态类,这样的话就不会持有外部Activity的引用。此时,采用弱引用(weakReference)的方式持有宿主Activity的引用

class MyActivity extends Activity {  
        static class MyTask extends AsyncTask<Void, Void, Void> {   
        // Weak references will still allow the Activity to be garbage-collected   
        private final WeakReference<MyActivity> weakActivity;    
        MyTask(MyActivity myActivity) {      
           this.weakActivity = new WeakReference<>(myActivity);   
        }   

        @Override   
        public Void doInBackground(Void... params) {      
           // do async stuff here   
       }   
        @Override   
        public void onPostExecute(Void result) {      
           // Re-acquire a strong reference to the activity, and verify      
           // that it still exists and is active.      
           MyActivity activity = weakActivity.get();
     
           if (activity == null  || activity.isFinishing()  || activity.isDestroyed()) {        
           // activity is no longer valid, don't do anything!        
            return;     
          }      
          // The activity is still valid, do main-thread stuff here   
       }  
    }
}

PS: (译者注)很重要的守则是让内部类为静态的,尤其是它们要做耗时的后台任务的时候。或者更好的方法是把这个类移到外面作为单独的类。用非静态的内部类做耗时的后台任务总是很糟糕的实践,不光是在安卓中。不过使用弱引用并非最佳方法,详情可参见两篇写的很好的网址。1. http://weixin.niurenqushi.com/article/2016-12-20/4728678.html 2. https://medium.com/google-developer-experts/weakreference-in-android-dd1e66b9be9d#.ppwaguxq2

2. 使用适当的contexts:
使用适当的上下文:
比如Toast,由于Toast需要在多个界面都能看到而不是只有一个界面,使用getApplicationContext() , 还有由于Service在activity里启动它之后能够一直运行,同样采用getApplicationContext()
Intent myService = new Intent(getApplicationContext(), MyService.class)

3. 确保关闭服务
举个例子:我用了intentService并在其中使用了谷歌位置服务的api,忘记调用googleApiClient.disconnect();
//Disconnect from API onDestroy()   

if (googleApiClient.isConnected()) {        
     LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, GoogleLocationService.this);        
     googleApiClient.disconnect();   
}

4. 检查 image 以及 bitmaps 的使用:
如果你正在使用Square's library Picasso 别忘了使用.fit()
Picasso.with(ActivityExample.this)
//Activity context               
            .load(object.getImageUrl())                           
            .fit() //This avoided the OutOfMemoryError               
            .centerCrop()   //makes image to not stretch               
            .into(imageView);

5. 广播不要忘记unregister

6. 使用 java.util.Observer (Observer pattern)的话,确保记得使用 deleteObserver(observer);


检测内存泄露工具:
LeakCanary 是一个开源java库,用于检测应用中的内存泄露
Step1:
在你的AndroidStudio应用 build.gradle中添加如下依赖:
dependencies {   

    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'   
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'   
    testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
Step2:
在 Application 类中添加如下:
public class ExampleApplication extends Application

{  
         @Override
         public void onCreate() {   
               super.onCreate();      
               if (LeakCanary.isInAnalyzerProcess(this)) {      
               // This process is dedicated to LeakCanary for heap analysis.      
               // You should not init your app in this process.      
                    return;   
              }   
             LeakCanary.install(this);
             }
}
这个时候,当你的activity发生泄露时,LeakCanary会自动侦测到
在 debug build 中,如果检测到某个 activity 有内存泄露,LeakCanary 自动地手机端显示一个通知(译者注)





10

主题

1265

帖子

1391

安币

Android大神

安医生安卓安全专家|手机安全卫士|手机安全管家|手机安全软件

Rank: 6Rank: 6

发表于 2016-12-23 11:47:16 | 显示全部楼层
׿ʿ好的内容真的很多~赞

9

主题

548

帖子

-3

安币

限制会员

发表于 2016-12-23 11:47:26 | 显示全部楼层
׿ʿ好的内容真的很多~赞

8

主题

550

帖子

-135

安币

限制会员

发表于 2016-12-23 11:47:36 | 显示全部楼层
学习...学习...

17

主题

542

帖子

-99

安币

限制会员

发表于 2016-12-23 11:54:28 | 显示全部楼层
帮帮顶顶!!

7

主题

606

帖子

300

安币

攻城狮

Rank: 3Rank: 3

发表于 2016-12-23 11:57:00 | 显示全部楼层
感谢分享,安卓巴士有你更精彩:lol

85

主题

1046

帖子

85

安币

程序猿

Rank: 2

发表于 2016-12-23 12:01:52 | 显示全部楼层
支持,感谢,祝巴士越来越好~
*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /5 下一条
联系我们
关闭
合作电话:
13802416937
Email:
[email protected]
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表