четверг, 26 июня 2008 г.

Простейший мидлет с возможностью работы с HTTP

Задача: написать мидлет, который будет посылать некоторый POST-запрос на сервер и выводить ответ.

Аппаратное обеспечение

Проверялось на Sony Ericsson k320i и на Nokia 2600 classic.

Сервер

На сервере у нас простое Web-приложение, написанное на ASP.NET. Для этого приложения напишем хэндлер Handler.ashx, который будет принимать и обрабатывать запросы. К примеру, он будет получать значение переменной message, и возвращать строку "Message is <значение>"
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Handler : IHttpHandler
{
  public void ProcessRequest(HttpContext context)
  {
    string msg = context.Request["message"];
    context.Response.ContentType = "text/plain";
    context.Response.Write(String.Format("Message is: {0}", msg));
  }

  public bool IsReusable
  {
    get
    {
      return false;
    }
  }
}

Создание мидлета

Для работы использовалась среда NetBeans 6.1. Создаем Mobile Application с профилем MIDP 2.0 (c 2.1 на указанных телефонах мидлет не заработал). На форму мидлета добавим StringItem и назовем MessageString. Также добавим на форму команду OkCommand, и в ее обработчик (не знаю, как это по-явовски правильно называется) добавим вызов функции CallServer Сама функция выглядит примерно таким образом:
public void CallServer()
{
  Runnable r = new Runnable()
  {
    public void run()
    {
      HttpConnection conn = null;
      InputStream is = null;
      OutputStream os = null;
      try
      {
        conn = (HttpConnection) Connector.open("http://localhost:1988/Handler.ashx");

        // Настройки соединения
        conn.setRequestMethod(HttpConnection.POST);
        conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
        conn.setRequestProperty("Content-Language", "en-US");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

        // GenerateString - некоторая функция, возвращающая строку
        String str = "message=" + GenerateString() + "\r\n";

        // Посылка сообщения
        os = conn.openOutputStream();
        os.write(str.getBytes());
        //os.flush();

        // Смотрим, какой код пришел с сервера
        int rc = conn.getResponseCode();
        if (rc != HttpConnection.HTTP_OK)
        {
          throw new IOException("HTTP responce code: " + rc);
        }                 

        // Получение ответа и вывод его в строке MessageString
        is = conn.openInputStream();
        int ch;
        StringBuffer data = new StringBuffer();
        while ((ch = is.read()) != -1)
        {
          data.append((char) ch);
        }
        MessageString.setText(data.toString());
      }
      catch (Exception ex)
      {
        MessageString.setText("something failed: " + ex.getMessage());
      }
      finally
      {
          // Закрытие соединений
        try
        {
          if (is != null)
          {
            is.close();
          }
          if (os != null)
          {
            os.close();
          }
          if (conn != null)
          {
            conn.close();
          }
        }
        catch (Exception e)
        {
        }
      }
    }
  };
  new Thread(r).start();
}
При работе с HttpConnection обязательно нужно создавать отдельный поток (Runnable), потому что иначе при установке соединения будет возникать дедлок. А возникает он по следующей причине. Поток, инициирующий соединение, блокируются до тех пор, пока соединение не будет установлено. То есть, если код выполняется в системном потоке мидлета, то блокируется системный поток. И тут мидлет вдруг решает спросить у пользователя разрешения на выполнение операции соединения. Без разрешения соединение не установится, а разрешить не получится, потому что системный поток заблокирован. Отсюда дедлок. Статья по этому поводу

Комментариев нет: