Android 内存优化知识点梳理总结

yizhihongxing

Android 内存优化知识点梳理总结

一、内存泄漏

内存泄漏指由于疏于释放内存而导致内存溢出的一种情况。在 Android 中,可能导致内存泄漏的场景包括:

  • 非静态内部类引用外部类实例
  • Handler 引起的内存泄漏
  • 单例模式中的 Context 引起的内存泄漏
  • ListView/RecyclerView 的 ViewHolder 引起的内存泄漏
  • Bitmap 引起的内存泄漏

解决方案包括:

  • 尽量避免使用非静态内部类引用外部类实例,如果必须使用可以使用弱引用或静态内部类
  • 尽量使用 Application Context 而不是 Activity Context
  • 在使用 Handler 时,尽量使用静态内部类并在内部弱引用一下外部类
  • 在 Activity/Fragment 销毁时及时取消掉相关联的消息
  • 在使用 ListView/RecyclerView 时,尽量减少 ViewHolder 中的变量数目以及对 Bitmap 等占用较大的资源的引用

以 Handler 引起的内存泄漏的示例说明:

public class MyActivity extends Activity {

    private HandlerThread mWorkThread;
    private Handler mWorkHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWorkThread = new HandlerThread("MyWorkThread");
        mWorkThread.start();
        mWorkHandler = new Handler(mWorkThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // do something
            }
        };
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 导致内存泄漏的写法,需要手动调用 quit 方法停止 HandlerThread
        mWorkThread.quit();
    }

}

在上述代码中,由于 HandlerThread 是用在 Handler 中的,而 Handler 又被赋值给了成员变量 mWorkHandler,因此在 Activity onDestroy 时必须调用 mWorkThread.quit() 来手动停止 HandlerThread,否则就会导致内存泄漏。

二、内存抖动

内存抖动指的是申请一次性大量内存,而同时又频繁地进行内存分配和回收导致 GC 频繁执行的一种情况。

Android 中可能导致内存抖动的场景包括:

  • 频繁地创建临时对象
  • 频繁地使用 String 进行字符串拼接

解决方案包括:

  • 尽量避免频繁地创建临时对象,可以使用对象池或者使用静态方法/属性等方式来代替创建对象
  • 尽量避免频繁地使用 String 进行字符串拼接,可以使用 StringBuilder 或者使用其他方式来代替字符串拼接

以频繁地使用 String 进行字符串拼接的示例说明:

public class MyActivity extends Activity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.textview);
    }

    public void onButtonClick(View view) {
        String result = "";
        for (int i = 0; i < 100000; i++) {
            result += i;
        }
        mTextView.setText(result);
    }

}

在上述代码中,当按钮点击时会频繁地进行字符串拼接,由于 String 拼接会产生大量的临时对象,导致了内存抖动。改进的方案应该是使用 StringBuilder 进行字符串拼接,例如:

public class MyActivity extends Activity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.textview);
    }

    public void onButtonClick(View view) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 100000; i++) {
            builder.append(i);
        }
        mTextView.setText(builder.toString());
    }

}

三、大图加载

在 Android 中,由于内存有限制,一些较大的图片如果直接加载会导致 OOM 错误的出现,因此需要进行图片压缩或者分块加载等处理。

解决方案包括:

  • 使用图片压缩或者缩放等方式减少图片内存占用
  • 对于较大的图片,可以使用分块加载的方式进行处理,例如使用 SubsamplingScaleImageView 等库

以图片压缩的示例说明:

public class MyActivity extends Activity {

    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = findViewById(R.id.imageview);
        // 加载大图
        Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg");
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        // 计算出压缩比例
        int scaleFactor = Math.min(width/1000, height/1000);
        if (scaleFactor <= 0) {
            scaleFactor = 1;
        }
        // 根据压缩比例缩小图片
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = scaleFactor;
        Bitmap compressedBitmap = BitmapFactory.decodeFile("/sdcard/test.jpg", options);
        mImageView.setImageBitmap(compressedBitmap);
    }

}

在上述代码中,首先加载原始的大图,然后根据图片实际大小计算出需要压缩的比例,最后通过 BitmapFactory.Options 进行图片压缩,从而减少了图片的内存占用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android 内存优化知识点梳理总结 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • sql中的常用的字符串处理函数大全

    SQL中的常用字符串处理函数大全 SQL是一种用于管理关系型数据库的编程语言。在进行数据库查询,特别是字符串处理时,字符串函数是不可避免的一部分。 以下是一些常用的字符串处理函数和示例说明: 1. LENGTH函数 LENGTH函数用于返回字符串的长度。 例如,对于字符串”Hello, world!”,LENGTH函数将返回 13。 示例 SELECT LE…

    other 2023年6月20日
    00
  • Maven导入依赖时报错如何解决

    当使用Maven导入依赖时,可能会出现各种问题,比如找不到依赖、版本冲突等等。下面是一些常见的解决方法和建议: 一、检查maven配置 首先,我们应该检查我们的maven配置,确保Maven使用的是我们想要的本地仓库地址和远程仓库配置。可以在 pom.xml 文件中查看使用的本地仓库路径和远程仓库的配置信息。 另外,我们还可以通过检查 settings.xm…

    other 2023年6月27日
    00
  • VB6.0项目怎么添加用户控件?

    当开发VB6.0项目时,我们经常需要使用用户控件以更好地实现功能。下面是完整的添加用户控件步骤: 第一步:创建用户控件 首先,我们需要创建用户控件。创建用户控件的方法是打开Visual Basic 6.0软件,点击菜单栏的“文件 – 新建 – 用户控件”选项。然后,我们就可以开始在用户控件上绘制和添加控件,用来完成特定的功能。 第二步:编译用户控件 完成用户…

    other 2023年6月27日
    00
  • C++、python和go语言实现的简单客户端服务器代码示例

    我们来详细讲解一下C++、Python和Go语言实现的简单客户端服务器代码示例。 C++ 实现简单客户端服务器 使用C++实现一个简单的客户端和服务器端交互的程序,可以使用TCP/IP协议,以下是一份C++实现简单客户端服务器的示例代码。 服务器端代码 #include <iostream> #include <winsock2.h>…

    other 2023年6月27日
    00
  • 最简单的gitextensions教程(持续更新中)

    以下是详细讲解“最简单的GitExtensions教程”的完整攻略,过程中至少包含两条示例说明的标准Markdown格式文本: 最简单的GitExtensions教程 GitExtensions是一款开源的Git图形化界面工具,可以方便地管理Git仓库。本文将介绍最简单的GitExtensions教程,包括安装、配置和使用。 安装GitExtensions …

    other 2023年5月10日
    00
  • 小程序开发实战指南之封装自定义弹窗组件

    下面是关于“小程序开发实战指南之封装自定义弹窗组件”的完整攻略及两条示例说明: 一、封装自定义弹窗组件的目的 在微信小程序开发中,经常需要使用弹窗组件来提醒用户一些信息或让用户进行选择等操作。为了提高代码复用性,并且让开发更加方便快捷,我们需要将弹窗组件进行封装,使其可以更加方便地被其他页面调用使用。 二、封装弹窗组件的步骤 以下是封装自定义弹窗组件的步骤:…

    other 2023年6月25日
    00
  • php 判断IP为有效IP地址的方法

    当判断一个IP地址是否有效时,可以使用正则表达式和内置的PHP函数来实现。下面是一个完整的攻略,包含了两个示例说明。 方法一:使用正则表达式 首先,我们可以使用正则表达式来验证IP地址的格式是否正确。以下是一个示例代码: function isValidIP($ip) { $pattern = ‘/^((25[0-5]|2[0-4][0-9]|[01]?[0…

    other 2023年7月31日
    00
  • 软件生命周期各个阶段详细描述

    软件生命周期是指软件开发过程中的各个阶段,它包括了软件需求分析、软件设计、编码、测试、运维等阶段。在软件开发的过程中,我们需要按照软件生命周期的顺序进行开发,以确保软件开发的质量和效率。下面详细描述一下软件生命周期的各个阶段。 需求分析阶段 需求分析阶段是软件开发生命周期中的第一步。在此阶段中,我们需要与客户沟通,并了解客户的需求。我们应该要求客户提供尽可能…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部