Lib_rms - библиотека для работы с RMS

от
Прочие языки    rms, midlet pascal, java me

Lib_rms - библиотека для MIDlet Pascal, для грамотной работы с RMS.
Главное отличие в том, что данная библиотека имеет гораздо большие возможности, нежели стандартные средства работы с RMS в MIDlet Pascal.

#1 Бредословие
#2 Введение в RMS
#3 Подключение библиотеки
#4 Пример
#5 Обработка ошибок
#6 Несколько бесполезных событий
#7 Принцип чтения/записи
#8 Документация
#9 Реанимация

---
#1 Бредословие

Люди делятся на 2 категории: на тех, кто прошёл Quake от начала до конца, и на тех, у кого не хватило терпения или реакции, чтобы выпустить кишки всем злобным монстрам. Поколение игры Quake хорошо знает основной принцип: "Главное - не забыть сохраниться!"

---
#2 Введение в RMS

Хранение данных организовано в Java 2 ME с помощью системы управления записями. Данные представлены записями, которые помещаются в хранилище записей и не стираются при закрытии приложения, перезагрузке телефона или замене батареи. Размер и физическое местоположение хранилища в памяти телефона зависят от конкретной модели аппарата. Хранилище жёстко привязано к мидлету, и при удалении приложения из телефона, все данные, относящиеся к нему, удалятся вместе с ним.

Важный момент: у каждого приложения имеются свои хранилища, внутри которых размещаются пронумерованные, начиная с одного, записи.

---
#3 Подключение библиотеки

Для начала необходимо подключить библиотеку к проекту.
Lib_rms.class кидаем в /libs/
StringInputStream.class добавляем в ресурсы
StringOutputStream.class добавляем в ресурсы
Если хотим обрабатывать события (о которых мы поговорим чуть позже), то RMSListener.class добавляем в ресурсы

Теперь подключаем директивой uses к исходному коду:
  1. uses rms;

Если вы всё сделали правильно, то далее проблем у вас возникнуть не должно.

---
#4 Пример

Для начала необходимо открыть хранилище:

  1. rms.open('myrms');

То, что в кавычках - имя хранилища. Если такого хранилища обнаружено не будет, то будет создано новое с таким именем.

Далее запишем какую-нибудь бяку:

  1. rms.printInteger(5);
  2. rms.printString('F#CK');
  3. rms.printInteger(76);
  4. rms.add;

С помощью процедур printInteger/printString записываем данные, далее методом add добавляем записанные данные в запись с следующим индексом. Напоминаю, порядок записей в хранилище начинается с одного, то есть первая запись будет иметь индекс 1.
И закроем хранилище:

  1. rms.close;

Считываем в том же порядке:

  1. rms.open('myrms');
  2.     read(1);
  3.     debug(''+rms.inputInteger);
  4.     debug(rms.inputString);
  5.     debug(''+rms.inputInteger);
  6. rms.close;

Процедура read считывает данные с записи по указанному в параметрах номеру, далее с помощью функций inputInteger/inputString достаём эти данные.

Теперь изменим данные, находящиеся в первой записи:

  1. rms.open('myrms');
  2.     rms.printString('newdata');
  3.     rms.set(1);
  4. rms.close;

Догадаться не сложно: процедура set записывает данные в запись по указанному в параметрах номеру.

В целом пример будет выглядеть следующим образом:

  1. rms.open('myrms');
  2.     rms.printInteger(5);
  3.     rms.printString('F#CK');
  4.     rms.printInteger(76);
  5.     rms.add;
  6. rms.close;
  7.  
  8. rms.open('myrms');
  9.     read(1);
  10.     debug(''+rms.inputInteger);
  11.     debug(rms.inputString);
  12.     debug(''+rms.inputInteger);
  13. rms.close;
  14.  
  15. rms.open('myrms');
  16.     rms.printString('newdata');
  17.     rms.set(1);
  18. rms.close;
  19.  
  20. rms.open('myrms');
  21.     read(1);
  22.     debug(rms.inputString);
  23. rms.close;

Запускаем, смотрим лог вашего эмулятора, медитируем...

---
#5 Обработка ошибок

Ошибки есть всегда. Везде. И наша с вами задача поймать их. Допустим, открываем пустое хранилище и считываем с несуществующей записи с номером 1 несуществующие данные:

  1. rms.open('empty');
  2.     rms.read(1);
  3.     debug(rms.inputString);
  4. rms.close;

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

  1. procedure rms_exception(error:string);
  2. begin
  3.     debug(error);
  4. end;

Передаём на консоль сообщение об ошибке, смотрим на лог и видим:

  1. >>recordId=1

Мы решили прочитать данные с записи, которой нет!
Попробуем устранить эту ошибку :)

  1. procedure rms_exception(error:string);
  2. begin
  3.     if error='recordId=1' then
  4.     begin
  5.         rms.printString('data');
  6.         rms.add;
  7.     end
  8.     else
  9.     begin
  10.         debug(error);
  11.     end;
  12. end;

Снова запускаем код с обновлённым обработчиком ошибок. Теперь у нас в хранилище empty запись с индексом 1 не пустая, значит, мы можем смело запускать код ещё раз и быть уверенными, что обработчик ошибок не будет вызван. Запускаем ещё раз, смотрим лог. Получилось? А ведь получилось же!

