Суть статьи - написать простой виджет для своих нужд. Мой виджет отсчитывал оставшееся время до нового года. Т.к. новый год прошел - предлагаю каждому создать счетчик под свои нужды, а следующим шагом будет создание конфигурируемого виджета. ( Неплохо так, писал статью больше 3х месяцев =) )
Первым делом я начал искать что есть готового в Android для обратного отсчета времени. Оказалось, что существует системный класс CountDownTimer, который с лёгкостью справляется с задачей отсчета определенного времени, а как бонус - может выполнять определенные действия каждый заданный интервал. Исходя из этого вырисовывается следующий алгоритм - в onUpdate() виджета мы записываем старт счетчика. Частоту обновления виджета устанавливаем в 0. Теперь при включении виджета будет запускаться счетчик обратного отсчета.
Какой задать интервал выполнения действий для счетчика ? Пожалуй это будет одна минута. Во первых такой интервал будет меньше нагружать систему (и садить батарею), во вторых я думаю, что использование CountDownTimer в самом виджете вообще не правильно, поэтому будем стараться как можно реже использовать его события =)
Каждую минуту будет обновляться интерфейс виджета. Я решил не привязываться к счетчику и не высчитывать остаток времени, а брать данные об остатке минут, часов и дней прямо из системных констант. Для этого мы будем использовать системный класс Calendar.
Ну да ладно, меньше слов - больше действий ) Перейдем к написанию виджета. Я представлю сразу готовый код, чтобы можно было его рассмотреть.
NYCounter.javapackage com.newyear.counter; import java.util.Calendar; import java.util.Date; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.os.CountDownTimer; import android.widget.RemoteViews; public class NYCounter extends AppWidgetProvider{ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { final Context context_t = context; final RemoteViews views = new RemoteViews(context_t.getPackageName(), R.layout.widget); final AppWidgetManager wm = appWidgetManager; final int[] ids = appWidgetIds; //запускаем счетчик до 1 Января 2012 (а доживем ли ? =) ), с выполнением действия каждую минуту CountDownTimer timer = new CountDownTimer (dateToMilliSeconds(1,0,2012,0,0),60000) { public void onTick(long millisUntilFinished) { //выполняем регулярное действие Calendar c = Calendar.getInstance(); c.setTime(new Date()); int doy = c.get(Calendar.DAY_OF_YEAR); //получаем нынешний день int hod = c.get(Calendar.HOUR_OF_DAY); // час int moh = c.get(Calendar.MINUTE); // минуту //int som = c.get(Calendar.SECOND); // секунду int diy = 0; if (isLeapViaPopeGregory (c.YEAR)) { // проверяем на высокосный год diy = 366; } else { diy = 365; } int daysLeft = diy - doy; String hoursLeft = Integer.toString(24 - hod); String minutesLeft = Integer.toString(60 - moh); //String secondsLeft = Integer.toString(60 - som); if (hoursLeft.length() < 2) { hoursLeft = "0" + hoursLeft; } if (minutesLeft.length() < 2) { minutesLeft = "0" + minutesLeft; } //меняем текст виджета views.setTextViewText(R.id.dayCounter, daysLeft + ""); views.setTextViewText(R.id.hmCounter, hoursLeft + " : " + minutesLeft); wm.updateAppWidget(ids, views); } public void onFinish() { } }.start(); } public long dateToMilliSeconds(int day, int month, int year, int hour, int minute) { Calendar c = Calendar.getInstance(); c.set(year, month, day, hour, minute, 00); return c.getTimeInMillis(); } public static final boolean isLeapViaPopeGregory ( int yyyy ) { if ( yyyy < 0 ) return( yyyy + 1 ) % 4 == 0; if ( yyyy < 1582 ) return yyyy % 4 == 0; if ( yyyy % 4 != 0 ) return false; if ( yyyy % 100 != 0 ) return true; if ( yyyy % 400 != 0 ) return false; return true; } }
Теперь нам нужно описать виджет и "приделать" к нему дизайн.
xml/widget_info.xml
<?xml version="1.0" encoding="UTF-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="220dp" android:minHeight="144dp" android:updatePeriodMillis="0" android:initialLayout="@layout/widget"> </appwidget-provider>
layout/widget.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ball_red" > <TextView android:id="@+id/dayCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="0" android:paddingLeft="70px" android:paddingTop="15px" android:textColor="#FFFFFF" android:textSize="80px"/> <TextView android:id="@+id/hmCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="00 : 00" android:paddingLeft="50px" android:textColor="#FFFFFF" android:textSize="50px"/> <TextView android:id="@+id/sCounter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" android:paddingLeft="110px" android:textColor="#FFFFFF" android:textSize="30px"/> </LinearLayout>
AndroidManifest .xml<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.newyear.counter" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/ball_red" android:label="@string/app_name"> <receiver android:name="NYCounter" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver> </application> </manifest>Теперь нам осталось добавить лишь 2 вещи в проект - иконку и картинку, которая будет фоном для нашего виджета. Т.к. я делал новогодний виджет, то и картинка будет новогодней:
Собираем проект, проверяем на ошибки, запускаем на эмуляторе или на устройстве. Сразу предупреждаю, что виджет сырой и не претендует на звание "вот только так и нужно делать" ! Была поставлена задача, было найдено решение. Почти наверняка есть более удачные пути решения и я с удовольствием прочитаю их в комментариях.
В конечном счете должно получиться что-то похожее:
На момент написания кода и стилей для виджета все было ок, потому как число оставшихся дней было двухзначное ) Теперь вот не влазит... Это легко исправляется в стилях виджета путем уменьшения шрифта.
Я надеюсь развить тему этого виджета дальше и сделать его конфигурируемым. Хочется задавать самому фоновую картинку и дату/время отсчета. А пока на этом все, удачного кодинга!
Источник: http://ondroid.info
Комментариев нет:
Отправить комментарий