一、AsyncTask:
(一)、相關(guān)知識(shí)回顧:
1、開(kāi)發(fā)Android應(yīng)用時(shí)必須遵守單線程模型的原則:
????????Android UI操作并不是線程安全的,并且這些操作必須在UI線程中執(zhí)行。
2、單線程模型中始終要記住兩條法則:
1). 不要阻塞UI線程 ;
2). 確保只在UI線程中訪問(wèn)Android UI控件。
????????當(dāng)一個(gè)程序第一次啟動(dòng)時(shí),Android會(huì)同時(shí)啟動(dòng)一個(gè)對(duì)應(yīng)的主線程(Main Thread),主線程主要負(fù)責(zé)處理與UI相關(guān)的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,并把相關(guān)的事件分發(fā)到對(duì)應(yīng)的組件進(jìn)行處理。所以主線程通常又被叫做UI線程。
3、Android4.0以上版本中,主線程中不允許訪問(wèn)網(wǎng)絡(luò)。涉及到網(wǎng)絡(luò)操作的程序一般都是需要開(kāi)一個(gè)新線程完成網(wǎng)絡(luò)訪問(wèn)。但是在獲得頁(yè)面數(shù)據(jù)后,又不能將數(shù)據(jù)返回到UI界面中 。因?yàn)樽泳€程(Worker Thread)不能直接訪問(wèn)UI線程中的成員,也就是說(shuō)沒(méi)有辦法對(duì)UI界面上的內(nèi)容進(jìn)行操作,如果操作,將拋出異常:CalledFromWrongThreadException。
其實(shí),android提供了幾種在其他線程中訪問(wèn)UI線程的方法:
Activity.runOnUiThread( Runnable )
View.post( Runnable )
View.postDelayed( Runnable, long )
Handler消息傳遞機(jī)制(后續(xù)課程中講解)
????????這些類(lèi)或方法會(huì)使代碼很復(fù)雜很難理解。為了解決這個(gè)問(wèn)題,Android 1.5提供了一個(gè)工具類(lèi):AsyncTask,它使創(chuàng)建與用戶界面長(zhǎng)時(shí)間交互運(yùn)行的任務(wù)變得更簡(jiǎn)單。AsyncTask更輕量級(jí)一些,適用于簡(jiǎn)單的異步處理,不需要借助線程和Handler即可實(shí)現(xiàn)。
(二)、AsyncTask的代碼實(shí)現(xiàn):
1、AsyncTask是抽象類(lèi).AsyncTask定義了三種泛型類(lèi)型 Params,Progress和Result。
Params 啟動(dòng)任務(wù)執(zhí)行的輸入?yún)?shù),比如HTTP請(qǐng)求的URL。 一般用String類(lèi)型;
Progress 后臺(tái)任務(wù)執(zhí)行的百分比。 一般用Integer類(lèi)型;
Result 后臺(tái)執(zhí)行任務(wù)最終返回的結(jié)果,一般用byte[]或者String。
2、AsyncTask的執(zhí)行分為四個(gè)步驟,每一步都對(duì)應(yīng)一個(gè)回調(diào)方法(由應(yīng)用程序自動(dòng)調(diào)用的方法),開(kāi)發(fā)者需要做的就是實(shí)現(xiàn)這些方法。
1) 定義AsyncTask的子類(lèi);
2) 實(shí)現(xiàn)AsyncTask中定義的方法:(可以全部實(shí)現(xiàn),也可以只實(shí)現(xiàn)其中一部分)
onPreExecute(), 該方法將在執(zhí)行實(shí)際的后臺(tái)操作前被UI thread調(diào)用。可以在該方法中做一些準(zhǔn)備工作,如在界面上顯示一個(gè)進(jìn)度條。
doInBackground(Params...), 將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運(yùn)行在后臺(tái)線程中。這里將主要負(fù)責(zé)執(zhí)行那些很耗時(shí)的后臺(tái)計(jì)算工作??梢哉{(diào)用 publishProgress方法來(lái)更新實(shí)時(shí)的任務(wù)進(jìn)度。該方法是抽象方法,子類(lèi)必須實(shí)現(xiàn)。
onProgressUpdate(Progress...),在publishProgress方法被調(diào)用后,UI thread將調(diào)用這個(gè)方法從而在界面上展示任務(wù)的進(jìn)展情況,例如通過(guò)一個(gè)進(jìn)度條進(jìn)行展示。
onPostExecute(Result), 在doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調(diào)用,后臺(tái)的計(jì)算結(jié)果將通過(guò)該方法傳遞到UI thread.
3、核心代碼:
publicclassMainActivityextendsActivity?{
privatefinalstaticStringTAG=?"MainActivity";
privateString?urlString?=?"http://www.baidu.com/";
privateTextView?text_main_info;
@Override
protectedvoidonCreate(Bundle?savedInstanceState)?{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_main_info?=?(TextView)?findViewById(R.id.text_main_info);
//?調(diào)用異步任務(wù),執(zhí)行網(wǎng)絡(luò)訪問(wèn)
newMyTask(this).execute(urlString);
}
classMyTaskextendsAsyncTask?{
privateProgressDialog?pDialog;
privateContextcontext=null;
//?構(gòu)造方法,初始化進(jìn)度對(duì)話框
publicMyTask(Context?context)?{
this.context?=?context;
pDialog?=newProgressDialog(context);
pDialog.setIcon(R.drawable.ic_launcher);
pDialog.setTitle("提示:");
pDialog.setMessage("數(shù)據(jù)加載中。。。");
}
//?事先執(zhí)行方法中顯示進(jìn)度對(duì)話框
@Override
protectedvoidonPreExecute()?{
pDialog.show();
super.onPreExecute();
}
//?進(jìn)度條進(jìn)度改變方法。一般情況下,可以不寫(xiě)該方法
@Override
protectedvoidonProgressUpdate(Void...?values)?{
//TODOAuto-generated?method?stub
super.onProgressUpdate(values);
}
//?后臺(tái)執(zhí)行方法,這個(gè)方法執(zhí)行worker?Thread異步訪問(wèn)網(wǎng)絡(luò),加載數(shù)據(jù)。該方法中不可以執(zhí)行任何UI操作。
@Override
protectedbyte[]?doInBackground(String...?params)?{
BufferedInputStream?bis?=null;
ByteArrayOutputStream?baos?=newByteArrayOutputStream();
try{
URL?urlObj?=newURL(params[0]);
HttpURLConnection?httpConn?=?(HttpURLConnection)?urlObj.openConnection();
httpConn.setDoInput(true);
// httpConn.setDoOutput(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
if?(httpConn.getResponseCode() == 200) {
bis =?new?BufferedInputStream(httpConn.getInputStream());
byte[] buffer =?new?byte[1024 * 8];
int?c = 0;
while?((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
// Toast.makeText(context, baos.toByteArray().toString(),
// Toast.LENGTH_LONG).show();
return?baos.toByteArray();
}
}?catch?(Exception e) {
e.printStackTrace();
}?finally?{
try?{
if?(bis !=?null) {
bis.close();
}
if?(baos !=?null) {
baos.close();
}
}?catch?(IOException e) {
e.printStackTrace();
}
}
returnnull;
}
// 事后方法,這個(gè)方法主要作用是執(zhí)行對(duì)主線程中UI的操作。可以實(shí)現(xiàn)主線程和子線程之間的數(shù)據(jù)交互
@Override
protectedvoid?onPostExecute(byte[] result) {
super.onPostExecute(result);
if?(result ==?null) {
text_main_info.setText("網(wǎng)絡(luò)異常,加載數(shù)據(jù)失??!");
}?else?{
text_main_info.setText(new?String(result));
}
pDialog.dismiss();
}
}
@Override
publicboolean?onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
returntrue;
}
}
(三)、增加進(jìn)度條的異步任務(wù):
1、制作思路:
在異步任務(wù)內(nèi)部類(lèi)的構(gòu)造方法中new ProgressDialog();
在onPreExecute()中調(diào)用ProgressDialog對(duì)象的show()方法,顯示進(jìn)度對(duì)話框;
在doInBackground()方法中計(jì)算進(jìn)度,在while循環(huán)中通過(guò)調(diào)用publishProgress()方法將進(jìn)度數(shù)據(jù)隨時(shí)發(fā)布出去;
進(jìn)度數(shù)據(jù)的計(jì)算公式:publishProgress((int) ((count / (double) length) * 100)),其中count為當(dāng)前加載的文件長(zhǎng)度,length為文件的總長(zhǎng)度;
在onPostExecute()方法中調(diào)用?ProgressDialog對(duì)象的dismiss()方法,讓進(jìn)度條消失。
2、核心代碼:
? ? A、如果計(jì)算進(jìn)度?【在doInBackground()方法中增加如下代碼】
// 獲取內(nèi)容的長(zhǎng)度
int length = httpConn.getContentLength();
while ((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
count += c;
if (length > 0) {
// 如果知道響應(yīng)的長(zhǎng)度,調(diào)用publishProgress()更新進(jìn)度
publishProgress((int) ((count / (double) length) * 100));
}
}
? ? B、如果更新進(jìn)度?【在onProgressUpdate()方法中增加如下代碼】
????????????????????????????????????????pDialog.setProgress(values[0]);
(四)、為了正確的使用AsyncTask類(lèi),以下是幾條必須遵守的準(zhǔn)則:
1) Task的實(shí)例必須在UI thread中創(chuàng)建;
2) execute方法必須在UI thread中調(diào)用;
3) 不要手動(dòng)的調(diào)用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個(gè)方法 ;
4)?該task只能被執(zhí)行一次,否則多次調(diào)用時(shí)將會(huì)出現(xiàn)異常?;
? ? ? doInBackground方法和onPostExecute的參數(shù)必須對(duì)應(yīng),這兩個(gè)參數(shù)在AsyncTask聲明的泛型參數(shù)列表中指定,第一個(gè)為doInBackground接受的參數(shù),第二個(gè)為顯示進(jìn)度的參數(shù),第三個(gè)為doInBackground返回和onPostExecute傳入的參數(shù)。
二、JSON:
(一)、概念:JSON(javascript object notation) ,是一種輕量級(jí)的數(shù)據(jù)儲(chǔ)存和交換格式。它是完全獨(dú)立于語(yǔ)言的文本格式。JSON易于閱讀、編寫(xiě),也易于機(jī)器解析和生成。
(二)、JSON基本格式:
1、鍵值對(duì)對(duì)象格式:用“{}”包圍
2、數(shù)組格式:用“[]”包圍.
(三)、JSON PK XML:
1、json和xml在可讀性、可擴(kuò)展性上都不相上下;
2、解碼難度上看,json更方便和簡(jiǎn)潔;
3、json對(duì)數(shù)據(jù)描述性上比xml差;
4、應(yīng)用json實(shí)現(xiàn)功能的速度要遠(yuǎn)快于xml。
(四)、JSON解析原則:
1、看到{},創(chuàng)建JsonObject對(duì)象;
2、看到[],創(chuàng)建JsonArray對(duì)象;
3、看到JsonArray,要for循環(huán)遍歷。