К сожалению, обработчик ошибок может принимать не любые исключения :-( Так, например, при выполнении следующего кода обработчик ошибок никогда не будет вызван:

  1. rms.open('empty');
  2.     debug(rms.inputString);
  3. rms.close;

Всё дело в том, что мы читаем данные, предварительно не указав запись, откуда читаем => читать не от куда. Исключение, конечно, будет возбуждено, но обработчик ошибок никак на это не среагирует, потому что исключение совершенно другой природы, отличающийся от исключений, возникающих при работе с RMS.

---
#6 Несколько бесполезных событий

Чтобы отслеживать события, возникающие при работе с RMS, необходимо в ресурсы приложения, как было отмечено в самом начале, добавить RMSListener.class
Добавляем следующие обработчики событий:

  1. procedure rms_added(id:integer);
  2. begin
  3.     debug('added!');
  4. end;
  5.  
  6. procedure rms_changet(id:integer);
  7. begin
  8.     debug('changet!');
  9. end;
  10.  
  11. procedure rms_deleted(id:integer);
  12. begin
  13.     debug('deleted!');
  14. end;

Первый будет вызываться при добавлении новой записи.
Второй будет вызываться при изменении существующей записи.
Третий будет вызываться при удалении записей.
Параметр id указывает на номер записи.

Вводим следующий код для тестирования:

  1. rms.open('kalter');
  2.     rms.addListener;
  3.     rms.printString('lal');
  4.     rms.add;
  5.     rms.printInteger(5);
  6.     rms.set(1);
  7.     rms.deleterecord(1);
  8. rms.close;

С помощью процедуры addListener мы указали, что хотим обрабатывать события. Выполняем код на эмуляторе, смотри лог... Тут и комментировать нечего: создаём запись - вызывается rms_added, редактируем запись - вызывается rms_changet, удаляем запись - вызывается rms_deleted.

---
#7 Принцип чтения/записи

Момент истины настал.

Чтобы записать данные:

  1. rms.open('rms');
  2.     rms.printInteger(5);
  3.     rms.printString('data');
  4.     rms.add;
  5. rms.close;

Всё просто: записываем данные в буфер, затем записываем уже в запись методом add. После этого буфер очищается и можно что-нибудь записать:

  1. rms.open('rms');
  2.     rms.printInteger(5);
  3.     rms.printString('data');
  4.     rms.add;
  5.  
  6.     rms.printString('lol');
  7.     rms.printString('data!');
  8.     rms.add;
  9. rms.close;

Для чтения тоже используется специальный буфер. Для начала процедурой read считываем все байты в буфер, затем функциями inputString/inputInteger достаём значения из буфера.

  1. rms.open('rms');
  2.     read(1);
  3.     debug(''+rms.inputInteger);
  4.     debug(rms.inputString);
  5.  
  6.     read(2);
  7.     debug(inputString);
  8.     debug(inputString);
  9. rms.close;

Особенность - буфера два. Один для считывания, другой для записи.

---
#8 Документация

Весь список процедур и функций:

  1. procedure open(name:string); //Открывает хранилище. В случае отсутствия создаёт новое
  2. procedure deleteRecordStore(name:string); //Удаляет хранилище по имени
  3. function getLastModified:integer; //Время последнего изменения данных в хранилище записей
  4. function getName:string; //Имя хранилища
  5. function getNextRecordId:integer; //Номер, который будет присвоен следующей записи
  6. function getNumRecords:integer; //Количество записей в хранилище
  7. function getRecordSize(id:integer):integer; //Размер (в байтах) записи по указанному номеру
  8. function getSize:integer; //Размер (в байтах) хранилища
  9. function getSizeAvailable:integer; //Объём памяти (в байтах), доступный для расширения хранилища
  10. function getVersion:integer; //Номер версии хранилища
  11. procedure addListener; //Включить обработчик событий
  12. procedure deleteListener; //Отключить обработчик событий
  13. procedure deleteRecord(id:integer); //Удалить запись по указанному номеру
  14. procedure read(id:integer); //Прочитать в буфер данные записи по указанному номеру
  15. procedure add; //Добавить данные из буфера в запись
  16. procedure set(id:integer); //Добавить данные из буфера в запись по указанному номеру
  17. function inputInteger:integer; //Данные из буфера типа Integer
  18. function inputString:string; //Данные из буфера типа String
  19. procedure printInteger(value:integer); //Записывает переменную типа Integer в буфер
  20. procedure printString(value:string); //Записывает переменную типа String в буфер
  21. procedure close; //Закрывает хранилище

В случае ошибок функции будут возвращать '-1' или -1 в зависимости от возвращаемого типа (должны же они хоть что-нибудь вернуть).

Типов boolean, real, char в MIDlet Pascal'e, как таковых, нет. От чего нет ни одной процедуры/функции, работающей с ними.

---
#9 Реанимация

Исходный код библиотеки можно найти на GitHub.

В прикреплённом ниже архиве можно найти все необходимые файлы.
  Lib_rms.zip
  • +7
  • views 4645