Занятные баги-задачки

Mar 10, 2017 12:13


Последнее время активно чиним баги и зачищаем warning-и от анализаторов. А за это время накопилось несколько довольно занятных примеров.
Конечно, когда знаешь, в чем соль, то все просто и очевидно. Но в коде если не знать, то просто пропустишь как есть.
Первый пример, про закрывающиеся потоки, обычная java.
  1. static void saveToFile(@NonNull File storageFile) throws IOException {
  2. ObjectOutputStream stream = null;
  3. try {
  4.     stream = new ObjectOutputStream(new BufferedOutputStream(
  5.                     new FileOutputStream(storageFile)));
  6.     //действия со стримом
  7. } finally {
  8.     try {
  9.         if (strean != null) {
  10.             closeable.close();
  11.         }
  12.     } catch (IOException ignore) {
  13.     }
  14. }
  15. }

Это кажется, что это абсолютно безопасный код, написанный по идиомам java. С единственной оговоркой - тут должны быть try-with-resources, но в мире android-а так пока нельзя, к сожалению, если min sdk < 19: скомпилится и в 98% случаев будет работать, но в оставшихся 2% будет крешиться; и эта зависимость трудноотлавливаемая - зависимость от версии jvm на телефоне).
Но в этом коде есть проблема и sonar ее радостно находит.[Ответ]
Проблема возникнет, если внутренний поток FileOutputStream проинициализируется. А вот во время создания обертки произойдет любой exception. В этом случае поток останется открытым, а stream == null.

Здравствуй, утечка ресурсов!
Второй пример, про получение аттрибутов из кода, android.
У нас в приложении есть внутренний браузер на webview. И у этого браузера есть toolbar. Задаем выстору Toolbar-а через xml:
android:layout_height="?attr/actionBarSize"
Но после переворота приложения мы же не хотим перезагружать activity. Поэтому не пересоздаем эту активити и указываем: android:configChanges="orientation|screenSize". Но есть одна проблема - после поворота из portrait ориентации в landscape высота toolbar-а не меняется. Это логично с точки зрения кода (ведь ничего не пересоздаем). Но нелогично с точки зрения пользователей - зачем им широкий toolbar в landscape?
Тогда пишем небольшой кусочек кода:
  1. @Override
  2. public void onConfigurationChanged(Configuration newConfig) {
  3. super.onConfigurationChanged(newConfig);
  4. mAppBarLayout.getLayoutParams().height = getActionBarSize(getBaseContext());
  5. }
  6. public static int getActionBarSize(@NonNull Context context) {
  7. final int[] textSizeAttr = new int[]{android.R.attr.actionBarSize};
  8. TypedArray a = context.obtainStyledAttributes(textSizeAttr);
  9. final int indexOfAttrTextSize = 0;
  10. int size = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
  11. a.recycle();
  12. return size;
  13. }

Это работает... Но не на 4-х android-ах! На них toolbar становится уже, чем был изначально.
А в чем же проблема?[Ответ]
А проблем несколько! Дело в том, что в данном коде используется системный android.R.attr.actionBarSize. Но это не правильно и корректно использовать appCompat аттрибут (как раз сделано для обратной совместимости ведь). Но при попытке заменить android.R.attr.actionBarSize на android.support.v7.appcompat.R.attr.actionBarSize видим, что возвращается дефолтное значение -1. И тут мы натыкаемся на вторую проблему: нельзя получать StyledAttributes от Context-а. Стили и темы не успевают примениться. И значения просто нет! С использованием системного аттрибута actionBarSize это работало, потому что стили там и не нужны. А теперь - нет. И правильный вариант - передавать activity в эту функцию, а не контекст.

Работка, Программизмы, Мимолетное

Previous post Next post
Up