Ты никогда не задумывался, чем работа программиста отличается, например, от работы инженера-конструктора или прочниста (расслабься, сопромат вспоминать не будем)? Первое, что приходит в голову, — право на ошибки: действительно, процесс тестирования (отладки) занимает значительное время в любом проекте. Если продолжить размышлять, можно прибавить сюда и динамичность профессии.

В основе инженерных специальностей лежат методики, разработанные десятилетия назад, — так, методу конечных элементов скоро исполнится 70 лет, а он до сих пор не потерял актуальности. В программировании же все меняется со скоростью, близкой к скорости света. И нам приходится постоянно что-то изучать, пробовать чужие решения, изобретать собственные велосипеды, менять алгоритмы, внедрять стеки новых технологий — словом, участвовать в гонке без финиша. И если инженерам в их работе помогают умные книги, проверенные временем, то в нашем случае найти информацию, порой даже в официальных источниках, бывает очень проблематично. Не веришь? Что ж, тогда добро пожаловать в [А]ндрои[Д]…

 

Виджет и документация

Сегодня мы рассмотрим Android и его виджеты — только практику, никакой теории. За последней отсылаю тебя к недавней статье, где мы подробно рассматривали процесс создания «хакерского» виджета.

Итак, виджет представляет собой реализацию широковещательного приемника, каркас которого представлен ниже:

public class SkeletonAppWidget extends AppWidgetProvider {
  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    for (int appWidgetId : appWidgetIds) {
      ...
      appWidgetManager.updateAppWidget(appWidgetId, views);
      Log.d(DEBUG_TAG, "onUpdate : id = " + String.valueOf(appWidgetId));
    }
  }

  @Override
  public void onDeleted(Context context, int[] appWidgetIds) {
    Log.d(DEBUG_TAG, "onDeleted");
    super.onDeleted(context, appWidgetIds);
  }

  @Override
  public void onDisabled(Context context) {
    Log.d(DEBUG_TAG, "onDisabled");
    super.onDisabled(context);
  }

  @Override
  public void onEnabled(Context context) {
    Log.d(DEBUG_TAG, "onEnabled");
    super.onEnabled(context);
  }
}

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

Метод onUpdate() в цикле обновляет все экземпляры виджета по идентификаторам, хранящимся в массиве, дергая updateAppWidget().

Все сказанное можно найти в официальной документации Google, а также в любой книге по программированию под Android. Типичный виджет представлен на рис. 1.

Рис. 1. Обычный виджет
Рис. 1. Обычный виджет
 

Виджет vs программист

В качестве разминки предлагаю забыть половину из того, что мы написали, так как оно не работает! Я не зря поставил отладочную печать всех методов. Запустив код в эмуляторе или на реальном девайсе, можно легко убедиться, что ни onEnabled, ни onDisabled никогда не вызываются в Android 4.4 и ниже! (Чтобы не быть голословным, здесь и далее я тестирую код на устройствах с Android 4.4, 5.1, 6.0.)

Почему так? Видимо, сие есть тайна, доступная только джедаям Google. Вопрос в другом: почему об этом прямо не написать в документации? Особенно доставляют в общем-то правильные по сути механизмы запуска фонового сервиса (или сигнализации) для обновления информации виджетов в onEnabled с остановкой в onDisabled в примерах книг, предназначенных для Android 4. Получается, авторы не тестируют код, который сами же пишут?

Кто-то скажет, что в 5-й версии мобильной ОС это исправлено. Да, исправлено, но сбрасывать со счетов Android 4 пока рано. Кроме того, такие вещи не должны выявляться программистом опытным путем.

 

Виджет vs здравый смысл

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

<activity android:name=".WidgetSetup" android:label="@string/setup">
  <intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
  </intent-filter>
</activity>

Чтобы назначить для виджета эту активность, нужно добавить ее в соответствующий тег appwidget-provider с помощью атрибута configure, указав полное имя пакета:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
  xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:configure="com.hacker.widgetSample.WidgetSetup"
/>

Активность настройки ничем не отличается от обычной, но должна указать RESULT_OK в качестве результата и вернуть намерение с дополнительным параметром EXTRA_APPWIDGET_ID, являющимся идентификатором виджета. В противном случае считается, что пользователь отменил свое решение (например, нажал «Назад»), и виджет не будет добавлен.

Фрагмент активности:

Продолжение статьи доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

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

Вариант 2. Купи одну статью

Заинтересовала статья, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для статей, опубликованных более двух месяцев назад.


3 комментария

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Обвес macOS. Меняем скрытые настройки, ставим полезный софт и лезем под капот системы, перейдя на «мак»

Уверен, ты не раз слышал, что в Apple всё решают за пользователя и в macOS ничего нельзя т…