- 浏览: 2204405 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
在很久很久之前,看过一篇关于内存泄露的文章,里面列举了比较全的应该注意的问题,后来找不到原文地址,今天翻了微博,找到了该文章,为了方便日后自己查看,将注意的问题提取出来。在android开发中,我们的编码习惯可能会让我们编写出一些容易导致内存泄露的代码。所以我们应该要养成一个良好的编码习惯。
单例
平时,我们可能会这样写单例
然后这样写会有隐患,原因是如果我们再Activity中或者其他地方使用Singleton.getInstance()时,我们会顺手写this或者mContext(这个变量也是指向this)作为参数传进去。我们的Singleton是单例,意味着被初始化后就应该一直存在内存中,以方便我们以后调用的时候不会再次创建Singleton对象,但是Singleton中的mContext变量一直都会持有Activity中的Context,导致Activity即使执行了onDestroy方法,也不能够将自己销毁,但是ApplicationContext就显然有所不同了,它一直伴随着我们的应用存在,所以就不用担心前面所说的导致Activity无法销毁的问题了。于是就诞生了正确的写法。
匿名内部类
在Android开发中,很多地方会用到匿名内部类,比如事件的监听,Handler的消息处理等等,而一旦使用错误,也会导致内存泄露。
当我们执行了MainActivity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的MainActivity的引用,所以这导致了MainActivity无法回收,进而导致MainActivity持有的很多资源都无法回收,所以产生了内存泄露。然而一个静态的匿名内部类实例是不会持有外部类的引用的。所以正确的写法应该是这样的。
很多时候我们甚至会使用handler发送一个匿名Runnable对象,同样的也会导致内存泄露的问题。因此Runnable对象应该也要使用静态的匿名内部类。
使用的时候这样用就可以了
Handler
在使用了Handler之后,记得在onDestroy里面调用
移除相关消息。
我们可以使用
当参数为null时,可以清除掉所有跟次handler相关的Runnable和Message,我们在onDestroy中调用次方法也就不会发生内存泄漏了。
对以上几点做一个总结
- 不要让生命周期长于Activity的对象持有到Activity的引用
- 尽量使用Application的Context而不是Activity的Context
- 尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用。如果使用静态内部类,将外部实例引用作为弱引用持有。
- 垃圾回收不能解决内存泄露,了解Android中垃圾回收机制
Context
注意Context与ApplicationContext的区别
- View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
- Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
- ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
- Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。
大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?
- 数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。
- 数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
- 数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。
好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现。实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。
单例
平时,我们可能会这样写单例
public class Singleton{ private static Singleton instance; private Context mContext; private Singleton(Context mContext){ this.mContext = mContext; } public static Singleton getInstance(Context context){ if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(context); } } } return instance; } }
然后这样写会有隐患,原因是如果我们再Activity中或者其他地方使用Singleton.getInstance()时,我们会顺手写this或者mContext(这个变量也是指向this)作为参数传进去。我们的Singleton是单例,意味着被初始化后就应该一直存在内存中,以方便我们以后调用的时候不会再次创建Singleton对象,但是Singleton中的mContext变量一直都会持有Activity中的Context,导致Activity即使执行了onDestroy方法,也不能够将自己销毁,但是ApplicationContext就显然有所不同了,它一直伴随着我们的应用存在,所以就不用担心前面所说的导致Activity无法销毁的问题了。于是就诞生了正确的写法。
public class Singleton{ private static Singleton instance; private Context mContext; private Singleton(Context mContext){ this.mContext = mContext; } public static Singleton getInstance(Context context){ if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(context.getApplicationContext()); } } } return instance; } }
匿名内部类
在Android开发中,很多地方会用到匿名内部类,比如事件的监听,Handler的消息处理等等,而一旦使用错误,也会导致内存泄露。
public class MainActivity extends Activity{ private Button btn; private Handler handler = new Handler(){ @override public void handlerMessage(Message msg){ } }; @override public void onCreate(Bundle bundle){ super.onCreate(bundle); setContextView(R.layout.activity_main); btn=(Button)findViewById(R.id.btn); btn.setOnClickListner(View.OnClickListener(){ @override public void onClick(View view){ Message message = Message.obtain(); handler.sendMessage(message); } }); } }
当我们执行了MainActivity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的MainActivity的引用,所以这导致了MainActivity无法回收,进而导致MainActivity持有的很多资源都无法回收,所以产生了内存泄露。然而一个静态的匿名内部类实例是不会持有外部类的引用的。所以正确的写法应该是这样的。
public class MainActivity extends Activity{ private Button btn; private static class MyHandler extends Handler { private final WeakReference<MainActivity> mActivity; public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { MainActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler handler = new MyHandler(this); @override public void onCreate(Bundle bundle){ super.onCreate(bundle); setContextView(R.layout.activity_foo_layout); btn=(Button)findViewById(R.id.btn); btn.setOnClickListner(View.OnClickListener(){ @override public void onClick(View view){ Message message = Message.obtain(); handler.sendMessage(message); } }); } }
很多时候我们甚至会使用handler发送一个匿名Runnable对象,同样的也会导致内存泄露的问题。因此Runnable对象应该也要使用静态的匿名内部类。
private static class MyRunnable implements Runnable{ private WeakReference<TextView> textViewWeakReference; public MyRunnable(TextView textView){ textViewWeakReference = new WeakReference<TextView>(textView); } @override public void run(){ final TextView textView = textViewWeakReference.get(); if(textView != null){ textView.setText("OK"); } }; }
使用的时候这样用就可以了
handler.postDelayed(new MyRunnable(textView),1000 * 60 * 10);
Handler
在使用了Handler之后,记得在onDestroy里面调用
handler.removeCallbacksAndMessages(object token);
移除相关消息。
我们可以使用
handler.removeCallbacksAndMessages(null);
当参数为null时,可以清除掉所有跟次handler相关的Runnable和Message,我们在onDestroy中调用次方法也就不会发生内存泄漏了。
对以上几点做一个总结
- 不要让生命周期长于Activity的对象持有到Activity的引用
- 尽量使用Application的Context而不是Activity的Context
- 尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用。如果使用静态内部类,将外部实例引用作为弱引用持有。
- 垃圾回收不能解决内存泄露,了解Android中垃圾回收机制
Context
注意Context与ApplicationContext的区别
- View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
- Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
- ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
- Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。
大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?
- 数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。
- 数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
- 数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。
好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现。实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。
发表评论
-
带你深入理解 FLUTTER 中的字体“冷”知识
2020-08-10 23:40 635本篇将带你深入理解 Flutter 开发过程中关于字体和文 ... -
Flutter -自定义日历组件
2020-03-01 17:56 1111颜色文件和屏幕适配的文件 可以自己给定 import ... -
Dart高级(一)——泛型与Json To Bean
2020-02-23 19:13 1005从 Flutter 发布到现在, 越来越多人开始尝试使用 Da ... -
flutter loading、Progress进度条
2020-02-21 17:03 1181Flutter Progress 1 条形无固定值进度条 ... -
Flutter使用Https加载图片
2020-02-21 01:39 1020Flutter使用Https加载图片 使用http加载图片出 ... -
flutter shared_preferences 异步变同步
2020-02-21 00:55 848前言 引用 在开发原生iOS或Native应用时,一般有判断上 ... -
Flutter TextField边框颜色
2020-02-19 21:31 937监听要销毁 myController.dispose(); T ... -
flutter Future的正确用法
2020-02-18 21:55 808在flutter中经常会用到异步任务,dart中异步任务异步处 ... -
记一次Flutter简单粗暴处理HTTPS证书检验方法
2020-02-18 14:13 979最近在做Flutter项目到了遇到一个无解的事情,当使用Ima ... -
flutter 获取屏幕宽度高度 通知栏高度等屏幕信息
2019-07-27 08:39 1344##MediaQuery MediaQuery.of(con ... -
关于flutter RefreshIndicator扩展listview下拉刷新的问题
2019-07-10 19:40 1143当条目过少时listview某些嵌套情况下可能不会滚动(条目 ... -
flutter listview 改变状态的时候一直无限添加
2019-07-10 16:01 791setstate的时候会一直无限的调用listview.bui ... -
Flutter Android端启动白屏问题的解决
2019-07-09 00:51 1526问题描述 Flutter 应用在 Android 端上启动时 ... -
Flutter中SnackBar使用
2019-07-08 23:43 781底部弹出,然后在指定时间后消失。 注意: build(Bui ... -
Flutter 之点击空白区域收起键盘
2019-07-08 18:43 1792点击空白处取消TextField焦点这个需求是非常简单的,在学 ... -
Flutter 弹窗 Dialog ,AlertDialog,IOS风格
2019-07-08 18:04 1383import 'package:flutter/mate ... -
flutter ---TextField 之 输入类型、长度限制
2019-07-08 14:30 2337TextField想要实现输入类型、长度限制需要先引入impo ... -
【flutter 溢出BUG】键盘上显示bottom overflowed by 104 PIXELS
2019-07-08 11:13 1567一开始直接使用Scaffold布局,body:new Colu ... -
解决Flutter项目卡在Initializing gradle...界面的问题
2019-07-07 12:53 880Flutter最近很火,我抽出了一点时间对Flutter进行了 ... -
关于android O 上 NotificationChannel 的一些注意事项
2019-07-04 11:47 941最近在适配android O,遇到个问题,应用中原本有设置界面 ...
相关推荐
### Android开发编码规范 #### 1. 引言 ##### 1.1 目的 本文档旨在为Android开发人员提供一套系统化的编码规范指南,帮助团队统一代码风格,提高代码质量和可维护性。通过遵循这些规则,可以有效减少代码中的潜在...
在Android开发领域,遵循一套统一的编码规范是至关重要的,它能提高代码的可读性、可维护性和团队协作效率。百度作为中国领先的互联网科技公司,也推出了一套针对Android平台的Java编码规范,旨在帮助开发者养成良好...
开发者需要了解如何合理地使用这些机制来实现应用的功能,并处理好线程同步问题,避免内存泄漏等问题。 六、文件与数据库 应用中对文件和数据库的使用也是非常关键的,该部分会介绍文件存储的最佳实践和数据库(如...
《Android编码规范与性能优化详解》 ...总结,Android开发中遵循编码规范和进行性能优化是提升应用体验的基础。开发者应注重代码的可读性、可维护性,同时兼顾性能和资源利用率,以打造出高质量的Android应用。
Android系统会定期检测并报告可能导致内存泄漏的对象。内存泄漏会占用大量内存,降低应用性能,甚至导致应用无响应。开发者应使用工具如MAT (Memory Analyzer Tool) 或 Android Studio 自带的 Memory Profiler 来...
- 谨慎使用静态变量实现界面间的共享,以防止潜在的内存泄漏问题。 15. **日志管理** - 使用统一的日志标签(TAG)记录调试信息,并在发布版本中关闭日志输出。 16. **单元测试** - 实施单元测试策略,包括...
这份规范源自阿里巴巴集团在长期的Android开发实践中积累的经验和最佳实践,对于任何想要在Android平台上进行专业开发的工程师来说,都具有极高的参考价值。 1. **命名规范**: - 命名应清晰、简洁且具有描述性,...
2. **过度使用AsyncTask**:AsyncTask是Android中处理异步任务的一种简单方式,但滥用会导致内存泄漏和线程安全问题。应该考虑使用Handler、IntentService或现代的LiveData、ViewModel等库来处理后台任务。 3. **...
理解项目结构,遵循编码规范,使用版本控制工具如Git,可以帮助管理源码并解决问题。 总的来说,理解并解决这些常见错误需要开发者具备一定的基础和耐心。通过不断学习,熟悉开发工具,了解Android系统的运作机制,...
不当的内存管理、缓冲区溢出等问题可能导致安全漏洞,因此在使用C函数时要遵循安全编码规范。 6. **C库集成**:Android支持许多开源C库,如OpenSSL、FFmpeg等,可以用于加密、媒体处理等。熟悉如何在Android项目中...
本压缩包包含的“android小组_编程规范_20120303”文档,很可能是Android开发团队内部使用的一份详细编码规范指南,用于指导开发者按照最佳实践编写代码。 1. **命名规范**:在Android开发中,命名规范是基础。变量...
以下是一些核心的编码规范和建议: 1. DRD00-J: 不要在外部存储(如SD卡)上存储未加密的敏感信息。这包括用户的个人数据、登录凭据等,因为外部存储相对更容易被未经授权的访问。 2. DRD01-J: 限制应用的敏感内容...
6. **代码风格和一致性**:确保代码符合一定的格式和编码规范,提高代码可读性和团队协作效率。 "android-lint-summary" 这个开源项目的目标是改善原始 Lint 输出的用户体验,它可能提供了以下特性: 1. **美化...
在Android开发过程中,保持代码质量是非常重要的,而`AndroidLint`是Google提供的一款静态代码分析工具,用于检测潜在的代码问题、性能优化建议以及遵循编码规范。本项目"基于注释的Androidlint检查生成"专注于利用...
但是,不当的使用可能会导致内存泄漏、崩溃等问题。因此,了解内存管理、异常处理和性能调试技巧至关重要。 6. **源码分析**:书中提供的源码章节包括Chapter 10、Chapter 8、Chapter 13和Chapter 14等,分别涉及...
2. **内存管理优化**:新版本对内存管理进行了优化,降低了内存占用,减少了因内存泄漏导致的卡顿现象,提升了IDE的稳定性。 3. **更快的模拟器**:Android Emulator在新版本中也得到了升级,启动速度更快,运行更...
- **遵循编码规范**:清晰、简洁的代码更容易被优化。 - **使用编译器插件和Lint**:检查代码中的潜在问题,自动优化部分代码。 10. **持续测试与迭代** - **多设备测试**:不同的设备配置可能会影响性能,因此...
同时,它可能也考虑到了内存管理,避免了大量数据操作时可能导致的内存泄漏问题。 3. **更灵活的映射关系**: 原始的GreenDao可能在处理复杂的实体关系时有所限制,而优化版则可能增加了对多对多关系、自关联等...