droidQuery: The Android port of jQuery

40
droidQuery The Android port of jQuery Presented by Phil Brown

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.

Transcript of droidQuery: The Android port of jQuery

Page 1: droidQuery: The Android port of jQuery

droidQuery The Android port of jQuery

Presented by Phil Brown

Page 2: droidQuery: The Android port of jQuery

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

Page 3: droidQuery: The Android port of jQuery

1) What, Why, and How?

Page 4: droidQuery: The Android port of jQuery

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+.

Page 5: droidQuery: The Android port of jQuery

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.

Page 6: droidQuery: The Android port of jQuery

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

Page 7: droidQuery: The Android port of jQuery

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

Page 8: droidQuery: The Android port of jQuery

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.

Page 9: droidQuery: The Android port of jQuery

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

Page 10: droidQuery: The Android port of 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!”);}

};

Page 11: droidQuery: The Android port of jQuery

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/

Page 12: droidQuery: The Android port of jQuery

3) UI Traversal & Manipulation

Page 13: droidQuery: The Android port of jQuery

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.

Page 14: droidQuery: The Android port of jQuery

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);

Page 15: droidQuery: The Android port of jQuery

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

Page 16: droidQuery: The Android port of jQuery

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;}

Page 17: droidQuery: The Android port of jQuery

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()); } });

Page 18: droidQuery: The Android port of jQuery

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();

Page 19: droidQuery: The Android port of jQuery

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

Page 20: droidQuery: The Android port of jQuery

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);

}});

Page 21: droidQuery: The Android port of jQuery

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.

Page 22: droidQuery: The Android port of jQuery

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);

Page 23: droidQuery: The Android port of jQuery

Animation ShortcutsdroidQuery includes shortcuts for common animations including:

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

Page 24: droidQuery: The Android port of jQuery

4) Asynchronous Rest Client(Port of Ajax)

Page 25: droidQuery: The Android port of jQuery

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’}” +“}”);

Page 26: droidQuery: The Android port of jQuery

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”));

}}));

Page 27: droidQuery: The Android port of jQuery

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()

Page 28: droidQuery: The Android port of jQuery

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);

}});

}

Page 29: droidQuery: The Android port of jQuery

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);

Page 30: droidQuery: The Android port of jQuery

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

Page 31: droidQuery: The Android port of jQuery

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

Page 32: droidQuery: The Android port of jQuery

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.

Page 33: droidQuery: The Android port of jQuery

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);

Page 34: droidQuery: The Android port of jQuery

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());}

});

Page 35: droidQuery: The Android port of jQuery

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();

Page 36: droidQuery: The Android port of jQuery

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

Page 37: droidQuery: The Android port of jQuery

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.

Page 38: droidQuery: The Android port of jQuery

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?

Page 39: droidQuery: The Android port of jQuery

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