Android中Handler、HandlerThread、AsyncTask的应用

2024-02-04 10:18

本文主要是介绍Android中Handler、HandlerThread、AsyncTask的应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  Android应用程序的消息处理机制由消息循环、消息发送和消息处理三个部分组成的。而Handler、HandlerThread、AsyncTask类在消息处理中极其重要,它扮演者负责处理消息的角色。 

1. Handler :

废话不多说了,先看下面的代码:

package com.feixun.hu.hd;  import android.app.Activity;  
import android.os.Bundle;  
import android.os.Handler;  
import android.util.Log;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.EditText;  public class HandlerDemo extends Activity   
{  private int count = 0;  private EditText edit;  private Button start, stop;  private static final String TAG = "HandlerDemo";  /** Called when the activity is first created. */  @Override  public void onCreate(Bundle savedInstanceState)   {  super.onCreate(savedInstanceState);  setContentView(R.layout.main);  //打Log,查看主线程ID  Log.i(TAG, "MainThreadId" + Thread.currentThread().getId());  edit = (EditText)findViewById(R.id.edit);  start = (Button)findViewById(R.id.start);  stop = (Button)findViewById(R.id.stop);  //为按钮绑定监听  start.setOnClickListener(new OnClickListener()  {  @Override  public void onClick(View v)   {  //执行线程run方法  mHandler.post(r);  }  });  stop.setOnClickListener(new OnClickListener()  {  @Override  public void onClick(View v)   {  //移除线程run方法  mHandler.removeCallbacks(r);  }  });  }  private Handler mHandler = new Handler();  private Runnable r = new Runnable()   {  @Override  public void run()  {  // TODO Auto-generated method stub  count++;  edit.setText("" + count);  //每隔2秒执行一次run方法       mHandler.postDelayed(r, 2000);  //打Log查看线程所在ID  Log.i(TAG, "ThreadID" + Thread.currentThread().getId());      }  };  }  


上面的代码主要通过hanlder类是实现隔两秒count自增1的计数功能,然后在edit(EditText对象)中显示不断增加的计数值count;点击start按钮时会启动计数,点击stop按钮时停止计数;  上面的代码主要通过hanlder类是实现隔两秒count自增1的计数功能,然后在edit(EditText对象)中显示不断增加的计数值count;点击start按钮时会启动计数,点击stop按钮时停止计数;

 效果图如下:

  通过打Log可知,run方法所在的线程Id和onCreate方法所在的线程Id是相同的,也就是说,该run方法是在主线程中实现的。所以,Handler类的处理实现始终是在主线程上实现。但是,有的时候,需要开辟一个新的子线程处理一些超时的操作,避免你的应用程序主线程(UI线程)自己去处理这些超时的操作,从而出现ANR(Application Not Responding)异常。这时候就需要用到HandlerThread、AsyncTask来处理了。

2. HandlerThread :

在介绍HandlerThread之前,先给大家上代码,如下:

package com.feixun.hu.htd;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;public class HandlerThreadDemo extends Activity 
{private ProgressBar bar;private BarHandler mHandler;private Runnable BarThread;private static final String TAG = "HandlerThreadDemo";/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);//打log,查看主线程idLog.i(TAG, "Main Thread Id:" + Thread.currentThread().getId());//开启一个新的异步线程HandlerThread handlerThread = new HandlerThread("handler_thread");//在调用getLooper方法之前必须先调用start方法启动线程handlerThread.start();//异步线程加入循环消息队列处理机制mHandler = new BarHandler(handlerThread.getLooper());bar = (ProgressBar)findViewById(R.id.bar);Button start = (Button)findViewById(R.id.start);//为按钮绑定监听start.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {bar.setVisibility(ProgressBar.VISIBLE);mHandler.post(BarThread);}});BarThread = new Runnable(){int count = 0;@Overridepublic void run() {//打log,查看该方法所在的线程idLog.i(TAG, "Runnable Thread Id:" + Thread.currentThread().getId());//进度条每秒增加5分值count += 5;//创建消息发送至handlerMessage方法处理Message msg = new Message();Bundle data = new Bundle();data.putInt("count", count);msg.setData(data);mHandler.sendMessage(msg);//线程休眠一秒try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();			}}};}private class BarHandler extends Handler{public BarHandler(Looper looper){super(looper);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);bar.setProgress(msg.getData().getInt("count"));mHandler.post(BarThread);if(msg.getData().getInt("count") >= 100){mHandler.removeCallbacks(BarThread);}}};
}


  上面的Demo主要实现点击start按钮,进度条展现出来,以5分值的进度不断增加显示,直到count大于等于100,才终止进度。

main.xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><ProgressBar android:id="@+id/bar"android:layout_width="fill_parent"android:layout_height="wrap_content"android:max="100"style="@android:style/Widget.ProgressBar.Horizontal"android:visibility="gone"/><Button android:id="@+id/start"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/start"/></LinearLayout>

效果图如下:

 上面的代码,通过打Log可知两个方法所在的线程Id不一样,也就是说,通过HandlerThread类实现开启一个新的异步线程处理循环消息队列机制,值得注意的是,handlerMessage方法不是在主线程中运行的,而是在新开辟的异步线程handlerThread中运行的。该方法可以接收来着BarThread的run()方法里发过来的消息(通过hanlder.senMessage()方法发送),然后通过接收的消息来设置ProgressBar的进度等级(亲们,要谨记,UI组件的相关处理操作只能在主线程中,如果在新开的异步线程对应的Handler的handlerMessage中处理UI组件,会出现问题)。

3. AsyncTask :

   我们开发应用程序的时候,经常中需要创建一个子线程来在后台执行一个特定的计算任务,而在这个任务计算的过程中,需要不断地将计算进度或者计算结果展现在应用程序的界面中。典型的例子是从网上下载文件,为了不阻塞应用程序的主线程,我们开辟一个子线程来执行下载任务,子线程在下载的同时不断地将下载进度在应用程序界面上显示出来,这样做出来程序就非常友好。由于子线程不能直接操作应用程序的UI,因此,这时候,我们就可以通过往应用程序的主线程中发送消息来通知应用程序主线程更新界面上的下载进度。因为类似的这种情景在实际开发中经常碰到,Android系统为开发人员提供了一个异步任务类(AsyncTask)来实现上面所说的功能,即它会在一个子线程中执行计算任务,同时通过主线程的消息循环来获得更新应用程序界面的机会。

 

 实现AsyncTask类的回调方法介绍如下:

    i. onPreExecute(),该回调函数在任务被执行之后立即由主线程(UI线程)调用。这个步骤通常用来建立任务,在用户接口(UI)上显示进度条。(准备运行)

  ii. doInBackground(Params...),该回调函数由后台线程在onPreExecute()方法执行结束后立即调用,即该函数不在主线程中,而是在开启的一个异步线程。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,返回值被传递到onPostExecute()中处理。在该函数内也可以使用publishProgress(Progress...)来发布一个或多个进度单位(unitsof progress)。这些值将会在onProgressUpdate(Progress...)中被发布到UI线程。(后台运行)

  iii.onProgressUpdate(Progress...),该函数由UI线程在publishProgress(Progress...)方法调用完后被调用。一般用于动态地显示一个进度条。实现进度更新。

  iv. onPostExecute(Result),当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数处理。实现完成后台任务。

  v.  onCancelled (),在调用AsyncTask的cancel()方法时调用,从而实现取消任务。

 

AsyncTask构造函数的三个模板参数:

   i. Params,传递给后台任务的参数类型。

   ii. Progress,后台计算执行过程中,进步单位(progress units)的类型。(就是后台程序已经执行了百分之几了。)

   ii. Result, 后台执行返回的结果的类型。

:AsyncTask并不总是需要使用上面的全部3种类型。标识不使用的类型很简单,只需要使用Void类型即可。

 

  ok,仅仅介绍回调方法还是不够,上代码,通过代码分析讲解才深刻,Demo代码如下:

 

package com.feixun.com.atd;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.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;public class AsyncTaskDemo extends Activity 
{private ImageView image;private ProgressBar bar;private Button get;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);image = (ImageView)findViewById(R.id.image);bar = (ProgressBar)findViewById(R.id.bar);get = (Button)findViewById(R.id.btn);get.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {GetPictureTask task = new GetPictureTask();//执行下载网络图片,传入参数为图片所在的URL地址task.execute("http://csdnimg.cn/www/images/csdnindex_logo.gif");}});}private class GetPictureTask extends AsyncTask<String, Integer, Bitmap>{//在后台执行之前被调用,在UI线程中执行@Overrideprotected void onPreExecute() {image.setImageBitmap(null);bar.setProgress(0);}@Overrideprotected Bitmap doInBackground(String... params) {// TODO Auto-generated method stub//该方法执行后,将会调用onProgressUpdate(Integer... values) 方法publishProgress(0);//创建HttpCilent对象HttpClient hc = new DefaultHttpClient();publishProgress(30);//通过传入的参数URL字符串值,发送get请求HttpGet hg = new HttpGet(params[0]);Bitmap bm = null ;try {//响应请求HttpResponse hr = hc.execute(hg);//根据响应的内容获取Bitmap对象bm = BitmapFactory.decodeStream(hr.getEntity().getContent());} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return bm;}@Overrideprotected void onProgressUpdate(Integer... values) {// TODO Auto-generated method stubsuper.onProgressUpdate(values);bar.setProgress(values[0]);}@Overrideprotected void onPostExecute(Bitmap result){// TODO Auto-generated method stubsuper.onPostExecute(result);if(result != null){//根据获取返回的位图Bitmap获取图片image.setImageBitmap(result);Toast.makeText(AsyncTaskDemo.this, "成功获取图片", Toast.LENGTH_LONG).show();}else{Toast.makeText(AsyncTaskDemo.this, "获取图片失败",Toast.LENGTH_LONG).show();}}//在UI线程执行@Overrideprotected void onCancelled() {// TODO Auto-generated method stubsuper.onCancelled();bar.setProgress(0);}@Overrideprotected void onCancelled(Bitmap result) {// TODO Auto-generated method stubsuper.onCancelled(result);}}
}

   上面的代码实现点击一个按钮下载网络图片,然后以进度条的形式显示图片下载的进度。

 

  main.xml文件代码:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><ProgressBar android:id="@+id/bar"android:layout_width="fill_parent"android:layout_height="wrap_content"android:max="100"style="@android:style/Widget.ProgressBar.Horizontal"/><Button android:id="@+id/btn"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/get"/><ImageView android:id="@+id/image"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout>

 

注:最后,别忘了在manifest.xml文件里注册权限<uses-permission android:name="android.permission.INTERNET"/>

 

相关的Demo代码下载:http://download.csdn.net/detail/stevenhu_223/4653284

 

这篇关于Android中Handler、HandlerThread、AsyncTask的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677145

相关文章

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

Linux中Curl参数详解实践应用

《Linux中Curl参数详解实践应用》在现代网络开发和运维工作中,curl命令是一个不可或缺的工具,它是一个利用URL语法在命令行下工作的文件传输工具,支持多种协议,如HTTP、HTTPS、FTP等... 目录引言一、基础请求参数1. -X 或 --request2. -d 或 --data3. -H 或

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

Go信号处理如何优雅地关闭你的应用

《Go信号处理如何优雅地关闭你的应用》Go中的优雅关闭机制使得在应用程序接收到终止信号时,能够进行平滑的资源清理,通过使用context来管理goroutine的生命周期,结合signal... 目录1. 什么是信号处理?2. 如何优雅地关闭 Go 应用?3. 代码实现3.1 基本的信号捕获和优雅关闭3.2