Android特定语言 Xtendroid

Xtendroid是一款Android的领域特定语言,它大大降低样板代码,同时提供巨大的工具支持。Xtendroid利用Xtend transpiler实现,它的特点是能够在Java代码编辑或编译期间具有拓展方法和活动注释(实时编辑代码生成器)功能。活动注释,他特别能够让Xtend比Kotlin或者Groovy语言更加适合DSL的创建。Xtendroid支持的Eclipse和IntelliJ/ Android Studio,其中包括代码完成,调试等。

举例特点

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 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) {     confirm("Less than a day to go! Do it now?") [         // user wants to do it now         doIt()     ]  }

Note: using all of the above makes writing unit tests and instrumentation tests very easy, and fun!

猜你喜欢

转载自www.cnblogs.com/1994jinnan/p/11859217.html
今日推荐