【问题标题】:My application uses a lot of Ram and closes unexpectedly我的应用程序使用了大量的 Ram 并意外关闭
【发布时间】:2015-04-22 11:33:28
【问题描述】:

现在我几乎完成了我的应用程序。说实话,我支持应用程序的设计。我正在获取图像以使其看起来更漂亮。 我遇到了一个问题。 首先我想解释一下是什么让这个应用程序变得更好,以便他们更好地理解问题。

该应用程序是一个问题游戏,答案是对还是错。每个问题都有一个图像。 每个问题都是一个片段,会随着 fragmentManager 的变化而变化。

没有图像的应用问题完美运行。但是添加图像时,应用程序在到达最后一个问题时会自动停止并关闭。

1- 使用 Android 2.1 的虚拟机,应用程序不会停止,但如果您变慢了。 2- 使用带有 Android 4.4.4 应用程序的移动 xperia Z2 到达第 10 题停止并关闭。

我认为问题在于管理内存位图。

但是如何实现管理内存位图来清理图像使用的内存。

第一组题主代码为:

public class Grp1Fragment extends Fragment {

    private int ContArrayAsk = 0;
    private int ContRight = 0;
    private int ContFailed= 0;
    private int ContArrayResults =0;
    private String msg = "";

    private Button buttonTrue;
    private Button buttonFalse;
    private Button buttonNextAsk;
    private Button buttonShareScore;

    private View view;



    String[] arrayFragmentAResultsGrp1 = new String[]{"false","false","false","true","false","true","true","true","false","true",};

    private Fragment[] fragmentsChangeAsk = new Fragment[]{
                                                    new Grp1FragmentP1(),
                                                    new Grp1FragmentE1(),
                                                    new Grp1FragmentP2(),
                                                    new Grp1FragmentE2(),
                                                    new Grp1FragmentP3(),
                                                    new Grp1FragmentE3(),
                                                    new Grp1FragmentP4(),
                                                    new Grp1FragmentE4(),
                                                    new Grp1FragmentP5(),
                                                    new Grp1FragmentE5(),
                                                    ...

                                };

    public Grp1Fragment() {
        // Required empty public constructor


    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);

