Glance startup task что это
Перейти к содержимому

Glance startup task что это

  • автор:

Play with Openstack Glance

Glance architecture

What registry does? For code api, it providers CRUD access to images, communicating to DB.

Storage adapter at glance_store project. Cinder, filesystem, RBD, sheepdog, http are supported. There is general store interface at glance_store.driver.py::Store .

VM image: disk format vs container format, refer to here:

  • Disk format is the format of the VM’s disk image.
  • Container format is disk + metadata of actual virtual machine.

Glance does have a queuing system, also tasks and status. See here.

Glance image status transition

P.S. Best ways to gather information for installation & deployment of Openstack components

  • How to install: check Openstack official manuals. This is the BEST reference.
  • Config options: github source /etc/*.conf
  • Search config option name in source code.
  • Search in source code test cases for how to use example.

After play install and architecture diving, a complete review of config options will get you a good understanding on project status and problem to solve.

Nova use glance client to get image information for glance. Downloading image is handled by “download handlers”. Glance is not used in downloading.

# stable/juno # nova is using glanceclient to communicate to glance nova.image.api.py::download() sesion.download() # session = GlanceImageService(client=glance_client) image = self.show() # using glanceclient . # download image chunks, not using glance data = open(dst_path, 'wb') for chunk in image_chunks: data.write(chunk) 
  • Nova workflow
  • Vm boost with image workflow
  • Glance introduction
  • Nova boot from volume

Install and Config

I’ve tried using glance + swift without keystone. Later found out that glance can only get swift address from keystone endpoints. It doesn’t even have a config option to fill in swift address alone. See config.

So in the end I decided to deploy glance alone using file stone. Following official developer doc, and installation manual.

mkdir workspace cd workspace/ git clone https://github.com/openstack/glance cd glance git checkout stable/juno pip install -r requirements.txt python setup.py install cd .. 

Create user for glance

useradd -r -s /sbin/nologin glance 

Create necessary directories.

# remember to change to proper permission mkdir /etc/glance mkdir /var/lib/glance mkdir /var/lib/glance/image-cache/ mkdir /var/lib/glance/images/ mkdir /var/lib/glance/scrubber chown -R glance:glance /var/lib/glance mkdir /var/log/glance chown -R glance:glance /var/log/glance mkdir /var/run/glance chown -R glance:glance /var/run/glance # copy config files cp -r glance/etc/* /etc/glance/ 

For configuration files, refer to github source etc. Below is config file for glance-api.conf . Actually, I recommend copy the modify on official config files, rather than overwrite them like what I do now.

echo ' [DEFAULT] debug = True sql_connection = mysql://root:123work@localhost/glance default_store = file image_cache_dir = /var/lib/glance/image-cache/ log_file = /var/log/glance/api.log [paste_deploy] # here I dont use keystone flavor = [glance_store] stores = glance.store.filesystem.Store ' > /etc/glance/glance-api.conf 

Configuration file for glance-registry.conf

echo ' [DEFAULT] debug = True sql_connection = mysql://root:123work@localhost/glance default_store = file log_file = /var/log/glance/registry.log [paste_deploy] # here I dont use keystone flavor = ' > /etc/glance/glance-registry.conf 

Need to create glance table in mysql

. # create table 'glance' in mysql, collation=utf8, and grant proper permission glance-manage -v db_sync 

Start Service

su -s /bin/bash glance -c '/bin/glance-control glance-api start' su -s /bin/bash glance -c '/bin/glance-control glance-registry start' # to stop #su -s /bin/bash glance -c '/bin/glance-control glance-registry stop' #su -s /bin/bash glance -c '/bin/glance-control glance-api stop' 

Verify Operation

First, let’s download the image.

mkdir /tmp/images cd /tmp/images/ wget http://cdn.download.cirros-cloud.net/0.3.2/cirros-0.3.2-x86_64-disk.img 

I have to avoid using glanceclient, becuase it force me to authenticate on keystone, which I don’t have now. So I use curl.

# list images, I don't have auth on glance curl -i -X GET http://127.0.0.1:9292/v1/images/detail # send by base64 encode base64 /root/cirros-0.3.2-x86_64-disk.img | curl http://127.0.0.1:9292/v1/images --trace - -i -X POST -H 'Content-Transfer-Encoding: base64' -H 'Content-Type: application/octet-stream' -H 'x-image-meta-name: cirros' -H 'x-image-meta-disk_format: qcow2' -H 'x-image-meta-container_format: bare' --data-binary @- # using glance without keystone, I cannot create public image, nor can I list them detail. So, change image to public in db mysql -uroot -p -e "use glance; update glance.images set is_public=1;" # list images again curl -i -X GET http://127.0.0.1:9292/v1/images/detail # to retrieve image metadata curl -i -X HEAD http://127.0.0.1:9292/v1/images/7253b5ab-00a1-4bac-9bd4-1c66364a4265 # to retrieve image metadata and image data curl -i -X GET http://127.0.0.1:9292/v1/images/7253b5ab-00a1-4bac-9bd4-1c66364a4265 

Show the image data stored. It is in different size of the original one, because of the encoding when upload.

# show glance stored image $ ll /var/lib/glance/images/ -rw-r----- 1 glance glance 20450682 Nov 14 09:14 7253b5ab-00a1-4bac-9bd4-1c66364a4265 # show original image file $ ll cirros-0.3.2-x86_64-disk.img -rw-rw-rw- 1 root root 15138816 Nov 6 09:12 cirros-0.3.2-x86_64-disk.img 
  • An example on maillist
  • Glance API simle doc
  • See usecase on testcases

Create an Issue or comment below

Glance startup task что это

An Eye on your system

Glances is a cross-platform system monitoring tool written in Python.

Features

  • CPU
  • Memory
  • Load
  • Process list
  • Network interface
  • Disk I/O
  • IRQ / Raid
  • Sensors
  • Filesystem (and folders)
  • Docker
  • Monitor
  • Alert
  • System info
  • Uptime
  • Quicklook (CPU, MEM, LOAD)

Cross-platform

Written in Python, Glances will run on almost any plaftorm : GNU/Linux, FreeBSD, OS X and Windows.

API

Glances includes a XML-RPC server and a RESTful JSON API which can be used by another client software.

Web UI

No terminal at hand ? Use the built-in Web UI and monitor your system from any device.

Export

Export all system statistics to CSV, InfluxDB, Cassandra, OpenTSDB, StatsD, ElasticSearch or even RabbitMQ. Glances also provides a dedicated Grafana dashboard.

Get started

Glances Auto Install script

To install the latest Glances production ready version, just enter the following command line:

$ curl -L https://bit.ly/glances | /bin/bash
$ wget -O- https://bit.ly/glances | /bin/bash

Note: Only supported on some GNU/Linux distributions.

PyPI: The simple way

Glances is on PyPI. By using PyPI, you are sure to have the latest stable version.

To install, simply use pip:

$ pip install glances

Community

Get help from others users or from the Glances developers and stay in touch with us. But never forget : always RTFM!

Chat for developers

Users’ mailing list

Twitter

Documentation

You want more informations or contribute to the Glances project ? Look at our user manual and the development wiki.

Мощный мониторинг за пять минут с помощью Glances

Допустим, что у нас не очень обширная инфраструктура: несколько небольших VPSок, подкроватник, NAS и два ноутбука, торчащих в сеть. Тем не менее, за ней всё равно надо приглядывать, и заниматься этим вручную раздражает всё больше с каждой новой машиной. Я стал искать систему мониторинга, которая могла бы не съедая лишних ресурсов агрегировать информацию отовсюду в единый дашборд, желательно без геморроя с настройкой. В итоге, как только десятки мелких консольных утилит были отброшены вместе с чрезмерно усложнёнными корпоративными хреновинами вроде Prometheus и RabbitMQ, поиск быстро привёл меня к Glances — утилите, берущей лучшее от обоих миров.

Glances — довольно старый консольный инструмент мониторинга на Python, который на Хабре незаслуженно обошли вниманием. Первые релизы вышли в 2014 году, а самый свежий появился 23 января. У проекта почти 18к звёзд на Github, больше сотни контрибьюторов и тысячи форков.

Список отслеживаемых данных:

  • Нагрузка на CPU, информация и температура
  • Загруженность памяти (RAM, swap)
  • Средняя загруженность
  • Список и количество процессов
  • Использование сетевых интерфейсов
  • Операции с диском
  • Состояние IRQ и RAID
  • Большинство доступных датчиков
  • Свободное место на диске и распределение по разделам/папкам
  • Список контейнеров, их потребление и процессы
  • Аптайм, алёрты и другие мелочи

Вся нужная информация доступна буквально по одной команде:

Но пока это лишь консольная утилита, а нам нужно гораздо больше. Вся мощь Glances раскрывается в его огромном количестве интеграций и выходных форматов. Во-первых, из коробки он умеет выводить информацию в веб-версию и XML-RPC/RESTful API. То есть поставив его на все машины и скинув вывод из всех эндпойнтов на один сервер, можно уже добиться желаемого. Но консольный вывод с десятка устройств читать неудобно ни в каком виде, а уж тем более пытаться уместить его на одном экране, поэтому смотрим интеграции:

  • Cassandra/Scylla
  • CouchDB
  • Elasticsearch
  • InfluxDB
  • Kafka
  • MQTT
  • OpenTSDB
  • Prometheus
  • Riemann
  • StatsD
  • ZeroMQ

Установка и настройка

Вариантов установки много, но стабильнее всего работает установка через PyPI:

 pip install glances 

Можно сразу доустановить дополнительные модули:

 pip install 'glances[action,browser,cloud,cpuinfo,docker,export,folders,gpu,graph,ip,raid,snmp,web,wifi]' 

Полный список установок InfluxDB здесь, стандартный вариант для Ubuntu/Debian x64:

 wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.0.4-amd64.deb sudo dpkg -i influxdb2-2.0.4-amd64.deb 

Создаём базу glances с любым пользователем и передаём данные в конфиг Glances следующего вида:

 # glances.conf [influxdb] host=localhost port=8086 protocol=http user=admin password=foobar db=glances prefix=localhost 

Затем запускаем утилиту с экпортом данных в InfluxDB и использованием конфига, где к ней указан доступ:

 glances --export influxdb -С glances.conf 

Почти готово, осталось открыть InfluxDB для доступа извне:

 # /etc/influxdb/influxdb.conf [http] enabled = true bind-address = ":8086" auth-enabled = true log-enabled = true write-tracing = false pprof-enabled = true pprof-auth-enabled = true debug-pprof-enabled = false ping-auth-enabled = true # по хорошему нужно включить https, но я не заморачивался :) # https-enabled = true # https-certificate = "/etc/ssl/influxdb.pem" 

Все операции выше повторяем на отслеживаемых машинах, затем на агрегирующем сервере ставим графану:

 wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add - echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list sudo apt-get update sudo apt-get install grafana sudo systemctl daemon-reload sudo systemctl start grafana-server sudo systemctl status grafana-server 

Открываем интерфейс на 3000 порту, логинимся и добавляем наши удалённые источники данных (Configuration > Data sources > Add data source > InfluxDB):

Импортируем его в графану (+ > Import) и настраиваем под себя, повторяем для всех машин. Готово! Теперь в одном интерфейсе мы можем подробно рассмотреть все метрики (как на КДПВ), а ключевые, вроде нагрузки на CPU, можно собрать на одном общем дашборде.

Заключение

Раньше я думал, что настраивать удалённый мониторинг на несколько машин это жуткий геморрой (или можно отдать всю работу готовым сервисам, но с большей нагрузкой и без гибкой подстройки), а оказывается нужно было просто найти подходящий инструмент. Конечно, при желании можно забить на графики и смотреть консольный вывод или обрабатывать API по-своему. Мне нравится такая вариативность.

На правах рекламы

Эпично! Виртуальные серверы на базе новейших процессоров AMD EPYC, которые подойдут не только для мониторинга, но и для размещения проектов любой сложности, от корпоративных сетей и игровых проектов до лендингов и VPN.

  • мониторинг
  • мониторинг сервера
  • Glances

Берём Glance Widgets под контроль

В этой статье я хочу показать как создавать виджеты с состоянием для Android приложения с помощью Glance Compose, обновлять каждый экземпляр отдельно от остальных, настраивать их с помощью конфигурационной активити и закреплять экземпляры из приложения. Пример того, что должно получиться вы можете видеть на видео.

Glance — библиотека, входящая в семейство Jetpack, позволяющая через Jetpack Compose Runtime создавать виджеты для Android и Tiles для WearOS. Она пришла на смену RemoteViews в декабре 2021 года и призвана облегчить нам жизнь через упрощение создания дизайна виджетов и взаимодействие с ними. Библиотека поддерживает интероп с RemoteViews и на момент написания статьи находится в альфа версии.

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

Какие плюсы?

Помимо очевидного плюса отказа от RemoteViews, который даёт Compose, в копилку стоит добавить также GlanceStateDefinition, который создаётся свой на каждый экземпляр виджета. Что это и за что его нужно любить? StateDefinition — это хранилище на основе DataStore, которое по-сути просто файл. Когда мы добавляем новый виджет, то для него нам предоставляется только к нему прикреплённый стор, который будет единым источником правды для этого виджета. Он выступает в роли посредника между приложением и состоянием виджета и о нём можно думать как о некотором хранилище remember значений, если приводить аналогию с обычным миром Compose. Мы ещё вернёмся к этой сущности ниже.

Также, на мой взгляд, Google добавил довольно удобную систему обновления виджетов. Если раньше для синхронизации вьюшек виджета с состоянием данных нам нужно было где-то хранить его widgetId, бросать Intent, выдумывать свои менеджеры для этого, то сейчас у нас есть пара функций верхнего уровня, с помощью которых можно обновить все виджеты одного типа или выполнить обновление с некоторым предикатом, с помощью которого будут затронуты лишь те экземпляры, которые нам нужны. Это мы тоже посмотрим далее.

Какие ограничения?

Glance поддерживает набор собственных Composable функций и GlanceModifier и не поддерживает MaterialTheme. Смешивать Glance со стандартным Compose не следует, в лучшем случае это будет проигнорировано. На момент написания статьи поддерживаются Box, Row, Column, Text, Button, LazyColumn, Image и Spacer.. К сожалению пока-что нужно создавать xml файл с метадатой, в будущем обещают отказаться от него. Ну и самое неприятное — мы не увидим привычных нам remember, так как в Glance нет рекомпозиции и состояния в привычном нам понимании для Compose. Придётся немного изменить образ мышления, но как только это сделаете — то создавать и расширять виджеты становится легко и очень быстро. Ещё одно ограничение — отсутствие кастомных шрифтов.

Перед тем как приступить к написанию кода давайте ещё посмотрим на то, из каких компонентов состоит вся связка и кто за что отвечает.

GlanceAppWidgetManager — это менеджер наших Glance виджетов, с помощью которого будем получать идентификаторы имеющихся экземпляров виджетов и запрашивать у системы установку виджета напрямую из приложения.

GlanceAppWidgetReciever — класс, который обновляет виджеты когда это необходимо и пришёл на смену AppWidgetProvider. Но в отличие от своего предшественника вся работа спрятана под капот.

GlanceAppWidget — сам виджет. От него мы будем наследоваться и реализовывать свои экземпляры. В этом классе находится точка входа в Composable часть виджета через функцию Content.

GlanceStateDefinition — интерфейс с функциями доступа к контейнеру состояния Glance виджета. Мы будем использовать PreferencesGlanceStateDefinition, который для каждого нового экземпляра виджета будет создавать свой собственный файл для сохранения состояния.

Состояние виджета будет храниться в виде набора примитивов в сторе и для их сохранения мы будем использовать набор функций из androidx.datastore.preferences.core.

И последний интересный компонент — это класс ActionParameters, который позволяет пробрасывать параметры в обработчики нажатий на вьюшки виджета.

  • добавлять для заметки индивидуальный виджет через лаунчер
  • добавлять виджет из заметки напрямую
  • обновлять виджет при редактировании заметки к которой он прикреплён
  • открывать приложение с нужной заметкой при нажатии на виджет

Для создания виджета с состоянием нам нужно выполнить следующие шаги:

  1. Определяем набор значений, из которых будет складываться состояние виджета
  2. Создаём виджет, наследуясь от GlanceAppWidget
  3. Определяем действия, которые которые нужно обрабатывать при нажатии на элементы виджета
  4. Добавляем ресивер и регистрируем его в манифесте
  5. Добавляем метадату
  6. Добавляем конфигурационную активити и обработку сохранения привязки виджета к заметке.

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

val noteId = longPreferencesKey("noteId") val noteTitle = stringPreferencesKey("noteTitle") val noteText = stringPreferencesKey("noteText") val noteUpdatedAt = stringPreferencesKey("noteUpdatedAt")

Ниже создаю виджет и ресивер

class NoteWidget : GlanceAppWidget() < override var stateDefinition: GlanceStateDefinition= PreferencesGlanceStateDefinition @Composable override fun Content() < NoteWidgetContent() >> class NoteWidgetReceiver : GlanceAppWidgetReceiver()

Так как ресивер является BroadcastReceiver, то его нужно зарегистрировать в манифесте.

Чтобы не захламлять NoteWidget я вынес вёрстку в отдельную функцию NoteWidgetContent. Для краткости я не привёл тут импорты, но стоит обратить внимание на то, что в вёрстке используются import androidx.glance и элементы из Glance вместо стандартных из Compose. Например androidx.glance.text.Text вместо androidx.compose.material.Text

@Composable fun NoteWidgetContent(prefs: Preferences) < val noteId = prefs[noteIdPK] ?: Long.MIN_VALUE val noteTitle = prefs[noteTitlePK].orEmpty() val noteText = prefs[noteTextPK].orEmpty() val updatedAt = prefs[noteLastUpdatePK].orEmpty() LazyColumn( modifier = GlanceModifier .background(imageProvider = ImageProvider(R.drawable.widget_background)) .appWidgetBackground() .padding(16.dp) ) < if (noteTitle.isNotEmpty()) item < WidgetText(noteTitle, noteId) >if (noteText.isNotEmpty()) item < WidgetText(noteText, noteId) >if (updatedAt.isNotEmpty()) item < WidgetText(updatedAt, noteId, 16.sp) >> > @Composable fun WidgetText(text: String, noteId: Long, fontSize: TextUnit = 20.sp)

Далее нужно добавить файл xml с настройками виджета и файлы с разметкой, которые в этой конфигурации указаны. Повторюсь, мы опустим рассмотрение этих базовых моментов, по ним информации достаточно. Нам важно разобраться с тем, как виджету работать с состоянием.

Теперь у нас есть необходимый минимум, чтобы можно было на лаунчере вызвать меню виджетов и выбрать наш. Для того, чтобы на этом шаге мы могли выбрать к какой заметке привязать экземпляр виджета, нам нужно добавить конфигурационную активити. Не забудьте добавить её в xml файле с настройками виджета

android:configure="com.example.note_glance_widget.widget.config.ConfigWidgetActivity"

Весь код активити находится тут, нам же интересна та его часть, которая касается выбора заметки и привязки её к виджету. Это происходит в методе saveWidgetState, в который передаётся идентификатор заметки.

private fun saveWidgetState(id: Long) = lifecycleScope.launch(Dispatchers.IO) < val glanceId = GlanceAppWidgetManager(applicationContext).getGlanceIdBy(widgetId) val note = repository.getNote(id)?.let < it.toEntity() >?: return@launch updateAppWidgetState(applicationContext, glanceId) < prefs ->prefs[noteIdPK] = id prefs[noteTitlePK] = note.title prefs[noteTextPK] = note.text prefs[noteLastUpdatePK] = note.formatUpdatedAt > NoteWidget().update(applicationContext, glanceId) >

widgetId тут у нас хранится как свойство активити и инициализируется с помощью интента, в котором лежит по ключу AppWidgetManager.EXTRA_APPWIDGET_ID
Для того, чтобы обновить виджет и сохранить в его сторе нужные нам данные, необходимо получить glanceId. GlanceAppWidgetManager умеет конвертировать идентификаторы виджетов в GlanceId с помощью метода getGlanceIdBy, это тут и используется. Далее я беру заметку, по которой был клик, и с помощью функции updateAppWidgetState сохраняю в стор виджета нужные значения по ключам, которые мы описывали ранее. На этом этапе данные в стор виджета сохранены, но его отображение ещё не обновлено. Для этого нужно явно вызвать NoteWidget().update(applicationContext, glanceId). После закрытия активити мы должны увидеть виджет с данными из его состояния. Если сейчас открыть песочницу приложения, то в ней можно найти сторы, которые создаются для каждого виджета индивидуально и удаляются вместе с ними.

Идём дальше. Теперь если мы будем редактировать наши заметки, то увидим, что в виджетах информация не обновляется. Не порядок, давайте исправлять.
Я добавлю функцию, которая будет принимать заметку и сохранять её значения в тот стор, в котором лежит идентификатор этой заметки. Для того, чтобы понять в какой стор сохранить данные, я получаю от GlanceAppWidgetManager все glanceId, пробегаюсь по их сторам в методе updateAppWidgetState и, если идентификатор заметки в сторе совпадает с идентификатором обновляемой заметки, обновляю данные. У виджетов есть метод updateIf, который принимает лямбду — предикат, в которой мы определяем наше условие. Он поможет нам обновить отображение только того виджета, который относится к обновляемой заметке и не дёргать лишний раз другие экземпляры.

suspend fun GlanceAppWidgetManager.mapNoteToWidget(context: Context, note: Note) = getGlanceIds(NoteWidget::class.java) .forEach < glanceId ->updateAppWidgetState(context, glanceId) < prefs ->if(prefs[noteIdPK] == note.id) < prefs[noteTitlePK] = note.title prefs[noteTextPK] = note.text prefs[noteLastUpdatePK] = note.formatUpdatedAt >> NoteWidget().updateIf(context) < it[noteIdPK] == note.id >>

Осталось 2 задачи — разобраться как открывать нужную заметку по нажатию на виджет и как закреплять виджеты напрямую из приложения.
Клики по элементам виджета Glance реализуются с помощью набора нескольких колбеков
actionRunCallback
actionStartActivity
actionStartService
actionStartBroadcastReceiver
Тут есть довольно хорошее их описание и базовых вещей, которые мы упустили.
Для открытия активити я буду использовать actionStartActivity и передавать аргументом идентификатор заметки, который возьму из стора виджета.

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

val noteIdParam = longPreferencesKey(«noteIdParam»)

Теперь добавим текстовым элементам в виджете обработчик кликов по ним:

@Composable fun WidgetText(text: String, noteId: Long, fontSize: TextUnit = 20.sp) < Text( text = text, style = TextStyle( fontWeight = FontWeight.Normal, fontSize = fontSize, textAlign = TextAlign.Start, color = ColorProvider( day = Color.White, night = Color.White ) ), modifier = GlanceModifier.clickable( actionStartActivity( parameters = actionParametersOf( noteIdParam to noteId ) ) ) ) >

Далее в RootActivity получаем идентификатор из интента и открываем нужную заметку. Тут есть место оптимизации логики навигации, но статья не об этом. По виджету кликнули, данные в активити переданы, заметка открылась.

Берёмся за последнюю задачу — закрепление виджета из приложения. Это мы будем делать на экране заметки с помощью метода handlePinWidget

private fun handlePinWidget(noteId: Long)

У GlanceAppWidgetManager есть метод requestPinGlanceAppWidget. Он принимает на вход класс ресивера нашего виджета и PendingIntent, который будет являться колбеком и вызовется системой после того, как отработает закрепление виджета. Тот компонент, который будет добавлен в этот PendingIntent, будет ответственен за настойку этого экземпляра виджета. Я для этой цели создам BroadcastReciever и положу в Intent с ним идентификатор заметки, которая должна быть закреплена.

class PinWidgetReceiver : BroadcastReceiver() < @Inject lateinit var repository: NotesRepository override fun onReceive(context: Context, intent: Intent) < val noteId = intent.getLongExtra(NOTE_ID, Long.MIN_VALUE) CoroutineScope(EmptyCoroutineContext).launch < delay(3000) val note = repository.getNote(noteId)?.let < it.toEntity() >?: return@launch val glanceManager = GlanceAppWidgetManager(context) val lastAddedGlanceId = glanceManager.getGlanceIds(NoteWidget::class.java).last() mapNoteToWidget(context, lastAddedGlanceId, note) > > private suspend fun mapNoteToWidget(context: Context, lastAddedGlanceId: GlanceId, note: Note) < updateAppWidgetState(context, lastAddedGlanceId) < prefs ->prefs[noteIdPK] = note.id prefs[noteTitlePK] = note.title prefs[noteTextPK] = note.text prefs[noteLastUpdatePK] = note.formatUpdatedAt > NoteWidget().update(context, lastAddedGlanceId) > >

Тут есть магическое место с ожиданием трёх секунд. Дело в том, что если это не сделать, то почему-то нам не доступен сразу стор нового виджета. Скорее всего дело в асинхронном процессе его создания. 3 секунды у меня хватает для того, чтобы стор был корректно предоставлен. Возможно я тут не прав и буду рад, если поправите меня и укажете корректный способ получения синхронного доступа к стору.
В этом случае обновление виджета будет выполняться через получение последнего добавленного идентификатора GlanceId с помощью метода GlanceAppWidgetManager.getGlanceIds.

Это всё, что я хотел показать, надеюсь материал был полезным и поможет вам разобраться с тем, как добавить состояние в Glance виджет.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *