Clojure Dojo Liverpool - 2 September 2014
by Claudia Doppioslash
The wrapper for Android's Java API
A plugin for our trusty lein
"0.2.3"
"3.0.2"
Both developed by Alex Yakushev
Add to lein profiles.clj
Add to project.clj
Add lein droid to your lein profiles:
{:user {:plugins [ [lein-droid "0.2.3"] ]
On unix-like systems the file is at
~/.lein/profiles.clj
On Windows it should be at
%USERPROFILE%\.lein\profiles.clj
Also the path to your Android sdk:
:android {:sdk-path "/path/to/androidsdk"}}}
$ lein droid new AndroidClojureTutorial \
com.doppioslash.androidtut \
:activity Reader \
:target-sdk 17 \
:app-name AndroidClojureTutorial
com.doppioslash.androidtut
bundleID: a unique identifier for your app on the google play store
activities: units of functionality in android, roughly equivalent to views in ios
target sdk: the minimum version of the android os that the app will run on
app name: the name the app will show on the device home screen
Lein droid automatically added a whole bunch of things to the project.clj, including:
Time to connect your device to the pc with the USB cable
Whenever in doubt use DEBUG=1 before the lein droid command to see verbose output:
$ DEBUG=1 lein doall
Use
$ lein droid doall
to run the app on your device. The repl on the pc will execute the code on the actual device.
Setting up ADB for the first time might be troublesome. Some possible issues:
If you have emacs with cider do M-x cider and answer 127.0.0.1 and 9999
Depending on what version of cider and cider nrepl you have there could be some trouble.
A lein repl :connect 9999 is the equivalent..
The code you're inputing is actually running on the Android device (magic! =))
So let's try to change the activity we see on screen.
(require 'package) (add-to-list 'package-archives '("melpa-stable" . "http://melpa-stable.milkbox.net/packages/") t) (package-initialize) (unless (package-installed-p 'clojure-mode) (package-refresh-contents) (package-install 'clojure-mode)) (unless (package-installed-p 'cider) (package-refresh-contents) (package-install 'cider)) (require 'cider) (add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode) (setq cider-repl-wrap-history t) (add-hook 'cider-repl-mode-hook 'paredit-mode) (setq nrepl-buffer-name-show-port t) (setq cider-known-endpoints '(("android" "127.0.0.1" "9999")))
cider-nrepl
Add it to :plugins [[cider/cider-nrepl "0.7.0"]] in project.clj
=> (in-ns 'your-ns)
You can change the text in the text view, change the string and then C-x C-e on the ending parentesis of on-ui.
You should see it change it in real time on device.
Making layouts on Android looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a TextView" />
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button" />
</LinearLayout>
Yes, it's as painful as it looks.
Luckily enough Neko makes it looks like this:
(def main-layout [:linear-layout {:orientation :vertical
:id-holder true
:def `mylayout}
[:edit-text {:hint "Write here",:id ::edit}]
[:button {:text "Add text" :on-click (fn [_](add-text))}]
[:text-view {:text @lines,:id ::articles}]])
No extra xml files sprinkled in a hundred directories,
easy map syntax.
We'll use linear layout, which:
"is a view group that aligns all children in a single direction, vertically or horizontally. You can specify the layout direction with the android:orientation attribute."
With Neko that would look like:
[:linear-layout {:orientation :vertical}]
(declare ^android.widget.LinearLayout mylayout)
(def main-layout [:linear-layout {:orientation :vertical,
:id-holder true
:def `mylayout}])
an :id-holder flag
:def attribute
a forward declaration
(also for AOT compilation)
To access the layout by name we need:
(declare ^android.widget.LinearLayout mylayout) (declare add-text) (def lines (atom "")) (def main-layout [:linear-layout {:orientation :vertical :id-holder true :def `mylayout} [:edit-text {:hint "Write here",:id ::edit}] [:button {:text "Add text" :on-click (fn [_](add-text))}] [:text-view {:text @lines,:id ::articles}]])
We'll use the neko.ui namespace which wraps the native android java api ui.
Let's make something useful
...(make-ui main-layout)...
C-x C-e as before and it will show the new UI.
(defn get-elmt [elmt]
(str (.getText (elmt (.getTag mylayout)))))
(defn set-elmt [elmt s]
(on-ui (config (elmt (.getTag mylayout)) :text s)))
(defn update-ui []
(set-elmt ::lines @lines)
(set-elmt ::edit ""))
(defn add-text []
(swap! lines str (get-elmt ::edit) "\n")
(update-ui))
Hopefully the basic editor works and you can see how interactive developing Android with Clojure is.