Почему падает мобильное приложение 1С при удалении записи из независимого регистра сведений и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке мобильных приложений на платформе 1С:Предприятие разработчики периодически сталкиваются с ситуацией, когда при попытке удалить запись из независимого регистра сведений мобильное приложение аварийно завершает свою работу (вылетает). При этом в конфигурации могут отсутствовать какие-либо подписки на события или обработчики событий в модуле набора записей. Разберем причины такого поведения и способы надежного устранения ошибки.

Причины аварийного завершения работы мобильного приложения

Проанализируем основные факторы, вызывающие сбой при работе с регистрами сведений в мобильной среде:

  1. Ошибки конкретных релизов мобильной платформы: В ранних и промежуточных сборках (например, 8.3.10.51) присутствовали внутренние ошибки платформенного кода работы с локальной СУБД SQLite. При вызове стандартных команд удаления или использовании объекта МенеджерЗаписи происходило некорректное освобождение ресурсов или конфликт блокировок (database locked), что приводило к критическому сбою нативного процесса (SIGSEGV).
  2. Конфликт удаления и активной выборки: Если удаление выполняется внутри цикла обхода выборки (Пока Выборка.Следующий() Цикл) через менеджер записи, мобильная СУБД блокирует файл базы данных из-за одновременной попытки чтения и модификации.
  3. Сбой обновления интерфейса: Падение может происходить не в момент физического удаления записи, а при автоматическом обновлении динамического списка на форме, когда строка, на которой находился фокус, внезапно исчезает.
  4. Сложные и составные типы в измерениях: Использование составных типов данных или длинных строковых полей в измерениях независимого регистра повышает вероятность внутренних ошибок движка базы данных при формировании предикатов удаления.

Способ 1. Обновление версии мобильной платформы

Первое и главное действие при возникновении необъяснимых падений нативных методов — проверка и обновление используемой мобильной платформы. Релизы мобильной платформы выпускаются с регулярными исправлениями системных ошибок работы со встроенной СУБД SQLite. Если используется проблемный релиз (например, 8.3.10.51), необходимо пересобрать приложение на стабильной или тестовой сборке с исправлением (например, 8.3.10.77, 8.3.10.80 или более актуальных версиях ветки 8.3).

Способ 2. Программное удаление через пустой НаборЗаписей с отбором

Посмотрим на наиболее устойчивый и рекомендованный способ программного удаления записей независимого регистра сведений на мобильной платформе. Вместо использования РегистрСведенийМенеджерЗаписи или интерактивных команд списка надежнее использовать запись пустого объекта РегистрСведенийНаборЗаписей с установленным отбором по ключевым измерениям.

Рассмотрим пример кода для удаления записи на сервере:


&НаСервере
Процедура УдалитьЗаписьРегистраНаСервере(ЗначениеКлюча1, ЗначениеКлюча2)
    
    НачатьТранзакцию();
    Попытка
        Набор = РегистрыСведений.МойНезависимыйРегистр.СоздатьНаборЗаписей();
        
        // Устанавливаем отборы по всем ключевым измерениям
        Набор.Отбор.Измерение1.Установить(ЗначениеКлюча1);
        Набор.Отбор.Измерение2.Установить(ЗначениеКлюча2);
        
        // Запись пустого набора с замещением удаляет соответствующие записи
        Набор.Записать(Истина);
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение;
    КонецПопытки;
    
КонецПроцедуры

Такой подход гарантирует корректную транзакционную изоляцию и минимизирует вероятность блокировок на уровне встроенной базы данных SQLite.

Способ 3. Перехват интерактивного удаления на форме списка

Если удаление инициируется пользователем через стандартную командную панель динамического списка или контекстное меню, разберем по шагам, как перехватить операцию и избежать сбоя отрисовки интерфейса:

  1. В свойствах таблицы формы переопределяем стандартное поведение через обработчик ПередУдалением, установив Отказ = Истина.
  2. Вызываем собственную серверную процедуру удаления через пустой РегистрСведенийНаборЗаписей.
  3. После выполнения удаления программно обновляем динамический список на клиенте с помощью метода ОповеститьОбИзменении() или команды обновления элементов формы.

Пример реализации перехвата удаления в модуле формы:


&НаКлиенте
Процедура СписокПередУдалением(Элемент, Отказ)
    
    Отказ = Истина; // Отменяем стандартное платформенное удаление
    
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Выполняем безопасное удаление на сервере
    УдалитьЗаписьРегистраНаСервере(ТекущиеДанные.Измерение1, ТекущиеДанные.Измерение2);
    
    // Оповещаем интерфейс об изменении данных
    ОповеститьОбИзменении(Тип("РегистрСведенийКлючЗаписи.МойНезависимыйРегистр"));
    Элементы.Список.Обновить();
    
КонецПроцедуры

Способ 4. Правильная организация массового удаления записей

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

Разберем правильный алгоритм массового удаления:

  1. Выполняем запрос к регистру и выгружаем все ключевые поля во временную коллекцию (массив структур или ТаблицаЗначений).
  2. Закрываем выборку и освобождаем результат запроса.
  3. В отдельном цикле по полученной коллекции производим удаление через пустые наборы записей.

&НаСервере
Процедура УдалитьУстаревшиеЗаписиНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Регистр.Измерение1 КАК Измерение1,
        |   Регистр.Измерение2 КАК Измерение2
        |ИЗ
        |   РегистрСведений.МойНезависимыйРегистр КАК Регистр
        |ГДЕ
        |   Регистр.ФлагУдаления = ИСТИНА";
    
    ТаблицаДляУдаления = Запрос.Выполнить().Выгрузить();
    
    НачатьТранзакцию();
    Попытка
        Для Каждого Стр Из ТаблицаДляУдаления Цикл
            Набор = РегистрыСведений.МойНезависимыйРегистр.СоздатьНаборЗаписей();
            Набор.Отбор.Измерение1.Установить(Стр.Измерение1);
            Набор.Отбор.Измерение2.Установить(Стр.Измерение2);
            Набор.Записать(Истина);
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение;
    КонецПопытки;
    
КонецПроцедуры

Рекомендации по структуре метаданных

Для предотвращения нестабильной работы локальной базы мобильного приложения обратим внимание на структуру самого регистра:

  1. Типы данных измерений: Избегайте составных типов данных в измерениях независимых регистров. Используйте примитивные типы (Строка фиксированной длины, Число, Дата, Булево) либо ссылки на конкретные справочники.
  2. Очистка кэша и базы при отладке: При частых падениях приложения на тестовом устройстве внутренняя структура SQLite может быть повреждена. В процессе разработки рекомендуется периодически выполнять полную переустановку приложения или очистку хранилища в настройках Android/iOS.
← На главную