Перейти к содержимому

Android приложение упало как найти причину падения

  • автор:

[Андроид] как отследить причину падения приложения?

вопрос к андроид профи.
пользуюсь для спорт. тренировок приложение RunKeeper
оно пишет трек скорость и т.п.
внезапно обнаруживаю что в середине тренировки оно падает.
все данные , трек и т.п. полученные в первой половине тренировки теряются.
как выяснить в чем причина такого поведения программмы и где это посмотреть?
вопрос кстати касается не конкретно этой программы а любой, я не раз видел такой текст ошибки и для других программ. в свете такого события надёжность телефона как девайса падает до нуля, а ведь надёжность — один из ключевых факторов в пользовании электронной техникой (кому хочется потерять весь текст в ворде который он набирал два часа)

Такое сообщение говорит лишь о том, что приложение упало. В 99.9% случаев вина на программистах приложения.
Если всё настроено нормально, то разработчики проекта получат крэш-репорт со всеми данными (жми кнопку «Отчёт»). Если телефон рутованный, можно посмотреть стэк падения, но вряд ли он тебе что-то скажет.

то есть такой вариант как убийство приложения из за неъватки памяти — невозможен?

то есть такой вариант как убийство приложения из за неъватки памяти — невозможен?

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

это гадание на кофейной гуще. может память, может нет. где посмотреть развернутый текст ошибки?
и глобально — если у меня то и дело вылетает ранкипер, яндекс карты, навигатор и еще куча других программ то мне просто надо ждать выхода новых версий ( с новыми багами , муахаха) а текущими не пользоваться просто отложив андроид телефон в сторонку?

а текущими не пользоваться просто отложив андроид телефон в сторонку?

Можешь тогда и яблоные устройства отложить в сторонку.
На ипаде регулярно падает пара приложений.
Проблема тут скорее всего в программистах.

пока другого выхода нет — мои друзья пользуются RunKeeper без проблем и горя не знают, а у меня он падает. но меня переспектива отказаться от его использования не устраивает. как посмотреть логи проблемы?

Или, если без adb, но есть рут, какой-нибудь CatLog.

