Android Handler详细使用方法实例
本文主要介绍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详细使用方法实例相关推荐
- pythongui项目实例_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...
PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...
- android 实例源码解释,Android Handler 原理分析及实例代码
Android Handler 原理分析 Handler一个让无数android开发者头疼的东西,希望我今天这边文章能为您彻底根治这个问题 今天就为大家详细剖析下Handler的原理 Handler使 ...
- pythongui界面实例带注释_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...
PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...
- Android Handler中post方法与send方法的区别及使用
目录 概述 Handler使用sendMessage方法 Handler使用post方法 post方法与send方法的区别 全部代码 效果图 后记 概述 Handler机制是Android中线程通信的 ...
- Android Handler的使用方法
如何让程序5秒钟更新一下Title. 首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示: package com.example.androidha ...
- 解决Android Handler的handleMessage()方法内TextView.setText偶尔不执行的问题
前言 最近项目中要加一个体温测量的外设模块 利用android的串口通信 可以完美的取到测量的体温数据 获取到数据后,在用Handler发送数据到View渲染时 发现一个问题 就是数据能测量到 但是渲 ...
- android随机数方法,Android生成随机数的方法实例
本文实例为大家分享了Android生成随机数的具体代码,供大家参考,具体内容如下 java文件 package com.example.my_xm_bw_luowei; import android. ...
- android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例
Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...
- Android Handler讲述很详细的一篇文章
Android中的Handler <一> Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 ...
最新文章
- AppStore审核2.1被拒大礼包过审经历
- c10k问题及其解决方案
- 在家办公的第一天,钉钉、企业微信集体“崩溃”...
- quick cocos2dx 3.x 配置win32工程
- 怎么把原来的墙拆掉_电视墙避坑指南要收好!拆掉重装太心累...
- ActiveMQ 事务消息 手工签收
- mysql字段中有逗号隔开_在MySQL字段中使用逗号分隔符
- 编译linux tq2440,QT4.8.2在TQ2440开发板上的移植(一)--编译和安装
- linux 内核定时器精度_高精度时钟工作机制简介
- 【转】C#中的弱事件:不同的解决方法
- (转)python类:magic魔术方法
- [jQuery] form提交到iframe之后,获取iframe里面内容
- 远程mysql_java.sql.SQLException: null, message from server: Host 'xxx' is not allowed to connect
- 天行数据API智能机器人接口
- regester正则用法_Regester(正则表达式测试器)官方版
- mysql交互式服务检测_MySQL innotop实时监测工具
- 微信小程序开发中,图片报403问题(图片加载失败)解决办法
- 华为第十届 关灯计划
- Linux常用命令(penguin)
- 开发直播平台直播系统软件app搭建流程解决方案