Android-Query

Android-QueryGoogle Code上的网址:https://code.google.com/archive/p/android-query

Android-QueryGitHub上的网址:https://github.com/chunjiangshieh/android-library-androidquery

Demo地址:https://github.com/chunjiangshieh/android-demo-androidquery

在前端开发中,jQuery曾经是最流行的开发库,它极大地减少了执行异步任务和操作DOM所需要的代码数量。Android-Query想要为Android开发者提供类似jQuery的功能。

Android-Query使用起来非常简单,总共的类只有26个,非常少。

1.1、AQuery

AQuery是核心类,几乎所有的操作都通过此类完成。

AQuery的实现如下:

package com.androidquery;

import android.app.Activity;
import android.content.Context;
import android.view.View;

public class AQuery extends AbstractAQuery<AQuery> {

	public AQuery(Activity act) {
		super(act);
	}

	public AQuery(View view) {
		super(view);
	}

	public AQuery(Context context) {
		super(context);
	}

	public AQuery(Activity act, View root) {
		super(act, root);
	}

}

AQuery的实现,我们看到:AQuery只提供了几个构造方法,其他所有的方法都是其父类AbstractAQuery实现的。

需要注意的是:

Activity中使用AQuery,可以调用public AQuery(Activity activity)

Fragment中使用AQuery,可以调用public AQuery(Activity activity, View root)

如果通过LayoutInflater解析了View,可以调用public AQuery(View view)

1.2、简化代码

AQuery简化了附加事件处理程序的过程。它不会构建出接口或者匿名类,我们只需要确保它们不会把事件处理程序的方法名拼写错。示例:

aq.id(R.id.button).clicked(this, "buttonClicked");

AQuery会根据条件来链接方法(conditionally chaining methods),让你可以回避所有检查。考虑一下这段代码:

aq.id(R.id.address).text(name).background(R.color.red).textColor(R.color.black).enabled(true).visible().clicked(this, "addressClicked");

如果控件地址不存在,那么后面所有设置方法和事件处理程序都会停止。尽管这可能会让调试更困难,但是它可以极大地减少了代码行数。

1.3、网络请求

AQuery还可以很容易地调用HTTP请求。它包含了针对简单和多个部分POST操作的支持, 并且能够接受二进制、JSONHTML以及XML格式的数据。

HTTP请求支持所有的请求方式,比如GETPOST FORMPOST JSONPUTDELETE等请求。

HTTP协议的详细内容,请参看:HTTP

1.3.1、GET请求

示例:

/**
 * GET请求,是异步请求
 * @param context  上下文
 * @param urlPath  URL的路径
 * @param params   URL的参数
 * @param type     返回值类型
 * @param callback 请求的回调
 */
public static <K> void asyncGet(Context context, String urlPath, List<BasicNameValuePair> params, Class<K> type, AjaxCallback<K> callback) {
	AQuery aQuery = new AQuery(context);

	String url = BASE_URL + urlPath;

	String urlParams = "";
	if (params != null && !params.isEmpty()) {
		urlParams = URLEncodedUtils.format(params, "UTF-8");
	}

	if (!TextUtils.isEmpty(urlParams)) {
		url += "?" + urlParams;
	}

	callback.url(url).type(type);
	callback.header("Accept", "*/*");
	callback.header("Connection", "Keep-Alive");
	callback.header("Authorization", "xxxxx");
	callback.header("User-Agent", "Android");
	callback.header("Referer", "http://blog.fpliu.com");

	aQuery.ajax(callback);
}
1.3.2、POST请求

POST用于提交数据,POST一般必然包含请求体,而请求体可以有多种形式:FORMJSONXML等格式化形式的字符串,或者其他自定义格式的数据形式。

1.3.2.1、FORM提交

示例一:

/**
 * POST请求,请求体是表单,是异步请求
 * @param context  上下文
 * @param urlPath  URL的路径
 * @param params   请求参数
 * @param type     返回值类型
 * @param callback 请求的回调
 */
public static <K> void asyncPostForm(Context context, String urlPath, Map<String, Object> params, Class<K> type, AjaxCallback<K> callback) {
	callback.header("Accept", "*/*");
	callback.header("Connection", "Keep-Alive");
	callback.header("Authorization", "xxxxx");
	callback.header("User-Agent", "Android");
	callback.header("Referer", "http://blog.fpliu.com");

	AQuery aQuery = new AQuery(context);
	aQuery.ajax(BASE_URL + urlPath, params, type, callback);
}

示例二:

