( 这个github 中是 HandlerThread 的一个用法,和本文的HanderThread写法不同 https://github.com/whtchl/HandlerThread)

本文主要介绍Android中Handler的简单使用方法,Handler跟多线程,消息队列联系很紧密,在平常的实际程序开发中比较常见。本文分为4个简单的例子来学习handler。

开发环境为android4.1.

Handler使用例1

这个例子是最简单的介绍handler使用的,是将handler绑定到它所建立的线程中.
本次实验完成的功能是:单击Start按钮,程序会开始启动线程,并且线程程序完成后延时1s会继续启动该线程,每次线程的run函数中完成对界面输出nUpdateThread…文字,不停的运行下去,当单击End按钮时,该线程就会停止,如果继续单击Start,则文字又开始输出了。

软件界面如下:

实验主要部分代码和注释:

MainActivity.java:

package com.example.handler1;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {private TextView text_view = null;private Button start = null;private Button end = null;//使用handler时首先要创建一个handlerHandler handler = new Handler();//要用handler来处理多线程可以使用runnable接口,这里先定义该接口//线程中运行该接口的run函数Runnable update_thread = new Runnable(){public void run(){//线程每次执行时输出"UpdateThread..."文字,且自动换行//textview的append功能和Qt中的append类似,不会覆盖前面//的内容,只是Qt中的append默认是自动换行模式text_view.append("\nUpdateThread...");//延时1s后又将线程加入到线程队列中handler.postDelayed(update_thread, 1000);}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text_view = (TextView)findViewById(R.id.text_view);start = (Button)findViewById(R.id.start);start.setOnClickListener(new StartClickListener());end = (Button)findViewById(R.id.end);end.setOnClickListener(new EndClickListener());}private class StartClickListener implements OnClickListener{public void onClick(View v) {// TODO Auto-generated method stub//将线程接口立刻送到线程队列中handler.post(update_thread);}                }private class EndClickListener implements OnClickListener{public void onClick(View v) {// TODO Auto-generated method stub//将接口从线程队列中移除handler.removeCallbacks(update_thread);}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}
}

activity_main.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" ><TextViewandroid:id="@+id/text_view"android:layout_width="fill_parent"android:layout_height="200dip"android:text="@string/hello_world"tools:context=".MainActivity" /><Button android:id="@+id/start"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/start"/><Button android:id="@+id/end"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/end"/>
</LinearLayout>

Handler使用例2

这个例子比刚才那个例子稍微复杂些。因为这个例子中用到了handler的消息队列机制,即通过handler中一个线程向消息队列中用sendMessage方法发送消息,发送的消息当然可以用来传递参数。在handler中用handleMessage来处理消息,处理方法是获得消息队列中的消息参数,用这些参数来完成另外一些功能。

本实验实现的是当开始按钮按下时,会启动一个线程,并绑定到handler中,该线程发送带有参数的message到handler的消息队列中,消息队列的另一端获取该消息,并且用该消息的参数来更新进度条。

软件打开后:

单击Start按钮后,更新的进度条结果如下(怎么感觉4.1版本android进度条那么小呢?不懂该怎么设置):

实验主要部分代码和注释:

MainActivity.java:

package com.example.handler2;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends Activity {private ProgressBar progress_bar = null;private Button start = null;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);progress_bar = (ProgressBar)findViewById(R.id.progress_bar);start = (Button)findViewById(R.id.start);start.setOnClickListener(new StartOnClickListenr());}private class StartOnClickListenr implements OnClickListener{public void onClick(View v) {// TODO Auto-generated method stub//让进度条显示出来progress_bar.setVisibility(View.VISIBLE);//将线程加入到handler的线程队列中update_progress_bar.post(update_thread);}}//创建一个handler,内部完成处理消息方法Handler update_progress_bar = new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stub//super.handleMessage(msg);//显示进度条progress_bar.setProgress(msg.arg1);//重新把进程加入到进程队列中update_progress_bar.post(update_thread);}       };//不加这个分号则不能自动添加代码Runnable update_thread = new Runnable(){int i = 0;public void run() {// TODO Auto-generated method stubi += 10;//首先获得一个消息结构Message msg = update_progress_bar.obtainMessage();//给消息结构的arg1参数赋值msg.arg1 = i;//延时1s,java中的try+catch用来排错处理try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO: handle exceptione.printStackTrace();}//把消息发送到消息队列中update_progress_bar.sendMessage(msg);if(i == 100)//把线程从线程队列中移除update_progress_bar.removeCallbacks(update_thread);}       };@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}
}

activity_main.xml:

<RelativeLayout 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" ><Button android:id="@+id/start"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="@string/start"/><ProgressBar android:id="@+id/progress_bar"android:layout_width="fill_parent"android:layout_height="100dip"android:layout_alignParentTop="true"style="?android:attr/progressBarStyleHorizontal"android:visibility="gone"/>
</RelativeLayout>

Handler使用例3

上面2个例子表面上看handler使用了post方法启动了runnbale,其实启动的线程和activity主线程是同一个线程,因为它只是运行了线程的run方法,而不是start方法。Mars老师实验3的目的是为了验证仅使用handler的post方法是否处于同一个线程。

该实验在主activtiy的onCreate函数中打印了2条关于本线程的信息,然后创建一个handler并为它绑定一个线程,在线程的run方法中也打印了线程的信息,观察2者的信息是否一样。

结果如下:

说明这2个线程确实是同一线程,并且可以看出主界面中的文字大概过了10s才显示出来,因为语句setContentView(R.layout.activity_main);放在了handler的post启动语句后面,而handler绑定的线程中又延时了10s,所以同时也证明了只有是同一个线程才会出现这种情况。

程序主要代码和注释如下:

MainActivity.java:

package com.example.handler3;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
public class MainActivity extends Activity {//新建一个handlerprivate Handler handler = new Handler();@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//将runnable加载到handler的线程队列中去//  handler.post(r);        Thread t = new Thread(r);t.start();setContentView(R.layout.activity_main);//打印activtiy线程信息System.out.println("activity_id---->"+Thread.currentThread().getId());System.out.println("activity_name---->"+Thread.currentThread().getName());}Runnable r = new Runnable(){public void run() {// TODO Auto-generated method stub//打印新建线程信息System.out.println("handler_id---->"+Thread.currentThread().getId());System.out.println("handler_name---->"+Thread.currentThread().getName());//延时10s,为了观察主界面中内容出现的时间try {Thread.sleep(10000);} catch (InterruptedException e) {// TODO: handle exceptione.printStackTrace();}}};@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}
}

如果把语句:

handler.post(r);

换成:

Thread t = new Thread(r);
t.start();

其它的不变,则程序运行时主界面内容立刻就显示出来了,且系统输出如下:
这2者都说明这样绑定的线程与它所在的activity线程就不是同一个线程了。

Handler使用例4

这个例子将学会怎样不使用runnable来启动一个线程,而是用HandlerThread的looper来构造一个handler,然后该handler自己获得消息,并传递数据,然后又自己处理消息,当然这是在另一个线程中完成的。

消息结构中传递简单的整型可以采用它的参数arg1和arg2,或者传递一些小的其它数据,可以用它的object,该object可以是任意的对象。当需要传送比较大的数据是,可以使用消息的setData方法,该方法需要传递一个Bundle的参数。Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已。

程序主要代码和注释如下:

MainActivity.java:

package com.example.handler4;
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.view.Menu;
public class MainActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);System.out.println("activity_ID---->"+Thread.currentThread().getId());//新建一个HanderThread对象,该对象实现了用Looper来处理消息队列的功能HandlerThread handler_thread = new HandlerThread("handler_thread");handler_thread.start();//MyHandler类是自己继承的一个类,这里采用hand_thread的Looper来初始化它MyHandler my_handler = new MyHandler(handler_thread.getLooper());//获得一个消息msgMessage msg = my_handler.obtainMessage();//采用Bundle保存数据,Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已Bundle b = new Bundle();b.putString("whether", "晴天");b.putInt("temperature", 34);msg.setData(b);//将msg发送到自己的handler中,这里指的是my_handler,调用该handler的HandleMessage方法来处理该mugmsg.sendToTarget();}class MyHandler extends Handler{//空的构造函数public MyHandler(){}//以Looper类型参数传递的函数,Looper为消息泵,不断循环的从消息队列中得到消息并处理,因此//每个消息队列都有一个Looper,因为Looper是已经封装好了的消息队列和消息循环的类public MyHandler(Looper looper){//调用父类的构造函数super(looper);}@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubSystem.out.println("Handler_ID---->"+Thread.currentThread().getId());System.out.println("Handler_Name---->"+Thread.currentThread().getId());//将消息中的bundle数据取出来Bundle b = msg.getData();String whether = b.getString("whether");int temperature = b.getInt("temperature");System.out.println("whether= "+whether+" ,temperature= "+temperature);}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}
}

总结:

Android中的handler可以用来完成异步的消息出来,即发送消息和接收消息相互独立,可以同时运行。在例1和例2中,实际上handler中使用的线程是与它所在的activity处于同一个主线程,因为handler中调用的runnable接口是直接运行该接口的run函数的,而不是start函数。例3专门比较了这2中情况。例4学会使用怎样在新线程中处理消息的方法。



Android Handler详细使用方法实例相关推荐

  1. pythongui项目实例_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...

    PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...

  2. android 实例源码解释,Android Handler 原理分析及实例代码

    Android Handler 原理分析 Handler一个让无数android开发者头疼的东西,希望我今天这边文章能为您彻底根治这个问题 今天就为大家详细剖析下Handler的原理 Handler使 ...

  3. pythongui界面实例带注释_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...

    PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...

  4. Android Handler中post方法与send方法的区别及使用

    目录 概述 Handler使用sendMessage方法 Handler使用post方法 post方法与send方法的区别 全部代码 效果图 后记 概述 Handler机制是Android中线程通信的 ...

  5. Android Handler的使用方法

    如何让程序5秒钟更新一下Title. 首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示: package com.example.androidha ...

  6. 解决Android Handler的handleMessage()方法内TextView.setText偶尔不执行的问题

    前言 最近项目中要加一个体温测量的外设模块 利用android的串口通信 可以完美的取到测量的体温数据 获取到数据后,在用Handler发送数据到View渲染时 发现一个问题 就是数据能测量到 但是渲 ...

  7. android随机数方法,Android生成随机数的方法实例

    本文实例为大家分享了Android生成随机数的具体代码,供大家参考,具体内容如下 java文件 package com.example.my_xm_bw_luowei; import android. ...

  8. android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例

    Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...

  9. Android Handler讲述很详细的一篇文章

    Android中的Handler <一> Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 ...

