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