/**
 * POST请求,请求体是表单,是异步请求
 * @param context  上下文
 * @param urlPath  URL的路径
 * @param params   请求参数
 * @param type     返回值类型
 * @param callback 请求的回调
 */
public static <K> void asyncPostForm(Context context, String urlPath, List<BasicNameValuePair> params, Class<K> type, AjaxCallback<K> callback) {
	try {
		HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
		callback.param(AQuery.POST_ENTITY, entity);
	} catch (UnsupportedEncodingException e) {
		DebugLog.e(TAG, "asyncPostForm()", e);
	}

	callback.url(BASE_URL + urlPath)
			.header("Accept", "*/*")
			.header("Connection", "Keep-Alive")
			.header("Authorization", "xxxx")
			.header("User-Agent", "Android")
			.header("Referer", "http://blog.fpliu.com")
			//其实默认就是表单提交,这个头可以不加
			.header("Content-Type", "application/x-www-form-urlencoded")
			.method(AQuery.METHOD_POST)
			.type(type);
	AQuery aQuery = new AQuery(context);
	aQuery.ajax(callback);
}
1.3.2.2、JSON提交

示例:

/**
 * POST请求,请求体是JSON,是异步请求
 * @param context     上下文
 * @param urlPath     URL的路径
 * @param json        JSON字符串,使用String类型可以支持GSON、fastJson、json-lib等库的转化,而不局限于一种
 * @param type        返回值类型
 * @param callback    请求的回调
 */
public static <K> void asyncPostJson(Context context, String urlPath, String json, Class<K> type, AjaxCallback<K> callback) {
	try {
		StringEntity stringEntity = new StringEntity(json, HTTP.UTF_8);
		stringEntity.setContentType("application/json");
		callback.param(AQuery.POST_ENTITY, stringEntity);
	} catch (UnsupportedEncodingException e) {
		DebugLog.e(TAG, "asyncPostJson()", e);
	}

	callback.url(BASE_URL + urlPath)
			.header("Accept", "*/*")
			.header("Connection", "Keep-Alive")
			.header("Authorization", "xxxx")
			.header("User-Agent", "Android")
			.header("Referer", "http://blog.fpliu.com")
			//必须加这个头
			.header("Content-Type", "application/json")
			.method(AQuery.METHOD_POST)
			.type(type);
	AQuery aQuery = new AQuery(context);
	aQuery.ajax(callback);
}
1.3.2.3、XML提交

实际上,XML提交只需要将JSON提交的头中的Content-Type修改为application/xml即可。

示例:

/**
 * POST请求,请求体是XML,是异步请求
 * @param context     上下文
 * @param urlPath     URL的路径
 * @param xml         XML字符串
 * @param type        返回值类型
 * @param callback    请求的回调
 */
public static <K> void asyncPostXml(Context context, String urlPath, String xml, Class<K> type, AjaxCallback<K> callback) {
	try {
		StringEntity stringEntity = new StringEntity(xml, HTTP.UTF_8);
		stringEntity.setContentType("application/xml");
		callback.param(AQuery.POST_ENTITY, stringEntity);
	} catch (UnsupportedEncodingException e) {
		DebugLog.e(TAG, "asyncPostXml()", e);
	}

	callback.url(BASE_URL + urlPath)
			.header("Accept", "*/*")
			.header("Connection", "Keep-Alive")
			.header("Authorization", "xxxx")
			.header("User-Agent", "Android")
			.header("Referer", "http://blog.fpliu.com")
			//必须加这个头
			.header("Content-Type", "application/xml")
			.method(AQuery.METHOD_POST)
			.type(type);
	AQuery aQuery = new AQuery(context);
	aQuery.ajax(callback);
}
1.3.2.4、Multipart提交

示例:

/**
 * POST请求,请求体是Multipart,是异步请求
 * @param context  上下文
 * @param urlPath  URL的路径
 * @param params   请求参数
 * @param type     返回值类型
 * @param callback 请求的回调
 */
public static <K> void asyncPostMultipart(Context context, String urlPath, Map<String, Object> params, Class<K> type, AjaxCallback<K> callback) {
	callback.header("Accept", "*/*");
	callback.header("Connection", "Keep-Alive");
	callback.header("Authorization", "xxxx");
	callback.header("User-Agent", "Android");
	callback.header("Referer", "http://blog.fpliu.com");

	AQuery aQuery = new AQuery(context);
	aQuery.ajax(BASE_URL + urlPath, params, type, callback);
}