最新文章

  1. AppStore审核2.1被拒大礼包过审经历
  2. c10k问题及其解决方案
  3. 在家办公的第一天,钉钉、企业微信集体“崩溃”...
  4. quick cocos2dx 3.x 配置win32工程
  5. 怎么把原来的墙拆掉_电视墙避坑指南要收好!拆掉重装太心累...
  6. ActiveMQ 事务消息 手工签收
  7. mysql字段中有逗号隔开_在MySQL字段中使用逗号分隔符
  8. 编译linux tq2440,QT4.8.2在TQ2440开发板上的移植(一)--编译和安装
  9. linux 内核定时器精度_高精度时钟工作机制简介
  10. 【转】C#中的弱事件:不同的解决方法
  11. (转)python类:magic魔术方法
  12. [jQuery] form提交到iframe之后,获取iframe里面内容
  13. 远程mysql_java.sql.SQLException: null, message from server: Host 'xxx' is not allowed to connect
  14. 天行数据API智能机器人接口
  15. regester正则用法_Regester(正则表达式测试器)官方版
  16. mysql交互式服务检测_MySQL innotop实时监测工具
  17. 微信小程序开发中,图片报403问题(图片加载失败)解决办法
  18. 华为第十届 关灯计划
  19. Linux常用命令(penguin)
  20. 开发直播平台直播系统软件app搭建流程解决方案

热门文章

  1. cdh 安装_CDH 中为spark 安装 python3
  2. 前端 验证码隐藏怎么实现_完成图形验证码
  3. OPENCV已知内参求外参
  4. 数电实验报告实验一_大二下学期的两三事之数电实验amp;课设
  5. 一个简单的synchronized多线程问题、梳理与思考
  6. #define 的换行问题
  7. 【转】C#对象的深拷贝与浅拷贝
  8. 【Tree】迷宫生成算法
  9. post 与 get 的区别
  10. python 发邮件-带附件-文本-html