        android.support.v4.app.FragmentManager managerAsk = getActivity().getSupportFragmentManager();
        managerAsk.beginTransaction()
                .add(R.id.fragmentaskGRP1, fragmentsChangeAsk[0])
                .add(R.id.fragmentaskGRP1, fragmentsChangeAsk[1])
                ...
                .hide(fragmentsChangeAsk[1])
                .hide(fragmentsChangeAsk[2])
        ...
                .commit();
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_grp1, container, false);
        return view;
    }


    @Override
    public void onViewCreated(View view, Bundle savedInstanceState){
        super.onViewCreated(view, savedInstanceState);


        buttonTrue = (Button) view.findViewById(R.id.buttontruegpr1);
        if(buttonTrue != null){
            buttonTrue.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    if (arrayFragmentAResultsGrp1[ContArrayResults].equals("true")) {
                        Toast.makeText(getActivity(), "Respuesta correcta", Toast.LENGTH_SHORT).show();
                        ContRight++;
                        ContArrayAsk++;
                        ContArrayAsk++;
                        ContArrayResults++;
                        setContent(ContArrayAsk);
                        validarpantallafinal();
                    }else{
                        Toast.makeText(getActivity(), "Respuesta incorrecta", Toast.LENGTH_SHORT).show();
                        ContFailed++;
                        ContArrayAsk++;
                        ContArrayResults++;
                        setContent(ContArrayAsk);
                        buttontrueorfalsedisabled();
                        validarpantallafinal();
                    }
                }
            });
        }


        buttonFalse = (Button) view.findViewById(R.id.buttonfalsegpr1);
        if(buttonFalse != null) {
            buttonFalse.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    if (arrayFragmentAResultsGrp1[ContArrayResults].equals("false")) {
                        Toast.makeText(getActivity(), "Respuesta correcta", Toast.LENGTH_SHORT).show();
                        ContRight++;
                        ContArrayAsk++;
                        ContArrayAsk++;
                        ContArrayResults++;
                        setContent(ContArrayAsk);
                        validarpantallafinal();
                    } else {
                        Toast.makeText(getActivity(), "Respuesta incorrecta", Toast.LENGTH_SHORT).show();
                        ContFailed++;
                        ContArrayAsk++;
                        ContArrayResults++;
                        setContent(ContArrayAsk);
                        buttontrueorfalsedisabled();
                        validarpantallafinal();
                    }
                }
            });
        }


        buttonNextAsk = (Button) view.findViewById(R.id.buttonnextaskgrp1);
        buttonNextAsk.setEnabled(false);
        buttonNextAsk.setVisibility(View.INVISIBLE);
        if(buttonFalse != null) {
            buttonNextAsk.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    //Toast.makeText(getActivity(), "Ha pulsado el botón siguiente pregunta", Toast.LENGTH_LONG).show();
                    buttontrueorfalseenabled();
                    ContArrayAsk++;
                    setContent(ContArrayAsk);
                    validarpantallafinal();
                }
            });
        }


        buttonShareScore = (Button) view.findViewById(R.id.buttonsharescoregrp1);
        buttonShareScore.setEnabled(false);
        buttonShareScore.setVisibility(View.INVISIBLE);
        if(buttonShareScore != null) {
            buttonShareScore.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    msg = msg.concat(getString(R.string.message_share_score_grp1) +
                                                "\nPreguntas acertadas: "+ Integer.toString(ContRight) +
                                                "\nPreguntas falladas: " + Integer.toString(ContFailed) +
                                                "\n" + getString(R.string.message_share));
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_SEND);
                    intent.putExtra(Intent.EXTRA_TEXT, msg);
                    intent.setType("text/plain");
                    startActivity(Intent.createChooser(intent,
                            getString(R.string.action_share)));
                    //Toast.makeText(getActivity(), "Ha pulsado el botón compartir resultados\nAciertos:" + Integer.toString(ContRight) + "\nFallos:" + Integer.toString(ContFailed), Toast.LENGTH_LONG).show();
                }
            });
        }

    }

    public void buttontrueorfalseenabled(){
        buttonTrue.setEnabled(true);
        buttonTrue.setVisibility(View.VISIBLE);
        buttonFalse.setEnabled(true);
        buttonFalse.setVisibility(View.VISIBLE);
        buttonNextAsk.setEnabled(false);
        buttonNextAsk.setVisibility(View.INVISIBLE);
    }

    public void buttontrueorfalsedisabled(){
        buttonTrue.setEnabled(false);
        buttonTrue.setVisibility(View.INVISIBLE);
        buttonFalse.setEnabled(false);
        buttonFalse.setVisibility(View.INVISIBLE);
        buttonNextAsk.setEnabled(true);
        buttonNextAsk.setVisibility(View.VISIBLE);
    }

    public void validarpantallafinal(){
        if (ContArrayAsk == fragmentsChangeAsk.length-1){
            buttonTrue.setEnabled(false);
            buttonTrue.setVisibility(View.INVISIBLE);
            buttonFalse.setEnabled(false);
            buttonFalse.setVisibility(View.INVISIBLE);
            buttonNextAsk.setEnabled(false);
            buttonNextAsk.setVisibility(View.INVISIBLE);
            buttonShareScore.setEnabled(true);
            buttonShareScore.setVisibility(View.VISIBLE);
            TextView score = (TextView) view.findViewById(R.id.textScoregrp1);
            score.setText("Felicidades, ha terminado las preguntas del apartado de Historia.\n"+
                           "Las preguntas acertadas son: " + Integer.toString(ContRight) +
                           "\nLas preguntas falladas son: " + Integer.toString(ContFailed));

        }
    }

    public void setContent(int index){

        Fragment toHide1 = null;
        Fragment toHide2 = null;
        Fragment toHide3 = null;
        Fragment toHide4 = null;
        Fragment toHide5 = null;
        Fragment toHide6 = null;
        Fragment toHide7 = null;
        Fragment toHide8 = null;
        Fragment toHide9 = null;
        Fragment toHide10 = null;
        Fragment toHide11 = null;
        Fragment toHide12 = null;
        Fragment toHide13 = null;
        Fragment toHide14 = null;
        Fragment toHide15 = null;
        Fragment toHide16 = null;
        Fragment toHide17 = null;
        Fragment toHide18 = null;
        Fragment toHide19 = null;
        Fragment toHide20 = null;
        Fragment toShow = null;

        switch (index){
            case 0:
                toHide1 = fragmentsChangeAsk[1];
                toHide2 = fragmentsChangeAsk[2];
                toHide3 = fragmentsChangeAsk[3];
                toHide4 = fragmentsChangeAsk[4];
                toHide5 = fragmentsChangeAsk[5];
                toHide6 = fragmentsChangeAsk[6];
                toHide7 = fragmentsChangeAsk[7];
                toHide8 = fragmentsChangeAsk[8];
                toHide9 = fragmentsChangeAsk[9];
                toHide10 = fragmentsChangeAsk[10];
                toHide11 = fragmentsChangeAsk[11];
                toHide12 = fragmentsChangeAsk[12];
                toHide13 = fragmentsChangeAsk[13];
                toHide14 = fragmentsChangeAsk[14];
                toHide15 = fragmentsChangeAsk[15];
                toHide16 = fragmentsChangeAsk[16];
                toHide17 = fragmentsChangeAsk[17];
                toHide18 = fragmentsChangeAsk[18];
                toHide19 = fragmentsChangeAsk[19];
                toHide20 = fragmentsChangeAsk[20];
                toShow = fragmentsChangeAsk[0];
                break;
            case 1:
                toHide1 = fragmentsChangeAsk[0];
                toHide2 = fragmentsChangeAsk[2];
                ...
        case 20:
        ...
        }
        android.support.v4.app.FragmentManager managerAsk = getActivity().getSupportFragmentManager();
        managerAsk.beginTransaction()
                .hide(toHide1)
                .hide(toHide2)
                ...
                .show(toShow)
                .commit();

    }


}

如何用图片显示问题的示例:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:id="@+id/fragment_grp1_e1">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/GRP1error1"
        android:id="@+id/textViewGrp1e1"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        style="@style/textAsk"/>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:contentDescription="@string/impask"
        android:src="@mipmap/img1"
        android:layout_below="@+id/textViewGrp1e1"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

在 Android Studio 中,您可以看到已使用的内存。当我运行应用程序时,它使用 188Mb。应用使用时很快达到190MB。

我们使用的图片大小不超过 300kb。 已安装应用的重量为 6Mb。

非常感谢您的帮助

【问题讨论】:

  • 堆栈跟踪说明了什么?是不是说内存不足?
  • 你在哪里加载图片?我在这里没有看到如何显示实际图像的代码,除非它只是在这里指定 android:src="@mipmap/img1" 在不需要它们时不会缓存它们(我猜,无论如何):stackoverflow.com/questions/477572/… - 无论哪种方式,你都应该在显示位图之前调整它们的大小,我建议使用 Picasso 库来加载图像。
  • 这是由于 ImageView。每个片段都使用一个大小为 200x200 dp 的大 ImageView,每个这样的 ImageView 在 mdpi 屏幕上占用大约 300kb 的 RAM。我建议您不要在开始时创建所有片段,而是一个一个地切换它们,这样一次将创建唯一的 1 个片段。

标签: android android-fragments memory-leaks bitmap android-memory


【解决方案1】:

您的问题是您实际上所有 20 个片段都始终在内存中,它们中都有一个大位图。

    android.support.v4.app.FragmentManager managerAsk = getActivity().getSupportFragmentManager();
    managerAsk.beginTransaction()
            .hide(toHide1)
            .hide(toHide2)
            ...
            .show(toShow)
            .commit();

考虑到您只需要显示的一个 Fragment,该程序的结构应确保始终只创建一个 Fragment。事实上,我什至不确定是否应该有两个以上的片段(grpE 和 grpP),这取决于它们是否真的改变了布局,还是仅仅改变了内容。

如果做不到,至少使用FragmentStatePagerAdapter之类的机制,这样你不需要的片段就不会被实际创建,占用内存。

【讨论】:

    【解决方案2】:

    您正在使用许多片段,并且每个片段都有带有 ImageView 的布局。

    你的方法看起来像:

    每个问题都是新的片段并且有新的布局。你正在展示 问题显示时的那个片段。

    为什么你的方法没有优化?

    • questionset 中添加新问题时,您将添加多少次新 Fragment。您当前的方法是静态,您需要手动为新问题添加片段和布局
    • Android DVM 备用更多的堆大小当片段进入应用程序。您正在应用程序中初始化许多片段。这使用了比必要更多的堆大小(大约 199MB)

    以上几点的解决方法:

    • 更好地使用更少的片段和相应的布局。当您需要显示下一个问题时,只需 replace 当前布局文本字段和带有下一个问题信息的图像字段。这样,当您想要显示新问题时,您不需要手动添加片段
    • Nullify 任何未使用的 ImageView。这样您将防止内存泄漏要了解更多防止内存泄漏的方法:Google 工程师 Google IO Memory optimization 的精彩视频一定会帮助您

    【讨论】:

    • 非常感谢 Kushal,我通过 TextView 更改了将随 setText 更改的片段。我还放了 Imagevew,它将随 setImageResource 改变。该应用程序显着减少了内存使用量。现在几乎不占用任何内存。我很感激。在这个网站上我学到了很多东西。还要感谢:EpicPandaForce、Stan、inmyth。
    • 谢谢你..我很高兴你的问题得到解决..享受学习
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2018-12-23
    相关资源
    最近更新 更多