標籤:
雖然今天禮拜六還在加班,但是在等介面,所以還是有很多時間來自己學點東西的,所以就接著昨天的來。今天繼續學的是不通過主線程來更新主線程的介面的問題。
昨天是用的開啟線程調用Handler來更新線程,那個效果用的方面比較廣闊,那麼我們還有幾種方法將耗時的代碼剝離出來不在主線程裡面執行,然後通過各種方法來更新UIThread .今天學到的是利用AsynTask來更新主介面的空間。
然後我們先來說說AsynTask:
AsynTask:Asynchronous Task(非同步任務)
使用過AsyncTask 的同學都知道一個非同步載入資料最少要重寫以下這兩個方法:
- doInBackground(Params…) 後台執行,比較耗時的操作都可以放在這裡。注意這裡不能直接操作UI。此方法在後台線程執行,完成任務的主要工作,通常需要較長的時間。在執行過程中可以調用publicProgress(Progress…)來更新任務的進度。
- onPostExecute(Result) 相當於Handler 處理UI的方式,在這裡面可以使用在doInBackground 得到的結果處理操作UI。 此方法在主線程執行,任務執行的結果作為此方法的參數返回
有必要的話你還得重寫以下這三個方法,但不是必須的:
- onProgressUpdate(Progress…) 可以使用進度條增加使用者體驗度。 此方法在主線程執行,用於顯示任務執行的進度。
- onPreExecute() 這裡是終端使用者調用Excute時的介面,當任務執行之前開始調用此方法,可以在這裡顯示進度對話方塊。
- onCancelled() 使用者調用取消時,要做的操作
使用AsyncTask類,以下是幾條必須遵守的準則:
- Task的執行個體必須在UI thread中建立;
- execute方法必須在UI thread中調用;
- 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法;
- 該task只能被執行一次,否則多次調用時將會出現異常;
好了繼續以往風格,再說需求:
需求是在介面通過輸入一個完整的網址然後通過點擊按鈕來訪問網路,在訪問的時候展示一個進度條,然後將得到的網頁代碼顯示在主介面上。
然後上代碼:TestAsynTaskActivity
package com.example.testandroid;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View.OnClickListener;import java.io.ByteArrayOutputStream;import java.io.InputStream;import java.util.ArrayList;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import android.app.ProgressDialog;import android.content.Context;import android.content.DialogInterface;import android.os.AsyncTask;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class TestAsynTaskActivity extends Activity implements OnClickListener { private TextView message; private Button open; private EditText url; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_asyn_task); message = (TextView) findViewById(R.id.show); url = (EditText) findViewById(R.id.url); open = (Button) findViewById(R.id.open); open.setOnClickListener(this); } private void connect() { PageTask task = new PageTask(this); task.execute(url.getText().toString()); } class PageTask extends AsyncTask<String, Integer, String> { // 可變長的輸入參數,與AsyncTask.exucute()對應 ProgressDialog pdialog; public PageTask(Context context) { pdialog = new ProgressDialog(context, 0); pdialog.setButton("cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int i) { dialog.cancel();//這個方法過時了。 } }); pdialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { finish(); } }); pdialog.setCancelable(true); pdialog.setMax(100); pdialog.setTitle("正在請求網路!"); pdialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); pdialog.show(); } @Override protected String doInBackground(String... params) { try { HttpClient client = new DefaultHttpClient(); // params[0]代表串連的url HttpGet get = new HttpGet(params[0]); HttpResponse response = client.execute(get); HttpEntity entity = response.getEntity(); long length = entity.getContentLength(); InputStream is = entity.getContent(); String s = null; if (is != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buf = new byte[128]; int ch = -1; int count = 0; while ((ch = is.read(buf)) != -1) { baos.write(buf, 0, ch); count += ch; if (length > 0) { // 如果知道響應的長度,調用publishProgress()更新進度 publishProgress((int) ((count / (float) length) * 100)); } // 讓線程休眠100ms Thread.sleep(100); } s = new String(baos.toByteArray()); } // 返回結果 return s; } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onCancelled() { super.onCancelled(); } @Override protected void onPostExecute(String result) { // 返回HTML頁面的內容 message.setText(result); pdialog.dismiss(); } @Override protected void onPreExecute() { // 任務啟動,可以在這裡顯示一個對話方塊,這裡簡單處理 message.setText("正在更新。。。"); } @Override protected void onProgressUpdate(Integer... values) { // 更新進度 System.out.println("" + values[0]); message.setText("" + values[0]); pdialog.setProgress(values[0]); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.open: connect(); break; default: break; } }}
下面是xml檔案
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/show" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:background="@drawable/shape1" android:hint="@string/tv_hint" /> <EditText android:id="@+id/url" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_below="@id/show" android:layout_marginLeft="15dp" android:layout_marginTop="15dp" android:background="@null" android:hint="在這裡輸入網址" /> <Button android:id="@+id/open" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/url" android:layout_marginLeft="15dp" android:layout_marginTop="15dp" android:background="@drawable/shape2" android:text="開啟網頁" android:textColor="#FFFFFF" android:textSize="20dp" /> </RelativeLayout> </ScrollView></RelativeLayout>
最後,因為是要訪問網路,我們要記得在manifest檔案裡面加入INTERNET許可權。好啦簡單的一個AsynTask的實現就完成了!
Android AsynTask更新主介面