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

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例

《PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例》词嵌入解决NLP维度灾难,捕捉语义关系,PyTorch的nn.Embedding模块提供灵活实现,支持参数配置、预训练及变长... 目录一、词嵌入(Word Embedding)简介为什么需要词嵌入?二、PyTorch中的nn.Em