Android移动开发|[android]Xutils详细介绍

什么是Xutils xUtils 包含了很多实用的android工具,xUtils 源于Afinal框架,对Afinal进行了大量重构,使得xUtils支持大文件上传,更全面的http请求协议支持,拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响.


xUitls最低兼容android 2.2 (api level 8)



xUtils下载和引入类库
下载地址:https://github.com/wyouflf/xUtils
解压包并将xUtils-*.jar复制到项目的libs下

为什么要使用Xutils?
在aFinal基础上进行重构和扩展的框架,相比aFinal有很大的改善, 基于网路的应用,只要处理得当,能让大家彻底的摆脱各种工具类和重复代码的困扰

xUtils实现的技术(重点)
Java反射(Reflect)技术 作用

  1. 动态获取在当前Java虚拟机中的类、接口或者对象信息
  2. 解除两个类之间的耦合性,即在未得到依赖类的情况下,自身应用可以通过编译
  3. 动态依赖注入(即需要某一类对象时动态生成类实例,并设置到被依赖的类中),减少编译时的内存开销
一句话:在运行时通过类名(一般声明在了注解上)动态加载一个类。 获取Class对象的三种方式
java中,一切皆对象。也就是说,基本类型int float 等也会在jvm的内存池像其他类型一样中生成
一个Class对象。而数组等组合型数据类型也是会生成一个Class对象的,而且更令人惊讶的是,java中数组的本来面目其实就是某个类,惊讶中的惊讶是,含有相同元素的相同维数的数组还会共同享用同一个Class对象!其实根据我的臆想,数组的length性质应该就保存在这个Class对象里面
1、使用Class类的静态方法: Class.forName(String name) 2、类的语法:T.class,代表了与其匹配的Class对象 3、使用类的实例化的getClass方法: obj.getClass()

java.lang.Class类
获取类的构造器java.lang.reflect.Constructor
获取类的成员变量java.lang.reflect.Field
public Field[] getFields()获取所有的public成员变量 public Field getField(String name)获取任意public成员变量 public Field[] getDeclaredFields()获取所有的成员变量 public Field getDeclaredField(String name)获取任意指定名字的成员变量 public void setAccessible(boolean flag) 设置私有属性是否可访问 Field 重要方法set(Object obj, Object value) 字段设置为指定的新值。
获取类的方法java.lang.reflect.Method
public Method[] getMethods()获取所有的共有方法的集合 public Method getMethod(String name,Class... parameterTypes) 获取指定公有方法 public Method[] getDeclaredMethods()获取所有的方法 public Method getDeclaredMethod(String name,Class... parameterTypes) 获取任意指定方法 Method重要方法invoke(Object obj ,Object…parmasType) 执行对象的方法,第一个参数为类实例对象,第二个参数:对象方法的参数
Class类的实例化方法 newInstance()
获取类的全名:getName()
获取类的简称:getSimpleName()
获取类的包名:getPackage()




