之前簡(jiǎn)單的介紹了Android-Handler的消息傳遞機(jī)制可缚,其中計(jì)算質(zhì)數(shù)的demo在利用子Handler去計(jì)算和更新TextView的時(shí)候顯的十分復(fù)雜作谚。其實(shí)Android還提供了另外一種簡(jiǎn)化的方法叫異步任務(wù)(AsyncTask)怕篷;相對(duì)來說AsyncTask更輕量級(jí)一些捶朵,適用于簡(jiǎn)單的異步處理括荡。
我們來看看利用AsyncTask進(jìn)行開發(fā)后的計(jì)算質(zhì)數(shù)demo,Java代碼如下:
public class AsyncTaskActivity extends AppCompatActivity {
private TextView tv_calculate_result;
private EditText edit_number;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
tv_calculate_result = (TextView) findViewById(R.id.tv_calculate_result);
edit_number = (EditText) findViewById(R.id.edit_number);
findViewById(R.id.btn_calculate).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TextUtils.isEmpty(edit_number.getText().toString().trim())) {
Toast.makeText(AsyncTaskActivity.this, "請(qǐng)輸入數(shù)字", Toast.LENGTH_SHORT).show();
} else {
CalculateTask calculateTask = new CalculateTask();
calculateTask.execute(edit_number.getText().toString().trim());
}
}
});
}
private class CalculateTask extends AsyncTask<String,Integer,String>{
@Override
protected String doInBackground(String... params) {
int upper = Integer.parseInt(params[0]);
List<Integer> nums = new ArrayList<>();
//計(jì)算從2開始脉课,到upper的所有質(zhì)數(shù)
outer:
for (int i = 2; i <= upper; i++) {
//用i除以從2開始,到i的平方根的所有數(shù)
for (int j = 2; j <= Math.sqrt(i); j++) {
//如果可以整除财异,則表明這個(gè)數(shù)不是質(zhì)數(shù)
if (i != 2 && i % j == 0) {
continue outer;
}
}
nums.add(i);
}
return nums.toString();
}
@Override
protected void onPostExecute(String s) {
tv_calculate_result.setText(s);
}
}
}
運(yùn)行效果:
對(duì)于AsyncTask我們主要重寫了doInBackground()和onPostExecute()兩個(gè)方法就解決了我們之前的問題倘零。
AsyncTask<Params, Progress, Result>抽象類
AsyncTask<Params, Progress, Result>是一個(gè)抽象類,通常用于被繼承戳寸,繼承時(shí)需要指定一下三個(gè)泛型參數(shù)呈驶。
- Params:?jiǎn)?dòng)任務(wù)執(zhí)行的輸入?yún)?shù)的類型。
- Progress:后臺(tái)任務(wù)完成的進(jìn)度值類型疫鹊。
- Result:后臺(tái)執(zhí)行任務(wù)完成后返回結(jié)果的類型袖瞻。
如何使用AsyncTask
使用AsyncTask只要三步即可。
- 創(chuàng)建AsyncTask的子類拆吆,并為三個(gè)泛型參數(shù)指定類型聋迎。如果某個(gè)不需要指定就設(shè)置為Void。
- 根據(jù)需要锈拨,實(shí)現(xiàn)AsyncTask的如下方法砌庄。
doInBackground(Params...):后臺(tái)線程將要完成的任務(wù)。該方法可以調(diào)用publishProgress(Progress... values)方法更新任務(wù)的執(zhí)行進(jìn)度。
onProgressUpdate(Progress... values):在doInBackground()中調(diào)用publishProgress()方法更新任務(wù)的執(zhí)行進(jìn)度后會(huì)觸發(fā)該方法娄昆。
onPreExecute():執(zhí)行后臺(tái)耗時(shí)操作前調(diào)用佩微。通常用于完成一些初始化的準(zhǔn)備工作,比如在界面上顯示進(jìn)度條等萌焰。
onPostExecute(Result result):當(dāng)doInBackground()完成后哺眯,系統(tǒng)會(huì)自動(dòng)調(diào)用此方法并將doInBackground()的返回值傳給該方法。
- 調(diào)用AsyncTask子類的實(shí)例的execute(Params... params)開始執(zhí)行耗時(shí)任務(wù)。
使用AsyncTask要遵守的規(guī)則
- 必須在UI線程中創(chuàng)建AsyncTask的實(shí)例街州;
- 必須在UI線程中調(diào)用AsyncTask的execute()方法活尊。
- AsyncTask的doInBackground(Params...)、onProgressUpdate(Progress... values)夺姑、onPreExecute()、onPostExecute(Result result)方法掌猛,不應(yīng)該有程序員代碼調(diào)用盏浙,而是Android系統(tǒng)負(fù)責(zé)調(diào)用。
- 每個(gè)AsyncTask只能被執(zhí)行一次荔茬,多次調(diào)用會(huì)引發(fā)異常废膘。
以下是一個(gè)使用異步任務(wù)執(zhí)行下載的實(shí)例,代碼如下:
public class AsyncTaskActivity extends AppCompatActivity {
private TextView tv_show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
tv_show = (TextView) findViewById(R.id.tv_show);
findViewById(R.id.btn_down).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DownTask downTask = new DownTask(AsyncTaskActivity.this);
try {
downTask.execute(new URL("http://www.reibang.com/p/e807eb8c31f0"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
private class DownTask extends AsyncTask<URL, Integer, String> {
//可變長(zhǎng)的輸入?yún)?shù)慕蔚,與AsyncTask.execute()對(duì)應(yīng)
ProgressDialog pdialog;
//定義記錄已經(jīng)讀取的行數(shù)
int hasRead = 0;
Context mContext;
public DownTask(Context ctx) {
mContext = ctx;
}
@Override
//后臺(tái)進(jìn)程將要完成的任務(wù)
protected String doInBackground(URL... params) {
StringBuilder sb = new StringBuilder();
try {
URLConnection conn = params[0].openConnection();
//打開conn連接對(duì)應(yīng)的輸入流丐黄,并將它包裝成BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
hasRead++;
publishProgress(hasRead);//更新任務(wù)的執(zhí)行進(jìn)度
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
//當(dāng)doInBackground()完成后系統(tǒng)會(huì)自動(dòng)調(diào)用此方法并將doInBackground()的返回值傳給該方法
protected void onPostExecute(String s) {
//返回HTML頁面內(nèi)容
tv_show.setText(s);
pdialog.dismiss();
}
@Override
//執(zhí)行后臺(tái)耗時(shí)操作前被調(diào)用
protected void onPreExecute() {
pdialog = new ProgressDialog(mContext);
pdialog.setTitle("正在下載...");
pdialog.setMessage("任務(wù)正在執(zhí)行中,請(qǐng)等待...");
pdialog.setCancelable(false);
pdialog.setMax(202);
pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pdialog.setIndeterminate(false);//設(shè)置對(duì)話框的進(jìn)度條是否顯示進(jìn)度
pdialog.show();
}
@Override
//在doInBackground()中調(diào)用publishProgress()方法更新任務(wù)會(huì)觸發(fā)該方法
protected void onProgressUpdate(Integer... values) {
//更新進(jìn)度
tv_show.setText("已讀取了【" + values[0] + "】行孔飒!");
pdialog.setProgress(values[0]);
}
}
}
運(yùn)行效果:
參考文章
- 《瘋狂android講義》(第3版)第3章3.6 異步任務(wù)