droidQuery: The Android port of jQuery

Preview:

DESCRIPTION

This presentation was given at DevFest Twin Cities in 2013, and introduces droidQuery - the Android port of jQuery, that allows UI manipulation and traversal of the Android layout, asynchronous REST client calls, event handling, animations, and much more.

Citation preview

droidQuery The Android port of jQuery

Presented by Phil Brown

Overview1) What, Why and How?2) Understand the Syntax3) UI Traversal & Manipulation4) Asynchronous Rest Client (Ajax)5) Everything Else

1) What, Why, and How?

WHAT IS droidQuery?❏ A port of the popular javascript library jQuery.

❏ jQuery is:“... a fast, small, and feature-rich JavaScript library [that]makes things like HTML document traversal andmanipulation, event handling, animation, and Ajax* much simpler with an easy-to-use API.”

-- www.jquery.com❏ A java library that makes things like layout traversal and

manipulation, event handling, animation, and Ajax simple to implement on Android 2.2+.

WHY DOES IT EXIST?❏ Makes developing apps faster

❏ Chaining Method calls❏ Fewer Lines of Code

❏ Simplifies common tasks❏ Asynchronous RESTful API calls❏ Animations❏ Etc

❏ Familiar syntax for web developers to learn Android development.

Without droidQuery:OnClickListener listener = new

OnClickListener() { public void onClick(View v){

Log.i(“test”, “clicked”); }

};Button b1 =

(Button) findViewById(R.id.b1);b1.setOnClickListener(listener);Button b2 =

(Button) findViewById(R.id.b2);b2.setOnClickListener(listener);Button b3 =

(Button) findViewById(R.id.b3);b3.setOnClickListener(listener);

With droidQuery:$.with(this, R.id.b1, R.id.b2, R.id.b3) .click(new Function() { public void invoke($ d, Object… args){ Log.i(“test”, “clicked”); } });

Example

HOW DOES IT WORK?❏ Ported From the jQuery Documentation❏ Made to be as syntactically like jQuery as possible

❏ No generics❏ $ for class name

❏ Reflection/Proxying Techniques for advanced CSS, Animation, and Event handling

❏ Asynchronous Rest API based on Apache HTTPClient❏ Uses NineOldAndroids to support animations and attributes for low APIs

What are my alternatives?❏ No other library offers all of the features that droidQuery provides.❏ Many libraries support Asynchronous Network Tasks

❏ Android Volley❏ Spring for Android❏ AndroidAnnotations❏ Picasso

❏ Image Specific❏ Android Query

❏ Also provides APIs similar to jQuery, but syntax is very different.

❏ For animations supporting lower APIs, you can use NineOldAndroids.

2) Understand the Syntax(And a comparison to jQuery)

In jQuery:❏ The variable ‘$’ is used as an alias to the jQuery function, and as such is

commonly used to access variables and functions within jQuery.

❏ $(“#myButton”).click(function(event) {console.log(“element clicked!”);

});

❏ droidQuery’s main class is $.java.

❏ $.with(myButton).click(new Function() {public void invoke($ d, Object… args) {

Log.i(“droidQuery”, “view clicked!”);}

};

droidQuery Syntax❏ $.java❏ Function❏ Instantiation using $.with(...)

❏ Modeled after picasso*❏ Accepts Context, View, View[], List<View>, Context and

vararg int ids, etc❏ Assumes common callback syntax for event handling:

❏ Listeners should be an inner interface of the Object ❏ public interface OnFoobarListener {

public void|boolean onFoobar();}

* - http://square.github.io/picasso/

3) UI Traversal & Manipulation

Selectors❏ Select one or multiple UI elements❏ Powerful shortcut for manipulating both individual views and groups of views❏ There are many selector methods provided by droidQuery, including:

❏ .selectVisible()❏ .union()*❏ .intersect()*❏ .id()❏ .ids()

❏ .selectAll()❏ .selectByType()❏ .selectChildren()❏ .selectEmpties()❏ .selectFocused()❏ .selectHidden()❏ .selectImages()❏ .selectOnlyChilds()❏ .selectParents()

* - special case that accepts a second droidQuery instance as a parameter.

Selector Example//Show hidden Views, Hide Shown Views$ hidden = $.with(this).selectHidden();$.with(this).selectShown().hide();hidden.show();

//Edit views that contain a LinearLayout as only subview$.with(this) .selectByType(“android.widget.LinearLayout”) .selectOnlyChilds() .selectParents().attr(“backgroundColor”, Color.RED);

Manipulate the SelectionOnce a selection has been made, these (and other) methods will manipulate each View in the selection. Think of them as setters on all the Views in the selection.

❏ .attr(“name”, value)❏ .val(Object)❏ .text(int), .text(String)❏ .html(int), .html(String)❏ .mask(...)❏ .id(int)❏ .focus()❏ .focusOut()❏ .tag(Object)

❏ .image(Drawable), .image(Bitmap), .image(String)❏ .image(String, int, int, error)

❏ Set Image to Asset, File, or URL❏ .image(List<String>, int, int, error)

