• Stars
    star
    242
  • Rank 161,169 (Top 4 %)
  • Language Xtend
  • License
    MIT License
  • Created over 10 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Xtendroid is a DSL (domain-specific language) for Android that greatly reduces boilerplate code while providing great tooling support

Xtendroid

Xtendroid is a DSL (domain-specific language) for Android that is implemented using the Xtend transpiler, which features extension methods and active annotations (edit-time code generators) that expand out to Java code during editing or compilation. Active annotations, in particular, make Xtend more suitable for DSL creation than languages like Kotlin or Groovy (e.g. see @AndroidActivity). Xtendroid supports both Eclipse and IntelliJ/Android Studio, including code completion, debugging, and so on.

Xtendroid can replace dependency injection frameworks like RoboGuice, Dagger, and Android Annotations, with lazy-loading getters that are automatically generated for widgets in your layouts. With Xtend's lambda support and functional-style programming constructs, it reduces/eliminates the need for libraries like RetroLambda and RxJava. With it's database support, Xtendroid also removes the need for ORM libraries.

Features by example

Anonymous inner classes (lambdas)

Android code:

// get button widget, set onclick handler to toast a message
Button myButton = (Button) findViewById(R.id.my_button);

myButton.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
      Toast.makeText(this, "Hello, world!", Toast.LENGTH_LONG).show();
   }
});

Xtendroid code:

import static extension org.xtendroid.utils.AlertUtils.* // for toast(), etc.

// myButton references getMyButton(), a lazy-getter generated by @AndroidActivity
myButton.onClickListener = [View v|    // Lambda - params are optional
   toast("Hello, world!")
]

Note: Semi-colons optional, compact and differentiating lambda syntax, getters/setters as properties.

Type Inference

Android code:

// Store JSONObject results into an array of HashMaps
ArrayList<HashMap<String,JSONObject>> results = new ArrayList<HashMap<String,JSONObject>>();

HashMap<String,JsonObject> result1 = new HashMap<String,JSONObject>();
result1.put("result1", new JSONObject());
result2.put("result2", new JSONObject());

results.put(result1);
results.put(result2);

Xtendroid (Xtend) code:

var results = #[
    #{ "result1" -> new JSONObject },
    #{ "result2" -> new JSONObject }
]

Note: compact notation for Lists and Maps, method call brackets are optional

Multi-threading

Blink a button 3 times (equivalent Android code is too verbose to include here):

import static extension org.xtendroid.utils.AsyncBuilder.*

// Blink button 3 times using AsyncTask
async [
    // this is the doInBackground() code, runs in the background
    for (i : 1..3) { // number ranges, nice!
        runOnUiThread [ myButton.pressed = true ]
        Thread.sleep(250) // look ma! no try/catch!
        runOnUiThread [ myButton.pressed = false ]
        Thread.sleep(250)
    }
    
    return true
].then [result|
    // This is the onPostExecute() code, runs on UI thread
    if (result) {
        toast("Done!")
    }
].onError [error|
    toast("Oops! " + error.message)
].start()

Note: sneaky throws, smoother error handling. See documentation for the many other benefits to using the AsyncBuilder.

Android boilerplate removal

Creating a Parcelable in Android:

public class Student implements Parcelable {
    private String id;
    private String name;
    private String grade;

    // Constructor
    public Student(){
    }

    // Getter and setter methods
    // ... ommitted for brevity!
    
    // Parcelling part
    public Student(Parcel in){
        String[] data = new String[3];

        in.readStringArray(data);
        this.id = data[0];
        this.name = data[1];
        this.grade = data[2];
    }

    @Оverride
    public int describeContents(){
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeStringArray(new String[] {this.id,
                                            this.name,
                                            this.grade});
    }
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public Student createFromParcel(Parcel in) {
            return new Student(in); 
        }

        public Student[] newArray(int size) {
            return new Student[size];
        }
    };
}

Xtendroid:

// @Accessors creates getters/setters, @AndroidParcelable makes it parcelable!
@Accessors @AndroidParcelable class Student {
    String id
    String name
    String grade
}

Note: the above Xtendroid code essentially generates the same Android code above, into the build/generated folder, which gets compiled normally. Full bi-directional interoperability with existing Java classes.

Functional programming

@Accessors class User {
    String username
    long salary
    int age
}

var List<User> users = getAllUsers() // from somewhere...
var result = users.filter[ age >= 40 ].maxBy[ salary ]
        
toast('''Top over 40 is «result.username» earning «result.salary»''')

Note: String templating, many built-in list comprehension functions, lambdas taking a single object parameter implicitly puts the object in scope.

Builder pattern