Java注解(Annotaion)技术 作用
注解相当于一种标记,程序中加了注解之即程序就有了标记,在其他程序中可以用反射来了解你的类及各种元素上的标记,一般有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。 一句话:注解是代码的描述。
常用的3个注解
@Override 重写父类或实现接口中的方法 @Deprecated 类或其成员已过时 @SuppressWarnings 排除相关警告
注解的声明
以@interface关键字的方式来定义,并声明元注解(注解的注解,用于标识注解的生命周期、使用位置等) 4种元注解
@Retention元注解
表示需要在什么级别保存该注释信息(生命周期)
RetentionPolicy.SOURCE: 停留在java源文件,编译器被丢掉
RetentionPolicy.CLASS:停留在class文件中,但会被VM丢弃(默认)
RetentionPolicy.RUNTIME:内存中的字节码,VM将在运行时也保留注解,因此可以通过反射机制读取注解的信息
@Target元注解
默认值为任何元素,表示该注解用于什么地方(类、方法、变量等)
ElementType.PACKAGE: 包声明
ElementType.TYPE: 类、接口(包括注解类型)或enum声明
ElementType.CONSTRUCTOR: 构造器声明
ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
ElementType.METHOD: 方法声明
ElementType.PARAMETER: 参数声明
ElementType.LOCAL_VARIABLE: 局部变量声明
@Documented :将注解包含在JavaDoc中
@Inheried :允许子类继承父类中的注解
实例1: 注入姓名
第一步: File->New->Annotation,给定注解名(如Name) 第二步:声明元注解,包括@Retention和@Target 第三步:声明注解的属性及默认值 第四步:使用注解 第五步: 解析注解
@Name 注解的定义,见com.qftrain.annotation.Name.java文件中代码: --------------------------------------------------------------------------------package com.qftrain.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)//运行时 @Target(ElementType.FIELD)//用于类中的属性字段 public @interface Name { //声明注解的属性 String value() default "disen"; } --------------------------------------------------------------------------------使用@Name注解和解析,见com.qftrain.test.T1.java文件中代码: -------------------------------------------------------------------------------- package com.qftrain.test; import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class T1 { @Name("你好!") //使用注解,向name属性字段中注入内容 public String name; /** * @param args */ public static void main(String[] args) {T1 t1=new T1(); //解析T1类中的注解 parseAnnotation(t1); System.out.println(t1.name); } private static void parseAnnotation(T1 t1) { try { //获取类中的相关属性成员 Field f= t1.getClass().getField("name"); f.setAccessible(true); //设置属性成员可访问//TODO 获取属性成员的注解 Annotation[] as= f.getDeclaredAnnotations(); if(as!=null && as.length>0){ Annotation a=as[0]; //如果注解存在,获取第一个注解System.out.println(a.annotationType()); //获取注解的类型String aName=a.annotationType().getName(); if(aName.equals(Name.class.getName())){ Name n=(Name)a; //如果注解是Name,则强转f.set(t1, n.value()); } }} catch (Exception e) { e.printStackTrace(); } }}



