分享好友 最新动态首页 最新动态分类 切换频道
Android App Development with Clojure
2024-12-27 02:11

I've been programming in Java since I was an undergrad in college in 2006. While working a contract job in 2011-2012 in which I was hired to work with a huge mess of Java code1, I was left wondering if Java was rotting my brain. Surely, there has got to be a better way. After an impractical detour2, I decided to take on learning Clojure, a Lisp dialect for the JVM. After a two-year journey of hacking personal projects, Clojure is now my general programming language of choice.

While learning how to write apps for Android, I was back to programming in Java and again was left thinking that there has got to be a better way! I looked into developing Android apps using Clojure. Although there is still much room for maturation, the efforts of Daniel Solano Gómez,Alex Yakuchev, and Zach Oakes show a promising future for Clojure in Android development.

Prerequisites

This tutorial is directed towards Clojure programmers who are seeking an alternative to the Java language for Android development. I will assume that you already know the basics of Clojure3 and Android.

We will be using Alex Yakushev's lein-droid tool for project management. We will also be using Alex's fork of Daniel Solano Gómez's neko library which provides function wrappers and alternatives to the Android Java API. However, neko does not replace everything as of the time of this writing and is subject to change so keep the Android docs handy. There will be some Java interop in this tutorial. We will be usingemacs with the nrepl plugin for this tutorial.

Be forewarned: some tools in this setup are still very young and are in fast development. New versions may pop up as of the time of this writing (Sep 25, 2013) and may introduce breaking changes. For your information, here are the versions of the tools that I am using:

 
           

Now that you have been forewarned, let's begin.

What are we making?

Let's make a simple event listing app. This will not be a full-fledged calendar app, but rather a simple tool to pencil in events and have them sorted in chronological order. I have a text file on my desktop that I use to pencil in dates for gigs, practices, and other events.

Our app will be based off of this simple idea.

Using lein-droid to setup our project

Alex's Tutorial is a good introduction to lein-droid. Skim through the tutorial to familiarize yourself with the basic lein-droidcommands.

This is how my ~/.lein/profiles.clj looks like:

 
           

NOTE: Change the directory to reflect your own sdk's path. And if there is a later version of lein-droid, consider using that.

Run this command at the terminal:

 
           

This will create a template file structure for an Android app. Open the project.clj file and change the neko version in :dependenciesto "3.0.0-preview1".

If you have an actual Android device at hand, connect it to your computer. If not, you can setup an emulator. Now run lein droid doall at the terminal. This will build the app, install the app to you device, and open an nREPL server within our running app.

Define the Layout

Let's open the main Clojure source file located at https://blog.csdn.net/weixin_33910460/article/details/src/events/src/clojure.main.clj in emacs and start defining the layout and the application. Now run this in emacs: M-x nrepl and enter the local machine for 'Host' and '9999' for 'Port'. Now you have a REPL inemacs which is connected to your running app. As you will see in a bit, this is neat-o torpedo.

To start evaluating definitions within our app's namespace, enter this command into the REPL: (in-ns 'org.stuff.events.main) Then, evaluate the ns form in the source file by moving the cursor after the closing parenthesis of the ns form and hitting C-x C-e.

Let's now code a definition for the layout of the app. The make-ui macro takes in a vector of elements which will be transformed into XML (learn more here). This structure can be anonymously passed into make-ui, but let's give it a named definition:

 
           

Evaluate this def form. Let's change the defactivity form to look like this:

 
           

Interactive Development

To demonstrate the power of REPL driven development, move your cursor after the closing parenthesis of the on-ui form (after the third-to-last ) from the end), then hit C-x C-e.

[pic here]

After you have finished geeking out on how cool what just happened was, let's add a button to the layout. Our def form for main-layoutshould now look like this:

 
           

Evaluate this form. Then evaluate the on-ui form to update the app. (From now on, you can assume that newly added code should be evaluated.)

[pic]

Adding Functionality

The app doesn't really do anything right now. Let's add attributes to our layout elements for functionality.

 
           

In order to access the layout by name, we added a :def attribute to our main-layout, an :id-holder flag, and a forward declaration form near the top of the source file. Additionally, our edit-text elements have :id attributes with a keyword value. The declare form allows us later to compile this code using AOT (more on using lein to build later).

With these additions, we can now access the values of these elements using .getTag. Enter some text into the edit-text fields in the running app then try these at the REPL:

[pic here]

 
           

Let's write a helper function for our convenience:

 
           

Now let's have that button do some work.

 
           

We added an :on-click attribute to our :button element whose value is a callback function. Note the forward declaration for that callback function.

Well, we know that we need to add an event to the listing. First, let's add a new element to the layout that will contain the listing. We will use an atom4 to hold the current state of the listing.

 
           

