Разработка под мобильную платформу 1С имеет ряд специфических ограничений, с которыми разработчики часто сталкиваются при попытке перенести логику фоновых процессов из настольных и клиент-серверных решений. Нередко возникает ситуация, когда фоновые задания стартуют с большой задержкой (от 30 секунд до нескольких минут), накапливаются в очередь и затем отрабатывают разом («пачкой»), либо приводят к нестабильной работе приложения.
Разберем подробнее, почему мобильная платформа ведет себя подобным образом, как устроен механизм фоновых задач на мобильных устройствах и как корректно реализовать запуск фонового обмена данными с передачей прогресса на клиент.
Проанализируем ключевые архитектурные отличия мобильной платформы 1С от настольной версии:
ФоновыеЗадания.Выполнить.СостояниеФоновогоЗадания.Активно, система ставит задачу в очередь либо может завершиться аварийно при некорректной очистке ресурсов.Посмотрим на практический пример организации фонового обмена данными с внешним сервером. В нем фоновый процесс циклически формирует сообщения о прогрессе, а клиентская форма с помощью обработчика ожидания периодически считывает их и информирует пользователя.
Разберем серверную процедуру запуска фонового задания:
&НаСервере
Процедура ОбновитьОстаткиИЦеныНаСервере(Товар, ИмяПроцедуры, УИДЗадания)
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(Товар);
// Запускаем процедуру в фоновом потоке
ФоновыеЗадания.Выполнить(ИмяПроцедуры, МассивПараметров, УИДЗадания, "Получение данных через фоновое задание");
КонецПроцедуры
На клиенте по нажатию команды подключаем обработчик ожидания и передаем управление серверу для создания задачи:
&НаКлиенте
Процедура ОбновитьОстаткиИЦены(Команда)
ИмяПроцедуры = "ОбщийМодульСервер.ВыполнитьОбменДанными";
УИДЗадания = Новый УникальныйИдентификатор;
// Подключаем опрос состояния с интервалом в 1 секунду
ПодключитьОбработчикОжидания("ОбработчикОжидания_СообщенияПользователю", 1, Ложь);
ОбновитьОстаткиИЦеныНаСервере(Элементы.Товары.ТекущаяСтрока, ИмяПроцедуры, УИДЗадания);
КонецПроцедуры
В процедуре фонового обмена (например, в общем модуле с признаком вызова на сервере) выполняется длительная работа и регистрируются пользовательские сообщения:
Процедура ВыполнитьОбменДанными(Товар) Экспорт
// В цикле обработки данных формируем сообщения о проценте выполнения
Для Индекс = 1 По 100 Цикл
// Выполнение полезной работы (HTTP-запрос, запись данных)
// ...
СообщениеПользователю = Новый СообщениеПользователю;
СообщениеПользователю.Текст = "Загружено " + Строка(Индекс) + " %";
СообщениеПользователю.Сообщить();
КонецЦикла;
КонецПроцедуры
Для чтения прогресса напишем функцию опроса состояния фонового задания на сервере с использованием метода ПолучитьСообщенияПользователю:
&НаСервере
Функция ПолучитьСообщенияИзФоновогоЗадания(ИмяПроцедуры, УИДЗадания)
Ответ = Новый Структура;
Ответ.Вставить("Результат", "ВПроцессе");
Ответ.Вставить("Сообщения", Новый Массив);
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("ИмяМетода", ИмяПроцедуры);
СтруктураОтбора.Вставить("Ключ", УИДЗадания);
МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(СтруктураОтбора);
Если МассивЗаданий.Количество() > 0 Тогда
ТекЗадание = МассивЗаданий[0];
Если ТекЗадание.Состояние <> СостояниеФоновогоЗадания.Активно Тогда
Ответ.Результат = "Завершено";
КонецЕсли;
// Считываем сообщения с удалением прочитанных (параметр Истина)
Ответ.Сообщения = ТекЗадание.ПолучитьСообщенияПользователю(Истина);
КонецЕсли;
Возврат Ответ;
КонецФункции
Клиентский обработчик ожидания принимает накопленные сообщения, отображает последнее состояние пользователю и отключает таймер при завершении задачи:
&НаКлиенте
Процедура ОбработчикОжидания_СообщенияПользователю() Экспорт
Ответ = ПолучитьСообщенияИзФоновогоЗадания("ОбщийМодульСервер.ВыполнитьОбменДанными", УИДЗадания);
МассивСообщений = Ответ.Сообщения;
Если МассивСообщений.Количество() > 0 Тогда
ОчиститьСообщения();
ТекстСообщения = "Загрузка данных: " + МассивСообщений[МассивСообщений.Количество() - 1].Текст;
Сообщить(ТекстСообщения);
КонецЕсли;
Если Ответ.Результат = "Завершено" Тогда
ОчиститьСообщения();
Сообщить("Загрузка данных успешно завершена.");
ОтключитьОбработчикОжидания("ОбработчикОжидания_СообщенияПользователю");
КонецЕсли;
КонецПроцедуры
Чтобы исключить зависания, ошибки и задержки в мобильном приложении, выполним следующие шаги:
ФоновыеЗадания.ПолучитьФоновыеЗадания. Не допускайте запуска нескольких фоновых процессов одновременно.HTTPСоединение обязательно указывайте явный параметр Таймаут. При потере мобильной связи фоновое задание без таймаута надолго останется в активном состоянии и заблокирует запуск последующих задач.