1

Теперь я почти закончил свое приложение. Честно говоря, я с дизайном приложения. Я получаю изображения, чтобы они выглядели красивее. И у меня проблема. Сначала я хочу объяснить, что делает приложение, поэтому они могут лучше понять проблему.Мое приложение использует много Ram и неожиданно закрывается

Приложение представляет собой игру вопросов, ответы верны или ложны. У каждого вопроса есть изображение. Каждый вопрос - это фрагмент, который будет изменяться с помощью instanceManager.

Замечания по применению без изображений отлично работают. Но добавление изображений, приложение, когда оно достигает последнего вопроса, останавливается и автоматически закрывается.

1- Использование виртуальной машины с Android 2.1, приложение не останавливается, но если вы становитесь медленнее. 2- Использование мобильного xperia Z2 с приложением Android 4.4.4 для доступа к вопросу номер 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. Когда приложение будет использовано в ближайшее время, оно достигнет 190 МБ.

Изображения, которые мы используем, весом не более 300 КБ. И вес установленного приложения составляет 6 Мб.

Большое спасибо за вашу помощь

+0

Что говорит трассировки стека? Это говорит об отсутствии памяти? – inmyth

+0

Где вы загружаете изображения? Я не вижу здесь кода для отображения фактического изображения, если только это не указано здесь 'android: src =" @ mipmap/img1 "', который не кэширует их, когда они не нужны (я предполагаю, так или иначе): http : //stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object - в любом случае, вы должны изменить размер растровых изображений перед их отображением, Я рекомендую использовать библиотеку Picasso для загрузки изображений. – EpicPandaForce

+1

Из-за ImageView. Каждый ваш фрагмент использует большой ImageView размером 200x200 dp, каждый такой ImageView занимает около 300 КБ в ОЗУ для экрана mdpi. Я предлагаю вам не создавать все свои фрагменты при запуске, а переключать их один за другим, так что только один фрагмент будет создан за один раз. – Stan

ответ

2

Вы используете много фрагментов, каждый из которых имеет макет с ImageView.

Ваш подход кажется как:

Каждый вопрос новый фрагмент и имеет новую структуру. Вы показываете , что Фрагмент при отображении вопроса.

Почему ваш подход не оптимизирован?

  • Сколько времени вы будете добавлять новый фрагмент, когда вы добавляете новый вопрос в questionset. Ваш текущий подход статического и вам нужно добавить вручную фрагмент и макет для нового вопроса
  • Android DVM щадит больше размеров кучи, когда фрагмент приходит в применении. Вы инициализируете много фрагментов в своем приложении. При этом используется намного больше размера кучи, чем это необходимо (примерно 199MB)

решения для вышеуказанных пунктов:

  • лучшего использование Меньше фрагмент и соответствующего расположения. Когда вам нужно отобразить следующий вопрос, просто введите replace текущее текстовое поле и поле изображения со следующей информацией о вопросе. Таким образом, вам не нужно добавлять фрагменты вручную, если вы хотите отображать новый объект ImageViews, который не используется, для отображения нового вопроса
  • Nullify. Таким образом, вы предотвратит утечки памяти Для более того, чтобы предотвратить утечку памяти: отличное видео из инженеров Google Google IO Memory optimization, безусловно, поможет вам
+0

Большое спасибо Kushal, Я изменил фрагменты TextView, которые будут меняться с помощью setText. Я также добавил Imagevew, который изменится с помощью setImageResource. Приложение значительно уменьшило использование памяти. Теперь вряд ли возьмем память. Я очень благодарен. На этом сайте я многому учусь. Спасибо также: EpicPandaForce, Stan, inmyth. – Natlum

+0

Спасибо. Я рад, что ваша проблема решена. – Kushal

3

Ваша проблема заключается в том, что вы на самом деле все 20 фрагментов в памяти во все времена, которые все имеют большое растровое изображение в них.

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

Программа должна быть построена так, что есть только один фрагмент создан в любое время, учитывая, что вы имеете нужду только для одного фрагмента, который отображается. На самом деле, я даже не уверен, есть ли более двух фрагментов (grpE и grpP), это зависит от того, действительно ли они изменяются в макете или только в контенте.

Если это невозможно, по крайней мере используйте механизм, например FragmentStatePagerAdapter, чтобы фрагменты, которые вам не нужны, фактически не создавались, занимая память.

Смежные вопросы