【Androoid的事件处理】-----异步任务

本文介绍了Android中解决新线程不能更新UI组件的问题的方法,包括使用Handler、Activity.runOnUiThread等,并重点讲解了AsyncTask的使用,通过两个实战案例演示如何在Android应用中更新UI线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、知识点

1、为了解决新线程不能更新UI组建的问题,Andorid提供了如下几种解决方案: 
  • 使用Handler实现线程之间的通信
  • Activity.runOnUiThread(Runnable) 
  • View.post(Runnable)
  • View.postDelayed(Runnable)

2、在Android应用程序中,在Android中UI线程响应不能超过5s,否则会出现ANR,因此我们常常将耗时操作放在非工作线程中执行,为了避免ANR(Application Not Response)异常,需要把耗时任务放置在子线程中来完成,或者使用AsyncTask类来完成;AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用。

3、AsyncTask的特点 :更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可。 

4、AsyncTask<Params,Progress,Result>,是一个抽象类,通常用于被继承,继承后,需要制定如下三个泛型参数:

  • Params: 启动任务执行的输入参数类型
  • Progress:后台任务完成的进度值的类型
  • Result:后台执行任务完成后返回结果的类型
5、使用AsyncTask的步骤 

(1).创建AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,可将它指定为void。 

(2).根据需要,实现AsyncTask的如下方法:

  •  onPreExecute():准备运行后台任务时。一般做一些初始化工作(如:显示进度对话框)。 注意,这个方法在UI线程(主线程)中执行
  •  doInBackground(Params …):正在后台运行。在后台线程中执行。一般编写需要在后台线程中执行的代码。注意,这个在后台线程中执行。 
  •  onProgressUpdate(Progress... values):进度更新时。一般就是更新进度显示。注意,这个方法在UI线程(主线程)中执行。一般在doInBackground()方法中调用publishProgress()方法来触发。
  • onPostExecute(Result result):当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground方法返回的值传给该方法。一般做一些清理资源工作(如:隐藏进度对话框)。 注意,这个方法在UI线程(主线程)中执行 

(3).调用AsyncTask子类的实例的execute(Params... params)开始执行耗时任务。  

6、AsyncTask异步加载时序图



7、使用AsyncTask时必须遵守的规则 

  • 必须在UI线程中创建AsyncTask的实例。 
  • 必须在UI线程中调用AsyncTask的execute()方法。 
  • AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params... params)、onProgressUpdate(Progress... values)方法,不应该由程序员代码调用,而是由Android系统负责调用。 
  • 每个AsyncTask只能被执行一次,多次调用将会引发异常。

二、实战

例1:
1、效果图

2、demo目录



3、xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textSize="21dp" />
    </LinearLayout>

    <Button
        android:id="@+id/update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="updateClick"
        android:text="更新"
        android:textSize="21dp" />

</LinearLayout>


4、代码
package com.BieWong.asynctaskupadate;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	Button update;
	TextView show;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		initView();// 初始化相应的UI组件
		setOnClickListener();// 对按钮进行监听

	}

	private void setOnClickListener() {
		update.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				AsynctaskUpdate ast = new AsynctaskUpdate(MainActivity.this);
				ast.execute();
			}
		});
	}

	private void initView() {
		update = (Button) findViewById(R.id.update);
		show = (TextView) findViewById(R.id.show);
	}

	// 创建内部类继承AsyncTask的方法
	class AsynctaskUpdate extends AsyncTask<Void, Integer, Integer> {
		// 定义Context用于传递上下文
		Context mContext;

		// 定义相应的构造器接受外部类的Context
		public AsynctaskUpdate(Context context) {
			mContext = context;
		}

		// 准备运行后台任务时。一般做一些初始化工作
		@Override
		protected void onPreExecute() {
			Toast.makeText(mContext, "执行任务开始", 2000).show();
		}

		// 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
		@Override
		protected Integer doInBackground(Void... params) {
			int i = 0;
			while (i < 100) {
				i++;
				// 调用publisProgress(),把参数传递给onProgressUpdate(Integer... values)
				publishProgress(i);

				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			return null;
		}

		// 接收在publishProgress()被调用以后执行的数据,用于更新进度
		@Override
		protected void onProgressUpdate(Integer... values) {
			show.setText(values[0].toString());
		}

		// 运行在ui线程中,在doInBackground()执行完毕后执行
		@Override
		protected void onPostExecute(Integer result) {
			Toast.makeText(mContext, "执行任务完成", 2000).show();
		}
	}
}
例2:
1、效果图

2、demo目录

3、xml文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ScrollView
        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:textSize="20dp" />
    </ScrollView>

    <Button
        android:id="@+id/download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="下载"
        android:textSize="21dp" />

</RelativeLayout>


4、代码文件
package com.example.asynctaskdownload;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
	TextView show;
	Button download;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		show = (TextView) findViewById(R.id.show);
		download = (Button) findViewById(R.id.download);
		download.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				DownTask task = new DownTask(MainActivity.this);
				try {
					task.execute(new URL("http://www.xiaomi.cn"));
				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		});
	}

	class DownTask extends AsyncTask<URL, Integer, String> {
		ProgressDialog pdialog;
		// 定义记录已经读取行的数量
		int hasRead = 0;
		Context mContext;

		public DownTask(Context ctx) {
			mContext = ctx;
		}

		@Override
		protected void onPreExecute() {
			pdialog = new ProgressDialog(mContext);
			// 设置对话框的标题
			pdialog.setTitle("任务正在执行中");
			// 设置对话框显示的内容
			pdialog.setMessage("任务正在执行中,敬请等待...");
			// 设置对话框不能用“取消”按钮关闭
			pdialog.setCancelable(false);
			// 设置该进度条的最大进度值
			pdialog.setMax(2000);
			// 设置对话框的进度条风格
			pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			// 设置对话框的进度条是否显示进度
			pdialog.setIndeterminate(false);
			pdialog.show();
		}

		@Override
		protected String doInBackground(URL... params) {
			StringBuilder sb = new StringBuilder();
			try {
				// 打开params数组的第一个的URL
				URLConnection conn = params[0].openConnection();
				// 打开conn连接对应的输入流,并将它包装成BufferedReader
				BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
				String line = null;
				while ((line = br.readLine()) != null) {
					// sb连接每次读完一行的数据,并换行
					sb.append(line + "\n");
					hasRead++;
					// publishProgress()把数据传递给onProgressUpdate()
					publishProgress(hasRead);
				}
				// 返回sb的值给onPostExecute() 方法,不能少!!
				return sb.toString();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			// 更新进度
			show.setText("已经读取了" + values[0] + "行数据!");
			// 设置对话框进度条的进度值
			pdialog.setProgress(values[0]);
		}

		@Override
		protected void onPostExecute(String result) {
			// 接收 doInBackground()方法的返回值,也就是HTML页面的内容
			show.setText(result);
			// 关闭对话框
			pdialog.dismiss();
		}
	}
}
5、AndroidManifest.xml文件内需要声明如下权限,来访问网络
  <uses-permission android:name="android.permission.INTERNET" />
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值