Home

Awesome

android-groovy-support

A support library to leverage Android development using Groovy. This is an attempt to port the features of Xtendroid to Groovy. In order to maintain performance, @CompileStatic is used to ensure that the Groovy code is statically compiled, rather than being run dynamically.

Activity and Fragment extensions

The toast, toastShort, and confirm methods are appended to Activities and Fragments as an extension, allowing you to write code such as:

    findViewById(R.id.btnExit).onClickListener = {v ->
        confirm("Are you sure you want to exit?") {
            toast("ok, bye!")
            finish()
        }
    }

Time extensions

The time extensions make it easier to work with java.util.Date objects, as in the example below:

def yesterday = 24.hours().ago()
def tomorrow = 24.hours().fromNow()
def futureDate = now + 48.days() + 20.hours() + 2.seconds()
if (futureDate - now() < 24.hours()) {
    // we are in the future!
}

Async

The Async class allows easy use of Android's AsyncTask using Groovy's closures (it is based on this):

    // run a background task
    Async.background {
        // This closure runs in a background thread, all other closures run in UI thread
        Thread.sleep(2_000)
        progress(100) // update progress
        return "I'm done!"
    } first {
        // optional closure to run onPreExecute()
        textview.setText("Loading...")
    } then { String result ->
        // optional closure for onPostExecute()
        textview.setText(result)
    } onProgress { Object[] progress ->
        // optional progress update
    } onCancelled {
        // optional closure to run when task is cancelled
    } onError { error ->
        // optional closure to handle any errors in the UI thread
        toast("ERROR! ${error.class.name} ${error.message}")
    } execute() // execute the task

Async takes care of running each closure in the correct thread, handling errors, and aborting the UI thread closures if the task has been cancelled.

DbService

A light-weight ORM solution is implemented by utilising the Abatis project (a fork of which is included).

Step 1: Initialize the database

In a string resource file (e.g. res/values/sqlmaps.xml), initialize the database using the dbInitialize string name. Multiple statements can be included, separated by ; (including INSERT statements:

<resources>
    <string name="dbInitialize">
        create table users (
           id integer primary key,
           firstName text not null,
           lastName text not null,
           age number
        );

        insert into users (firstName, lastName, age) values (\'John\', \'Smith\', 25);
    </string>

    <string name="dbGetOlderThan">
      select * from users
      where age > #age#
      order by age asc
    </string>
</resources>

Step 2: Model

Create a data model (bean) for your data:

@Canonical
class User {
    long id
    String firstName
    String lastName
    int age
}

Step 3: DbService class

The DbService class can be sub-classed, or used directly to perform CRUD operations:

def db = DbService.getInstance(activity, "dbname", 1)

// get all users order by lastName
def users = db.findAll("users", "lastName asc", User)
users.each { user ->
   Log.d("db", "Got user: " + user)
}

// get all users older than 18 (uses SQL defined above)
def adults = db.executeForBeanList(R.string.dbGetOlderThan,
   [ age: 18 ], User)

adults.each { adult ->
   Log.d("db", "Got user: " + adult)
}

// alternative to above without defining an SQL string
adults = db.findByFields("users", [ 'age >': 18 ],
    "age asc", User)

// can also do paging by specifying a limit and offset, e.g.
// get top 6 to top 10 users 18 or younger
adults = db.findByFields("users", [ 'age <=': 18 ], "age desc",
    5, 5, User)

// insert a record
def johnId = db.insert("users", [
   firstName: 'John',
   lastName: 'Doe',
   age: 43
])

// get back this user
def john = db.findById("users", johnId, User)
toast("Hi " + john)

// update this user
db.update("users", [lastName: 'Smith'], johnId)

// delete this user
db.delete("users", johnId)

Work in progress

More to come...