Here, we have a constructor which returns a new atom (an empty string). This enables us to have multiple listing objects to work with if we want to. In this tutorial, we will have one listing defined by (def listing (mt-listing)). The value of the listing atom is used for the :text attribute of the newly added :text-view element.

Before we define the callback function, let's play with the REPL and figure out what we actually want to do when the user hits that button. First, we want to update the listing atom with the contents of the :edit-text fields. Enter an event in the running app then run this in the REPL:

[pic here]

 
           

Next, we want to update the ui with the listing.

 
           

Let's write another helper function for setting the text of our elements.

 
           

Let's have our callback function perform these two tasks:

 
           

Now try hitting that button. Cool, huh?

[pic here]

If you need to clear your listing, just run (def listing (mt-listing)).

Hitting the button should also clear the edit fields. Let's write a function to take care of all that.

 
           

And let's have our add-event function call this.

 
           

If you're coding along at home (and I hope you are!), here is what our code should look like so far:

 
           

So far so good... So what? It might be a good idea to build your app right now by running at the terminal lein droid doall. Note that you may have to connect your REPL again after you run this command.

Just One Little Fix

If you rotated your screen, you may have noticed that the listing disappears. Let's fix that, shall we?

 
           

Rotate your screen. The REPL never ceases to amaze me.

The Date Picker

What's the point of an event listing without sorted dates? Let's use java interop to make a date picker5.

[pic of datepicker]

First, let's add some imports into our ns form:

 
           

Before we continue, let's change the defactivity form a bit so we can access our activity outside of this form.

 
           

Note that when the :def attribute is removed, we can refer to our MyActivity by myActivity. This is how we will refer to our activity in the upcoming function. Also note that re-evaluating this form may not be enough since the :on-create callback needs to be called. Rotating your screen will do!

Now we will use proxy to create an instance of an anonymous class:

 
           

Calling this function creates an instance of a date-picker object. Let's add a new button to the layout that will create then show this dialog.

 
           

Update your ui and try hitting that ... button. Now let's have that dialog update a :text-view with that chosen date.

 
           

Note that the new :text-view element and the button that spawns the picker are inside a nested :linear-layout element. Our date string will have the YYYYMMDD format. Now let's fill out that listener function in our proxy object.

 
           

Now try the date-picker again. Let's change add-event to include the date.

 
           

Here's what our source file looks like so far:

 
           

Sorting and Formatting the Listing

Now that we have dates, we can sort our listing. Let's change our mt-listing constructor to return a sorted-map atom.

 
           

We will now make a huge change to the add-event function. Are you ready? Let's leave formatting out of this and only deal with updating our data structure. The keys to our map will be an integer representing the date. Each date should be able to hold multiple events, so the value of the key will be a vector of location and name vectors.

 
           

Since our listing atom no longer references a string, we need to format our map. Since our data structure contains a vector of vectors, we will implement this using nested loops. To prevent this code from looking like a monstrosity, let's split it into two functions: one to loop over the dates and another to loop over the events within each date. Here we go.

 
           

Let's replace all occurrences in our code that assumes @listing to be a string with (format-listing @listing). In our layout:

 
           

And in update-ui:

 
           

Succinctness is Power

Here is the source code so far:

 
           

This is a bit over 100 lines of code. When I first attempted to write this app using Java, I was well over 1000 lines and didn't even have all this functionality before I gave up. If succinctness really is power6, then I'm never looking back.

The source code and the entire project directory can be found on my GitHub.

Suggestions and Tips

Hopefully this is enough to get you started developing Android apps in Clojure. I leave polishing the app as an exercise for you, dear reader. To make this app actually useful, you might want to make the sorted map data structure persistent using some sort of content provider. It might also help to make the :text-view for the listing scrollable once you have a lot of events listed.

Debugging and logging

You will probably run into errors and even bugs with the tools. adb will prove to be very valuable. In a spare terminal, run this command:

 
           

neko provides logging capabilities. Add this to the :use directive in the ns form:

 
           

Add this line near the top of your source file:

 
           

Now you can write lines to adb logcat by calling something like:

 
           
I lost my REPL!

Given the instability of the current tools, runtime errors in the code, and other bugs, you will probably lose your connection to the REPL at some point during development. Follow these steps to get back into your groove. In the terminal:

 
           

And in emacs: M-x nrepl, local machine for 'Host', and '9999' for 'Port'. Now in the REPL, run:

 
           
Then evaluate the ns form to get back into your running app's namespace. The important thing to know is that all the new code you wrote after your last build has to be evaluated at the REPL in order to get back to your previous state. Running lein droid doall at the terminal at key points of development can save you some steps whenever you lose your REPL connection.

Conclusion

The tools available for Android development are still young. Needless to say, you will probably run into some issues and bugs along the way. If you are serious about pursuing this bleeding edge stuff, get connected with the maintainers of these tools. Alex Yakushev in particular has been very helpful and quick to respond to me personally as I was learning how to use lein-droid. Phil Hagelberg (a.k.a. technomancy) oflein is also pretty responsive.

Feel free to get in touch and follow me on Twitter.

Notes

1 http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html

2 http://www.niemanlab.org/2011/11/in-praise-of-impractical-programming/

3 If you don't yet know Clojure, I recommend Joy of Clojure and watching Rich Hickey's talks. Despite it's power and simplicity, I wouldn't recommend Clojure to novice programmers. One should probably be fluent in at least two or three other languages before taking on Clojure. If you really want to dive into the rabbit hole, I recommend SICP before jumping into Clojure. Learning the Clojure way is quite a journey and deserves it's own blog post.

4 Use mutable state at your own judgment. Learn more about immutability, state, and identity here.

5 For reference, this code was translated from this page.

最新文章
神马优化seo_神马优化关键词快速排名(优化神马搜索引擎关键词排名工具)
1 移动端优化紧张性随着移动互联网的快速发展,手机搜刮用户数量巨大,企业需器重手机网站,否则大概错失大量客户百度神马和搜狗是重要搜刮引擎,各具官方优化指南2 优化指南要点百度移动优化指南夸大简便域名服务器稳固HTML5顺应性呆板可
无忧建站,打造轻松高效的网站建设体验,无忧自助建站
在当今这个信息爆炸、互联网高速发展的时代,网站已成为企业、个人乃至组织展示形象、传播信息、开展业务的重要平台,对于许多非技术背景的人来说,搭建一个专业、美观、功能齐全的网站并非易事,从域名注册、服务器选择到页面设计、功能开
珠宝直播间调查③丨售卖假珠宝的淘宝网店没有工商信息,记者15分钟注册假珠宝店无需证照
红星新闻此前报道,不少中老年人热衷在各个平台的直播间购买低价珠宝玉石。受访者余大妈就曾在2年里花费超3万元购入低价珠宝,其中不乏十几元的玉髓,几十元的和田玉、玛瑙、翡翠等。 为查验这些带着鉴定证书发货的珠宝是否为真,记者将余
科普重大通报“开端棋牌可以开挂吗”详细有挂内幕
【央视新闻客户端】登录新浪财经APP 搜索【信披】查看更多考评等级  债市研判六人谈  来源:债券杂志  特邀专家:  李东荣 中国人民银行原副行长、中国互联网金融协会创始会长  黄艺明 广发银行信用卡中心资产管理部副总经理  
比本科还牛的专科学校(比较牛的专科学校) 全国最好的大专排名一览表
今天大学科目网小编整理了比本科还牛的专科学校(比较牛的专科学校) 全国最好的大专排名一览表相关信息,希望在这方面能够更好帮助到大家。1、比本科还牛的专科学校(比较牛的专科学校)2、广州番禺职业技术学院王牌专业排名一览表3、全国
搜索广告召回技术在美团的实践
从美团流量场景角度来看,美团搜索广告分为两大类,一是列表推荐广告;二是搜索广告。推荐广告以展现商家模式为主,通常叫商家流。搜索广告的展现形式比较丰富,有商家模式,即以商家展现为主,
百度、吉利就“极越汽车”发表联合声明
集度汽车有限公司是百度控股与吉利控股投资设立的造车新势力初创公司,是探索汽车智能化转型的创新产物。由于行业竞争格局发生巨大变化,既定商业计划无法执行,经营遇到了挑战。极越汽车产品由吉利工厂制造,授权集度独家经营。百度、吉利
阿里云搜索是什么,与百度搜索有什么不同
阿里云搜索是阿里开发的提供给网购人群的一个专属的搜索引擎。
成品网站1.1.719:10分钟打造你的专属平台,原来建站竟然如此简单!
你想要拥有一个高端、精美、实用的网站?但繁琐的建站过程、昂贵的开发费用和专业技能的缺乏总让人头疼。其实,搭建网站也能像组装乐高一样简单有趣!成品网站1.1.719就是一款能快速帮你实现梦想的网站构建工具。这款神器就像一个建站百宝箱
剧本写作生成器app免费
剧本写作生成器app是一款免费的智能剧本生成软件。操作较为简单,用户只需简单描述角色的性格、外貌、背景等基本信息,AI就能快速生成人物形象,输入关键词即可生成各类剧本,涵盖悬疑推理、浪漫爱情等多种类型。在软件主页点击特定位置可
相关文章
推荐文章
发表评论
0评