Логин:   Пароль:






Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100
Rambler's Top100

Мобильная Java: СтатьиИспользование J2ME. Часть 3

Использование J2ME. Часть 3

Обзор

Данная часть будет не очень большой. В ней речь пойдет об организации долговременного хранения информации в мобильном устройстве с помощью пакета javax.microedition.rms.

Record Management System

Как и все в профиле MIDP система долговременного хранения информации реализована максимально просто. Все хранилище состоит из произвольного колличества RecordStore, которые в свою очередь состоят из произвольного количества записей. Запись является по сути дела массивом байт. Диаграмма основных классов представлена на рис.1.

Рисунок 1
Рисунок 1.
RecordStore
Cинглетон (ну почти синлетон :), является фабрикой для объектов опять же класса RecordStore. С помощью метода openRecordStore(String, boolean) Вы открываете или создаете новое хранилище записей, а далее добавляете, удаляете, изменяете или ищете в нем записи спомощью доступных методов.

RecordEnumeration
Итератор по множеству записей. Объект, реализующий этот интерфейс возвращается методом RecordStore.enumerateRecords (RecordFilter, RecordComparator). Среди обычных для итератора возможностей можно выделть то, что во-первых итератор двунаправленный, а во-вторых он умеет быть up-to-date всем изменениям в записях, по которым он ходит. Множество записей для итератора задается с помощью фильтра и компаратора.

RecordFilter
Интерфейс, который должен реализовать класс, если он хочет быть фильтром для выборки записей из хранилища. При выборке методу matches(byte[]) передается кандидат для выборки, если он подходит, метод должен вернуть true.

RecordComparator
Используется для сортировки записей при выборке. Методу compare(byte[], byte[]) передается две записи, которые нужно сравнить.

RecordListener
Вешается на хранилище записей. RecordStore будет уведомлять его о добавлении записи, изменении или удалении.

Использование RecordStore

Понятно, что использование RecordStore в таком виде, как оно описано выше, весьма затруднительно. Принимая во внимание то, что в CLDC и MIDP отсутствует механизм сериализации объектов, это становиться совсем очевидным. Поэтому предлагается создать некоторую обертку для хранилища данных в соответствую со спецификой нашей задачи.

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

  • Имя хоста (или адрес) сервера системы
  • Порт, на котором слушает сервер
  • Наш логин и пароль в системе
  • Список пользователей (аналогия из аськи - Contact List)

И так, нужно хранить строки и вектора (цифровой параметр "порт" сохраним тоже в виде строки).

Данную задачу будем решать так:

  1. введем константный идентификатор для каждого параметра, который нужно сохранить (пускай он будет представлен байтом, константный он потому, что не меняет свое значения между перезапусками приложения)
  2. при сохранении записи этот идентификатор будет записан перед самой полезной информацией
  3. при извлечении записи идентификатор будет являться критерием поиска необходимого параметра
  4. вектор хранить очень просто, нужно сохранять строки с одинаковыми идентификаторами
  5. не будем вводить метод для сохранения вектора, вместо этого несколько раз вызовем метод для сохранения строки

Сначала введем класс - фильтр по первому байту записи.

private class FirstByteFilter implients RecordFilter
{
 private byte criteria;

 // инициализируем класс нужным 
 // константным идентификатором
 public FirstByteFilter(byte criteria)
 {
  this.criteria = criteria;
 }

 // метод возвращает true, если первый байт записи
 // совпадает с идентификатором
 public boolean matches(byte[] candidate)
 {
  return (candidate[0] == criteria);
 }
}

Таким образом, с учетом что того, что RecordStore уже открыт, методы для сохранения/чтения строк и чтения векторов будут выглядить так:

/**
 * метод для чтения строки
 * @param criteria константный идентификатор записи
 * @return строка
 */
 private String getString(byte criteria)
 {
  String str = "";

  try
  {
   // выполняем поиск запрашиваемого параметра
   RecordEnumeration re = rs.enumerateRecords(
    new FirstByteFilter(criteria), null, false);

  // если нашли - извлекаем строку из массива
  //  байт пропуская первый байт,
  // т.к. он - идентификатор
  if (re.numRecords() > 0)
  {
   byte[] data = re.nextRecord();
   str = new String(data, 1, data.length - 1);
  }
 } catch (Exception e)
 {
  e.printStackTrace();
 }

 return str;
}

/**
 * метод для сохранения строки
 * если уже существует сторка с данным идентификатором,
 * этот метод заменит ее значение на новое
 * @param criteria идентификатор
 * @param value строка для сохранения
 */
private void setString(byte criteria, String value)
{
 try
 {
  // ищем старую запись с данным идентификатором
  RecordEnumeration re = rs.enumerateRecords(
  new FirstByteFilter(criteria), null, false);

  // делаем из строки массив байт,
  // с первым байтом идентификатором
  byte[] tmp = value.getBytes();
  byte[] data = new byte[tmp.length + 1];
  data[0] = criteria;
  Systi.arraycopy(tmp, 0, data, 1, tmp.length);

  // если запись с данным идентификатором уже есть,
  // то заменяем ее значение
  // если нет, то добавляем новую запись
  if (re.numRecords() > 0)
  {
   int id = re.nextRecordId();
   rs.setRecord(id, data, 0, data.length);
  } else
  {
   rs.addRecord(data, 0, data.length);
  }
 }
 catch (Exception e)
 {
  e.printStackTrace();
 }
}

/**
 * метод для чтения вектора
 * @param criteria first byte of necessary record
 * @return Vector of found strings
 */
private Vector getVector(byte criteria)
{
 Vector vec = null;

 try
 {
  // ищем все записи с подходящим идентификатором
  RecordEnumeration re = rs.enumerateRecords(
   new FirstByteFilter(criteria), null, false);

  // если нашли, то создаем новый вектор и
  // набиваем его значениями из итератора
  if (re.numRecords() > 0)
  {
   vec = new Vector(re.numRecords());
   while (re.hasNextElient())
   {
    byte[] data = re.nextRecord();
    // обратите опять внимание, что при создании строки
    //мы пропускаем первый байт записи
    vec.addElient(new String(data, 1, data.length - 1));
   }
  }
 } 
 catch (Exception e)
 {
  e.printStackTrace();
 }

 return vec;
}

Теперь введем идентификаторы для всех параметров а также методы для сохранения/извлечения каждого параметра отдельно.

 /** prefix for user name record */
 private static final byte RECORD_USERNAME = 0x01;
 /** prefix for password record */
 private static final byte RECORD_PASSWORD = 0x02;
 /** prefix for server name record */
 private static final byte RECORD_SERVERNAME = 0x10;
 /** prefix for server port record */
 private static final byte RECORD_SERVERPORT = 0x11;
 /** prefix for user list record */
 private static final byte RECORD_USERLIST = 0x20;

/**
 * return user name or null 
 * if user name not found in record store
 */
 public String getUserName()
 {
  return getString(RECORD_USERNAME);
 }

/**
 * save user name in record store
 */
 public void setUserName(String userName)
 {
  setString(RECORD_USERNAME, userName);
 }

/**
 * return server name or null 
 * if not found in record store
 */
 public String getServerName()
 {
  return getString(RECORD_SERVERNAME);
 }

/**
 * save server name in record store
 */
 public void setServerName(String serverName)
 {
  setString(RECORD_SERVERNAME, serverName);
 }

/**
 * return user list or null 
 * if not found in record store
 */
 public Vector getUserList()
 {
  return getVector(RECORD_USERLIST);
 }
И так далее.

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

/**
 * clear user list record store
 */
 public void clearUserList()
 {
  try
  {
   // получаем список всех записей,
   // которые нужно удалить
   RecordEnumeration re = rs.enumerateRecords(
new FirstByteFilter(RECORD_USERLIST), null, false);
   // удаляем все найденные записи

   if (re.numRecords() > 0)
   {
    while (re.hasNextElient())
    {
     rs.deleteRecord(re.nextRecordId());
    }
   }
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }

/**
 * этот метод похож на setString(),
 * за одним исключением - он
 * не проверяет присутствие записи 
 * с таким же идентификатором
 */
 public void addUserToList(String user)
 {
  try
  {
   byte[] tmp = user.getBytes();
   byte[] data = new byte[tmp.length + 1];
   data[0] = RECORD_USERLIST;
   Systi.arraycopy(tmp, 0, data, 1, tmp.length);

   rs.addRecord(data, 0, data.length);
  } 
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }

В завершении данной части статьи приведем диаграмму классов того, что получилось.

ClientDataStore
Рисунок 2. ClientDataStore


<< Часть 2


Автор: Вадим Гуров

Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 11

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/books/show2b.php on line 30
Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 91

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/news/worldnews.php on line 95