суббота, 21 мая 2011 г.

Модификация атрибутов объекта в Clojure

Часто необходимо модифицировать состояние объекта, особенно когда работаешь с java библиотекой, смысл которой сводится к вызову callback'ов и необходимо сохранять промежуточное состояние между вызовами. Например SAX парсер.

Clojure определяет три способа работы с изменяемыми данными.  Это ссылки, агенты и атомы. Все они описаны в статье Алексея Отта (http://alexott.net/ru/clojure/clojure-intro/).
Для моего случая подходит синхронное изменение и заворачивать обращения  к изменяемым переменным в транзакции нет необходимости. Поэтому я буду использовать атомы(atoms).

Для примера опишем класс com.Example. Объявим одновременно пространство имен и класс(com.Example) с помощью макроса ns.

(ns com.Example
  (:gen-class
    :state state
    :init init
    :constructors {[] []}
    :methods [[setAttr [clojure.lang.Keyword int] void],
              [getAttr [clojure.lang.Keyword] int],
              [removeAttr [clojure.lang.Keyword] void]]
    :main false))

:init - имя конструктора
:state - имя атрибута для хранения состояния объекта
:constructors - описание типов параметров конструкторов класса
:methods - описание доступных методов класса, в формате [имя [тип_параметра ...] тип_возвращаемого_значения]
:main - false - не генерировать, автоматически, метод main(первый метод который будет вызван для java программы)

Теперь код объявленных выше методов.

Конструктор:

(defn -init []
[[] (atom {})])

конструктор без параметров. Конструктор класса в clojure должен вернуть вектор с двумя элементами.

[ [superclass-constructor-args] state]

Первый элемент -  еще один вектор, содержит параметры конструктора родительского класса([] - для родительского конструктора без параметров). Второй элемент - значение переменной состояния(имя которой определяется через параметр :state). В нашем случае это хеш(maps). Применение функции atoms делает состояние объекта изменяемым.

После того как state в классе объявлен как изменяемый его можно модифицировать функцией swap!.

Атрибуты объекта будут хранится как ключевые слова(keywords) а значения - это целые числа.
Методы для сохранения и получения значения атрибутов объекта будут такими:


(defn -setAttr [this attr value]
  (swap! (.state this) assoc attr value))

(defn -getAttr [this attr]
  (get @(.state this) attr))

(defn -removeAttr [this attr]
  (swap! (.state this) dissoc attr))


И маленький пример использования
user=> (def ex (com.Example.))
#'user/ex
user=> (.state ex)
#<Atom@724eb043: {}>
user=> ex
#<Example com.Example@30c06258>
user=> (.setAttr ex :a 1)
nil
user=> (.setAttr ex :b 2)
nil
user=> (.setAttr ex :super-key -9)  
nil
user=> (.state ex)
#<Atom@724eb043: {:super-key -9, :b 2, :a 1}>
user=> (.getAttr ex :b)
2
user=> (.removeAttr ex :super-key)
nil
user=> (.state ex)                
#<Atom@724eb043: {:b 2, :a 1}>

четверг, 28 апреля 2011 г.

Запуск одного Activity из другого

Для того что бы в android приложении запустить одно Activity из другого(например для навигации по интерфейсу приложения) нужно воспользоваться механизмом межпроцессной коммуникации.  Для передачи данных между процессами служит объект класса Intent. Для запроса activity, описанного в объекте класса Intent, служат методы startActivity и startActivityForResult.
Существует несколько конструкторов для создания объекта Intent. Если говорить про запуск Activity для решения задач навигации по интерфейсу(собственных интерфейсов), то можно использовать конструктор вида

 public Intent (Context packageContext, Class<?> cls)

с жестким заданием имени класса. Так же для запуска activity понадобится описать в файле AndroidManifest.xml вызываемую activity.

<activity android:name="com.example.MyExampleActivity"
android:label="@string/app_name" />

И запустить activity вызовом метода startActivity.

Код на Java для запроса activity может быть записать так:

this.startActivity(
    new Intent(this, com.example.MyExampleActivity.class)
);

На clojure запуск одной Activity из другой будет таким:

(.startActivity this (Intent. this com.example.MyExampleActivity)

this - текущая activity

понедельник, 18 апреля 2011 г.

Программирование на clojure под android

В первом посте хочу написать о том зачем эти посты вообще нужны и о чем будут последующие.

зачем: учится новому, получать обратную связь, обсуждать, решать проблемы
о чем: о программировании на clojure под android

Началось все с того что меня заинтересовала разработка под Android. Вслед за этим возник естественный вопрос на чем разрабатывать. От "официальных" языков разработки под android(Java, С++) я был далек и большого желания их изучать и применять не было. Но со времен института остался интерес к функциональным языкам. Особенно к Lisp(на котором я решал исключительно студенческие задачи). Поэтому почитав о Lisp и android побольше я нашел для себя такую связку как clojure + android.  
Clojure - функциональный язык программирования, транслируется в Java байт код, имеет глубокую интергацию с ЯП Java. Команда clojure заявляет о поддержке платформы android(точнее dalvik - виртуальной машины andorid). По причинам глубокой интеграции с java и заявлению по поддержке android думаю что clojure станет хорошей альтернативой java на android.