IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 内存泄漏以优化大全,kotlin语法教程 -> 正文阅读

[移动开发]内存泄漏以优化大全,kotlin语法教程

mHandler 通过弱引用的方式持有 Activity,当 GC 执行垃圾回收时,遇到 Activity 就会被回收并释放所有占据的内存单元。这样就不会发生内存泄漏了。 上面的做法确实避免了 Activity 导致的内存泄漏,发送的 msg 不再已经没有持有 Activity 的引用了,但是 msg 还是有可能存在消息队列 MessageQueue 中,所有更好的是在 Activity 销毁时就将 mHandler 的回调和发送的消息给移除掉。

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacksAndMessages(null);

}

Thread、AsyncTask

非静态内部类造成内存泄漏还有一种情况就是使用 Thread 或者 AsyncTask。 比如在 Activity 中直接 new 一个子线程 Thread:

public class ThreadActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_thread);

new Thread(new Runnable() {

@Override

public void run() {

//Something

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

}

或者直接新建 AsyncTask 异步任务:

public class AsyncTaskActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_async);

new AsyncTask<Void, Void, Void>() {

@Override

protected Void doInBackground(Void… voids) {

//something

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

}.execute();

}

}

很多初学者都会像上面这样新建线程和异步任务,殊不知这样的写法非常不友好,这样方式新建的子线程 Thread 和 AsyncTask 都是匿名内部类对象,默认就隐式的持有外部 Activity 的引用,导致 Activity 内存泄漏。要避免内存泄漏的话还是需要像上面 Handler 一样使用静态内部类 + 弱引用的方式。

未取消注册或回调导致内存泄漏


比如我们在 Activity 中注册广播,如果在 Activity 销毁后不取消注册,那么这个广播会一直存在系统中,同上面所说的非静态内部类一样持有 Activity 引用,导致内存泄漏。因此注册广播后在 Activity 销毁后一定要取消注册。

public class BroadcastActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_broadcast);

registerReceiver(mReceiver, new IntentFilter());

}

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

//接收到广播需要做的逻辑

}

};

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(mReceiver);

}

}

在注册观察者模式的时候,如果不及时取消也会造成内存泄漏。比如使用 Retrofit + RxJava 注册网络请求的观察者回调,同样作为匿名内部类持有外部引用,所以需要记得在不用或者销毁的时候取消注册。

Timer 和 TimerTask 导致内存泄漏


Timer 和 TimerTask 在 Android 中通常会被用来做一些计时或循环任务,比如实现无限轮播的 ViewPager:

public class TimerActivity extends AppCompatActivity {

private ViewPager mViewPager;

private PagerAdapter mAdapter;

private Timer mTimer;

private TimerTask mTimerTask;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_timer);

init();

mTimer.schedule(mTimerTask, 3000, 3000);

}

private void init() {

mViewPager = findViewById(R.id.view_pager);

mAdapter = new ViewPagerAdapter();

mViewPager.setAdapter(mAdapter);

mTimer = new Timer();

mTimerTask = new TimerTask() {

@Override

public void run() {

runOnUiThread(new Runnable() {

@Override

public void run() {

loopViewpager();

}

});

}

};

}

private void loopViewpager() {

if (mAdapter.getCount() > 0) {

int curPos = mViewPager.getCurrentItem();

curPos = (++curPos) % mAdapter.getCount();

mViewPager.setCurrentItem(curPos);

}

}

private void stopLoopViewPager() {

if (mTimer != null) {

mTimer.cancel();

mTimer.purge();

mTimer = null;

}

if (mTimerTask != null) {

mTimerTask.cancel();

mTimerTask = null;

}

}

@Override

protected void onDestroy() {

super.onDestroy();

stopLoopViewPager();

}

}

当我们 Activity 销毁时,有可能 Timer 还在继续等待执行 TimerTask,它持有 Activity 的引用不能被回收,因此当我们 Activity 销毁的时候要立即 cancel 掉 Timer 和 TimerTask,以避免发生内存泄漏。

集合中的对象未清理造成内存泄漏


这个比较好理解,如果一个对象放入到 ArrayList、HashMap 等集合中,这个集合就会持有该对象的引用,当我们不再需要这个对象时,也并没有将它从集合中移除,这样只要集合还在使用(而此对象已经无用了),这个对象就造成了内存泄漏。并且如果集合被静态引用的话,集合里面那些没有用的对象更会造成内存泄漏了,所以在使用集合时要及时将不用的对象从集合 remove,或者 clear 集合,以避免内存泄漏。

资源未关闭或释放导致内存泄漏


在使用 IO、File 流或者 Sqlite、Cursor 等资源时要及时关闭。这些资源在进行写操作时通过都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以至于发生内存泄漏。因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄漏。

属性动画造成内存泄漏


动画同样是一个耗时任务,比如在 Activity 中启动了属性动画(ObjectAnimator),但是在销毁的时候没有调用 cancel 方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用 Activity ,这就造成 Activity 无法正常释放。因此同样要在 Activity 销毁的时候 cancel 掉属性动画,避免发生内存泄漏。

@Override

protected void onDestroy() {

super.onDestroy();

mAnimator.cancel();

}

WebView 造成内存泄漏


关于 WebView 的内存泄漏,因为 WebView 在加载网页后会长期占用内存而不能被释放,因此我们在 Activity 销毁后要调用它的 destroy() 方法来销毁它以释放内存。 另外在查阅 WebView 内存泄漏相关资料时看到这种情况: WebView 下面的 Callback 持有 Activity 引用,造成 WebView 内存无法释放,即使是调用了 WebView.destroy() 等方法都无法解决问题(Android 5.1 之后)。 最终的解决方案是:在销毁 WebView 之前需要先将 WebView 从父容器中移除,然后在销毁 WebView。 详细分析过程可以参考这篇文章:WebView 内存泄漏解决方法

@Override

protected void onDestroy() {

super.onDestroy();

if (mWebView != null) {

((ViewGroup) mWebView.getParent()).removeView(mWebView); //先从父控件中移除 WebView.

mWebView.stopLoading();

mWebView.getSettings().setJavaScriptEnabled(false);

mWebView.clearHistory();

mWebView.removeAllViews();

mWebView.destroy();

mWebView = null;

}

}

总结


内存泄漏在 Android 内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄漏我们不一定就能注意到,所有在编码的过程中养成良好的习惯。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:

  • 构造单例的时候尽量别用 Activity 的引用

  • 静态引用是注意引用对象的置空或者少用静态引用

  • 使用静态内部类 + 弱引用代替非静态内部类

  • 及时取消广播或者观察者注册

ngs().setJavaScriptEnabled(false);

mWebView.clearHistory();

mWebView.removeAllViews();

mWebView.destroy();

mWebView = null;

}

}

总结


内存泄漏在 Android 内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄漏我们不一定就能注意到,所有在编码的过程中养成良好的习惯。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:

  • 构造单例的时候尽量别用 Activity 的引用

  • 静态引用是注意引用对象的置空或者少用静态引用

  • 使用静态内部类 + 弱引用代替非静态内部类

  • 及时取消广播或者观察者注册

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-03 01:19:17  更:2022-02-03 01:19:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 14:06:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码