❏ Set different Strings for different views in the selection

UI Manipulation Example 1@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

if (convertView == null) layout = LayoutInflater.from(mContext) .inflate(R.layout.cell, parent, false);

Message data = getItem(position);

$.with(layout, R.id.title).text(data.getTitle()) .id(R.id.image).image(data.getImageUrl());

return convertView;}

UI Manipulation Example 2String[] urls = new String[] { “http://bit.ly/mmlogo.png”, “http://bit.ly/mmicon.png”, “http://bit.ly/mmthumb.png” };

int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics());

$.with(this, R.id.logo, R.id.icon, R.id.thumb) .image(Arrays.asList(urls), px, px, new Function() { public void invoke($ d, Object… args) { Log.e(“Images”, args[0].toString()); } });

Getter ShortcutsThe setter methods discussed previously become getters (for the first View in the selection) when the last parameter is removed.

$ d = $.with(this, android.R.id.text1);CharSequence text0 = d.text();CharSequence text1 = (CharSequence) d.attr(“text”);CharSequence text2 = (CharSequence) d.val();

CSS❏ Current CSS-related Methods*

include:❏ .height()❏ .width()❏ .innerHeight()❏ .innerWidth()❏ .outerHeight()❏ .outerWidth()❏ .offset()❏ .position()❏ .scrollLeft()❏ .scrollTop()

❏ Future CSS-Related Methods include:❏ .css(String)❏ .addClass(...)❏ .hasClass(...)❏ .removeClass(...)

* All of these methods can be used to get or set the attribute

Animations$.with(this, R.id.logo)

.animate(“{ width:48dp, height:48dp }”, 400, $.Easing.BOUNCE, new Function() {

public void invoke($ d, Object… args) {d.toast(“Animation Complete”, 1);

}});

Animations, cont’d❏ Uses a JSON string specifying animation properties, end values, and

units. ❏ Units can be any of: px, %, em, dp, dip, sp, in, mm, pt, or none

(defaults to px)❏ Property names must be accessible using Getters or Setters (or via

ViewHelper, from NineOldAndroids).

❏ Additionally, an AnimationOptions Object is passed that provides parameters and callbacks for the animation, including duration, interpolator, etc - making these animation highly customizable and responsive.

Animation LonghandAnimationOptions options = new AnimationOptions();options.duration(400) .easing($.Easing.ACCELERATE_DECELERATE) .debug(true) .reverse(true) .repeatCount(2) .progress(new Function() {

public void invoke($ d, Object… args) {Log.i(“animate”, args[0]+“=”+args[1]);

} }));$.with(this).selectImages()

.animate(“{ width:200%, height:200% }”, options);

Animation ShortcutsdroidQuery includes shortcuts for common animations including:

❏ .fadeIn()❏ .fadeOut()❏ .fadeTo()❏ .fadeToggle()❏ .slideLeft()❏ .slideUp()❏ .slideRight()❏ .slideDown()

4) Asynchronous Rest Client(Port of Ajax)

The $.ajax() MethodThis method is used to start an asynchronous REST request. There are multiple parameter types this accepts, however primarily developers will use one of:

❏ AjaxOptions❏ $.ajax(new AjaxOptions().url(“http://example.com”));

❏ String❏ Does not support Functions, but may be useful where either global

event handlers are already set, or where no callbacks are needed.❏ $.ajax(“{ url:’http://www.example.com’,” +

“ type:’PUT’,” +“ data:{foo:1, bar:’example’}” +“}”);

AjaxOptions Example$.ajax(new AjaxOptions()

.url(“http://www.weath.er/getTemperature”)

.data(“{\“zipcode\”:\“55408\”}”)

.error(new Function() {public void invoke($ d, Object… args) {

AjaxError error = (AjaxError) args[0];Log.e(“Ajax”, error.toString());

}}).success(new Function() {

public void invoke($ d, Object… args) {JSONObject json = (JSONObject) args[0];Map<String, Object> data = $.map(json);Log.e(“Ajax”, “Temp: ”+ data.get(“Celsius”));

}}));

Ajax: Global Event HandlersGlobal Ajax Event Handlers:Register/Respond to Ajax Events for global requests. These are specified using the .global() method of the AjaxOptions Object.

❏ $.ajaxComplete()❏ $.ajaxBeforeSend()❏ $.ajaxError()❏ $.ajaxStart()❏ $.ajaxStop()❏ $.ajaxSuccess()

Global Event Handlers Examplepublic void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);$.ajaxStart(new Function() {

public void invoke($ d, Object… args) {setProgressBarIndeterminateVisibility(true);

}});$.ajaxStop(new Function() {

public void invoke($ d, Object… args) {setProgressBarIndeterminateVisibility(false);

}});

}

Other Ajax Methods❏ Helper Methods

❏ $.serialize()❏ $.serializeArray()

❏ Low-Level Methods❏ $.ajaxSetup()

❏ Shorthand Methods❏ $.get()❏ $.getJSON()❏ $.getScript()❏ $.post()❏ $.load()

AjaxOptions options = new AjaxOptions();Integer[] timeouts = new Integer[]{480,419,504,503,522,598,599};options.error(new Function() {

public void invoke($ d, Object… args) {AjaxError error = (AjaxError) args[0];Log.e(“Ajax Error”, error.toString());

}}.statusCode(timeouts, new function() {

public void invoke($ d, Object… args) {Log.e(“Ajax Error”,“Timeout(“+args[0]+

“)”);AjaxOptions o = (AjaxOptions) args[1];$.ajax(o.statusCode(timeouts, $.noop()));

}}));$.ajaxSetup(options);

droidQuery Ajax AdditionsAdditionally, droidQuery provides advanced caching and redundancy handling.❏ Caching

❏ Saves statically - not persistent across JVM sessions❏ Customizable

❏ ON/OFF❏ Timeout Interval❏ Per-Request caching technique (timeout, never timeout, only delete when

cache is cleared)❏ Direct access to cache

❏ Redundancy Handling❏ Ensures that only one identical request goes out at the same time❏ Customize how to handle redundant requests

❏ Respond-To-All (default), Respond-To-First, Off

5) Everything Else(well, not everything...)

