當前位置:首頁 > 資訊 > info6 > 正文

異步任務AsyncTask及JSON解析

發表于: 2017-01-05   作者:Chen_xiaobao   來源:轉載   瀏覽:
摘要: 一、AsyncTask:1、開發Android應用時必須遵守單線程模型的原則:?????????AndroidUI操作并不是線程安全的,并且這些操作必須在UI線程中執行。2、單線程模型中始終要記住兩條法則:?1).不要阻塞UI線程;2).確保只在UI線程中訪問AndroidUI控件。????????當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(MainThread),主線程主要
一、AsyncTask:
1、開發Android應用時必須遵守 單線程模型的原則: 
        Android UI操作并不是線程安全的,并且這些操作必須在UI線程中執行。

2、單線程模型中始終要記住兩條法則: 

1). 不要阻塞UI線程 ;
2). 確保只在UI線程中訪問Android UI控件。
        當一個程序第一次啟動時,Android會同時啟動一個對應的 主線程( Main Thread),主線程主要負責處理與UI相關的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,并把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做 UI線程

3、Android4.0以上版本中, 主線程中不允許訪問網絡。涉及到網絡操作的程序一般都是需要開一個新線程完成網絡訪問。但是在獲得頁面數據后,又不能將數據返回到UI界面中 。因為 子線程Worker Thread)不能直接訪問UI線程中的成員,也就是說 沒有辦法對UI界面上的內容進行操作,如果操作,將拋出異常: CalledFromWrongThreadException

其實,android提供了幾種在其他線程中訪問UI線程的方法: 
  • Activity.runOnUiThread( Runnable ) 
  • View.post( Runnable ) 
  • View.postDelayed( Runnable, long ) 
  • Handler消息傳遞機制(后續課程中講解)
        這些類或方法會使代碼很復雜很難理解。為了解決這個問題,Android 1.5提供了一個工具類:AsyncTask,它使創建與用戶界面長時間交互運行的任務變得更簡單。AsyncTask更輕量級一些,適用于簡單的異步處理,不需要借助線程和Handler即可實現。 


(二)、AsyncTask的代碼實現:

1、AsyncTask是抽象類.AsyncTask定義了三種泛型類型 Params,Progress和Result。 
  • Params 啟動任務執行的輸入參數,比如HTTP請求的URL。 一般用String類型;
  • Progress 后臺任務執行的百分比。 一般用Integer類型;
  • Result 后臺執行任務最終返回的結果,一般用byte[]或者String。 

2、AsyncTask的執行分為 四個步驟,每一步都對應一個回調方法(由應用程序自動調用的方法),開發者需要做的就是實現這些方法。 
1) 定義AsyncTask的子類; 
2) 實現AsyncTask中定義的方法:(可以全部實現,也可以只實現其中一部分) 
  • onPreExecute(), 該方法將在執行實際的后臺操作前被UI thread調用。可以在該方法中做一些準備工作,如在界面上顯示一個進度條。 
  • doInBackground(Params...), 將在onPreExecute 方法執行后馬上執行,該方法運行在后臺線程中。這里將主要負責執行那些很耗時的后臺計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
  • onProgressUpdate(Progress...),在publishProgress方法被調用后,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。 
  • onPostExecute(Result), 在doInBackground 執行完成后,onPostExecute 方法將被UI thread調用,后臺的計算結果將通過該方法傳遞到UI thread. 
3、核心代碼:

publicclass MainActivity extends Activity {
privatefinalstatic String TAG = "MainActivity";
private String urlString = "http://www.baidu.com/";
private TextView text_main_info;


@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_main_info = (TextView) findViewById(R.id.text_main_info);
// 調用異步任務,執行網絡訪問
new MyTask(this).execute(urlString);
}


class MyTask extends AsyncTask<String, Void, byte[]> {
private ProgressDialog pDialog;
private Context context = null;


// 構造方法,初始化進度對話框
public MyTask(Context context) {
this.context = context;
pDialog = new ProgressDialog(context);
pDialog.setIcon(R.drawable.ic_launcher);
pDialog.setTitle("提示:");
pDialog.setMessage("數據加載中。。。");
}


// 事先執行方法中顯示進度對話框
@Override
protectedvoid onPreExecute() {
pDialog.show();
super.onPreExecute();
}


// 進度條進度改變方法。一般情況下,可以不寫該方法
@Override
protectedvoid onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}


// 后臺執行方法,這個方法執行worker Thread異步訪問網絡,加載數據。該方法中不可以執行任何UI操作。
@Override
protectedbyte[] doInBackground(String... params) {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
URL urlObj = new URL(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 = newbyte[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;
}


// 事后方法,這個方法主要作用是執行對主線程中UI的操作。可以實現主線程和子線程之間的數據交互
@Override
protectedvoid onPostExecute(byte[] result) {
super.onPostExecute(result);
if (result == null) {
text_main_info.setText("網絡異常,加載數據失敗!");
} 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;
}
}


(三)、增加進度條的異步任務:
1、制作思路:
  1. 在異步任務內部類的構造方法中new ProgressDialog();
  2. 在onPreExecute()中調用ProgressDialog對象的show()方法,顯示進度對話框;
  3. 在doInBackground()方法中計算進度,在while循環中通過調用publishProgress()方法將進度數據隨時發布出去;
  4. 進度數據的計算公式:publishProgress((int) ((count / (double) length) * 100)),其中count為當前加載的文件長度,length為文件的總長度;
  5. 在onPostExecute()方法中調用 ProgressDialog對象的dismiss()方法,讓進度條消失。
2、核心代碼:
    A、如果計算進度?【在doInBackground()方法中增加如下代碼】

// 獲取內容的長度
int length = httpConn.getContentLength();
while ((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();

count += c;

if (length > 0) {
// 如果知道響應的長度,調用publishProgress()更新進度
publishProgress((int) ((count / (double) length) * 100));
}
}

    B、如果更新進度?【在onProgressUpdate()方法中增加如下代碼】

                                        pDialog.setProgress(values[0]);




(四)、為了正確的使用AsyncTask類,以下是幾條必須遵守的準則: 
  1) Task的實例必須在UI thread中創建; 
  2) execute方法必須在UI thread中調用;
  3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法 ;
  4)   該task只能被執行一次,否則多次調用時將會出現異常  
      doInBackground方法和onPostExecute的參數必須對應,這兩個參數在AsyncTask聲明的泛型參數列表中指定,第一個為doInBackground接受的參數,第二個為顯示進度的參數,第三個為doInBackground返回和onPostExecute傳入的參數。


異步任務AsyncTask及JSON解析

版權所有 IT知識庫 CopyRight ? 2009-2015 IT知識庫 IT610.com , All Rights Reserved. 京ICP備09083238號
广东25选5开奖结果