xUtils 包含了很多實用的android工具。xUtils 源於Afinal框架,對Afinal進行了大量重構,使得xUtils支持大文件上傳,更全面的http請求協議支持,擁有更加靈活的ORM,更多的事件註解支持且不受混淆影響。同時需要注意的是,xUitls最低兼容android 2.2 (api level 8) 。今天我們的主題是整體介紹下xUtils,主要介紹它重要的四大組件。具體各個組件的使用,會在之後幾天陸續爲大家奉上。下面開始:
一、ViewUtils
你受夠了重複冗長的findViewById了嘛?你受夠了各種監聽事件的綁定了嘛?在這裏,你只需要一句註解,如@ViewInject、@OnClick,就能輕鬆擺脫小白似的代碼,大大的上了一個檔次。
二、HttpUtils
支持的HTTP七種請求方式,非常便捷的滿足你的接口請求的需要。同時還支持大文件上傳下載,以及同步異步請求。
三、BitmapUtils
你的程序因OOM強制關閉過嘛?你在爲加在網絡圖片頭疼嘛?有了組件,你將永久擺脫前面的問題。
四、DbUtils
簡單易用又出色的ORM框架,真的是誰用誰知道,直接輕鬆存儲各種對象到sqlite數據庫中,同時也能非常方便的進行各種條件查詢,甚至分頁查詢,還有對錶中數據的更新刪除等操作,真正的實現。一行代碼就可以進行增刪改查。並且可通過註解自定義表名,列名,外鍵,唯一性約束,NOT NULL約束,CHECK約束等,支持事務。
由於xUtils是基於aFinal的,這個開源框架是國內的某位大神寫的,所以瞭解了aFinal之後再回頭看xUtils,纔會更有收穫。同時,也要向這位大神以及衆多的開源貢獻者致敬,有了他們的奉獻和開源的精神,才涌現出一個個耳熟能詳的更加優秀的更加穩定的框架。我們衆所周知的Linux就是這麼誕生的。
昨天對xUtils整體上做了一個簡單的介紹,今天咱們就代碼碼起,真刀實槍的也看看,看看如何快速便捷的把xUtils給集成到大家的項目中去。xUtils中有四大組件可以供我們使用,分別是ViewUtils、HttpUtils、BitmapUtils以及DbUtils。如果你沒能先讀一下我的上一篇文章,那麼請你移步過去先整體瞭解一下,再回過頭來看這篇文章,相信你回更有體會的。
下面依次開始介紹這些組件具體的使用。
一、ViewUtils android中得ioc(控制反轉)框架,可以完全使用註解的方式來完成UI的綁定和事件綁定。簡單的說,ViewUtils的功能就是做這個的,但是可以說,就這麼個功能確是能極大的簡化我們的代碼。下面我們看下具體的代碼,順便對比下註解的方式綁定ID和findViewById之間的差別。
- <span style="white-space:pre"> </span>@ViewInject(R.id.btn)
- private Button btn;
- @ViewInject(R.id.img)
- private ImageView img;
- @ViewInject(R.id.list)
- private ListView list;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- ViewUtils.inject(this);}
<span style="white-space:pre"> </span>@ViewInject(R.id.btn)
private Button btn;
@ViewInject(R.id.img)
private ImageView img;
@ViewInject(R.id.list)
private ListView list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ViewUtils.inject(this);}
- <p style="margin-top:0px; margin-bottom:0px; font-size:14px; font-family:Monaco; color:rgb(119,119,119)"></p>
<p style="margin-top:0px; margin-bottom:0px; font-size:14px; font-family:Monaco; color:rgb(119,119,119)"></p>
- </pre><pre name="code" class="java"><span style="white-space:pre"> </span>@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- btn = (Button) findViewById(R.id.btn);
- img = (ImageView) findViewById(R.id.img);
- list = (ListView) findViewById(R.id.list);
- }
</pre><pre name="code" class="java"><span style="white-space:pre"> </span>@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btn = (Button) findViewById(R.id.btn);
img = (ImageView) findViewById(R.id.img);
list = (ListView) findViewById(R.id.list);
}
如果項目中得Activity中的控件相當多,那麼想象一下代碼中累積的那一大坨就真心受不了。通過xUtils的簡單註解,就能輕鬆擺脫無盡壞味道的代碼。
注意:在使用註解綁定控件的時候,一定記得在onCreate中調用ViewUtils.inject(this);
下面我們再對比下Android中事件綁定的區別。
- <span style="white-space:pre"> </span>@OnClick({ R.id.btn, R.id.img })
- public void clickMethod(View v) {
- Toast.makeText(SecondActivity.this, "you clicked button!",
- Toast.LENGTH_SHORT).show();
- }
- @OnItemClick(R.id.list)
- public void itemClick(AdapterView<?> parent, View view, int position,long id) {
- Toast.makeText(SecondActivity.this, "position--->" + position,
- Toast.LENGTH_SHORT).show();
- }
<span style="white-space:pre"> </span>@OnClick({ R.id.btn, R.id.img })
public void clickMethod(View v) {
Toast.makeText(SecondActivity.this, "you clicked button!",
Toast.LENGTH_SHORT).show();
}
@OnItemClick(R.id.list)
public void itemClick(AdapterView<?> parent, View view, int position,long id) {
Toast.makeText(SecondActivity.this, "position--->" + position,
Toast.LENGTH_SHORT).show();
}
- <span style="white-space:pre"> </span>btn.setOnClickListener(this);
- list.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view,
- int position, long id) {
- Toast.makeText(SecondActivity.this, "position--->" + position,
- Toast.LENGTH_SHORT).show();
- }
- });<pre name="code" class="java"><span style="white-space:pre"> </span>@Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.btn:
- Toast.makeText(SecondActivity.this, "you clicked button!",
- Toast.LENGTH_SHORT).show();
- break;
- default:
- break;
- }
- }
<span style="white-space:pre"> </span>btn.setOnClickListener(this);
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(SecondActivity.this, "position--->" + position,
Toast.LENGTH_SHORT).show();
}
});<pre name="code" class="java"><span style="white-space:pre"> </span>@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn:
Toast.makeText(SecondActivity.this, "you clicked button!",
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
原本綁定Button的監聽事件要麼用醜陋的內部類,要麼Activity實現OnClickListener,在複寫的onClick方法中去根據id。而xUtils只要通過簡單的一句註解就能實現監聽事件的功能,而且可以實現多個控件共用一個監聽方法。同時xUtils提供onClick、onItemClick、onLongClick等15種事件監聽註解。
注意:在使用註解監聽事件的時候,監聽方法名是自定義的,但是一定要保證方法的訪問修飾符爲public,同時方法的參數要與Android原來的監聽方法參數一致,不僅參數類型,而且要保證參數的順序。
二、BitmapUtils 加載網絡或本地bitmap的時候無需擔心再遇到OOM的現象,管理bitmap的內存採用了LRU算法,同時也能避免列表滑動過程中發生圖片錯位等得現象。加載網絡圖片時,還可以配置運行線程的數量,緩存路徑等。。。通過BitmapUtils的各種構造器,可以很方便的創建出本地緩存路徑和緩存的大小,以及內存緩存的大小。
- <span style="white-space:pre"> </span>BitmapUtils utils = new BitmapUtils(this);
- BitmapDisplayConfig config = new BitmapDisplayConfig(this);
- config.setLoadingDrawable(getResources().getDrawable(R.drawable.loading));
- config.setLoadFailedDrawable(getResources().getDrawable(R.drawable.failed));
- config.setImageLoadCallBack(new ImageLoadCallBack() {
- @Override
- public void loadFailed(ImageView imageView, Drawable drawable) {
- }
- @Override
- public void loadCompleted(ImageView imageView, Drawable drawable,
- BitmapDisplayConfig config) {
- }
- });
- config.setBitmapMaxWidth(480);
- config.setBitmapMaxHeight(720);
- / utils.display(img, "http://img1.gtimg.com/news/pics/hv1/63/26/1451/94357968.jpg");
- utils.display(img, "http://img1.gtimg.com/news/pics/hv1/63/26/1451/94357968.jpg", config);
<span style="white-space:pre"> </span>BitmapUtils utils = new BitmapUtils(this);
BitmapDisplayConfig config = new BitmapDisplayConfig(this);
config.setLoadingDrawable(getResources().getDrawable(R.drawable.loading));
config.setLoadFailedDrawable(getResources().getDrawable(R.drawable.failed));
config.setImageLoadCallBack(new ImageLoadCallBack() {
@Override
public void loadFailed(ImageView imageView, Drawable drawable) {
}
@Override
public void loadCompleted(ImageView imageView, Drawable drawable,
BitmapDisplayConfig config) {
}
});
config.setBitmapMaxWidth(480);
config.setBitmapMaxHeight(720);
// utils.display(img, "http://img1.gtimg.com/news/pics/hv1/63/26/1451/94357968.jpg");
utils.display(img, "http://img1.gtimg.com/news/pics/hv1/63/26/1451/94357968.jpg", config);
BitmapUtils在用來加載網絡圖片時,可以配置加載圖片尺寸的大小,加載成功和失敗的回調以及加載過程中圖片的配置。同時也可以選擇不配置。
- //bitmapUtils.display(testImageView, "/sdcard/test.jpg"); //支持加載本地圖片
- // 使用ListView等容器展示圖片時可通過PauseOnScrollListener控制滑動和快速滑動過程中時候暫停加載圖片
- listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true));
- listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true), customListener);
//bitmapUtils.display(testImageView, "/sdcard/test.jpg"); //支持加載本地圖片
// 使用ListView等容器展示圖片時可通過PauseOnScrollListener控制滑動和快速滑動過程中時候暫停加載圖片
listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true));
listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true), customListener);
明天再講剩下的兩個組件:DbUtils和HttpUtils
接上回,繼續介紹xUtils的最後兩個模塊:DbUtils和HttpUtils。首先先介紹第一個SQLite數據庫操縱的簡單ORM框架,只要能理解xUtils爲我們提供的api,相信你也能熟練的把DbUtils用到項目中去。
操縱數據庫的工具類,無論多牛X,總離不開最根本的CRUD,即創建,查詢,更新和刪除。下面從這四個角度依次介紹xUtils是如何簡便持久化數據的。大家都知道,在Android裏面如果要存儲一個對象,我們需要創建一個SQLiteOpenHelper,然後還得創建一張對應對象各個屬性的表,還得繼續把我們的對象轉換成ContentValues,進而去存儲。真心是麻煩的不能再麻煩了,我們現在介紹的DbUtils就能讓你輕鬆解脫麻繩一樣的代碼。DbUtils在進行save操作的時候,會根據java反射反射出對象的各個字段,然後去查詢數據庫中是否存在這個對象類型對應的表,如果表已經存在,直接進行插入操作;如果不存在,就先動態的創建的一張對應我們對象的表,再進行插入處理。直接上代碼,大家看。
- <span style="white-space:pre"> </span>@OnClick(R.id.insert)
- public void insert(View v) {
- Student stu = null;
- for (int i = 0; i < 20; i++) {
- stu = new Student();
- stu.setAge(10 + i);
- stu.setName("jack" + i);
- mList.add(stu);
- try {
- dbUtils.save(stu);
- } catch (DbException e) {
- e.printStackTrace();
- }
- }
- }
<span style="white-space:pre"> </span>@OnClick(R.id.insert)
public void insert(View v) {
Student stu = null;
for (int i = 0; i < 20; i++) {
stu = new Student();
stu.setAge(10 + i);
stu.setName("jack" + i);
mList.add(stu);
try {
dbUtils.save(stu);
} catch (DbException e) {
e.printStackTrace();
}
}
}
注意:並不是所有的實體對象都快可以通過這種方式去存儲,一定要保證對象的類型中有int類型的id或者_id的屬性,這就對應數據庫表中的主鍵字段。如果類型中沒有id字段,可以通過@Id註解去指定一個int類型的字段作爲主鍵。如果表中的又字段不想被存儲在數據庫中,也可以通過@Transient去實現忽略。如果直接存儲一個對象的列表,這樣也是被允許的,達到批量存儲的目的。
DbUtils可以幫助對SQL語句不是很熟悉的同學快速的實現查詢,而不用去寫sql查詢語句,而且可以對查詢結果進行排序和分頁,使用簡單,功能強大。大家可以看下,下面的幾行代碼就能實現複雜的查詢功能
- <span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
- <span style="white-space:pre"> </span>dbUtils.findAll(Selector.from(Student.class)
- <span style="white-space:pre"> </span>.where("_id", "<", 10).and("age", ">", 10).orderBy("_id")
- <span style="white-space:pre"> </span>.limit(pageSize).offset(pageSize * pageIndex));
<span style="white-space:pre"> </span>dbUtils.findAll(Selector.from(Student.class)
<span style="white-space:pre"> </span>.where("_id", "<", 10).and("age", ">", 10).orderBy("_id")
<span style="white-space:pre"> </span>.limit(pageSize).offset(pageSize * pageIndex));
同樣的,也可以對數據庫中得數據進行便捷的更新。下面演示的是更新Student對應的表中的第一條記錄的age這個字段。這個比較簡單,就直接上代碼看吧。
- <span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
- <span style="white-space:pre"> </span>@OnClick(R.id.update)
- public void update(View v){
- try {
- List<Student> stus = dbUtils.findAll(Selector.from(Student.class));
- Student stu = stus.get(0);
- stu.setAge(20);
- dbUtils.update(stu);
- } catch (DbException e) {
- e.printStackTrace();
- }
- }
<span style="white-space:pre"> </span>@OnClick(R.id.update)
public void update(View v){
try {
List<Student> stus = dbUtils.findAll(Selector.from(Student.class));
Student stu = stus.get(0);
stu.setAge(20);
dbUtils.update(stu);
} catch (DbException e) {
e.printStackTrace();
}
}
最後一個就是數據的刪除。一個實體對象,一組實體對象,根據條件刪除,刪除表,刪除整個數據庫,這些操作都可以通過一句簡單的代碼來實現,看了代碼就明白了。
- <span style="white-space:pre"> </span>@OnClick(R.id.delete)
- public void delete(View v){
- try {
- List<Student> stus = dbUtils.findAll(Selector.from(Student.class));
- dbUtils.delete(stus.get(0));
- dbUtils.deleteAll(stus);
- dbUtils.deleteById(Student.class, WhereBuilder.b("age", "==", 20));
- dbUtils.dropTable(Student.class);
- dbUtils.dropDb();
- } catch (DbException e) {
- e.printStackTrace();
- }
- }
今天介紹xUtils的最後一個模塊——HttpUtils,拖了那麼久,終於要結束了。另外,碼字不易,如果大家有什麼疑問和見解,歡迎大家留言討論。HttpUtils是解決日常工作過程中繁雜的上傳下載文件以及各種Get和post請求的必備工具類,通過這個類,開源非常方便關注接口的業務,不必再再寫那麼冗長的代碼。下面全文都圍繞着四個中心點去依次展開,分別是:HttpGet請求,HttpPost請求,下載文件和上傳文件。
HttpGet請求。相信從事Android網絡應用的開發的同學對這個一定不會陌生,長期的開發會讓大家積累下一個可以複用的工具類。而xUtils就是幫助了我們把那些工具類給抽象整合成一個更具擴展性的幫助類。比如HtttpGet請求,這裏只簡要介紹下關鍵的應用方法,具體的細節還請大家自己去下載xUtils的源碼去研究研究了,我們介紹的足夠應用到我們的應用開發中去了。通常的HttpGet請求會把一系列的請求參數掛在請求地址的後面,拖出一節長長的尾巴,十分的惹人厭,這裏可以通過像HttpPost請求的參數那樣組成一個類似BasicNameValuePair的對象直接封裝到請求方法中去,省去拼接url的麻煩,同時也可以設置超時時間。另外請求的方法中提供了一個回調類,這個類中有處理不同請求結果的回調方法,比如說請求過程中的回調,請求成功的回調以及請求出現錯誤時的回調。下面直接上代碼看下。
- RequestParams params = new RequestParams();
- params.addQueryStringParameter("method", "info");
- params.addQueryStringParameter("access_token",
- "3.1042851f652496c9362b1cd77d4f849b.2592000.1377530363.3590808424-248414");
- HttpUtils http = new HttpUtils();
- http.configCurrentHttpGetCacheExpiry(1000 * 10);
- http.send(HttpRequest.HttpMethod.GET,
- "https://pcs.baidu.com/rest/2.0/pcs/quota",
- params,
- new RequestCallBack<String>() {
- @Override
- public void onStart() {
- resultText.setText("conn...");
- }
- @Override
- public void onLoading(long total, long current) {
- resultText.setText(current + "/" + total);
- }
- @Override
- public void onSuccess(String result) {
- resultText.setText("response:" + result);
- }
- @Override
- public void onFailure(HttpException error, String msg) {
- resultText.setText(msg);
- }
- });
RequestParams params = new RequestParams();
params.addQueryStringParameter("method", "info");
params.addQueryStringParameter("access_token",
"3.1042851f652496c9362b1cd77d4f849b.2592000.1377530363.3590808424-248414");
HttpUtils http = new HttpUtils();
http.configCurrentHttpGetCacheExpiry(1000 * 10);
http.send(HttpRequest.HttpMethod.GET,
"https://pcs.baidu.com/rest/2.0/pcs/quota",
params,
new RequestCallBack<String>() {
@Override
public void onStart() {
resultText.setText("conn...");
}
@Override
public void onLoading(long total, long current) {
resultText.setText(current + "/" + total);
}
@Override
public void onSuccess(String result) {
resultText.setText("response:" + result);
}
@Override
public void onFailure(HttpException error, String msg) {
resultText.setText(msg);
}
});
HttpPost請求。爲了統一請求的風格,HttpPost請求的方式和HttpGet的幾乎可以說是一模一樣,一樣提供了各種對應不同結果的回調方法,大家自己看下面的代碼就曉得了,真是一目瞭然。
- RequestParams params = new RequestParams();
- params.addQueryStringParameter("method", "mkdir");
- params.addQueryStringParameter("access_token", "3.1042851f652496c9362b1cd77d4f849b.2592000.1377530363.3590808424-248414");
- params.addBodyParameter("path", "/apps/測試應用/test文件夾");
- HttpUtils http = new HttpUtils();
- http.send(HttpRequest.HttpMethod.POST,
- "https://pcs.baidu.com/rest/2.0/pcs/file",
- params,
- new RequestCallBack<String>() {
- @Override
- public void onStart() {
- resultText.setText("conn...");
- }
- @Override
- public void onLoading(long total, long current) {
- resultText.setText(current + "/" + total);
- }
- @Override
- public void onSuccess(String result) {
- resultText.setText("upload response:" + result);
- }
- @Override
- public void onFailure(HttpException error, String msg) {
- resultText.setText(msg);
- }
- });
RequestParams params = new RequestParams();
params.addQueryStringParameter("method", "mkdir");
params.addQueryStringParameter("access_token", "3.1042851f652496c9362b1cd77d4f849b.2592000.1377530363.3590808424-248414");
params.addBodyParameter("path", "/apps/測試應用/test文件夾");
HttpUtils http = new HttpUtils();
http.send(HttpRequest.HttpMethod.POST,
"https://pcs.baidu.com/rest/2.0/pcs/file",
params,
new RequestCallBack<String>() {
@Override
public void onStart() {
resultText.setText("conn...");
}
@Override
public void onLoading(long total, long current) {
resultText.setText(current + "/" + total);
}
@Override
public void onSuccess(String result) {
resultText.setText("upload response:" + result);
}
@Override
public void onFailure(HttpException error, String msg) {
resultText.setText(msg);
}
});
下面爲大家介紹一個非常非常實用的功能,就是通過Http協議去下載文件,再也不必爲Android中下載文件而寫下一大坨一大坨的代碼,如此長的代碼調試起來真是能氣死人。還記得以前做過一個項目,有個需求就是能下載視頻的,而且還要能支持斷點下載,只寫那麼一個下載工具類就寫了一兩天,再加上調試,真心把人都給逼瘋了。要是xUtils早點在那個時候面世,想那時做那個需求也不必那麼通過。HttpUtils爲開發者提供了非常方便的下載api,可以通過簡單的幾個參數來實現下載,甚至斷點下載的功能。上代碼。
- <span style="white-space:pre"> </span>HttpHandler handler = http.download(
- downloadAddrEdit.getText().toString(),
- "/sdcard/fileexplorer.apk",
- true, // 如果目標文件存在,接着未完成的部分繼續下載。
- true, // 如果從請求返回信息中獲取到文件名,下載完成後自動重命名。
- new RequestCallBack<File>() {
- @Override
- public void onStart() {
- resultText.setText("conn...");
- }
- @Override
- public void onLoading(long total, long current) {
- resultText.setText(current + "/" + total);
- }
- @Override
- public void onSuccess(File result) {
- resultText.setText("downloaded:" + result.getPath());
- }
- @Override
- public void onFailure(HttpException error, String msg) {
- resultText.setText(error.getExceptionCode() + ":" + msg);
- }
- });
<span style="white-space:pre"> </span>HttpHandler handler = http.download(
downloadAddrEdit.getText().toString(),
"/sdcard/fileexplorer.apk",
true, // 如果目標文件存在,接着未完成的部分繼續下載。
true, // 如果從請求返回信息中獲取到文件名,下載完成後自動重命名。
new RequestCallBack<File>() {
@Override
public void onStart() {
resultText.setText("conn...");
}
@Override
public void onLoading(long total, long current) {
resultText.setText(current + "/" + total);
}
@Override
public void onSuccess(File result) {
resultText.setText("downloaded:" + result.getPath());
}
@Override
public void onFailure(HttpException error, String msg) {
resultText.setText(error.getExceptionCode() + ":" + msg);
}
});
注意:下載過程中如果需要暫停下載,也只需簡單的一行代碼來實現:mHandler.stop(),如果設置斷點下載的話,下次會重新開始的話,會自動從上次下載的斷點處繼續下載。
最後介紹的功能就是上傳文件了,這個也是在項目中也是非常常見的。比如用戶上傳頭像,再比如網盤應用需要把本地文件上傳到雲端等等。同時HttpUtils也同時爲開發者提供了上傳過程中和上傳結果的各個回調接口。大家在使用HttpUtils上傳文件的時候,只要仿照下面的代碼去碼代碼就快可以基本滿足業務的需要了。
- <strong> </strong>RequestParams params = new RequestParams();
- params.addQueryStringParameter("method", "upload");
- params.addQueryStringParameter("path", "/apps/測試應用/test.zip");
- // 請在百度的開放access_tokenapi測試頁面找到自己的access_token
- params.addQueryStringParameter("access_token", "3.1042851f652496c9362b1cd77d4f849b.2592000.1377530363.3590808424-248414");
- params.addBodyParameter("file", new File("/sdcard/test.zip"));
- HttpUtils http = new HttpUtils();
- http.send(HttpRequest.HttpMethod.POST,
- "https://pcs.baidu.com/rest/2.0/pcs/file",
- params,
- new RequestCallBack<String>() {
- @Override
- public void onStart() {
- resultText.setText("conn...");
- }
- @Override
- public void onLoading(long total, long current) {
- resultText.setText(current + "/" + total);
- }
- @Override
- public void onSuccess(String result) {
- resultText.setText("upload response:" + result);
- }
- @Override
- public void onFailure(HttpException error, String msg) {
- resultText.setText(msg);
- }
- });