首页 > 代码库 > [android]Xutils具体介绍

[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 排除相关警告

注解的声明

以@interfacekeyword的方式来定义,并声明元注解(注解的注解,用于标识注解的生命周期、使用位置等)

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
第三步:声明注解的属性及默认值
第四步:使用注解
第五步: 解析注解
<span style="font-size:14px;">@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();
		}
	}

}</span>


实例2: 高速查找UI

第一步: 创建注解@UI
第二步:创建@UI注解的解析工具类
第三步:创建BaseActivity,重写onStart()方法。并在方法中运行@UI解析工具类的方法
第四步:应用注解查找UI
<span style="font-size:14px;">(一)创建@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();
	}

}</span>

四大模块

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类型的。

</span>

解析UI凝视

ViewUtils.inject(this);

<span style="font-size:14px;">(一)在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)</span>

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控制滑动和高速滑动过程中时暂停载入图片

<span style="font-size:18px;">//仅处理与图片相关的事件,第二个參数:滚动时是否暂停,第三个參数:高速滑动时是否暂停
listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true));
//同一时候处理ListView.OnScrollListener事件
listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true, customListener));</span>

注意

BitmapLoadCallBack<T extends View>:图片载入监听器
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)
<span style="font-size:14px;">  //实例化图片显示的配置
			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); //将显示图片的配置设置到图片工具类中</span>


HttpUtils模块

模块介绍

支持同步,异步方式的请求;
支持大文件上传,上传大文件不会oom;
支持GET,POST,PUT,MOVE。COPY,DELETE。HEAD。OPTIONS。TRACE。CONNECT请求;
下载支持301/302重定向,支持设置是否依据Content-Disposition重命名下载的文件;
返回文本内容的请求(默认仅仅启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。

普通get方法

<span style="font-size:18px;">HttpUtils http = new HttpUtils();
http.send(HttpRequest.HttpMethod.GET,
    "http://www.lidroid.com",
    new RequestCallBack<String>(){
        @Override
        public void onl oading(long total, long current, boolean isUploading) {
            testTextView.setText(current + "/" + total);
        }

        @Override
        public void onSuccess(ResponseInfo<String> responseInfo) {
            textView.setText(responseInfo.result);
        }

        @Override
        public void onStart() {
        }

        @Override
        public void onFailure(HttpException error, String msg) {
        }
});</span>

post方法


<span style="font-size:18px;">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<String>() { @Override public void onStart() { testTextView.setText("conn..."); } @Override public void onl oading(long total, long current, boolean isUploading) { if (isUploading) { testTextView.setText("upload: " + current + "/" + total); } else { testTextView.setText("reply: " + current + "/" + total); } } @Override public void onSuccess(ResponseInfo<String> responseInfo) { testTextView.setText("reply: " + responseInfo.result); } @Override public void onFailure(HttpException error, String msg) { testTextView.setText(error.getExceptionCode() + ":" + msg); } });</span>


下载文件

<span style="font-size:18px;">HttpUtils http = new HttpUtils();
HttpHandler handler = http.download(url,"/data/data/package/cache/abc.apk",
    true, // 假设目标文件存在,接着未完毕的部分继续下载。

server不支持RANGE时将从新下载。 true, // 假设从请求返回信息中获取到文件名称。下载完毕后自己主动重命名。 new RequestCallBack<File>() { @Override public void onStart() { testTextView.setText("conn..."); } @Override public void onl oading(long total, long current, boolean isUploading) { testTextView.setText(current + "/" + total); } @Override public void onSuccess(ResponseInfo<File> responseInfo) { testTextView.setText("downloaded:" + responseInfo.result.getPath()); } @Override public void onFailure(HttpException error, String msg) { testTextView.setText(msg); } }); ... //调用cancel()方法停止下载 handler.cancel();</span>




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<Parent> 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<Parent> 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<DbModel> dbModels = db.findDbModelAll(Selector.from(Parent.class).groupBy("name").select("name", "count(name)"));
...

List<DbModel> dbModels = db.findDbModelAll(sql); // 自己定义sql查询
db.execNonQuery(sql) // 运行自己定义sql
...


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

[android]Xutils具体介绍