实例2: 快速查找UI 第一步: 创建注解@UI 第二步:创建@UI注解的解析工具类 第三步:创建BaseActivity,重写onStart()方法,并在方法中执行@UI解析工具类的方法 第四步:应用注解查找UI
(一)创建@UI注解,见com.qftrain.annotation.UI.java文件中的代码: ------------------------------------------------------------------------ package com.qftrain.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface UI { int id(); //View 的id String click() default "click"; }------------------------------------------------------------------------(二)创建@UI注解解析工具类,见com.qftrain.annotation.UiHandler.java文件中的代码: ------------------------------------------------------------------------------------------ package com.qftrain.annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.app.Activity; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; public class UiHandler { // 处理Activity类中成员的注解 public static void handleAnnotation(final Activity activity) {// 获取类中所有成员 Field[] fields = activity.getClass().getDeclaredFields(); for (Field f : fields) {Log.i("anno", "field-" + f.getName()); // 开启类成员属性的访问性 f.setAccessible(true); //获取属性字段的UI注解 final UI ui = f.getAnnotation(UI.class); if (ui != null) { //如果当前字段上包含UI注解Log.i("anno", "--" + ui.id()); Log.i("anno", "--" + ui.click()); try {//概据注入的id,查找Activity中View控件 View view = activity.findViewById(ui.id()); f.set(activity, view); // 设置View的实例// 查找Activity中的处理点击事件的方法 final Method method = activity.getClass() .getDeclaredMethod(ui.click(), View.class); // 判断View是否注入了点击事件 if (!(ui.click().equals("click"))) {//设置点击事件 view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try {if (method != null) { method.setAccessible(true); //设置方法可访问 method.invoke(activity, v); }} catch (Exception e) { e.printStackTrace(); } } }); }} catch (Exception e) { e.printStackTrace(); } } } }}------------------------------------------------------------------------------------------ (三)创建BaseActivity类,代码如下:package com.qftrain.ui01; import android.app.Activity; import com.qftrain.annotation.UiHandler; public class BaseActivity extends Activity { @Override protected void onStart() { super.onStart(); //解析当前类及其子类的注解 UiHandler.handleAnnotation(this); }} ------------------------------------------------------------------------------------------ (四)使用@UI注解实现查找UI控件,代码如下:package com.qftrain.ui01; import android.app.Activity; import com.qftrain.annotation.UiHandler; public class BaseActivity extends Activity { @Override protected void onStart() { super.onStart(); //解析当前类及其子类的注解 UiHandler.handleAnnotation(this); }} ------------------------------------------------------------------------------------------ package com.qftrain.ui01; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.qftrain.annotation.UI; public class MainActivity extends BaseActivity { @UI(id = R.id.tvId,click="hiClick") //注入View的id和点击事件处理方法 private TextView tv; @UI(id = R.id.prgId) private ProgressBar prg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //事件处理方法 public void hiClick(View view){ Toast.makeText(getApplicationContext(), "您击了我", 0).show(); } @Override protected void onStart() { super.onStart(); // 在代码中引用颜色资源 tv.setTextColor(getResources().getColor(R.color.yellow)); new Thread() { @Override public void run() { int p = 0; while (p <= 100) { prg.setProgress(p); prg.setSecondaryProgress(p + 5); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }p += 2; } } }.start(); }}


四大模块 ViewUtils模块 模块介绍
android中的ioc(控制反转)框架,完全注解方式就可以进行UI绑定和事件绑定; 新的事件绑定方式,使用混淆工具混淆后仍可正常工作; 目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event 查找UI控件
@ViewInject(R.id.edittext)
通过View的id,查找View
----------------------------
public class MainActivity extends Activity{
@ViewInject(R.id.tv1Id)
private TextView tv1;
@ViewInject(R.id.btn1Id)
private Button btn;
}
注册UI控件的事件
@OnClick(R.id.download_btn)
一定要保证方法的访问修饰符为public
同时方法的参数要与Android原来的监听方法参数一致,不仅参数类型,而且要保证参数的顺序
为id为btn1Id的Button控件设置点击事件处理方法
------------------------------------------------------
@OnClick(R.id.btn1Id)
public void aa(View v){
Toast.makeText(getApplicationContext(),"hello",0).show();
}
------
说明:
1) 方法的访问范围一般为public ,但如果为private也不会正常执行,因为通过反射机制获取的方法是所有方法。
2) 方法无返回类型
3) 方法的参数必须是View类型的。
解析UI注释
ViewUtils.inject(this);
(一)在Activity中注入 ------------------ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ViewUtils.inject(this); //注入view和事件 ... }(二)在Fragment中注入 ------------------ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.bitmap_fragment, container, false); // 加载fragment布局 ViewUtils.inject(this, view); //注入view和事件 ... }(三)在BaseAdapter中注入 ------------------ public View getView(int position, View convertView, ViewGroup parent) { ViewHolder vHolder=null; if(convertView==null){ convertView=LayoutInflater.from(context).inflate(R.layout.item_jx, null); vHolder=new ViewHolder(); ViewUtils.inject(vHolder, convertView); ... } ... }(四)在PreferenceFragment中注入 ------------------ public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ViewUtils.inject(this, getPreferenceScreen()); //注入view和事件 ... } ViewUtils.inject()的重载方法 ------------------ // inject(View view); // inject(Activity activity) // inject(PreferenceActivity preferenceActivity) // inject(Object handler, View view) // inject(Object handler, Activity activity) // inject(Object handler, PreferenceGroup preferenceGroup) // inject(Object handler, PreferenceActivity preferenceActivity)


BitmapUtils模块
模块介绍
加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象
支持加载网络图片和本地图片
内存管理使用lru算法,更好的管理bitmap内存
可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等.
基本使用
实例化BitmapUtils
BitmapUtils bUtils=new BitmapUtils(getApplicationContext(),"/mnt/sdcard/");
bUtils.configThreadPoolSize(5); //配置线程池大小
bUtils.configDiskCacheEnabled(true); //启用扩展存储缓存