это надо запускать заранее до старта программы? сейчас прошлые ошибки уже не посмотреть? вообще конечно странное отношение к юзеру как к лоху — ошибка и всё, а что сломалось хер покажут(((

вообще конечно странное отношение к юзеру как к лоху — ошибка и всё, а что сломалось хер покажут(((

зачем юзеру нужно что-то большее чем «отправить отчет об ошибке»?

какому юзеру? мне?

не в курсе. я знаю что мне надо устранить ошибку так как иначе я не могу пользоваться софтом этим.

я знаю что мне надо устранить ошибку

ты разработчик?

я юзер. и если выяснится что проблема в моём телефоне то я поменяю ОС или телефон, а не буду ждать манны небесной, которая никогда не случится.

если выяснится что проблема в моём телефоне то я поменяю ОС или телефон

а разве ты это уже не выяснил выше?

мои друзья пользуются RunKeeper без проблем и горя не знают, а у меня он падает.

нет, пока не выяснил. так как есть ненулевая вероятность что проблема еще в моем стиле пользования телефоном (запускаю сразу 20 -30 разных софтин , к примеру), а может реально в софте.
в общем гадать на кофейной гуще я не хочу — меня интересует лог ошибки.

запускаю сразу 20 -30 разных софтин , к примеру

Так если стабильно падает, то целый один раз не запускай ничего, кроме этой проги — и проверишь.

это и будет гадание на кофейной гуще. целый один раз — не показатель. тут статистика нужна с логами

с 90% вероятностью тыт там увидишь сегфолт и access violation с адресом, где упало, которые тебе ничего не скажут
может еще стэктрейс вида
1. <>.RunKeeper 0xfffff 11234
2. <>.RunKeeper 0 5678
3. <>.RunKeeper 0xaaa 90123
4. <>.RunKeeper 0xcccc11234
5. <>.RunKeeper 0x12345 11234
6. <>.RunKeeper 0xabcdef 11234
7. .event
самое полезное на что можно надеяться: ворнинги типа low system memory и т.п.

нет, пока не выяснил. так как есть ненулевая вероятность что проблема еще в моем стиле пользования телефоном (запускаю сразу 20 -30 разных софтин , к примеру), а может реально в софте.
в общем гадать на кофейной гуще я не хочу — меня интересует лог ошибки.

Я вот одного не пойму: разве тут форму разработчиков этой проги? Не логичнее было бы с ними связаться?

Да 99%, что прога непричём. Либо руки, либо девайс.

Я вот одного не пойму: разве тут форму разработчиков этой проги? Не логичнее было бы с ними связаться?

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

с 90% вероятностью тыт там увидишь сегфолт и access violation с адресом, где упало, которые тебе ничего не скажут
может еще стэктрейс вида
1. <>.RunKeeper 0xfffff 11234
2. <>.RunKeeper 0 5678
3. <>.RunKeeper 0xaaa 90123
4. <>.RunKeeper 0xcccc11234
5. <>.RunKeeper 0x12345 11234
6. <>.RunKeeper 0xabcdef 11234
7. .event
самое полезное на что можно надеяться: ворнинги типа low system memory и т.п.

с удовольствием гляну на них. где их можно посмотреть?

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

Тогда я бы ставил на хардварную проблему. У меня я-навигатор не падает, даже когда памяти совсем мало.

с удовольствием гляну на них. где их можно посмотреть?

Тебе уже три раза написали — logcat. Последние сколько-то строк логов ты увидишь. Втыкай сразу после падения и смотри. А если всё падает реально часто — просто поработай с воткнутым кабелем и всё увидишь, что тебе позволено.
PS Если телефон не рутован, скорее всего очень немного.

Тогда я бы ставил на хардварную проблему. У меня я-навигатор не падает, даже когда памяти совсем мало.

это потому что ты кроме навигатора не запускаешь еще сто пицот приложений

с 90% вероятностью тыт там увидишь сегфолт и access violation с адресом,

предполал, что на андроиде Java, которая выдаёт человекочитаемый stacktrace.
Это предположение ошибочное?

ndk, обфускаторы, вот это всё

Как решить проблему сбоя приложения на Android

как решить проблему с падением приложения

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

Что такое сбой приложения?

ошибка сбоя приложения

Операционная система Google Android может иметь ошибка, затрагивающая конкретное приложение, или в самом приложении может быть ошибка, которая затрагивает его самого или блокирует всю систему. Когда приложения, написанные на Java, неожиданно завершают работу из-за необработанного сигнала или исключения, будет выдано сообщение о сбое приложения, указывающее на наличие проблемы.

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

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

Не имея возможности отлаживать приложение, невозможно узнать причину проблемы, но можно что-то сделать, чтобы устранить эту проблему своевременно или навсегда.

Когда это происходит, приложение даже не нужно запускать. Они также могут дать сбой при работе в фоновом режиме.. Что-то, что смущает многих пользователей, но это не редкость. Это может произойти, даже если вы специально не используете это приложение.

Как решить проблему сбоя приложения: возможные причины и решения

APPCRASH

Когда такая проблема возникает у вас, вы должны знать об этих возможных причинах и как легко решить проблемы с падением приложения:

Конкретные проблемы в приложении

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

Чтобы исправить это, лучше всего просто принудительно закрыть приложение. Другой способ сделать это:

  1. Войдите в настройки
  2. Перейти в раздел Управление приложениями
  3. Нажмите «Управление приложениями».
  4. Затем найдите приложение, из-за которого возникла проблема с аварийным приложением, и нажмите на него.
  5. Внизу вы увидите опцию «Принудительная остановка». Щелкните здесь.
  6. Теперь попробуйте снова открыть приложение и посмотреть, возникает ли ошибка снова. Если это все еще происходит, выполните следующие действия.

Перезагрузите операционную систему

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

В этих случаях просто перезагрузить мобильный:

  1. Нажмите кнопку питания на несколько секунд
  2. Появится меню с опцией «Перезагрузить», которую вы должны выбрать.
  3. Примите и дождитесь перезапуска. Попробуйте открыть приложение и посмотреть, правильно ли оно работает. Если это не так, перейдите к шагам, описанным в следующем разделе.

Проблемы с кешем приложений

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

  1. Войдите в настройки
  2. Перейти в раздел Управление приложениями
  3. Нажмите «Управление приложениями».
  4. Затем найдите приложение, из-за которого возникла проблема с аварийным приложением, и нажмите на него.
  5. Внизу вы увидите опцию «Очистить данные». Щелкните здесь.
  6. Теперь попробуйте снова открыть приложение и посмотреть, возникает ли ошибка снова. Если ошибка повторится, выполните действия, описанные в следующем разделе.

Проблемы с настройками приложения

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

  1. Войдите в настройки
  2. Перейти в раздел Управление приложениями
  3. Нажмите «Управление приложениями».
  4. Затем найдите приложение, из-за которого возникла проблема с аварийным приложением, и нажмите на него.
  5. Здесь вы найдете опцию Clear Defaults. Щелкните здесь.
  6. Теперь попробуйте снова открыть приложение и посмотреть, возникает ли ошибка снова. Если это все еще не удается, перейдите к следующему разделу.

Переустановите проблемное приложение

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

  1. Перейти в Google Play
  2. Найдите проблемное приложение
  3. Нажмите на него и нажмите «Удалить».
  4. Теперь переустановите приложение

Проверьте разрешения приложения

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

  1. Перейти к настройкам
  2. Затем к приложениям
  3. разрешений
  4. Найдите нужное приложение и проверьте, адекватны ли разрешения.

Обновите приложения и систему

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

  1. Перейти в Google Play
  2. Войдите в меню
  3. Затем перейдите в Управление приложениями и устройствами.
  4. Нажмите на вкладку «Управление».
  5. Затем доступны обновления
  6. И обновите приложения, которые есть в списке. Если приложение, вызывающее проблемы, не найдено, перейдите к следующему разделу.

Очистить кэш Android

Другим несколько более радикальным шагом является очистить кеш самой операционной системы Android. Это может решить некоторые проблемы, особенно связанные с производительностью. Следующие шаги:

  1. Выключите мобильный телефон
  2. Теперь одновременно нажмите кнопку громкости (+) и кнопку питания. Вы должны удерживать их в течение нескольких секунд.
  3. Вы увидите, что мобильный запускается и входит в режим восстановления. Теперь вы можете бросить их.
  4. В меню с черным фоном вы можете перемещаться с помощью клавиш громкости +/- для перехода вверх и вниз или с помощью кнопки питания для выбора нужного параметра.
  5. Выберите Очистить раздел кэша.
  6. Дождитесь завершения процесса и перезагрузки системы. Теперь вы можете проверить, вызывает ли приложение сбой приложения. Если это так, продолжайте в этом руководстве.

Место для хранения

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

  • Удалите приложения, которые вы не используете
  • Удалите ненужные данные (загрузки, документы. )
  • Загружайте фото или видео, которые не хотите потерять, в облако или делайте резервную копию на другом носителе
  • Переместите приложения или данные на карту памяти microSD

Сброс к заводским настройкам

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

  1. Выключите мобильный телефон
  2. Теперь одновременно нажмите кнопку громкости (+) и кнопку питания. Вы должны удерживать их в течение нескольких секунд.
  3. Вы увидите, что мобильный запускается и входит в режим восстановления. Теперь вы можете отпустить кнопки.
  4. В меню с черным фоном вы можете перемещаться с помощью клавиш громкости +/- для перехода вверх и вниз или с помощью кнопки питания для выбора нужного параметра. В этом случае Wipe data/Factory reset.
  5. Дождитесь завершения процесса и перезагрузки системы. Если это все еще не исправило, проблема, вероятно, более серьезная, с самой операционной системой или с оборудованием.

поврежденное ПЗУ

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

В этих случаях, вероятно, ром поврежден или внутренняя память, где установлен Android, выходит из строя. В этих случаях вы можете попытаться восстановить мобильный телефон, установив новое ПЗУ, если у вас есть необходимые для этого знания. Или, если это повторяется, считайте, что это аппаратный сбой, и замените мобильное устройство другим.

Содержание статьи соответствует нашим принципам редакционная этика. Чтобы сообщить об ошибке, нажмите здесь.

Полный путь к статье: Справка Android » приложений » Учебники » Как решить проблему сбоя приложения на Android

Что такое утечки памяти в android, как проверить программу на их отсутствие и как предотвратить их появление

В этой статье для начинающих android-разработчиков я постараюсь рассказать о том, что такое «утечки памяти» в android, почему о них стоит думать на современных устройствах, выделяющих по 192МБ на приложение, как быстро найти и устранить эти утечки в малознакомом приложении и на что нужно обращать особое внимание при разработке любого приложения.

Конечная цель этой статьи — ответ на простой вопрос:
Куда нажать, чтобы узнать, какую строчку в приложении поправить?

Что такое «утечка памяти»?

Начнем с того, что же называется «утечкой памяти». В строгом понимании объект можно назвать утечкой памяти, если он продолжает существовать в памяти даже после того, как на него потеряны все ссылки. С этим определением сразу же возникает проблема: память для всех объектов, которые вы создаете, выделяется при участии сборщика мусора, и все созданные объекты сборщик мусора помнит, независимо от того, есть у вас ссылка на объект, или нет.

На самом деле сборщик мусора устроен крайне примитивно (на самом деле нет — но принцип работы действительно простой): есть граф, в котором каждый существующий объект — это вершина, а ссылка от любого объекта на любой другой объект — ребро. Некоторые вершины на этом графе — особые. Это корни сборщика мусора (garbage collection roots) — те сущности, которые созданы системой и продолжают свое существование независимо от того, ссылаются на них другие объекты или нет. Если и только если на графе существует любой путь от данного объекта до любого корня, объект не будет уничтожен сборщиком мусора.

В этом и заключается проблема — если объект не уничтожен, значит существует цепочка ссылок от корня до данного объекта (либо, если такой цепочки не существует, объект будет уничтожен при следующей сборке мусора).А это значит, что ни один объект не может являться утечкой памяти в строгом понимании этого термина. Собственно даже того, что сам сборщик мусора хранит ссылку на каждый существующий объект в системе, уже достаточно.

Попытки получить в java «чистую» утечку памяти предпринимались неоднократно и, безусловно, продолжают предприниматься, однако ни один из способов не способен заставить сборщика мусора забыть ссылку на объект, не освободив память. Существуют утечки памяти, связанные с выделением памяти нативным кодом (JNI), однако в этой статье мы их не будем рассматривать.

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

Итак, определение «утечки памяти» в строгом смысле нам не подходит. Поэтому далее будем понимать утечку памяти как объект, который продолжает существовать после того, как он должен быть уничтожен.

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

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

Почему нужно тратить время на устранение утечек памяти?

Приложения уже давно не падают из-за того, что вы забыли пережать ресурсы в папку drawable-ldpi. Готовясь к написанию этой статьи, я провел простой эксперимент: я взял одно из работающих приложений, и добавил в него утечку памяти таким образом, что ни одно создаваемое activity никогда не выгружалось из памяти (стал добавлять их в статический список). Я открыл приложение и начал прокликивать экраны, ожидая, когда же приложение наконец упадет на моем Nexus 5. Наконец, через 5 минут и 55 экранов, приложение упало. Ирония в том, что, по данным Google Analytics, обычно пользователь за сессию посещает 3 экрана.

Так нужно ли волноваться по поводу утечек памяти, если пользователь может их просто не заметить? Да, и есть три причины почему.

Во-первых, если в вашем приложении работает что-то, что работать не должно, это может привести к очень серьёзным и трудно отлаживаемым проблемам.

Например, вы разработали приложение для социальной сети. В этом приложении можно обмениваться сообщениями между пользователями, где на экране обмена сообщениями есть таймер, который делает запрос на сервер каждые 10 секунд с целью получения новых сообщений, но вы забыли этот таймер выключить при выходе с экрана. К чему это приведет визуально? Да ни к чему. Вы не заметите, что приложение делает что-то не то. Но при этом приложение продолжит каждые 10 секунд посылать запрос на сервер. Даже после того, как вы выйдете из приложения. Даже после того, как вы выключите экран (поведение может варьироваться от телефона). Если пользователь зайдет на экраны общения с тремя разными друзьями, в течение часа вы получите 1000 лишних запросов на сервер и одного пользователя, очень рассерженного на ваше приложение, которое усиленно потребляет батарею. Именно такие результаты я получил с тестовым приложением на телефоне с выключенным экраном.

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

Во-вторых, не все приложения потребляют мало памяти, и не все телефоны выделяют много памяти.

Помните про приложение, которое упало только после 5 минут и 55 не выгруженных экранов? Так вот для этого же приложения мне каждую неделю приходит 1-2 отчета о падении с OutOfMemoryException (в основном с устройств до 4.0; у приложения 50.000 установок). И это при том, что утечек памяти в приложении нет. Поэтому даже сейчас вы можете изрядно подпортить себе карму, выложив приложение с утечками памяти, особенно если ваше приложение потребляет много памяти. Как обычно в мире android, от блестящего будущего нас отделяет суровое настоящее.

В-третьих, мужик должен всё уметь! (я же обещал, что все 3 причины будут серьёзные)

Теперь, когда я, надеюсь, убедил вас в необходимости отлавливать утечки памяти, давайте рассмотрим основные причины их появления.

Никогда не сохраняйте ссылки на activity (view, fragment, service) в статических переменных

Один из первых вопросов, с которым сталкивается каждый начинающий разработчик, это как передать объект из одного activity в следующий. Самое простое и самое неправильное решение, которое мне периодически приходится видеть, это запись первого activity в статическую переменную и обращение к этой переменной из второго activity. Это крайне неудачный подход. Не только потому, что он моментально приводит к утечке памяти (статическая переменная продолжит существовать пока существует приложение, и activity, на который она ссылается, никогда не будет выгружен). Этот подход также может привести к ситуации, когда вы будете обмениваться информацией не с тем экраном, ведь экран, невидимый пользователю, может в любой момент быть уничтожен и пересоздан лишь когда пользователь к нему вернется.

Почему же утечка activity — такая большая проблема? Дело в том, что если сборщик мусора не соберет activity, то он не соберет и все view и fragment, а вместе с ними и все прочие объекты, расположенные на activity. В том числе не будут высвобождены картинки. Поэтому утечка любого activity — это, как правило, самая большая утечка памяти, которая может быть в вашем приложении.

Никогда не записывайте ссылки на activity в статические переменные. Используйте передачу объектов через Intent, либо вообще передавайте не объект, а id объекта (если у вас есть база данных, из которой этот id потом можно достать).

Этот пункт также относится к любым объектам, временем жизни которых напрямую или косвенно управляет android. Т.е. к view, fragment, service и т.д..

View и fragment объекты содержат ссылку на activity, в котором они расположены, поэтому, если утечет один единственный view, утечет сразу всё — activity и все view в нём, а, вместе с ними, и все drawable и всё, на что у любого элемента из экрана есть ссылка!

Будьте аккуратны при передаче ссылки на activity (view, fragment, service) в другие объекты

Рассмотрим простой пример: ваше приложение для социальной сети отображает фамилию, имя и рейтинг текущего пользователя на каждом экране приложения. Объект с профилем текущего пользователя существует с момента входа в аккаунт до момента выхода из него, и все экраны вашего приложения обращаются за информацией к одному и тому же объекту. Этот объект также периодически обновляет данные с сервера, так как рейтинг может часто меняться. Необходимо, чтобы объект с профилем уведомлял текущее activity об обновлении рейтинга. Как этого добиться? Очень просто:

@Override protected void onResume()

Как добиться в этой ситуации утечки памяти? Тоже очень несложно! Просто забудьте отписаться от уведомлений в методе onPause:

@Override protected void onPause() < super.onPause(); /* Забудьте про следующую строчку и вы получите серьёзную утечку памяти */ currentUser.removeOnUserUpdateListener(this); >

Из-за такой утечки памяти activity будет продолжать обновлять интерфейс каждый раз, когда профиль будет обновляться даже после того, как экран перестанет быть видим пользователю. Хуже того, таким образом экран может подписать 2, 3 или больше раза на одно и то же уведомление. Это может привести к видимым тормозам интерфейса в момент обновления профиля — и не только на этом экране.

Что делать, чтобы избежать этой ошибки?

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

Во-вторых, вы должны периодически проверять своё приложение на наличие утечек памяти.

В-третьих, есть и альтернативный подход к проблеме: вы можете сохранять не ссылки на объекты, а слабые ссылки. Это особенно полезно для наследников класса View — ведь у них нет метода onPause и не совсем понятно, в какой момент они должны отписываться от уведомления. Слабые ссылки не считаются сборщиком мусора как связи между объектами, поэтому объект, на который существуют только слабые ссылки, будет уничтожен, а ссылка перестанет ссылаться на объект и примет значение null. Чтобы не возиться каждый раз с не очень удобными в использовании слабыми ссылками, вы можете воспользоваться примерно следующим шаблонным классом:

public class Observer  < private ArrayListstrongListeners = new ArrayList(); private ArrayList weakListeners = new ArrayList(); public void addStrongListener(I listener) < strongListeners.add(listener); >public void addWeakListener(I listener) < weakListeners.add(new WeakReference(listener)); > public void removeListener(I listener) < strongListeners.remove(listener); for (int i = 0; i < weakListeners.size(); ++i) < WeakReferenceref = weakListeners.get(i); if (ref.get() == null || ref.get() == listener) < weakListeners.remove(i--); >> > public List getListeners() < ArrayListactiveListeners = new ArrayList(); activeListeners.addAll(strongListeners); for (int i = 0; i < weakListeners.size(); ++i) < WeakReferenceref = weakListeners.get(i); I listener = ref.get(); if (listener == null) < weakListeners.remove(i--); continue; >activeListeners.add(listener); > return activeListeners; > > 

Который будет работать примерно вот так:

public class User < . public interface OnUserUpdateListener < public void onUserUpdate(); >private Observer updateObserver = new Observer(); public Observer getUpdateObserver() < return updateObserver; >> . @Override protected void onFinishInflate() < super.onFinishInflate(); /* Мы подписываемся на уведомления при создании объекта */ currentUser.getUpdateObserver().addWeakListener(this); >/* . и никогда от этих уведомлений не отписываемся */ . 

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

Есть только одна тонкость при использовании метода addWeakListener: на объект, который вы добавляете, должен кто-то ссылаться. Иначе сборщик мусора уничтожит этот объект до того, как он получит свое первое уведомление:

/* Не делайте так! */ currentUser.getUpdateObserver().addWeakListener(new OnUserUpdateListener() < @Override public void onUserUpdate() < /* Этот код не будет вызван */ >>); 

Таймеры и потоки, которые не отменяются при выходе с экрана

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

public class HandlerActivity extends Activity < private Handler mainLoopHandler = new Handler(Looper.getMainLooper()); private Runnable queryServerRunnable = new Runnable() < @Override public void run() < new QueryServerTask().execute(); mainLoopHandler.postDelayed(queryServerRunnable, 10000); >>; @Override protected void onResume() < super.onResume(); mainLoopHandler.post(queryServerRunnable); >@Override protected void onPause() < super.onPause(); /* Вы забыли написать строчку ниже и в вашем приложении появилась утечка памяти */ /* mainLoopHandler.removeCallbacks(queryServerRunnable); */ >. > 

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

Никогда не сохраняйте ссылки на fragment в activity или другом fragment

Я очень много раз видел эту ошибку. Activity хранит ссылки на 5-6 запущенных фрагментов даже не смотря на то, что на экране всегда виден только 1. Один фрагмент хранит ссылку на другой фрагмент. Фрагменты, видимые на экране в разное время, общаются друг с другом по прямым закешированным ссылкам. FragmentManager в таких приложениях выполняет чаще всего рудиментарную роль — в нужный момент он подменяет содержимое контейнера нужным фрагментом, а сами фрагменты в back stack не добавляются (добавление фрагмента, на который у вас есть прямая ссылка, в back stack рано или поздно приведет к тому, что фрагмент будет выгружен из памяти; после возврата к этому фрагменту будет создан новый, а ваша ссылка продолжит ссылаться на существующий, но невидимый пользователю фрагмент).

Это очень плохой подход по целому ряду причин.

Во-первых, если вы храните в activity прямые ссылки на 5-6 фрагментов, то это тоже самое, как если бы вы хранили ссылки на 5-6 activity. Весь интерфейс, все картинки и вся логика 5 неиспользуемых фрагментов не могут быть выгружены из памяти, пока запущено activity.

Во-вторых, эти фрагменты становится крайне сложно переиспользовать. Попробуйте перенести фрагмент в другое место программы при условии, что он должен быть обязательно запущен в одном activity с фрагментами, x, y и z, которые переносить не надо.

Относитесь к фрагментам как к activity. Делайте их максимально модульными, общайтесь между фрагментами только через activity и fragmentManager. Это может казаться излишне сложной системой: зачем так стараться, когда можно просто передать ссылку? Но, на самом деле, такой подход сделает вашу программу лучше и проще.

По этой теме есть отличная официальная статья от Google: «Communicating with Other Fragments». Перечитайте эту статью и никогда больше не сохраняйте указатели на фрагменты.

Обобщённое правило

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

Все утечки памяти появляются тогда и только тогда, когда вы сохраняете ссылку на объект с коротким жизненным циклом (short-lived object) в объекте с длинным жизненным циклом (long-lived object).

Помните об этом и всегда внимательно относитесь к таким ситуациям.

У этого правила нет красивого короткого названия, такого как KISS, YAGNI или RTFM, но оно применимо ко всем языкам со сборщиком мусора и ко всем объектам, а не только к activity в android.

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

Куда нажать, чтобы узнать, какую строчку в приложении поправить?

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

Для того, чтобы определить наличие и источник утечек памяти в приложении вам потребуется немного времени и MAT. Если вы никогда раньше не пользовались MAT, установите его как plugin к eclipse, откройте DDMS perspective и найдите кнопку «Dump HPROF file». Нажатие на эту кнопку откроет дамп памяти выбранного приложения. Если вы используете Android Studio, то процесс будет немного сложнее, так как на данный момент MAT все ещё не существует как плагин к Android Studio. Поставьте MAT как отдельную программу и воспользуйтесь инструкцией со stackoverflow.

Выполните следующие шаги:

  1. Установите приложение на устройство, подключенное к компьютеру и попользуйтесь им таким образом, чтобы оказаться на каждом экране как минимум однажды. Если один экран может быть открыт с разными параметрами, постарайтесь открыть его со всеми возможными комбинациями параметров. Вообщем — пройдитесь по всему приложению, как если бы вы проверяли его перед релизом. После того как вы прошли все экраны, нажимайте кнопку «назад» до тех пор, пока не выйдите из приложения. Не нажимайте кнопку home — ваша задача завершить все запущенные activity, а не просто скрыть их.
  2. Нажмите на кнопку Cause GC несколько раз. Если вы этого не сделаете, в дампе будут видны объекты, которые подлежат уничтожению сборщиком мусора, но ещё не были уничтожены.
  3. Сделайте дамп памяти приложения нажав на кнопку «Dump HPROF file».
  4. В открывшемся окне сделайте OQL запрос: «SELECT * FROM instanceof android.app.Activity»

Заключение

Если вы прокликали все экраны в своем приложении и не нашли ни одного подозрительного объекта, то, с вероятностью 99.9%, в вашем приложении нет серьёзных утечек памяти.

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

Список литературы

  1. Investigating Your RAM Usage
    https://developer.android.com/tools/debugging/debugging-memory.html
  2. Java Performance blog
    http://kohlerm.blogspot.ru/2009/07/eclipse-memory-analyzer-10-useful.html
  3. Avoiding memory leaks
    http://android-developers.blogspot.co.uk/2009/01/avoiding-memory-leaks.html
  4. Memory Analysis for Android Applications
    http://android-developers.blogspot.ru/2011/03/memory-analysis-for-android.html
  5. Detecting a Memory Leak
    http://blog.crowdint.com/2013/10/02/fixing-memory-leaks-in-android-applications.html
  6. DEBUGGING MEMORY LEAKS ON ANDROID FOR BEGINNERS: PROGRAMMATIC HEAP DUMPING
    http://novoda.com/blog/memory-debugging-on-android-part-1
  7. How To Identify If Your App is Leaking Memory
    http://www.littleeye.co/blog/2013/04/24/identify-memory-leaks-android-apps/
  8. Fixing an Android Memory Leak
    http://therockncoder.blogspot.ru/2012/09/fixing-android-memory-leak.html
  9. Managing Your App’s Memory
    https://developer.android.com/training/articles/memory.html
  10. HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID
    http://www.raizlabs.com/dev/2014/03/wrangling-dalvik-memory-management-in-android-part-1-of-2/
    http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of-2/
  11. How to discover memory usage of my application in Android
    http://stackoverflow.com/questions/2298208/how-to-discover-memory-usage-of-my-application-in-android/2299813#2299813
  • Android
  • memory management
  • память
  • утечки памяти
  • руководство для новичков

Определить причину падения приложения на телефоне android

Я разрабатываю приложение на андроид, и само собой его тестирую. Обычным делом при тестировании приложения являются падения приложения, чаще всего эти падения происходят из-за видимых причин, что-то не учтено в коде. Но вот проблема возникла на устройстве находящемся далеко от меня и у меня нету возможности посмотреть логи и причину падения. Почему-то не подгружены строковые ресурсы и много других косяков, которых почему-то нету на подавляющем количестве телефонов. Я уже задавал подобный вопрос Непонятная проблема программы android y xiaomi но когда падение произошло на другом телефоне. Почему-то программа крашится(( Может есть какие-то очевидные причины. Вот на данный момент мне сказали что приложение упало на телефоне Samsung. Мне удалось подключить проблемный телефон и получить вроде как причину падения:

08-06 15:47:45.351 3394-3394/? E/PhoneInterfaceManager: [PhoneIntfMgr] getAllowedCarriers: CommandException: com.android.internal.telephony.CommandException: REQUEST_NOT_SUPPORTED 08-06 15:47:45.355 3394-3394/? E/PhoneInterfaceManager: [PhoneIntfMgr] getAllowedCarriers: CommandException: com.android.internal.telephony.CommandException: REQUEST_NOT_SUPPORTED 

но опять таки я не уверен. Я просто не могу понять почему на большинстве телефонов программа работает а на некоторых не работает? код на котором падает приложение:

 submitBtn = findViewById(R.id.btn_submit); submitBtn.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < sendPost(); >>); public void sendPost() < final EditText titleEt = findViewById(R.id.login); final EditText bodyEt = findViewById(R.id.password); final String a = titleEt.getText().toString().trim(); final String b = bodyEt.getText().toString().trim(); final Button btn = findViewById(R.id.btn_submit); HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://сервер/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create()) .build(); APIService mAPIService = retrofit.create(APIService.class); //retrofit.create(APIService.class); mAPIService.auth(new Post(a, b)).enqueue(new Callback() < @Override public void onResponse(@NonNull Callcall, @NonNull Response response) < if (response.isSuccessful()) < Toast.makeText(LoginActivity.this, "Post submitted to API.", Toast.LENGTH_LONG).show(); Intent intent = new Intent(LoginActivity.this, SecondScreen.class); btn.getBackground().setColorFilter(Color.parseColor("#1cd000"), PorterDuff.Mode.MULTIPLY); //TextView txt = findViewById(R.id.access_token); String token = Objects.requireNonNull(response.body()).getAccess_token(); //txt.setText(token); startActivity(intent); tok_pref = getSharedPreferences("access_token",MODE_PRIVATE); SharedPreferences.Editor editor = tok_pref.edit(); editor.putString(ACCESS_TOKEN,token); editor.commit(); saveData(); titleEt.addTextChangedListener(new TextWatcher() < @Override public void onTextChanged(CharSequence s, int start, int before, int count) < if (s.toString().trim().length() == 0) < btn.setEnabled(false); findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#FF0000"), PorterDuff.Mode.MULTIPLY); >else < btn.setEnabled(true); >> @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) < // TODO Auto-generated method stub >@Override public void afterTextChanged(Editable s) < // TODO Auto-generated method stub >>); > else < Toast.makeText(LoginActivity.this, "Unable to submit post to API.Error. ", Toast.LENGTH_LONG).show(); findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#FF0000"), PorterDuff.Mode.MULTIPLY); >> @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) < Toast.makeText(LoginActivity.this, "Unable to submit post to API.", Toast.LENGTH_LONG).show(); >>); > Заранее 

спасибо за помощь и ценные советы.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *