vertical” android_updateperiodmillis=”1800000″ xmlns_android=”http://schemas.android.com/apk/res/android”> </appwidget-provider>
configure описывает activity отвественную за конфигурацию виджета при добавлении и вообще.
minHeight и minWidth описывает малые размеры для корректного отображения виджета. К огорчению, здесь нет механизма в стиле “1 клетка на 2 клеточки”. На страничке документации по andoroid есть хорошее описание какие размеры должны быть (См. ссылки в конце статьи). В этом примере 1 клеточка в высоту, 2 в ширину.
updatePeriodMillis может быть установлен в 1800000 (30мин). Меньше вроде как не умеет (Вообще умеет, но просит реализации таймера).
resizeMode описывает как юзер может изменять размеры виджета. Можно установить в “none”, тогда размеры изменять будет нельзя. Можно в “horizontal”, можно в “vertical”, можно в оба сразу “horizontal vertical”. Наименования молвят сами за себя.
Шаг 3. Заходим в AndroidManifest.xml
Добавляем наш виджет и его кофигуратор в секцию <application>:
<!– added –> <receiver android_name=”widgets.MyWidget”> <intent-filter> <action android_name=”android.appwidget.action.APPWIDGET_UPDATE” /> </intent-filter> <meta-data android_name=”android.appwidget.provider” android:resource=”@xml/example_info” /> </receiver> <activity android_name=”widgets.MyWidgetConfig”> <intent-filter> <action android_name=”android.appwidget.action.APPWIDGET_CONFIGURE” /> </intent-filter> </activity> <!– added –>
<?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns_android=”http://schemas.android. Добавим в widget_main последующие элементы: TextView, Button со последующими ID:
widgetBtn
Установим ширину и высоту для layout в значения “wrap_content”.
Итого:
<?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns_android=”http://schemas.android.com/apk/res/android” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:orientation=”vertical”> <TextView android:id=”@+id/widgetText” android:layout_width=”match_parent” android:layout_height=”wrap_content” android:text=”TextView” /> <Button android:id=”@+id/widgetBtn” android:layout_width=”match_parent” android:layout_height=”wrap_content” android:text=”Button” /> </LinearLayout>
Виджеты являются в определённом роде BroadcastReciever которые обрабатывают определённые действия. Как и BroadcastReciever, обрабатывают деяния они способом onRevieve() который в предстоящем обрабатывает данные иными способами. Тем не наименее, виджет является наследником класса AppWidgetProvider (в свою очередь, наследник того самого BroadcastReciever), который всё несколько упрощает.
Разглядим что нам дает AppWidgetProvider:
onEnabled — вызывается один раз, когда виджет создаётся (добавляется на экран).
onUpdate — вызывается при обновлении виджета в данный в XML файле интервал. Основной функционал виджета находится конкретно тут. Как уже было сказано, ежели для вас необходимо вызывать этот способ почаще чем раз в 30 минут, следует добавить таймер (используя класс AlarmManager).
onDeleted — вызывается, когда виджет удалён с экрана.
onDisabled — вызывается, когда все виджеты удалены с экрана. Т.е. можно добавлять сколько угодно экземпляров этого виджета, и когда крайний из добавленных будет удалён, этот способ сработает. В этом и отличие от onDeleted
onRestored — вызывается при восстановлении AppWidget из бекапа. Откликается на ACTION_WIDGET_RESTORED. В обыкновенном случае будет сходу вызван onUpdate. Даже не знаю как этот способ можно использовать.
OnAppWidgetOptionsChanged — вызывается при изменении размеров виджета (да, ежели такие конфигурации вообщем разрешены в XML настройках).
onReceive — вызывается для обработки событий иными методами.
Наследуем наш класс от AppWidgetProvider (extends AppWidgetProvider).
Жмём правой клавишей на классе, позже Generate -> Override Methods…
Избираем onUpdate и onDelete. 1-ый будет вызываться при обновлении виджета, 2-ой — при удалении.



@Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Toast.makeText(context, “Widget deleted”, Toast.LENGTH_SHORT).show(); }
Важно!
Этот способ будет вызываться в зависимости от опций из res/xml/example_info.xml но при разработке через конфигуратор он вызван не будет. Будет вызван onEnabled() (но и то как-то, по моим ощущениям, кривовато).
Сделаем экземпляр класса RemoteViews (референс: RemoteViews(String packageName, int layoutId) ). Где обращаемся к context из пренимаемых onUpdate характеристик (берем оттуда имя) и layout самого виджета. Установим текст “Hello widget!” способом .setTextViewText (референс: setTextViewText(int viewId, CharSequence text)). Опосля что добавим ещё одну строчку, которая укажет приложению на необходимость применить изготовленные конфигурации. Таковой финт не типичен для работы с Activity, но для виджетов каждое изменение в виджете обязано сопровождаться обновлением.
Без такового обновления будет вылетать ошибка “Problem Loading Widget”. Проделывать эти деяния нужно со всеми appWidgetIds. Используем конструкцию for (foreach):
for (int appWidgetId : appWidgetIds) { RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_main); view.setTextViewText(R.id.widgetText, “Hello widget!”); appWidgetManager.updateAppWidget(appWidgetId, view); }
- Создать Intent. В качетсве характеристик — контекст и имя класса Activity-сонфигуратора с .class в конце.
- Добавить в него ID виджета, который запрашивает вызов конфигуратора (с помошью .putExtra). Ожидается переменная int для «поля» AppWidgetManager.EXTRA_APPWIDGET_ID
- Создать объект PendingIntent, который будет назначен кнопочке для посылки-по-нажатию. См.аргументы ниже.
Попутно определим все нужные характеристики ещё раз (тут не плохо было бы помыслить о том, как не повторяться с тем, что мы описывали в onUpdate). В отличии от onUpdate, принимаемое значение способа лишь context, так что нужно вынуть откуда-то и ID. Для этого вводим объект класса ComponentName. Итак код:
@Override public void onEnabled(Context context) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main); AppWidgetManager awm = AppWidgetManager.getInstance(context); ComponentName compName = new ComponentName(context, MyWidget.class); int[] widgetIds = awm.getAppWidgetIds(compName); for (int widgetId : widgetIds) { Intent intentBtnPwr = new Intent(context, MyWidgetConfig.class); intentBtnPwr.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); PendingIntent pi = PendingIntent.getActivity(context, widgetId, intentBtnPwr, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.widgetBtn, pi); awm.updateAppWidget(widgetId, remoteViews); } }
Шаг 6. Перейдём к MyWidgetConfig.java Объявляем переменные для всего класса. EdText — поле ввода на экране конфигурации виджета awManager — менеджер, который пригодиться для работы с виджетом, thisContext — контекст awID — переменная для хранения ID добавляемого виджета Клавишу добавлять не будем, просто привяжем её к Listener и опишем нужное поведение позднее.
public class NoWolWidgetConfig extends Activity { EditText EdText; AppWidgetManager awManager; Context thisContext; int awID; …
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.widget_main_config); …
EdText = (EditText)findViewById(R.id.configWidgetText);
Intent intent = getIntent();
Bundle bundleExtras = intent.getExtras(); if (bundleExtras != null){ awID = bundleExtras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); }else finish();
thisContext = NoWolWidgetConfig.this; awManager = AppWidgetManager.getInstance(thisContext);
final RemoteViews awRV = new RemoteViews(thisContext.getPackageName(), R.layout.widget_main);
findViewById(R.id.configWidgetBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Action starts here 😉 } });
awRV.setTextViewText(R.id.widgetText, ((EditText) findViewById(R.id.configWidgetText)).getText().toString());
Intent intentBtnPwr = new Intent(thisContext, MyWidgetConfig.class); intentBtnPwr.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID); PendingIntent pi = PendingIntent.getActivity(thisContext, awID, intentBtnPwr, PendingIntent.FLAG_UPDATE_CURRENT); awRV.setOnClickPendingIntent(R.id.widgetBtn, pi);
awManager.updateAppWidget(awID, awRV);
Intent resultIntent = new Intent(); resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID); setResult(RESULT_OK, resultIntent); finish();
manifests/AndroidManifest.xml
<?xml version=”1.0″ encoding=”utf-8″?> <manifest xmlns_android=”http://schemas.android.com/apk/res/android” package=”com.blogspot.developersu.we.widgetexample”> <application android:allowBackup=”true” android:icon=”@mipmap/ic_launcher” android:label=”@string/app_name” android:roundIcon=”@mipmap/ic_launcher_round” android:supportsRtl=”true” android:theme=”@style/AppTheme”> <activity android_name=”.MainActivity”> <intent-filter> <action android_name=”android.intent.action.MAIN” /> <category android_name=”android.intent.category.LAUNCHER” /> </intent-filter> </activity> <!– added –> <receiver android_name=”widgets.MyWidget”> <intent-filter> <action android_name=”android.appwidget.action.APPWIDGET_UPDATE” /> </intent-filter> <meta-data android_name=”android.appwidget.provider” android:resource=”@xml/example_info” /> </receiver> <activity android_name=”widgets.MyWidgetConfig”> <intent-filter> <action android_name=”android.appwidget.action.APPWIDGET_CONFIGURE” /> </intent-filter> </activity> <!– added –> </application> </manifest> com.blogspot.developersu.we.widgetexample/MainActivity
package com.blogspot.developersu.we.widgetexample; /* * It doesn’t make sense to cover this code by any license, ’cause everything described here * has been widely used by thousands of coders all around the world. So most likely I’ve already * stolen this code in their eyes and you’re going to steal it from me. LOL. * Bye! * * Dmitry Isaenko, * 2017, Russia * https://developersu.blogspot.com/2017/07/androidwidget.html * */ import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { int awID; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } widgets/MyWidget
package widgets; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; import android.widget.Toast; import com.blogspot.developersu.we.widgetexample.R; public class MyWidget extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); for (int appWidgetId : appWidgetIds) { RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_main); view.setTextViewText(R.id.widgetText, “Hello widget!”); appWidgetManager.updateAppWidget(appWidgetId, view); } } @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Toast.makeText(context, “Widget deleted”, Toast.LENGTH_SHORT).