应用场景:
在开发Android应用时(特别是Android 4.0以后)必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则:1. 不要阻塞UI线程
2. 确保只在UI线程中访问Android UI工具包
当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask
它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。
AsyncTask是抽象类,它定义了三种泛型类型参数: Params,Progress,Result
Params 启动任务执行的输入参数,比如HTTP请求的URL。
Progress 后台任务执行的百分比。 比如进度条的进度 【可选】
Result 后台执行任务最终返回的结果,比如String ListView需要的数据。
注意事项:
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
(1) Task的实例必须在UI thread中创建
(2) execute方法必须在UI thread中调用
(3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
(4) 该task只能被执行一次,否则多次调用时将会出现异常 【未检测】
知识点介绍:【对象介绍】
import android.os.AsyncTask; /** * AsyncTask<Params, Progress, Result> * AsyncTask是抽象类,它定义了三种泛型类型参数: Params,Progress,Result * Params 启动任务执行的输入参数,比如HTTP请求的URL。 * Progress 后台任务执行的百分比。 比如进度条的进度 【可选】 * Result 后台执行任务最终返回的结果,比如String ListView需要的数据。 */ public class TestTask extends AsyncTask<String, String, String> { /** * 该方法将在执行实际的后台操作前被UI Thread[UI线程]调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。 */ @Override protected void onPreExecute() { super.onPreExecute(); } /** * 在后台运行耗时操作,如:文件下载,网络访问等等 */ @Override protected String doInBackground(String... params) { return null; } /** * 与UI控件交互的方法 ,修改UI控件的操作,例如进度条的显隐与更新,提示信息的显隐等等 */ @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); } /** * 可以与UI控件交互 ,例如更新ListView、GridView的显示数据 */ @Override protected void onPostExecute(String result) { super.onPostExecute(result); } }
使用方式:
第一步:先建android工程,添加 AsyncTaskActivity。第二步:在/res/layout/activity_async_task.xml文件中填写如下代码。
<LinearLayout 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" android:orientation="vertical" tools:context=".AsyncTaskActivity" > <EditText android:id="@+id/etURL" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="URL" android:text="" /> <Button android:id="@+id/btnConn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="确定"/> <TextView android:id="@+id/tvPage" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="网页代码" /> </LinearLayout>第三步:AndroidManefest.xml 添加网络访问权限。
<uses-permission android:name="android.permission.INTERNET"/>第四步:在AsyncTaskActivity.java中填写如下代码。
import java.io.ByteArrayOutputStream; import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class AsyncTaskActivity extends Activity { private EditText metURL; private TextView mtvPage; private Button mbtnConn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_async_task); metURL = (EditText) findViewById(R.id.etURL); // 输入网址 mbtnConn = (Button) findViewById(R.id.btnConn); // 连接网站 mtvPage = (TextView) findViewById(R.id.tvPage); // 显示网页 mbtnConn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { connURL(); } }); } private void connURL() { URLTask urlTask = new URLTask(this); // 实例化抽象AsyncTask urlTask.execute(metURL.getText().toString().trim()); // 调用AsyncTask,传入url参数 } /** 继承AsyncTask的子类,下载url网页内容 */ class URLTask extends AsyncTask<String, Integer, String> { ProgressDialog proDialog; public URLTask(Context context) { proDialog = new ProgressDialog(context, 0); proDialog.setButton("cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); proDialog .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { finish(); } }); proDialog.setCancelable(true); proDialog.setMax(100); proDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); proDialog.show(); } @Override protected void onPreExecute() { mtvPage.setText(R.string.hello_world); // 可以与UI控件交互 } @Override protected String doInBackground(String... params) { // 在后台,下载url网页内容 try { HttpGet get = new HttpGet(params[0]); // url HttpResponse response = new DefaultHttpClient().execute(get); if (response.getStatusLine().getStatusCode() == 200) { // 判断网络连接是否成功 HttpEntity entity = response.getEntity(); long len = entity.getContentLength(); // 获取url网页内容总大小 InputStream is = entity.getContent(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int ch = -1; int count = 0; // 统计已下载的url网页内容大小 while (is != null && (ch = is.read(buffer)) != -1) { bos.write(buffer, 0, ch); count += ch; if (len > 0) { float ratio = count / (float) len * 100; // 计算下载url网页内容百分比 publishProgress((int) ratio); // android.os.AsyncTask.publishProgress(Integer... values) } Thread.sleep(100); } String result = new String(bos.toString("utf-8")); return result; } } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onProgressUpdate(Integer... values) { // 可以与UI控件交互 mtvPage.setText("" + values[0]); // 获取 publishProgress((int)ratio)的values proDialog.setProgress(values[0]); } @Override protected void onPostExecute(String result) { // 可以与UI控件交互 mtvPage.setText(result); proDialog.dismiss(); } } }