// Sample Builder class to create UI widgets, like Kotlin's Anko
class UiBuilder {
   def static LinearLayout linearLayout(Context it, (LinearLayout)=>void initializer) {
      new LinearLayout(it) => initializer
   }
   
   def static Button button(Context it, (Button)=>void initializer) {
      new Button(it) => initializer
   }
} 

// Now let's use it!
import static extension org.xtendroid.utils.AlertUtils.*
import static extension UiBuilder.*

contentView = linearLayout [
   gravity = Gravity.CENTER
   addView( button [
      text = "Say Hello!"
      onClickListener = [ 
         toast("Hello Android from Xtendroid!")
      ]
   ])
]

Note: You can create your own project-specific DSL!

Utilities

import static extension org.xtendroid.utils.AlertUtils.*
import static extension org.xtendroid.utils.TimeUtils.*

var Date yesterday = 24.hours.ago
var Date tomorrow = 24.hours.fromNow
var Date futureDate = now + 48.days + 20.hours + 2.seconds
if (futureDate - now < 24.hours) {
    // show an AlertDialog with OK/Cancel buttons
    confirm("Less than a day to go! Do it now?") [
        // user wants to do it now (clicked Ok)
        doIt()
    ] 
}

Note: you can easily create your own extension methods for your project.

Documentation

Xtendroid removes boilerplate code from things like activities and fragments, background processing, shared preferences, adapters (and ViewHolder pattern), database handling, JSON handling, Parcelables, Bundle arguments, and more!

View the full reference documentation for Xtendroid here.

Sample

Here's an example of an app that fetches a quote from the internet and displays it. First, the standard Android activity layout:

res/layout/activity_main.xml

<LinearLayout ...>

    <TextView
        android:id="@+id/main_quote"
        android:text="Click below to load a quote..."
        .../>

    <Button
        android:id="@+id/main_load_quote"
        android:text="Load Quote"
        ../>

</LinearLayout>

Now the activity class to fetch the quote from the internet (in a background thread), handle any errors, and display the result. Only imports and package declaration have been omitted.

MainActivity.xtend

@AndroidActivity(R.layout.activity_main) class MainActivity {

   @OnCreate   // Run this method when widgets are ready
   def init() {
        // make a progress dialog
        val pd = new ProgressDialog(this)
        pd.message = "Loading quote..."
        
        // set up the button to load quotes
        mainLoadQuote.onClickListener = [
           // load quote in the background, showing progress dialog
           async(pd) [
              // get the data in the background
              getData('http://www.iheartquotes.com/api/v1/random')
           ].then [result|
              // update the UI with new data
              mainQuote.text = Html.fromHtml(result)
           ].onError [error|
              // handle any errors by toasting it
              toast("Error: " + error.message)
           ].start()
        ]
   }

   /**
    * Utility function to get data from the internet. In production code,
    * you should rather use something like the Volley library.
    */
   def static String getData(String url) {
      // connect to the URL
      var c = new URL(url).openConnection as HttpURLConnection
      c.connect

      if (c.responseCode == HttpURLConnection.HTTP_OK) {
         // read data into a buffer
         var os = new ByteArrayOutputStream
         ByteStreams.copy(c.inputStream, os) // Guava utility
         return os.toString
      }

      throw new Exception("[" + c.responseCode + "] " + c.responseMessage)
   }
}

Declare the activity in your AndroidManifest.xml file, add the internet permission, and that's it! Note the lack of boilerplate code and Java verbosity in things like loading layouts and finding Views, exception handling, and implementing anonymous inner classes for handlers.

This and other examples are in the examples folder. The Xtendroid Test app is like Android's API Demos app, and showcases the various features of Xtendroid.

The wiki has a list of some projects that make use of Xtendroid, including the open source WebApps app.

Getting Started

Setup Eclipse or Android Studio with the Xtend plugin.

Clone the XtendApp skeleton app to jump-start your project. It is a pre-configured skeleton Xtendroid app for Android Studio 2+.

Method 1: Copy JAR file in

Method 2: Gradle build config

  • In your build.gradle file, add a compile dependency for com.github.tobykurien:xtendroid:0.13 and also add the Xtend compiler
  • A typical build.gradle file looks as follows:
buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'
        classpath 'org.xtext:xtext-android-gradle-plugin:1.0.3'
    }
}

apply plugin: 'android'
apply plugin: 'org.xtext.android.xtend'

repositories {
    mavenCentral()
}

android {
	dependencies {
		compile 'com.github.tobykurien:xtendroid:0.13'
		
		compile 'org.eclipse.xtend:org.eclipse.xtend.lib:2.9.1'

		// other dependencies here
	}

    packagingOptions {
        // exclude files that may cause conflicts
        exclude 'LICENSE.txt'
        exclude 'META-INF/ECLIPSE_.SF'
        exclude 'META-INF/ECLIPSE_.RSA'
    } 

	// other build config stuff
}

