轉(zhuǎn)載自https://blog.csdn.net/tyk9999tyk/article/details/53306035
1.xUtils3簡介以及配置
1)xUtils3簡介
xutils是前幾年比較火得一個(gè)開源框架,主要分四個(gè)重要的模塊:ViewUtils,HttpUtils,BitmapUtils,DbUtils,包含了很多實(shí)用的工具類,支持大文件上傳,且有更全面的http請求協(xié)議支持,擁有靈活的Orm,支持事件注解且不受代碼混淆影響。
但是Github上面的xutils已經(jīng)很久沒有更新了,并且隨著Android版本的升級和人們開發(fā)軟件思想的轉(zhuǎn)變,xutils也暴露出了些許的問題,例如xutils對Android6.0的兼容性就不是特別好,所以還是建議大家使用比較新的xutils3。下面來看看官方(https://github.com/wyouflf/xUtils3)對xUtils3的介紹:
* xUtils包含了很多實(shí)用的android工具;
* xUtils支持超大文件(超過2G)上傳,更全面的http請求協(xié)議支持(11種謂詞),擁有更加靈活的ORM, 更多的事件注解支持且不受混淆影響;
* xUtils 最低兼容Android 4.0 (api level 14);
* xUtils3變化較多所以建立了新的項(xiàng)目不在舊版(github.com/wyouflf/xUtils)上繼續(xù)維護(hù), 相對于舊版本:
* HTTP實(shí)現(xiàn)替換HttpClient為UrlConnection, 自動(dòng)解析回調(diào)泛型, 更安全的斷點(diǎn)續(xù)傳策略;
*?支持標(biāo)準(zhǔn)的Cookie策略, 區(qū)分domain, path;
*?事件注解去除不常用的功能, 提高性能;
*?數(shù)據(jù)庫api簡化提高性能, 達(dá)到和greenDao一致的性能;
*?圖片綁定支持gif(受系統(tǒng)兼容性影響, 部分gif文件只能靜態(tài)顯示), webp; 支持圓角, 圓形, 方形等裁剪, 支持自動(dòng)旋轉(zhuǎn)。
2)在我們的項(xiàng)目中快速配置xUtils3
xUtils3的配置十分的簡單:
2-1)使用Gradle構(gòu)建時(shí)添加一下依賴即可
compile 'org.xutils:xutils:3.3.36'
如果使用eclipse可以點(diǎn)擊下面鏈接下載aar文件, 然后用zip解壓,取出jar包和so文件。
Github下載:https://github.com/wyouflf/xUtils3
JCenter下載:http://jcenter.bintray.com/org/xutils/xutils/
Maven下載1:http://central.maven.org/maven2/org/xutils/xutils/
Maven下載2:http://repo1.maven.org/maven2/org/xutils/xutils/
2-2)加入權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2-3)創(chuàng)建Application
public class MyApp extends Application {
? ? @Override
? ? public void onCreate() {
? ? ? ? super.onCreate();
? ? ? ? x.Ext.init(this);
? ? ? ? x.Ext.setDebug(false); //輸出debug日志,開啟會(huì)影響性能
? ? }
}
2-4)在AndroidManifest文件中注冊MyApp
<application
? ? android:name=".MyApp"
? ? ...
</application>
xUtils3主要包含注解模塊、網(wǎng)絡(luò)模塊、圖片模塊和數(shù)據(jù)庫模塊,下面將做一一說明。
2.xUtils3注解模塊的使用
xUtils3注解模塊在實(shí)際開發(fā)中的使用如下:
1)Activity的注解的使用如下:
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
? ? @ViewInject(R.id.viewpager)
? ? ViewPager viewPager;
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? //setContentView(R.layout.activity_main);
? ? ? ? x.view().inject(this);
? ? ? ? ...
? ? }
}
2)Fragment的注解的使用如下:
@ContentView(R.layout.fragment_http)
public class HttpFragment extends Fragment {
? ? @Nullable
? ? @Override
? ? public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
? ? ? ? return x.view().inject(this, inflater, container);
? ? }
? ? @Override
? ? public void onViewCreated(View v, @Nullable Bundle savedInstanceState) {
? ? ? ? super.onViewCreated(v, savedInstanceState);
? ? }
}
3)為按鈕設(shè)置點(diǎn)擊事件
方法必須私有限定,
方法參數(shù)形式必須和type對應(yīng)的Listener接口一致.
注解參數(shù)value支持?jǐn)?shù)組: value={id1, id2, id3}
/**
* 單擊事件
* type默認(rèn)View.OnClickListener.class,故此處可以簡化不寫,@Event(R.id.bt_main)
*/
@Event(type = View.OnClickListener.class,value = R.id.bt_main)
private void testInjectOnClick(View v){
? ? Snackbar.make(v,"OnClickListener",Snackbar.LENGTH_SHORT).show();
}
/**
* 長按事件
*/
@Event(type = View.OnLongClickListener.class,value = R.id.bt_main)
private boolean testOnLongClickListener(View v){
? ? Snackbar.make(v,"testOnLongClickListener",Snackbar.LENGTH_SHORT).show();
? ? return true;
}
3.xUtils3網(wǎng)絡(luò)模塊的使用
xUtils3網(wǎng)絡(luò)模塊大大方便了在實(shí)際開發(fā)中網(wǎng)絡(luò)模塊的開發(fā),xUtils3網(wǎng)絡(luò)模塊大致包括GET請求、POST請求、如何使用其他請求方式、上傳文件、下載文件、使用緩存等功能,下面將做一一說明:
1)GET請求
RequestParams params = new RequestParams(url);
params.addQueryStringParameter("username","abc");
params.addQueryStringParameter("password","123");
x.http().get(params, new Callback.CommonCallback<String>() {
? ? @Override
? ? public void onSuccess(String result) {
? ? ? ? //解析result
? ? }
? ? //請求異常后的回調(diào)方法
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? //主動(dòng)調(diào)用取消請求的回調(diào)方法
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
下面我們來看下帶有緩存的GET請求,POST請求和其他請求方式類似,后面就不再贅述:
帶有緩存的GET請求:
RequestParams params = new RequestParams(url);
params.addQueryStringParameter("username","abc");
params.addQueryStringParameter("password","123");
// 默認(rèn)緩存存活時(shí)間, 單位:毫秒(如果服務(wù)器沒有返回有效的max-age或Expires則參考)
params.setCacheMaxAge(1000 * 60);
x.http().get(params, new Callback.CacheCallback<String>() {
? ? private boolean hasError = false;
? ? private String result = null;
? ? @Override
? ? public boolean onCache(String result) { //得到緩存數(shù)據(jù), 緩存過期后不會(huì)進(jìn)入
? ? ? ? this.result = result;
? ? ? ? return true; //true: 信任緩存數(shù)據(jù), 不再發(fā)起網(wǎng)絡(luò)請求; false不信任緩存數(shù)據(jù)
? ? }
? ? @Override
? ? public void onSuccess(String result) {
? ? ? ? //如果服務(wù)返回304或onCache選擇了信任緩存,這時(shí)result為null
? ? ? ? Log.i("JAVA", "開始請求");
? ? ? ? if (result != null) {
? ? ? ? ? ? this.result = result;
? ? ? ? }
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? ? ? hasError = true;
? ? ? ? Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
? ? ? ? if (ex instanceof HttpException) { //網(wǎng)絡(luò)錯(cuò)誤
? ? ? ? ? ? HttpException httpEx = (HttpException) ex;
? ? ? ? ? ? int responseCode = httpEx.getCode();
? ? ? ? ? ? String responseMsg = httpEx.getMessage();
? ? ? ? ? ? String errorResult = httpEx.getResult();
? ? ? ? ? ? //...
? ? ? ? } else { //其他錯(cuò)誤
? ? ? ? ? ? //...
? ? ? ? }
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? ? ? if (!hasError && result != null) {
? ? ? ? ? ? //成功獲取數(shù)據(jù)
? ? ? ? ? ? Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
? ? ? ? }
? ? }
});
上面onCache方法中需要注意的幾點(diǎn):
a)如果服務(wù)端沒有返回過期時(shí)間,參考params.setCacheMaxAge(maxAge)方法。
b)客戶端會(huì)根據(jù)服務(wù)端返回的header中max-age或expires來確定本地緩存是否給onCache方法。如果服務(wù)端沒有返回max-age或expires,那么緩存將一直保存,除非這里自己定義了返回false,那么xUtils將請求新數(shù)據(jù), 來覆蓋它。
c)如果信任該緩存返回true,將不再請求網(wǎng)絡(luò)。返回false繼續(xù)請求網(wǎng)絡(luò),但會(huì)在請求頭中加上ETag,Last-Modified等信息。如果服務(wù)端返回304,則表示數(shù)據(jù)沒有更新,不繼續(xù)加載數(shù)據(jù)。
2)POST請求
RequestParams params = new RequestParams(url);
params.addBodyParameter("username","abc");
params.addParameter("password","123");
params.addHeader("head","android"); //為當(dāng)前請求添加一個(gè)頭
x.http().post(params, new Callback.CommonCallback<String>() {
? ? @Override
? ? public void onSuccess(String result) {
? ? ? ? //解析result
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
3)其他網(wǎng)絡(luò)請求方式
RequestParams params = new RequestParams(url);
params.addParameter("username","abc");
x.http().request(HttpMethod.PUT, params, new Callback.CommonCallback<String>() {
? ? @Override
? ? public void onSuccess(String result) {
? ? ? ? //解析result
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
4)上傳文件
String path="/mnt/sdcard/Download/icon.jpg";
RequestParams params = new RequestParams(url);
params.setMultipart(true);
params.addBodyParameter("file",new File(path));
x.http().post(params, new Callback.CommonCallback<String>() {
? ? @Override
? ? public void onSuccess(String result) {
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
5)下載文件
這里以下載apk為例進(jìn)行說明,apk下載完成后,自動(dòng)調(diào)用系統(tǒng)的安裝方法。
url = "http://127.0.0.1/server/abc.apk";
RequestParams params = new RequestParams(url);
//自定義保存路徑,Environment.getExternalStorageDirectory():SD卡的根目錄
params.setSaveFilePath(Environment.getExternalStorageDirectory()+"/myapp/");
//自動(dòng)為文件命名
params.setAutoRename(true);
x.http().post(params, new Callback.ProgressCallback<File>() {
? ? @Override
? ? public void onSuccess(File result) {
? ? ? ? //apk下載完成后,調(diào)用系統(tǒng)的安裝方法
? ? ? ? Intent intent = new Intent(Intent.ACTION_VIEW);
? ? ? ? intent.setDataAndType(Uri.fromFile(result), "application/vnd.android.package-archive");
? ? ? ? getActivity().startActivity(intent);
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
? ? //網(wǎng)絡(luò)請求之前回調(diào)
? ? @Override
? ? public void onWaiting() {
? ? }
? ? //網(wǎng)絡(luò)請求開始的時(shí)候回調(diào)
? ? @Override
? ? public void onStarted() {
? ? }
? ? //下載的時(shí)候不斷回調(diào)的方法
? ? @Override
? ? public void onLoading(long total, long current, boolean isDownloading) {
? ? ? ? //當(dāng)前進(jìn)度和文件總大小
? ? ? ? Log.i("JAVA","current:"+ current +",total:"+total);
? ? }
});
4.xUtils3圖片模塊的使用
xUtils3圖片模塊,重點(diǎn)在于加載圖片的4個(gè)bind方法,loadDrawable與loadFIle用法和ImageOptions用法,需多加練習(xí)。
1)xUtils3 ImageOptions:
//通過ImageOptions.Builder().set方法設(shè)置圖片的屬性
ImageOptions imageOptions= new ImageOptions.Builder().setFadeIn(true).build(); //淡入效果
//ImageOptions.Builder()的一些其他屬性:
.setCircular(true) //設(shè)置圖片顯示為圓形
.setSquare(true) //設(shè)置圖片顯示為正方形
.setCrop(true).setSize(200,200) //設(shè)置大小
.setAnimation(animation) //設(shè)置動(dòng)畫
.setFailureDrawable(Drawable failureDrawable) //設(shè)置加載失敗的動(dòng)畫
.setFailureDrawableId(int failureDrawable) //以資源id設(shè)置加載失敗的動(dòng)畫
.setLoadingDrawable(Drawable loadingDrawable) //設(shè)置加載中的動(dòng)畫
.setLoadingDrawableId(int loadingDrawable) //以資源id設(shè)置加載中的動(dòng)畫
.setIgnoreGif(false) //忽略Gif圖片
.setParamsBuilder(ParamsBuilder paramsBuilder) //在網(wǎng)絡(luò)請求中添加一些參數(shù)
.setRaduis(int raduis) //設(shè)置拐角弧度
.setUseMemCache(true) //設(shè)置使用MemCache,默認(rèn)true
2)xUtils3 bind方法:
// assets file
x.image().bind(imageView, "assets://test.gif", imageOptions);
// local file
x.image().bind(imageView, new File("/sdcard/test.gif").toURI().toString(), imageOptions);
x.image().bind(imageView, "/sdcard/test.gif", imageOptions);
x.image().bind(imageView, "file:///sdcard/test.gif", imageOptions);
x.image().bind(imageView, "file:/sdcard/test.gif", imageOptions);
x.image().bind(imageView, url, imageOptions, new Callback.CommonCallback<Drawable>() {
? ? @Override
? ? public void onSuccess(Drawable result) {
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
3)xUtils3 loadDrawable方法:
x.image().loadDrawable(url, imageOptions, new Callback.CommonCallback<Drawable>() {
? ? @Override
? ? public void onSuccess(Drawable result) {
? ? ? ? imageView.setImageDrawable(result);
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
4)xUtils3 loadFile方法:
當(dāng)我們通過bind()或者loadDrawable()方法加載了一張圖片后,它會(huì)保存到本地文件中,那當(dāng)我需要這張圖片時(shí),就可以通過loadFile()方法進(jìn)行查找。
x.image().loadFile(url,imageOptions,new Callback.CacheCallback<File>(){
? ? @Override
? ? public boolean onCache(File result) {
? ? ? ? //在這里可以做圖片另存為等操作
? ? ? ? Log.i("JAVA","file:"+result.getPath()+result.getName());
? ? ? ? return true; //相信本地緩存返回true
? ? }
? ? @Override
? ? public void onSuccess(File result) {
? ? }
? ? @Override
? ? public void onError(Throwable ex, boolean isOnCallback) {
? ? }
? ? @Override
? ? public void onCancelled(CancelledException cex) {
? ? }
? ? @Override
? ? public void onFinished() {
? ? }
});
4.xUtils3數(shù)據(jù)庫模塊的使用
1)初始化配置和創(chuàng)建實(shí)體類
首先在項(xiàng)目Application中進(jìn)行初始化配置DaoConfig(與onCreate方法同級目錄下):
/**
* 初始化DaoConfig配置
*/
DbManager.DaoConfig daoConfig = new DbManager.DaoConfig()
? ? ? ? //設(shè)置數(shù)據(jù)庫名,默認(rèn)xutils.db
? ? ? ? .setDbName("myapp.db")
? ? ? ? //設(shè)置數(shù)據(jù)庫路徑,默認(rèn)存儲(chǔ)在app的私有目錄
? ? ? ? .setDbDir(new File("/mnt/sdcard/"))
? ? ? ? //設(shè)置數(shù)據(jù)庫的版本號(hào)
? ? ? ? .setDbVersion(2)
? ? ? ? //設(shè)置數(shù)據(jù)庫打開的監(jiān)聽
? ? ? ? .setDbOpenListener(new DbManager.DbOpenListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onDbOpened(DbManager db) {
? ? ? ? ? ? ? ? //開啟數(shù)據(jù)庫支持多線程操作,提升性能,對寫入加速提升巨大
? ? ? ? ? ? ? ? db.getDatabase().enableWriteAheadLogging();
? ? ? ? ? ? }
? ? ? ? })
? ? ? ? //設(shè)置數(shù)據(jù)庫更新的監(jiān)聽
? ? ? ? .setDbUpgradeListener(new DbManager.DbUpgradeListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
? ? ? ? ? ? }
? ? ? ? })
? ? ? ? //設(shè)置表創(chuàng)建的監(jiān)聽
? ? ? ? .setTableCreateListener(new DbManager.TableCreateListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onTableCreated(DbManager db, TableEntity<?> table){
? ? ? ? ? ? ? ? Log.i("JAVA", "onTableCreated:" + table.getName());
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? //設(shè)置是否允許事務(wù),默認(rèn)true
? ? ? ? //.setAllowTransaction(true)
DbManager db = x.getDb(daoConfig);
然后創(chuàng)建數(shù)據(jù)庫表ChildInfo的實(shí)體類:
/**
* onCreated = "sql":當(dāng)?shù)谝淮蝿?chuàng)建表需要插入數(shù)據(jù)時(shí)候在此寫sql語句
*/
@Table(name = "child_info",onCreated = "")
public class ChildInfo {
? ? /**
? ? * name = "id":數(shù)據(jù)庫表中的一個(gè)字段
? ? * isId = true:是否是主鍵
? ? * autoGen = true:是否自動(dòng)增長
? ? * property = "NOT NULL":添加約束
? ? */
? ? @Column(name = "id",isId = true,autoGen = true,property = "NOT NULL")
? ? private int id;
? ? @Column(name = "c_name")
? ? private String cName;
? ? public ChildInfo(String cName) {
? ? ? ? this.cName = cName;
? ? }
? ? //默認(rèn)的構(gòu)造方法必須寫出,如果沒有,這張表是創(chuàng)建不成功的
? ? public ChildInfo() {
? ? }
? ? public int getId() {
? ? ? ? return id;
? ? }
? ? public void setId(int id) {
? ? ? ? this.id = id;
? ? }
? ? public String getcName() {
? ? ? ? return cName;
? ? }
? ? public void setcName(String cName) {
? ? ? ? this.cName = cName;
? ? }
? ? @Override
? ? public String toString() {
? ? ? ? return "ChildInfo{"+"id="+id+",cName='"+cName+'\''+'}';
? ? }
}
之后就能進(jìn)行創(chuàng)建和刪除數(shù)據(jù)庫的操作了:
2)創(chuàng)建數(shù)據(jù)庫
//用集合向child_info表中插入多條數(shù)據(jù)
ArrayList<ChildInfo> childInfos = new ArrayList<>();
childInfos.add(new ChildInfo("zhangsan"));
childInfos.add(new ChildInfo("lisi"));
childInfos.add(new ChildInfo("wangwu"));
childInfos.add(new ChildInfo("zhaoliu"));
childInfos.add(new ChildInfo("qianqi"));
childInfos.add(new ChildInfo("sunba"));
//db.save()方法不僅可以插入單個(gè)對象,還能插入集合
db.save(childInfos);
3)刪除數(shù)據(jù)庫
db.dropDb();
1
4)刪除表
db.dropTable(ChildInfo.class);
1
5)新增表中的數(shù)據(jù)
ChildInfo childInfo = new ChildInfo("zhangsan123");
db.save(childInfo);
1
2
6)刪除表中的數(shù)據(jù)
//第一種寫法:
db.delete(ChildInfo.class); //child_info表中數(shù)據(jù)將被全部刪除
//第二種寫法,添加刪除條件:
WhereBuilder b = WhereBuilder.b();
b.and("id",">",2); //構(gòu)造修改的條件
b.and("id","<",4);
db.delete(ChildInfo.class, b);
7)修改表中的數(shù)據(jù)
//第一種寫法:
ChildInfo first = db.findFirst(ChildInfo.class);
first.setcName("zhansan2");
db.update(first,"c_name"); //c_name:表中的字段名
//第二種寫法:
WhereBuilder b = WhereBuilder.b();
b.and("id","=",first.getId()); //構(gòu)造修改的條件
KeyValue name = new KeyValue("c_name","zhansan3");
db.update(ChildInfo.class,b,name);
//第三種寫法:
first.setcName("zhansan4");
db.saveOrUpdate(first);
8)查詢表中的數(shù)據(jù)
//查詢數(shù)據(jù)庫表中第一條數(shù)據(jù)
ChildInfo first = db.findFirst(ChildInfo.class);
Log.i("JAVA",first.toString());
//添加查詢條件進(jìn)行查詢
List<ChildInfo> all = db.selector(ChildInfo.class).where("id",">",2).and("id","<",4).findAll();
for(ChildInfo childInfo :all){
? ? Log.i("JAVA",childInfo.toString());
}
5.xUtils3提供的其他一些方法
1)UI異步執(zhí)行
x.task().run(new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ? //異步代碼
? ? }
});
2)UI同步執(zhí)行
x.task().post(new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ? //同步代碼
? ? }
});