EditText和DialogFragment导致OutOfMemory崩溃

时间:2014-03-12 00:17:45

标签: android memory-leaks android-edittext android-dialogfragment

我遇到了令人烦恼的内存泄漏和崩溃,这似乎是一个平台错误。我试图调试/另一个/内存问题,但我一直发现这个与EditText相关的错误,保持我的观点以及那些观点。

给定一个DialogFragment,一个带有EditText和UI Monkey的布局我可以通过Out of Memory异常使以下简单的应用程序崩溃。

我已经在x86仿真器17-19上进行了测试,截至2014年3月21日的最新更新为16MB。在4.4.2上的Nexus 4上,我看到内存泄漏在五分钟内增加并增加和增加,但从未让它长到足以看到它崩溃,但在查看N4时会出现相同的泄漏。内存转储。

当按下选项菜单时,Activity会打开DialogFragment:

package org.example.edittextoom;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        DialogFragment df = new Df();
        df.show(getSupportFragmentManager(), "dialogtag");
        return true;
    }

    public static class Df extends DialogFragment {

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Dialog onCreateDialog = super.onCreateDialog(savedInstanceState);
            return onCreateDialog;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            // Using inflator from app context instead to attempt to avoid the issue with EditTexts holding onto Activity's
            View view = LayoutInflater.from(
                    getActivity().getApplicationContext()).inflate(
                    R.layout.dialog, container, false);
                    // Since disabling no suggestions is suppose to prevent the edit text leak
                    EditText et = (EditText) view.findViewById(R.id.editText1);
                    int it = et.getInputType();
                    et.setInputType(it | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
                    it = et.getInputType();
            return view;
        }

    }

}

这两种布局很简单。对话框有一个EditText。

activity_main.xml中

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

</RelativeLayout>

dialog.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:inputType="text|textNoSuggestions"
        />

</RelativeLayout>

让我们通过运行UI Monkey来查看内存泄漏。

adb shell monkey -p org.example.edittextoom --pct-nav 0 --pct-majornav 0 --pct-appswitch 0 800000

(如果你要运行它,请在屏幕尺寸最小的x86仿真器上运行它以提高速度。)

在它运行的同时,您也可以通过查看第五列来确认它占用的内存越来越多,大约一分钟左右(顺便提一下,它通常会在56000左右崩溃) :

$ adb shell ps | grep edittext
u0_a46    2727  794   177888 31596 ffffffff b7f34997 S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46    2727  794   177888 31784 ffffffff b7f3322a S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46    2727  794   177956 31852 ffffffff b7f34997 S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46    2727  794   178124 32064 ffffffff b7f3322a S com.example.edittextoom

然后它最终会崩溃(我发现的事件150,000到500,000)输出:

// CRASH: com.example.edittextoom (pid 13620)
// Short Msg: java.lang.OutOfMemoryError
// Long Msg: java.lang.OutOfMemoryError
// Build Label: generic_x86/sdk_x86/generic_x86:4.2/JOP40C/eng.android-build.20121231.103448:eng/test-keys
// Build Changelist: eng.android-build.20121231.103448
// Build Time: 1356921334000
// java.lang.OutOfMemoryError
//      at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
//      at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502)
//      at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:355)
//      at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:785)
//      at android.content.res.Resources.loadDrawable(Resources.java:1965)
//      at android.content.res.Resources.getDrawable(Resources.java:660)
//      at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2832)
//      at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2875)
//      at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:285)
//      at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:279)
//      at android.app.Dialog.setContentView(Dialog.java:482)
//      at android.support.v4.app.DialogFragment.onActivityCreated(DialogFragment.java:366)
//      at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1508)
//      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
//      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
//      at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
//      at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
//      at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
//      at android.os.Handler.handleCallback(Handler.java:725)
//      at android.os.Handler.dispatchMessage(Handler.java:92)
//      at android.os.Looper.loop(Looper.java:137)
//      at android.app.ActivityThread.main(ActivityThread.java:5039)
//      at java.lang.reflect.Method.invokeNative(Native Method)
//      at java.lang.reflect.Method.invoke(Method.java:511)
//      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
//      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
//      at dalvik.system.NativeStart.main(Native Method)
//
** Monkey aborted due to error.
Events injected: 131816
:Sending rotation degree=0, persist=false
:Dropped: keys=1534 pointers=13377 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=308525ms (0ms mobile, 0ms wifi, 308525ms not connected)
** System appears to have crashed at event 131816 of 800000 using seed 1393322223373

(有时模拟器不断占用内存并杀死应用程序,但是你没有得到强制关闭对话,所以UI Monkey进入循环,玩模拟器直到它再次启动应用程序,但无论如何,应用程序在占用了大量内存后被系统杀死。)

如果你停止UI monkey mid flow,通过取消它的过程,你可以检查MAT中的hprof以查看占用内存的内容(我退出应用程序并在查看hprof之前执行强制gc) ,看到它只保留了一个MainPageActivity但是63个实例的MainPageActivity $ Df,并且只运行了一分钟左右。我看到Nexus 4上的内存转储也是一样的。

如果列出对其中一个的传入引用,并单击Path To GC Roots并排除弱引用和软引用,则得到这个(它与我所看到的所有其他63个引用相同) :

enter image description here

但是,如果我将对话框中的EditText更改为带有id或带有id的TextView的ProgressBar,我不会发生此崩溃或MAT中显示的内存泄漏。所以我认为它与这个EditText causing memory leak错误相关,但是,没有任何解决方法可以工作,不会使EditText的InputConnection无效,也不会关闭建议(我已经完成了上面的例子)。如果我删除EditText的id,我也设法摆脱泄漏,但是我无法访问我的EditTexts。

你见过类似的,找到了解决方法,或者你是否可以在我的代码中看到一些疏忽?

此问题目前阻止我在应用程序中正确查找内存泄漏。

3 个答案:

答案 0 :(得分:5)

我遇到了同样的问题。由于编辑器内部的Blink,在Dialog中有一个EditText会泄漏内存。这种情况发生在三星Tab 10 4.4.2中,但并不是发生在Nexus 7 4.4.2上,这很奇怪。

绕过它的唯一方法是在EditText中禁用光标。使用setCursorVisible(false)。如果您希望光标闪烁,可以在关闭对话框之前禁用光标,这可以防止Blinker再次安排自己。

注意:rana的建议显然是错误的。他根本不了解静态嵌套类和非静态内部类之间的区别。非静态内部类将保存对您的活动的隐式引用,因此实际上您希望在此处使用静态嵌套类,即SAME在单独的文件中声明此类。

答案 1 :(得分:0)

您可以使用自定义视图替代DialogFragment,或使用对话框

答案 2 :(得分:-1)

将DialogFragment df声明为活动的一部分。你没事。