加载网络图片
bUtils.display(imageView, "http://www.baidu.com/logo.png")
加载本地图片
bitmapUtils.display(imageView, "/sdcard/a.jpg")
加载assets中的图片:加载本地图片
bitmapUtils.display(imageView, "assets/a.jpg")
暂停加载监听
在使用ListView显示图片时,可以通过PauseOnScrollListener控制滑动和快速滑动过程中时暂停加载图片
//仅处理与图片相关的事件,第二个参数:滚动时是否暂停,第三个参数:快速滑动时是否暂停 listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true)); //同时处理ListView.OnScrollListener事件 listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true, customListener));

注意
BitmapLoadCallBack:图片加载监听器
onLoadCompleted:加载完成了,可再次添加动画显示
onLoading:显示加载图片的进度
onLoadFailed:加载失败的 处理
了解config打头的方法
BitmapGlobalConfig配置
线程加载线程数量
bUtils.configThreadPoolSize(5); //配置线程池大小

配置缓存
路径:/data/data/{package}/cache/xx
bUtils.configMemoryCacheEnabled(true)
bUtils.configDefaultCacheExpiry(100*1024); //100k
加载显示动画
bUtils.configDefaultImageLoadAnimation(Animation)
BitmapDisplayConfig配置
图片宽高
bUtils.configDefaultBitmapMaxSize(int w,int h)
bUtils.configDefaultBitmapMaxSize(BitmapSize bs)
new BitmapSize(int w,int h) 指定宽和高
BitmapCommonUtils.getScreenSize(context) 依据屏幕尺寸
默认显示图片
bUtils.configDefaultLoadingImage(int resId)
bUtils.configDefaultLoadingImage(Bitmap b)
bUtils.configDefaultLoadingImage(Drawable d)
下载失败图片
bUtils.configDefaultLoadFailedImage(int resId)
bUtils.configDefaultLoadFailedImage(Bitmap b)
bUtils.configDefaultLoadFailedImage(Drawable d)
图片保存质量
bUtils.configDefaultBitmapConfig(Bitmap.Config.RGB_565);
图片加载动画
bUtils.configDefaultImageLoadAnimation(Animation)
//实例化图片显示的配置 BitmapDisplayConfig bdConfig=new BitmapDisplayConfig(); //设置显示图片特性 bdConfig.setBitmapConfig(Bitmap.Config.ARGB_4444); bdConfig.setBitmapMaxSize(BitmapCommonUtils.getScreenSize(context)); //图片的最大尺寸 bdConfig.setLoadingDrawable(context.getResources().getDrawable(R.drawable.ic_default)); //加载时显示的图片 bdConfig.setLoadFailedDrawable(context.getResources().getDrawable(R.drawable.ic_default)); //加载失败时显示的图片 bdConfig.setAutoRotation(true); //自动旋转 bdConfig.setShowOriginal(false); //不显示源图片 bdConfig.setAnimation(AnimationUtils.loadAnimation(context, R.anim.slide_in_from_top)); //显示图片执行的动画bUtils.configDefaultDisplayConfig(bdConfig); //将显示图片的配置设置到图片工具类中



HttpUtils模块 模块介绍
支持同步,异步方式的请求;
支持大文件上传,上传大文件不会oom;
支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
普通get方法
HttpUtils http = new HttpUtils(); http.send(HttpRequest.HttpMethod.GET, "http://www.lidroid.com", new RequestCallBack(){ @Override public void onLoading(long total, long current, boolean isUploading) { testTextView.setText(current + "/" + total); }@Override public void onSuccess(ResponseInfo responseInfo) { textView.setText(responseInfo.result); }@Override public void onStart() { }@Override public void onFailure(HttpException error, String msg) { } });

post方法

