Статьи

Рекомендации для Android: StrictMode

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

StrictMode имеет различные политики. Каждая политика имеет различные правила. У каждой политики также есть различные способы показать, когда правило нарушено. Сначала мы определим их, а затем приведем краткий пример их использования.

В настоящее время существует две категории политик, доступных для использования. Одним из них является политика потоков, а другим — политика ВМ (виртуальная машина, не путать с виртуальной памятью). Политика потоков может отслеживать:

  • Чтение с диска
  • Диск пишет
  • Доступ к сети
  • Пользовательский медленный код

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

Политика VM может отслеживать следующие проблемы:

  • Утечка объектов деятельности
  • Утечка объектов SQLite
  • Утечка закрываемых предметов

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

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

Чтобы включить и настроить StrictMode в вашем приложении, вы должны будете использовать методы StrictMode setThreadPolicy () и setVmPolicy () как можно раньше в жизненном цикле приложения. Когда дело доходит до политики потоков, вопрос о том, какой поток запускается, тоже имеет значение (он отслеживает ошибки только в этом потоке, обычно в основном потоке). Хорошее место для установки политик — это точки входа в ваше приложение и действия. Например, в простом приложении вам может потребоваться просто поместить код в метод onCreate () класса запуска Activity.

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

1
2
3
4
5
6
7
8
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
        .detectAll()
        .penaltyLog()
        .penaltyDialog()
        .build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
        .penaltyLog()
        .build());

Вы не должны оставлять этот код включенным в производственном приложении. Он предназначен только для опытного использования. Вместо этого можно использовать флаг для условного включения или отключения StrictMode.

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

Вот пример вывода LogCat, когда мы запускаем версию приложения TutList с включенным StrictMode (все политики, все правила):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
09-04 16:15:34.592: DEBUG/StrictMode(15883): StrictMode policy violation;
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1041)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:219)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:83)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:1829)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:1780)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at com.mamlambo.tutorial.tutlist.data.TutListProvider.update(TutListProvider.java:188)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.content.ContentProvider$Transport.update(ContentProvider.java:233)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.content.ContentResolver.update(ContentResolver.java:847)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at com.mamlambo.tutorial.tutlist.data.TutListProvider.markItemRead(TutListProvider.java:229)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at com.mamlambo.tutorial.tutlist.TutListFragment.onListItemClick(TutListFragment.java:99)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.support.v4.app.ListFragment$2.onItemClick(ListFragment.java:53)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.widget.AdapterView.performItemClick(AdapterView.java:282)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.widget.AbsListView.performItemClick(AbsListView.java:1037)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.widget.AbsListView$PerformClick.run(AbsListView.java:2449)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.widget.AbsListView$1.run(AbsListView.java:3073)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.os.Handler.handleCallback(Handler.java:587)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.os.Handler.dispatchMessage(Handler.java:92)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.os.Looper.loop(Looper.java:132)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.app.ActivityThread.main(ActivityThread.java:4123)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at java.lang.reflect.Method.invokeNative(Native Method)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at java.lang.reflect.Method.invoke(Method.java:491)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
09-04 16:15:34.592: DEBUG/StrictMode(15883): at dalvik.system.NativeStart.main(Native Method)

Вы можете убедиться в этом сами, добавив код StrictMode в Version Code 13 TutList. Просто выберите другой элемент из списка.

Что этот журнал говорит нам? Просто пометить сообщение как прочитанное следовало из основного потока. Вместо этого он съедает треть секунды! Мало того, что это удивительно медленно, влияние на интерфейс заметно.

А вот как выглядит диалоговое окно с предупреждением:

Экран, показывающий TutList с нарушением StrictMode

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

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

1
2
3
4
5
6
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
    .permitDiskWrites()
    .build());
doCorrectStuffThatWritesToDisk();
StrictMode.setThreadPolicy(old);

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

StrictMode — полезный класс в арсенале диагностических инструментов, доступных для разработчиков Android. С его помощью разработчики могут находить и устранять незначительные проблемы с производительностью, утечки объектов и другие трудно обнаруживаемые проблемы во время выполнения. Вы используете StrictMode? Есть ли другие политики, которые вы хотели бы видеть добавленными к этой функции Android SDK?

Разработчики мобильных приложений Лорен Дарси и Шейн Кондер являются соавторами нескольких книг по разработке Android: углубленная книга по программированию под названием « Разработка беспроводных приложений для Android, второе издание» и « Самс научи себя разработке приложений для Android за 24 часа, второе издание» . Когда они не пишут, они тратят свое время на разработку мобильного программного обеспечения в своей компании и оказание консультационных услуг. С ними можно связаться по электронной почте [email protected] , через их блог на androidbook.blogspot.com и в Twitter @androidwireless .

Купить Android-разработку беспроводных приложений, 2-е издание Купить Sam's Teach Yourself для Android-разработки приложений в течение 24 часов, второе издание Код Мамламбо в Код-Каньоне