AsyncTask异步处理的运用

时间:2022-08-27 14:46:26

应用场景:

在开发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();
		}
	}
}

页面效果:

AsyncTask异步处理的运用