AQuery会根据Map中的Value的类型不同, 自动以Multipart方式进行发送POST请求。

1.3.3、PUT请求

PUT请求与POST请求在协议本身,除了请求方法本身的不同,其他方面没有任何差别。 从Restful风格上讲:只是语义上不同,POST用于创建资源,而PUT用于更新资源。

所以将

.method(AQuery.METHOD_POST)

修改为:

.method(AQuery.METHOD_PUT)

即可。

1.3.4、DELETE请求

Delete请求用于删除资源,不应该携带大量信息,所以,一般Delete请求没有实体。

1.3.5、数据解析

由于请求的数据有可能是一个文件(File)、一张图片(Bitmap)、字符串、XMLJSON等。 而XMLJSON又涉及到解析的问题。JSON解析可以使用Google-Gsonfastjson等。

请求的时候,要求一个参数Class<K> type,它是返回的数据的类型,默认的,Android-Query只支持下面这些类型:

  • JSONObject.class
  • JSONArray.class
  • String.class
  • XmlDom
  • XmlPullParser
  • byte[].class
  • Bitmap.class
  • File.class

如果想要支持任意类型,必须实现com.androidquery.callback.Transformer接口,下面是一个实现参考:

public final class MyTransformer implements Transformer {

	private static final String TAG = MyTransformer.class.getSimpleName();

	@Override
	public <T> T transform(String url, Class<T> type, String encoding, byte[] data, AjaxStatus status) {
		Gson gson = new Gson();
		try {
			String jsonResult = new String(data);
			DebugLog.d(TAG, "result = " + jsonResult);
			return gson.fromJson(jsonResult, type);
		} catch (Exception e) {
			DebugLog.e(TAG, "transform()", e);
			return newInstance(type);
		}
	}

	private static <R> R newInstance(Class<R> clazz) {
		try {
			Constructor<R> constructor = clazz.getDeclaredConstructor();
			constructor.setAccessible(true);
			return (R) constructor.newInstance();
		} catch (Exception e) {
			DebugLog.e(TAG, "newInstance()", e);
			return null;
		}
	}
}

然后设置Transformer,如下:

callback.transformer(new MyTransformer());
1.3.6、缓存

1.3.7、同步

大部分时候,我们需要的是异步调用,但有些时候,我们也需要同步调用。

示例:

String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";

AjaxCallback<JSONObject> callback = new AjaxCallback<JSONObject>();           
callback.url(url).type(JSONObject.class);             

AQuery aQuery = new AQuery(context);
aQuery.sync(callback);
        
JSONObject result = callback.getResult();
AjaxStatus status = callback.getStatus();
1.3.8、下载文件

下载文件有单独的接口,在AQuery中有下面三个重载的接口:

public T download(String url, File target, AjaxCallback<File> cb)
public T download(String url, File target, Object handler, String callback)
public T download(String url, File target, boolean resume, AjaxCallback<File> cb)
public T download(String url, File target, boolean resume, Object handler, String callback)

调用这几个函数进行下载。resume参数表示是否要进行断点续传。

示例:

/**
 * 下载文件
 *
 * @param context  上下文
 * @param url      请求资源的路径
 * @param desFile  存储位置
 * @param callback 请求的回调
 */
public static void asyncDownload(Context context, String url, File desFile, AjaxCallback<File> callback) {
    callback.header("Accept", "*/*");
    callback.header("Connection", "Keep-Alive");
    callback.header("Authorization", "xxxxxxx");
    callback.header("User-Agent", "Android");
    callback.header("Referer", "http://blog.fpliu.com");

    AQuery aQuery = new AQuery(context);
    aQuery.download(url, desFile, true, callback);
}
1.4、加载图片

Android-Query支持异步加载图片,我们使用一行代码就能下载图片,对其进行缓存,并把它载入到控件中。

AQuery提供了下面这些重载的图片加载的函数:

public T image(int resid)
public T image(Drawable drawable)
public T image(Bitmap bm)
public T image(String url)
public T image(String url, boolean memCache, boolean fileCache)
public T image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId)
public T image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId, Bitmap preset, int animId)
public T image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId, Bitmap preset, int animId, float ratio)
public T image(String url, ImageOptions options)
public T image(BitmapAjaxCallback callback)
public T image(String url, boolean memCache, boolean fileCache, int targetWidth, int resId, BitmapAjaxCallback callback)
public T image(File file, int targetWidth)
public T image(File file, boolean memCache, int targetWidth, BitmapAjaxCallback callback)
public T image(Bitmap bm, float ratio)