При разработке мобильных приложений на платформе 1С:Предприятие одной из самых частых проблем становится стремительный рост размера базы данных на мобильном устройстве. Особенно остро этот вопрос встает, когда в приложении реализован функционал фотографирования объектов или загрузки изображений товаров для офлайн-работы. Разработчики часто сталкиваются с тем, что даже после программной очистки реквизитов с типом ХранилищеЗначения физический размер файла базы данных на устройстве под управлением ОС Android не уменьшается, продолжая занимать гигабайты памяти и вызывая предупреждения системы о нехватке свободного места.
В этой статье мы подробно разберем внутренние механизмы СУБД мобильной платформы, выясним причины такого поведения системы и рассмотрим эффективные практические способы решения этой проблемы — как оперативные (сжатие существующей базы), так и стратегические (изменение архитектуры хранения файлов).
Для начала проанализируем техническую сторону вопроса. Мобильная платформа 1С использует в качестве встроенной СУБД движок SQLite. Это легковесная и очень быстрая база данных, оптимизированная для работы на мобильных операционных системах. Однако у архитектуры хранения данных SQLite есть важная особенность, связанная с удалением записей.
Когда мы выполняем очистку реквизита объекта (например, присваиваем реквизиту с типом ХранилищеЗначения пустое значение Неопределено или удаляем элемент справочника целиком), физического удаления данных с диска не происходит. СУБД просто помечает страницы, на которых хранились эти данные, как «свободные» (так называемый список freelist) и планирует использовать их повторно при записи новых данных. С точки зрения операционной системы Android, файл базы данных сохраняет свой максимальный размер (например, 4 Гб), хотя фактически внутри него теперь может быть много пустого места.
Такой подход разработчиков SQLite обоснован следующими факторами:
Тем не менее, если свободное место на телефоне критически заканчивается, нам необходимо принудительно вернуть неиспользуемое пространство операционной системе.
Рассмотрим штатный инструмент платформы 1С для физического сжатия базы данных. Начиная с версии мобильной платформы 8.3.9, разработчикам и администраторам доступно встроенное меню администрирования непосредственно на мобильном устройстве.
Разберем по шагам, как запустить процедуру сжатия таблиц:
>) напротив нужного нам информационного приложения.Во время этого процесса мобильная платформа выполняет команду VACUUM для базы данных SQLite. СУБД создает новый чистый файл базы, копирует туда только актуальные (заполненные) данные, после чего заменяет им старый раздутый файл. Физический размер приложения на диске уменьшится до фактического объема хранящейся информации.
Важное предупреждение: Для выполнения операции VACUUM на мобильном устройстве временно требуется свободное место, сопоставимое с текущим размером базы данных. Если база занимает 4 Гб, а свободного места на телефоне осталось всего 200 Мб, процедура завершится ошибкой из-за нехватки памяти. В таком случае придется прибегнуть к альтернативным методам.
Если штатное тестирование на устройстве запустить не удается из-за нехватки свободного места, мы можем применить следующие методы:
1Cv8.1CD с мобильного устройства на компьютер (через USB-подключение или FTP-сервер). Затем открываем этот файл на компьютере с помощью утилиты проверки целостности chdbfl.exe (входит в стандартную поставку платформы 1С) либо загружаем его в Конфигуратор и запускаем полное тестирование и исправление с флагом сжатия таблиц. Сжатый файл возвращаем обратно на мобильное устройство. Данный метод отлично подходит для отладки разработчиком, но сложен для внедрения у конечных пользователей.Постоянно запускать сжатие таблиц — это борьба с симптомами, а не с причиной. Хранение картинок высокого разрешения внутри СУБД мобильного приложения является серьезной ошибкой проектирования. Разберем, как кардинально перестроить архитектуру приложения.
Вместо помещения бинарных данных картинок в реквизиты базы данных (через ХранилищеЗначения), правильным подходом будет сохранение картинок в виде обычных файлов во внутренней памяти устройства. В самой базе данных мы будем хранить только текстовый путь к этим файлам.
Посмотрим на пример кода, реализующий сохранение картинки во внешнюю файловую систему:
// Получаем уникальное имя для файла картинки на диске смартфона
ИмяФайла = РабочийКаталогДанныхПользователя() + "img_" + Строка(НоменклатураСсылка.УникальныйИдентификатор()) + ".jpg";
// Предположим, что ОтветОтСервера содержит двоичные данные картинки
ДвоичныеДанныеКартинки = ОтветОтСервера;
ДвоичныеДанныеКартинки.Записать(ИмяФайла);
// Записываем путь к файлу в текстовый реквизит справочника
ОбъектНоменклатуры = НоменклатураСсылка.ПолучитьОбъект();
ОбъектНоменклатуры.ПутьКФайлуКартинки = ИмяФайла;
ОбъектНоменклатуры.Записать();
При таком подходе процедура очистки данных становится мгновенной для операционной системы. Нам больше не нужно перезаписывать базу данных. Мы просто удаляем физический файл с диска устройства, используя стандартные методы платформы 1С:
// Процедура удаления файла картинки с диска
ОбъектНоменклатуры = НоменклатураСсылка.ПолучитьОбъект();
Если ЗначениеЗаполнено(ОбъектНоменклатуры.ПутьКФайлуКартинки) Тогда
Попытка
УдалитьФайлы(ОбъектНоменклатуры.ПутьКФайлуКартинки);
// Очищаем путь в базе данных
ОбъектНоменклатуры.ПутьКФайлуКартинки = "";
ОбъектНоменклатуры.Записать();
Исключение
ЗаписьЖурналаРегистрации("Ошибка удаления файла", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
В данном случае операционная система Android мгновенно высвобождает дисковое пространство, и размер приложения в диспетчере задач уменьшается без каких-либо дополнительных сжатий базы.
Часто мобильное приложение используется агентами или экспедиторами для фиксации состояния товаров, витрин или документов. Камеры современных телефонов создают снимки весом 4–10 Мб с разрешением более 4000х3000 пикселей. Такое качество избыточно для учетной системы 1С.
Рекомендуется программно уменьшать разрешение и качество картинок непосредственно перед сохранением на диске или в базе данных. Для этого используем специальный объект платформы ОбрабатываемаяКартинка.
Проанализируем пример оптимизации разрешения изображения перед записью:
// Создаем объект для обработки полученного снимка
ОбрабатываемоеИзображение = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// Задаем разумное ограничение по ширине и высоте (например, 1024x768 пикселей)
ОбрабатываемоеИзображение.УстановитьМаксимальныйРазмер(1024, 768);
// Получаем оптимизированную картинку в формате JPEG с качеством 70%
ОптимизированнаяКартинка = ОбрабатываемоеИзображение.ПолучитьКартинку(ФорматКартинки.JPEG, 70);
// Теперь получаем значительно уменьшенные двоичные данные
ДвоичныеДанныеДляСохранения = ОптимизированнаяКартинка.ПолучитьДвоичныеДанные();
Такое простое действие позволяет уменьшить размер каждой фотографии в 10–20 раз (с 5 Мб до 150-300 Кб). При этом визуальное качество на экранах смартфонов остается превосходным, текст на документах отлично читается, а база данных или папка приложения перестанут стремительно разрастаться.
Если специфика работы компании требует наличия картинок товаров, но при этом у сотрудников в течение дня периодически появляется интернет-соединение, хорошей практикой является динамическая загрузка файлов. Не стоит при утренней синхронизации выкачивать на устройство абсолютно все медиафайлы номенклатуры.
Рассмотрим оптимальный алгоритм динамического кэширования:
Сочетание архитектурного подхода (хранение файлов вне базы данных), предварительного сжатия картинок и периодического запуска сжатия SQLite позволит вашему мобильному приложению стабильно работать на любых устройствах Android без риска переполнения памяти.