Android:EditText 导致内存泄漏

Posted

技术标签:

【中文标题】Android:EditText 导致内存泄漏【英文标题】:Android: EditText causing memory leak 【发布时间】:2015-07-06 12:04:59 【问题描述】:

首先我想说这是我第一次必须处理性能问题,因为这是我第一次开发 android 应用程序。

应用程序

该应用程序是一个源代码编辑器,您可以在其中打开文件、修改它们并将它们保存回来。该应用由 4 个部分组成:

导航器视图:包含一个用于打开文件的 ListView 和一个用于打开文件夹的 TreeView。 代码视图容器:它保存包含实际代码的视图。 代码容器:这是一个包含文本视图和自定义 EditText 的小视图(由我扩展 EditText 类创建,但它尚未实现,因此它的行为与 EditText 完全一样)。 TextView 只是显示代码行。 打开和保存片段:我使用 2 个片段作为 DialogFragment:保存片段可让您导航本地文件系统以及关联帐户的 Dropbox 文件系统并保存当前文件。打开片段可让您导航相同的文件系统并打开文件。

问题

完成基本代码编辑器后,我转向语法高亮。现在,我想明确一点,即使没有语法高亮,也会产生泄漏,所以这不是问题。

无论如何,通过测试语法高度,我打开了“大”文件(1200 行代码),我注意到应用程序变得非常慢,这很明显,因为我正在对整个文本进行正则表达式(我会避免这种情况)通过仅突出显示可见文本)。这促使我在不使用大文件语法的情况下测试应用程序,我发现应用程序仍然有点慢,并且我注意到发生了一些内存泄漏。

特别是,当我打开一个大文件(1200 行代码)时,应用程序需要 1 秒才能在 textview 中显示代码行,而当我键入字符时,绘制速度很慢。此外,每当我键入删除字符时,都会发生内存泄漏。

检查

我尝试检查堆(使用 MAT),但如前所述,我在这方面没有任何经验,我不确定如何调查此问题。很抱歉,我无法上传屏幕截图(没有 *** 的许可),但我可以向您报告一些数字:

打开大文件前的系统

系统概览

泄密嫌疑人

问题 1

详情:

问题 2

问题 3

最大的***支配包

最大的物体

打开大文件后的系统

系统概览

泄密嫌疑人:

问题 1: 细节:

问题 2

问题 3 问题 4

最大的***支配包

最大的物体

从 Android 设备监视器:

打开大文件前的系统

打开大文件后的系统

部分分配:

提前谢谢你

编辑:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:id="@+id/codeScrollView"
android:fillViewport="true">

<LinearLayout
    android:layout_
    android:layout_
    android:orientation="horizontal">

    <TextView
        android:layout_
        android:layout_
        android:background="@drawable/lines_stroke"
        android:textColor="@android:color/white"
        android:text="@string/first_line"
        android:textSize="15dp"
        android:gravity="right"
        android:paddingLeft="15dp"
        android:paddingRight="5dp"
        android:id="@+id/edit_code_lines_view"/>

              <com.example.green.bachelorproject.customViews.codeEditView.TouchEditText
        android:layout_
        android:layout_
        android:background="@drawable/code_stroke"
        android:gravity="top"
        android:textColor="@android:color/white"
        android:textSize="15dp"
        android:paddingLeft="3dp"
        android:paddingRight="3dp"
        android:textCursorDrawable="@color/white"
        android:id="@+id/edit_code_content_view"/>

    </LinearLayout>
</ScrollView>

编辑

好的,伙计们,我发现了问题。如果您看到,每次我输入内容时,我都会更新 EditText 行,并且由于文本很长(1200 行),重新计算它需要一段时间。事件虽然关于那个!我必须找到一种更快的方法来显示代码行。一种选择是每行使用一个 TextView,这样我只更新需要更改的 TextView。但我不知道有 1200 个 TextView 对象是否很好。

包 com.example.green.bachelorproject.customViews.codeEditView; 导入android.content.Context; 导入android.graphics.Color; 导入android.graphics.Typeface; 导入 android.text.Editable; 导入 android.text.Spannable; 导入 android.text.SpannableStringBuilder; 导入 android.text.TextWatcher; 导入 android.text.style.ForegroundColorSpan; 导入android.util.AttributeSet; 导入android.util.Log; 导入 android.view.LayoutInflater; 导入 android.widget.EditText; 导入 android.widget.LinearLayout; 导入 android.widget.TextView; 导入utils.Colorizer; 导入 utils.Lexer; 导入 com.example.green.bachelorproject.events.UpdateCacheFileEvent; 导入 com.example.green.bachelorproject.R; 导入 de.greenrobot.event.EventBus; 导入 com.example.green.bachelorproject.internalFileSystem.InternalFile; 导入 java.util.ArrayList; /** * 由 Green 于 2015 年 2 月 26 日创建。 */ 公共类 CodeEditView 扩展 LinearLayout 私有上下文上下文; 私有 TextView 行; 私有 EditText 代码; 私人字体当前字体; 私有内部文件内部文件; 私人词法分析器; 私人着色器着色器; 公共 CodeEditView(上下文上下文) 超级(上下文); this.context = 上下文; 初始化(空); 公共 CodeEditView(上下文上下文,AttributeSet attrs) 超级(上下文,属性); this.context = 上下文; 初始化(属性); 私人无效初始化(属性集属性) //检查这个 LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); layoutInflater.inflate(R.layout.edit_code_layout, this); // this.colorizer = new Colorizer(); // this.colorizer.setColor("String", Color.rgb(218, 220, 95)); // this.colorizer.setColor("Number", Color.rgb(173, 125, 255)); // this.colorizer.setColor("Character", Color.rgb(218, 220, 95)); // this.colorizer.setColor("Operator", Color.rgb(234, 38, 116)); // this.colorizer.setColor("关键字", Color.rgb(234, 38, 116)); // this.colorizer.setColor("标识符", Color.WHITE); // this.colorizer.setColor("Type", Color.rgb(105, 216, 238)); // this.colorizer.setColor("评论", Color.rgb(117, 113, 91)); this.lexer = new Lexer(); this.lines = (TextView) findViewById(R.id.edit_code_lines_view); //this.lines.setTypeface(currentTypeface); this.code = (EditText) findViewById(R.id.edit_code_content_view); //this.code.setTypeface(currentTypeface); this.code.addTextChangedListener(new TextWatcher() @覆盖 public void beforeTextChanged(CharSequence s, int start, int count, int after) @覆盖 public void onTextChanged(CharSequence s, int start, int before, int count) @覆盖 public void afterTextChanged(Editable s) // writeToFile(); //EventBus.getDefault().post(new UpdateCacheFileEvent(code.getText().toString(), internalFile)); //setLines(); ); 私人无效 setLines() int usedLines = code.getLineCount(); 字符串文本 = "1" + System.lineSeparator(); for(int i = 2; i tokens = lexer.tokenize(content); // SpannableStringBuilder text = new SpannableStringBuilder(content); // // for(Lexer.Token t: tokens) // text.setSpan(new ForegroundColorSpan(colorizer.getColor(t)), t.start, t.end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // // code.setText(text); // code.post(new Runnable() // @Override //公共无效运行() // setLines(); // // ); 公共无效setFont(字体typeFace) this.lines.setTypeface(typeFace); this.code.setTypeface(typeFace);

编辑: 除了最近的发现之外,没有语法突出显示打字很快,但我在启用语法突出显示时仍然遇到延迟。当我打开文件时,高亮很快,但打字仍然很慢并且有内存泄漏消息

04-28 04:49:58.119: D/dalvikvm(2437): GC_EXPLICIT 释放 185K,17% 释放 6027K/7244K,暂停 1ms+1ms,共 5ms

出现。无论如何,我想知道对象 1 字节数组 (byte[], boolean[]) 是什么,因为它实际上使用了 2 MB。有什么建议吗?

编辑:

确实发现了问题。由于文件很大并且创建了很多跨度,所以当我在文件顶部更改某些内容时,editext 必须重新计算所有跨度的位置。

【问题讨论】:

所以应该让你附上图片。否则将它们上传到某个地方以便我们查看。 This video 还提供了一些提示,其中大部分您已经完成。不过值得一看。 【参考方案1】:

许多其他人也遇到了同样的问题。以下是一些提示:

来自codeninja:

那么实际的解决方案是什么?避免在 a 中使用 EditText 相对布局,请改用线性布局。根据詹姆斯的说法,如果你 看看 DDMS,很多重绘和重新计算发生在 输入与RelativeLayout 相关的文本。以便 给我们一个线索,问题确实是RelativeLayoutUpdate:我 忘了提到设置一个 EditText 的固定将有助于 很多与性能。它可以防止重新计算和重新绘制 布局。感谢 Giorgos Kylafas 在 cmets 中指出 下面的部分!他还提供了对您有用的链接 谈到 Android 性能提示,所以我建议阅读他的评论。

在第一种情况下,EditText 的宽度是“wrap_content”。每次你 改变文字,即EditText的内容,视图需要重新测量 并重新布局,这很慢。被包含在一个 RelativeLayout 使事情变得更糟,因为 RelativeLayout 是 总是多遍。

在第二种情况下,EditText 的宽度固定为“220 dip”。它的 测量和布局通过简单快捷。再加上你不使用 "layout_weight",所以它的父 LinearLayout 是单通的。 http://developer.android.com/guide/topics/ui/how-android-draws.html

来自另一个*** question:

避免在RelativeLayout中使用EditText,使用LinearLayout 而是。

来自另一个*** question:

我在 ListView 中使用 EditText 时遇到了类似的问题,即 通过使用加权宽度将 EditText 宽度更改为 0dp 来修复 匹配/填充父级。

我不确定为什么会发生这种情况,但我相信它是 因为当 EditText 的宽度设置为包裹内容时,它将 调整/重绘自身以使一切都适合,并且 ListView 将 还尝试重新绘制自己,以便一切都适合。所以通过使 EditText 有固定宽度,不再需要重绘。

总结:一定不要将 EditText 的宽度设置为 wrap-content!

【讨论】:

您好,谢谢您的回复,但实际上我的 EditText 是 fill_parent fill_parent 并且它在线性布局内。我将使用 xml 编辑问题 尝试设置固定宽度!你能把你的 EditText 自定义组件的代码分享给我们吗? 我会把它添加到问题中

以上是关于Android:EditText 导致内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

Android内存泄漏

android 内存泄漏和内存优化方案

Android 常见内存泄漏的解决方式

转载Android内存泄漏的8种可能

Android内存泄漏检测与MAT使用

Android OOM之内存泄漏详解