Android: ошибка OutOfMemory и стоп-сигнал

следующий лист представляет рабочий поток в приложении, о котором идет речь.

workflow

Я столкнулся с проблемами с ошибками OutOfMemory, в основном потому, что пользователи могли переключаться с активности B на активность D несколько раз (они показывают различный контент для каждой попытки), без уничтожения предыдущей активности. Это привело к очень большой загрузке, что привело к ошибке OutOfMemory.

Чтобы этого избежать, я выполнил рекомендацию о добавлении родительских активностей в манифест и создания новых столов с классом TaskStackBuilder:

void openDFromB()
{
    Intent i = new Intent(this, ActivityD.class);
    TaskStackBuilder.create(this)
        .addParentStack(ActivityD.class)
        .addNextIntent(i)
        .startActivities();
}

Если теперь пользователь переключается с действия B на D, MainMenu, A и B уничтожаются и создается новый Backstack (MainMenu, C, D). Это решает проблемы с памятью для уровня api более 10, но, к сожалению, TaskStackBuilder не создает блокировки для устройств pre api 11.

Любая идея, что делать, чтобы избегать пользователей, укладывающих бесконечное количество операций до api 11? Возможно ли это, или я должен попытаться освободить как можно больше ресурсов в onPause, чтобы получить максимальное количество накопленных действий до OoM?

заблаговременно!

Ответы

Ответ 1

Ответ Zabri - это хорошо, но я бы предложил другое, вероятно, лучше: Вы не закрываете все действия, но когда вы открываете новую активность, которая была открыта раньше, вы сообщаете системе, что она может очистить путь назад и снова открыть этот, конечно, с новым намерением и всеми новыми данными, которые вам нужны.

Итак, если вы делаете A-B-D-B-D-B, вместо того, чтобы иметь этот большой стек, у вас будет

  • A - B
  • A - B - D
  • A - B
  • A - B - D
  • A - B

Итак, если вы делаете C-D-B-D-B-D, ваш стек будет

  • C - D
  • C - D - B
  • C - D
  • C - D - B
  • C - D

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

Код для этого: создайте функцию, которая получает класс (что-то вроде ActivityD.class), там вы создаете намерение с флагами Intent.FLAG_ACTIVITY_CLEAR_TOP и Intent.FLAG_ACTIVITY_NEW_TASK, а затем, когда вам нужно открыть действие, просто вызовите эту функцию. Вы не заботитесь о том, работает ли в стеке или нет. Если это не так, оно создается нормально.

 protected void startActivity(Class<?> clase) {
    final Intent i = new Intent(this, clase);
    int flags = Intent.FLAG_ACTIVITY_CLEAR_TOP;
    flags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    i.setFlags(flags);
    startActivity(i);
}


startActivity(ActivityD.class);

Ответ 2

Попробуйте это -

Intent intent = new Intent(getApplicationContext(),yourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Другое решение -

Настройка android:noHistory="true" в действии в вашем файле манифеста удалит действие из стека всякий раз, когда он перемещается в сторону.

Но наиболее подходящим способом является вызов метода finish() всякий раз, когда вы начинаете новую активность, как в следующем примере кода -

Intent intent = new Intent(this, yourActivity.class);
startActivity(intent);
finish();

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

Ответ 3

Может быть, ваше приложение имеет утечку памяти и из-за того, что более старые действия не получают исправления GC и, в конечном итоге, увеличивают размер кучи каждый раз, когда происходит переключение активности.

Как найти утечки?
Пожалуйста, смотрите: http://www.youtube.com/watch?v=_CruQY55HOk

Литература:

Ответ 4

Я не знаю, как это работает с навигационным ящиком, но некоторое время назад я создавал приложение для Android, которое начиналось с экрана загрузки, а затем переходило к основной активности приложения. Поскольку мне не нужно/хотелось, чтобы пользователь когда-либо возвращался на экран загрузки, я просто позвонил finish(), прежде чем перейти к основному действию. Вот так:

Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();

И затем, когда пользователь нажал кнопку "Назад" из основного действия, они не дошли до активности загрузки, но где бы они ни были до этого.

Итак, вы также можете попробовать:

void openDFromB()
{
    Intent i = new Intent(this, ActivityD.class);
    startActivity(i);
    finish();
}

Как я уже сказал, я никогда не реализовал навигационный ящик, но что-то подсказывает мне, что это может нарушить все его поведение. Кроме того, вызов finish() в действии - такая базовая концепция, что я был бы удивлен, если бы вы не пробовали это уже.:) Но все же, я размещаю это как выстрел в темноте, на всякий случай, это поможет вам. Удачи.:)

Ответ 5

Здравствуйте, вы можете попробовать добавить следующий оператор в файл манифеста в тег приложения:

android:largeHeap="true"

Также убедитесь, что ваш android:targetSdkVersion равен 14.