[android]Xutils具體介紹

什麼是Xutils

xUtils 包括了很是多有用的android工具,xUtils 源於Afinal框架,對Afinal進行了大量重構,使得xUtils支持大文件上傳,更全面的http請求協議支持,擁有更加靈活的ORM,不少其它的事件註解支持且不受混淆影響.java


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


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對象裏面
一、使用Class類的靜態方法: Class.forName(String name)
 二、類的語法:T.class,表明了與其匹配的Class對象
 三、使用類的實例化的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) 獲取指定公有方法git

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

經過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)sql

必定要保證方法的訪問修飾符爲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類型的。json

</span>api

解析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 onLoading(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 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<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 onLoading(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
相關文章
相關標籤/搜索