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.