RequestParams params = new RequestParams(); params.addHeader("name", "value"); params.addQueryStringParameter("name", "value"); // 只包含字符串参数时默认使用BodyParamsEntity, // 类似于UrlEncodedFormEntity("application/x-www-form-urlencoded")。 params.addBodyParameter("name", "value"); // 加入文件参数后默认使用MultipartEntity("multipart/form-data"), // 如需"multipart/related",xUtils中提供的MultipartEntity支持设置subType为"related"。 // 使用params.setBodyEntity(httpEntity)可设置更多类型的HttpEntity(如: // MultipartEntity,BodyParamsEntity,FileUploadEntity,InputStreamUploadEntity,StringEntity)。 // 例如发送json参数:params.setBodyEntity(new StringEntity(jsonStr,charset)); params.addBodyParameter("file", new File("path")); ...HttpUtils http = new HttpUtils(); http.send(HttpRequest.HttpMethod.POST, "uploadUrl....", params, new RequestCallBack() {@Override public void onStart() { testTextView.setText("conn..."); }@Override public void onLoading(long total, long current, boolean isUploading) { if (isUploading) { testTextView.setText("upload: " + current + "/" + total); } else { testTextView.setText("reply: " + current + "/" + total); } }@Override public void onSuccess(ResponseInfo responseInfo) { testTextView.setText("reply: " + responseInfo.result); }@Override public void onFailure(HttpException error, String msg) { testTextView.setText(error.getExceptionCode() + ":" + msg); } });


下载文件
HttpUtils http = new HttpUtils(); HttpHandler handler = http.download(url,"/data/data/package/cache/abc.apk", true, // 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。 true, // 如果从请求返回信息中获取到文件名,下载完成后自动重命名。 new RequestCallBack() {@Override public void onStart() { testTextView.setText("conn..."); }@Override public void onLoading(long total, long current, boolean isUploading) { testTextView.setText(current + "/" + total); }@Override public void onSuccess(ResponseInfo responseInfo) { testTextView.setText("downloaded:" + responseInfo.result.getPath()); }@Override public void onFailure(HttpException error, String msg) { testTextView.setText(msg); } }); ... //调用cancel()方法停止下载 handler.cancel();




DbUtils模块 模块介绍
android中的orm框架,一行代码就可以进行增删改查; 支持事务,默认关闭; 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名); 支持绑定外键,保存实体时外键关联实体自动保存或更新; 自动加载外键关联实体,支持延时加载; 支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。
基本使用
DbUtils db = DbUtils.create(this); User user = new User(); //这里需要注意的是User对象必须有id属性,或者有通过@ID注解的属性 user.setName("xiaoming"); user.setAge("21"); db.save(user); // 使用saveBindingId保存实体时会为实体的id赋值 ... // 查找 Parent entity = db.findById(Parent.class, parent.getId()); List list = db.findAll(Parent.class); //通过类型查找Parent Parent = db.findFirst(Selector.from(Parent.class).where("name","=","test")); // IS NULL Parent Parent = db.findFirst(Selector.from(Parent.class).where("name","=", null)); // IS NOT NULL Parent Parent = db.findFirst(Selector.from(Parent.class).where("name","!=", null)); // WHERE id<54 AND (age>20 OR age<30) ORDER BY id LIMIT pageSize OFFSET pageOffset List【Android移动开发|[android]Xutils详细介绍】 list = db.findAll(Selector.from(Parent.class) .where("id" ,"<", 54) .and(WhereBuilder.b("age", ">", 20).or("age", " < ", 30)) .orderBy("id") .limit(pageSize) .offset(pageSize * pageIndex)); // op为"in"时,最后一个参数必须是数组或Iterable的实现类(例如List等) Parent test = db.findFirst(Selector.from(Parent.class).where("id", "in", new int[]{1, 2, 3})); // op为"between"时,最后一个参数必须是数组或Iterable的实现类(例如List等) Parent test = db.findFirst(Selector.from(Parent.class).where("id", "between", new String[]{"1", "5"})); DbModel dbModel = db.findDbModelAll(Selector.from(Parent.class).select("name")); //select("name")只取出name列 List dbModels = db.findDbModelAll(Selector.from(Parent.class).groupBy("name").select("name", "count(name)")); ...List dbModels = db.findDbModelAll(sql); // 自定义sql查询 db.execNonQuery(sql) // 执行自定义sql ...



DbUtils和HttpUtils参考:http://blog.csdn.net/rain_butterfly/article/details/37812371

    推荐阅读