Events❏ Refers to triggering and responding to

❏ User Input Events, such as clicks and swipes❏ Changes to the layout

❏ Set or trigger an event using the following methods:❏ .bind(), .on(), .one(), .change(), .click(), .longclick(), .swipe(), .

swipeLeft(), .swipeUp(), .swipeRight(), .swipeDown(), .focus(), .focusout(), .keydown(), .keyup(), .keypress()

❏ Relies on standard Callback syntax to create proxies for the bind(), on(), and one() methods.

❏ Using some of these methods will change a View’s existing onTouchListener.

Event Example (1 of 2)Function clickListener = new Function() {

public void invoke($ d, Object… args) {d.toast(“a button was clicked!”, Toast.LENGTH_SHORT);

}};

$ d = $.with(this).selectByType(Button.class);//any of the below result in the same functionalityd.click(clickListener);d.on(“click”, clickListener);d.bind(“click”, null, clickListener);

//this will only work the first time each view:d.one(“click”, clickListener);

Event Example (2 of 2)//handle EditText edit changesView editor = findViewById(R.id.myEditText);$.with(editor).change(new Function() {

public void invoke($ d, Object… args) {Log.i(“Change”, “EditText changed to: ” + d.text());}

});

FormsA Form layout allows quick creation of UI forms, plus simple validation. <self.philbrown.view.Form xmlns:android="http://schemas.android.com/apk/res/android" xmlns:droidQuery="http://schemas.android.com/apk/res-auto" android:id=”@+id/form” android:layout_width=”match_parent” android:layout_height=”match_parent” > <EditText android:layout_width=”wrap_content” android:layout_height=”wrap_content” droidQuery:layout_form_required=”true”/> </self.philbrown.view.Form>

//Then in code:boolean isValid = ((Form) findViewById(R.id.form)).validate();

Utilities

❏ Methods❏ .view(int)❏ .each(Function)❏ .parseJSON(String)❏ .parseXML(String)❏ .parseHTML(String)❏ $.map(JSONObject)❏ $.makeArray(JSONArray)❏ .data(), .data(Object)

Many additional classes and methods are bundled with droidQuery that can help simplify development:

❏ Classes❏ QuickMap/QuickEntry

❏ Map<String, ?> map = $.qm($.qe(“foo”, “bar”),

$.qe(“first”, 1));

❏ SwipeInterceptorView❏ EventCenter❏ Callbacks

droidQuery Extensions❏ Your project can be a droidQuery extension

1. Create a new library project2. Create a new Object that extends $Extension3. Override methods4. Include in app build path5. Access library code through droidQuery API

❏ Examples available on Github.

What’s next?❏ Finish CSS Integration❏ Update javaQuery (http://bit.ly/javaquery)❏ iQuery (Objective-c++)

❏ UITextView *view = [[UITextView] alloc] init];$ *d = new $(view);NSString *text;text = d->attr(@“text”, @“foobar”).attr(@“text”);NSLog(@“text=’%@’”, text);

❏ jQuery to (droid,java,i)Query generation? ❏ Hybrid jQuery/(droid,java,i)Query apps?

Thank You❏ droidQuery is still a work in progress. If you would like to contribute

❏ please start by watching the github repo (http://bit.ly/droidquery).❏ Use the @Modified annotation packaged with the project, to mark

your changes to the code.❏ Javadocs from most recent release are available at http://bit.ly/droidquery-

docs.

❏ Open Source Libraries that are used by droidQuery include:❏ NineOldAndroids - http://nineoldandroids.com/❏ cwac-task - https://github.com/commonsguy/cwac-task❏ jCSS-Parser - https://github.com/phil-brown/jCSS-Parser

droidQuery

Phil Brown@PhDBrownhttps://plus.google.com/+PhilBrown1/phil.brown@mentormate.com

Questions?

Recommended