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

相关文章

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库