Xtend

The latest version of Xtendroid is built with Xtend v2.9.1. For more about the Xtend language, see http://xtend-lang.org.

A port of Xtendroid to Groovy is in the works, see android-groovy-support

IDE Support

Xtend and Xtendroid are currently supported in Eclipse (Xtend is an Eclipse project) as well as Android Studio 2+ (or IntelliJ 15+). Here's how to use Xtendroid in Android Studio.

If you'd like to use Gradle for your build configuration, but still be able to develop in Eclipse, use the Eclipse AAR plugin for Gradle. This also allows you to use either Eclipse or Android Studio while maintaining a single build configuration.

Gotchas

There are currently some bugs with the Xtend editor that can lead to unexpected behaviour (e.g. compile errors). Here are the current bugs you should know about:

If in doubt, close and re-open the editor.

Some Xtend Gradle plugin gotchas:

More Repositories

1

rpi_lcars

Star Trek LCARS interface for Raspberry Pi using Pygame
Python
646
star
2

WebApps

DEPRECATED ⛔️ Android app to provide sandboxed (private) browsing of webapps
Xtend
229
star
3

SherlockNavigationDrawer

Modification of the Android NavigationDrawer sample to use ActionbarSherlock so that we can use the NavigationDrawer on older devices
Java
127
star
4

NSA_b_gone

A Linux shell script to improve your privacy online
Shell
83
star
5

WebMediaShare

DEPRECATED ⛔️ A fork of WebApps to allow sharing media from websites for the purpose of casting/sharing/downloading
Xtend
68
star
6

BatteryFu

BatteryFu (pronounced Battery-Foo, like in Kung-Fu) is an Android app that extends battery life (and lowers data usage) by changing always-on mobile/wifi data to periodic sync (meaning it disables your mobile data and/or Wifi, then checks your accounts every X minutes).
Java
68
star
7

GoogleApps

DEPRECATED ⛔️ An Android app to sandbox Google websites from your default browser, for privacy
Java
44
star
8

pi-tracking-telescope

An optical tracking telescope using OpenCV, Raspberry Pi, Arduino, and 3D printed parts
Python
40
star
9

MakerDroid

3D modelling and printing Android app! It allows the user to draw a shape on the device and have it printed out on a 3D printer
Python
21
star
10

Sparkler

Sparkler is an attempt to bring developer-friendliness to Java web development by using Rails/Sinatra-style Java libraries/frameworks together with Xtend to provide syntactic sugar and other fun language features (like extension methods and lambdas).
Xtend
21
star
11

rpi_tablet_os

Customization of Raspberry Pi OS for tablet use
Shell
10
star
12

baasbox_admin

An HTML 5 web component that can be used to create admin tools for BaasBox documents
HTML
7
star
13

ScriptDroid

Mobile development is too hard, especially for new developers! This project is an experiment to see how much we can simplify it for new developers, based on some of the work done in QML. It is targetted at Android and uses BeanShell Script to demonstrate some of the ideas.
Java
6
star
14

XtendApp

A skeleton Xtend app with gradle and Android Studio integration
Xtend
5
star
15

DroidOrb

Extensible, open source Android accessory
Java
4
star
16

MxitRuby

A skeleton Mxit app written in Ruby. A good starting point for your own Ruby app.
Ruby
4
star
17

android-groovy-support

A support library to leverage Android development using Groovy
Groovy
4
star
18

micropub-to-markdown

IndieWeb scripts for publishing using micropub to a static-site generator like Pelican
PHP
4
star
19

Android101

Android source material from Android 101 training
Java
3
star
20

Economics

Simulations of economics concepts using Ruby
Ruby
3
star
21

vCardImporter

Simple Firefox OS app to import contacts exported from ownCloud in vCard 3.0 format
JavaScript
2
star
22

OPHW-EL-BlueWatch

OPHW BlueMote Watch
Java
2
star
23

AndroidIntro

Code and presentation for Android Intro talk
JavaScript
1
star
24

libgdx-utils

Collection of libgdx notes and utility classes
Xtend
1
star
25

Ruby101

Introductory course to Ruby
Ruby
1
star
26

jozijs-2020

Building web apps in plain JavaScript https://www.meetup.com/Jozi-JS/events/271620720/
JavaScript
1
star
27

aircore

An Arduino sketch to drive the tachometer of a Jeep using an ignition coil pickup from the engine.
C++
1
star
28

tobykurien.github.io

CSS
1
star
29

transference

Game entry for Global Game Jam 2014
Java
1
star
30

webapp_skeleton

A minimal web application skeleton using web components and a simple router.
JavaScript
1
star
31

JoziJug

Demo app for Jozi JUG
Java
1
star