① Android Studio Handler 用法
you should import "Android.os.Handler" to override the method "handleMessage".
② Android中Handler的使用方法
Handler在Android中主要是负责发送和处理消息。它的主要用途大致是下面两个:
1)按计划发送消息或执行某个Runnanble;
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)
学写一下,在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理。在实例化Handler的时候,只要有Handler的指针,任何线程也都可以sendMessage。
Handler对于Message的处理是异步处理的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。
根据对视频的学习写了一个通过Button控件启动进度条(类似于下载等操作)的程序,简单介绍一下,有两个Button控件,一个是开始,点击之后会显示一个进度条以每次十分之一的进度进行(一开始是隐藏的),另一个是停止,可以中断进度。
java代码:
1 package zzl.handleactivity;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.os.Message;
7 import android.view.Gravity;
8 import android.view.View;
9 import android.view.View.OnClickListener;
10 import android.widget.Button;
11 import android.widget.ProgressBar;
12 import android.widget.Toast;
13
14 public class Handler_01 extends Activity {
15
16 //声明变量
17 private Button startButton=null;
18 private Button endButton=null;
19 private ProgressBar firstBar=null;
20 private Toast toast=null;
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.main);
25
26 //根据ID获取对象
27 startButton =(Button)findViewById(R.id.startButton);
28 endButton=(Button)findViewById(R.id.endButton);
29 firstBar=(ProgressBar)findViewById(R.id.firstBar);
30 //给对象设置动作监听器
31 startButton.setOnClickListener(new StartButtonListener());
32 endButton.setOnClickListener(new EndButtonListener());
33 }
34
35 class StartButtonListener implements OnClickListener{
36
37 @Override
38 public void onClick(View v) {
39 // TODO Auto-generated method stub
40 //一开始执行,加入到消息队列,不延迟,
41 //然后马上执行run方法
42 firstBar.setVisibility(View.VISIBLE);
43 firstBar.setMax(100);
44 handler.post(upRunnable);
45 toast=Toast.makeText(Handler_01.this, "运行开始", Toast.LENGTH_SHORT);
46 toast.setGravity(Gravity.CENTER, 0, 0);
47 toast.show();
48 }
49 }
50 class EndButtonListener implements OnClickListener{
51
52 @Override
53 public void onClick(View v) {
54 // TODO Auto-generated method stub
55 //停止
56 handler.removeCallbacks(upRunnable);
57 System.out.println("It's time to stop...");
58 }
59 }
60
61 //创建handler对象,在调用post方法
62 //异步消息处理:将下载或者处理大数据等等单独放到另一个线程
63 //更好的用户体验
64 Handler handler=new Handler(){
65
66 @Override
67 public void handleMessage(Message msg){
68 firstBar.setProgress(msg.arg1);
69 firstBar.setSecondaryProgress(msg.arg1+10);
70 //handler.post(upRunnable);
71 if(msg.arg1<=100) {
72 handler.post(upRunnable); //将要执行的线程放入到队列当中
73 }else {
74 handler.removeCallbacks(upRunnable);
75 }
76 }
77 };
78
79 //声明线程类:实现Runnable的接口
80 Runnable upRunnable=new Runnable() {
81
82 int i=0;
83 @Override
84 public void run() {//程序的运行状态
85 // TODO Auto-generated method stub
86 //postDelayed方法:把线程对象加入到消息队列中
87 // 隔2000ms(延迟)
88 System.out.println("It's time to start...");
89 i=i+10;
90 //获取Message消息对象
91 Message msg=handler.obtainMessage();
92 //将msg对象的arg1(还有arg2)对象的值设置
93 //使用这两个变量传递消息优点:系统消耗性能较少
94 msg.arg1=i;
95 try{
96 //设置当前显示睡眠1秒
97 Thread.sleep(1000);
98 }catch(InterruptedException e){
99 e.printStackTrace();
100 }
101 //将msg对象加入到消息队列当中
102 handler.sendMessage(msg);
103 if(i==100){//当值满足时,将线程对象从handle中剔除
104 handler.removeCallbacks(upRunnable);
105 firstBar.setVisibility(View.GONE);
106 //临时弹出
107
108 toast=Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT);
109 toast.setGravity(Gravity.CENTER, 0, 0);
110 toast.show();
111 }
112 }
113 };
114 }
main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:orientation="vertical"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 tools:context=".Handler_01" >
7
8 <ProgressBar
9 android:id="@+id/firstBar"
10 style="?android:attr/progressBarStyleHorizontal"
11 android:layout_width="200dp"
12 android:layout_height="wrap_content"
13 android:visibility="gone"/>
14
15 <Button
16 android:id="@+id/startButton"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:text="@string/start" />
20
21 <Button
22 android:id="@+id/endButton"
23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content"
25 android:text="@string/end" />
26
27 </LinearLayout>
总结:
1)当点击开始或者运行结束的时候,都会通过调用Toas弹出临时窗口,Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT),这一句一开始总是执行出错,原因在于必须调用它的show方法才可以显示出来,还可以通过设置它的位置来显示;
2)在xml中 android:text="@string/end",则需要在layout下的string文件中敲写相应的代码
3)原本代码有一些瑕疵,就是没有下面这一段代码:
1 if(msg.arg1<=100) {
2 handler.post(upRunnable); //将要执行的线程放入到队列当中
3 }else {
4 handler.removeCallbacks(upRunnable);
5 }
这样就导致了upRunnable的run方法出现了死循环,这样,虽然程序UI本身没有问题,但是内部却又很大的缺陷
这是因为
1 if(i==100){//当值满足时,将线程对象从handle中剔除
2 handler.removeCallbacks(upRunnable);
3 firstBar.setVisibility(View.GONE);
4 toast=Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT);
5 toast.setGravity(Gravity.CENTER, 0, 0);
6 toast.show();
7 }
这一段代码看似是把upRunnable线程从线程对象队列中移除,但是再次之前又前执行了handler.sendMessage(msg);这句代码
从而导致下面的代码又被执行到
1 public void handleMessage(Message msg){
2 firstBar.setProgress(msg.arg1);
3 firstBar.setSecondaryProgress(msg.arg1+10);
4
5 }
这样肯定会使upRunnable线程重新加入到线程对象队列中,updateThread的run方法重复执行,这就导致了死循环。所以必须加上之前的那段代码,通过判断来控制循环终止。并且run方法中的if(i==100)的那段代码也是可以不用的,不过我是写了一些其他代码就懒得优化了,这是后话了。
4) 刚刚大家看到我们可以通过敲写System.out.println在logcat中显示,一开始eclipse编译器中是没有,这是如何显示出来的?
大家可以再window的show view中找到logCat(deprecated)通过下图中绿色的“+”添加出来
然后显示内容的时候,选择右上角“V D I W E ”的I就可以比较清晰的显示出来了,当然你也可以选择另外一个logCat来显示,方法类似。
5)实际上,Handler在默认情况下,和调用它的Activity是处于同一个线程的。 上述Handler的使用示例中,虽然声明了线程对象,但是在实际调用当中它并没有调用线程的start()方法,而是直接调用当前线程的run()方法。
如果要实现调用另一个新的线程,只要注释post方法,然后加上这样两段代码即可: Thread t = new Thread(r); t.start();
③ android中Handler的post方法的作用是什么
在工作线程中执行耗时任务,当任务完成时,会返回UI线程,一般是更新UI。这时有两种方法可以达到目的。
一种是handler.sendMessage。发一个消息,再根据消息,执行相关任务代码。
另一种是handler.post(r)。r是要执行的任务代码。意思就是说r的代码实际是在UI线程执行的。可以写更新UI的代码。
(3)androidhandler的使用方法扩展阅读
一个APK文件结构为:
1、META-INF (注:Jar文件中常可以看到);
2、res (注:存放资源文件的目录) ;
3、AndroidManifest.xml (注:程序全局配置文件) ;
4、classes.dex (注:Dalvik字节码);
5、resources.arsc (注:编译后的二进制资源文件)。
Android在运行一个程序时首先需要UnZip,然后类似Symbian那样直接执行安装,和Windows Mobile中的PE文件有区别,这样做对于程序的保密性和可靠性不是很高,通过dexmp命令可以反编译,但这样做符合发展规律,微软的 Windows Gadgets或者说WPF也采用了这种构架方式。
在Android平台中dalvik vm的执行文件被打包为apk格式,最终运行时加载器会解压然后获取编译后androidmanifest.xml文件中的permission分支相关的安全访问,但仍然存在很多安全限制,如果你将apk文件传到/system/app文件夹下会发现执行是不受限制的。
参考资料来源:网络-Android
④ Android Handler机制 怎么用
Handler对象与其调用者在同一线程中,如果在Handler中设置了延时操作,则调用线程也会堵塞。每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。
在主线程中,可以直接使用new Handler()创建Handler对象,其将自动与主线程的Looper对象绑定;在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。这种情况下,需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上;或者通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。
Handler发送的消息都会加入到Looper的MessageQueue中。一说Handler包含两个队列:线程队列和消息队列;使用Handler.post()可以将线程对象加入到线程队列中;使用Handler.sendMessage()可以将消息对象加入到消息队列中。通过源码分析证实,Handler只有一个消息队列,即MessageQueue。通过post()传进去的线程对象将会被封装成消息对象后传入MessageQueue。
使用post()将线程对象放到消息队列中后,当Looper轮询到该线程执行时,实际上并不会单独开启一个新线程,而仍然在当前Looper绑定的线程中执行,Handler只是调用了该线程对象的run()而已。如,在子线程中定义了更新UI的指令,若直接开启将该线程执行,则会报错;而通过post()将其加入到主线程的Looper中并执行,就可以实现UI的更新。
使用sendMessage()将消息对象加入到消息队列后,当Looper轮询到该消息时,就会调用Handler的handleMessage()来对其进行处理。再以更新UI为例,使用这种方法的话,就先将主线程的Looper绑定在Handler对象上,重载handleMessage()来处理UI更新,然后向其发送消息就可以了。
⑤ Android 为什么使用Handler
在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化。有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过接收到的消息更新主UI线程的内容。
我们假设在一个UI界面上面,有一个按钮,当点击这个按钮的时候,会进行网络连接,并把网络上的一个字符串拿下来显示到界面上的一个 TextView上面,这时就出现了一个问题,如果这个网络连接的延迟过大,可能是10秒钟甚至更长,那我们的界面将处于一直假死状态,而如果这段时间超 过5秒钟的话,程序会出现异常。
这时我们会想到使用线程来完成以上工作,即当按钮被按下的时候新开启一个线程来完成网络连接工作,并把得到的结果更新到UI上面。但是,这时候又会 出现另一个问题,在Android中,主线程是非线程安全的,也就是说UI的更新只能在本线程中完成,其他线程无法直接对主线程进行操作。
为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。接下来举例来诠释Handler的基本使用方法。
Handler的工作原理
一般情况下,在主线程中我们绑定了Handler,并在事件触发上面创建新的线程用于完成某些耗时的操作,当子线程中的工作完成之后,会对Handler发送一个完成的信号,而Handler接收到信号后,就进行主UI界面的更新操作。
2
Handler与子线程协作实例
1、创建Handler实现类,在主UI所在类中的内部类
class MyHandler extends Handler {
public MyHandler() { }
public MyHandler(Looper L) {
super(L);
}
// 重写handleMessage方法,接受数据并更新UI
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//此处根据msg内容进行UI操作
}
}
2、子线程的实现
class MyThread implements Runnable {
public void run() {
Message msg = new Message();
Bundle b = new Bundle();
b.putString("cmd", "update");
msg.setData(b);
MainActivity.this.myHandler.sendMessage(msg);
//通知Handler更新UI
}
}
通过以上的两个实现,我们只需要在MainActivity中声明MyHandler实例对象就可以完成线程之间的通讯和界面的更新操作。
MyHandler myHandler = newMyHandler();
⑥ 能讲讲Android的Handler机制吗
Android的Handler机制是通俗讲为了互相发消息,一般是子线程给主线程发消息完成相应操作。
安卓中最常见的操作是子线程操作完事后得到数据想更新UI,安卓有规定不允许在子线程中刷新UI,所以Handler出现了。
使用和理解大致步骤。
创建全局Handler对象handler,然后在主线程中初始化它(一般在oncreate中),把它的handmessage里面的方法重写,这个方法是收到子线程发给它的消息后执行的逻辑。
在子线程中获取数据,调用handler.sendmessage,把要发的消息放在message中。message会添加到Messagequue(消息队列中,handler创建就带的)。
3.对象handler被创建和初始化的时候,系统自动会启动Handler.looper,也就是一个消息轮询器,它不断的去查看有没有消息进入到Messagequue(消息队列中),有就取出交给handler的handmessage去处理。//这段逻辑是系统自动执行,理解就行。*纯手打,不骗人~~~
⑦ android中handler的使用
Handler这部分我也在用,模仿例子套着用,主要用于子线程向主程序发消息,让Handler对象处理。你的疑问我也有,这new Handler(){},只是一瞬间就结束的,可它仍时刻监视着自已的消息以便随时再处理,这似乎有点不符常规令人不解,但细想一下,这就象一个按钮控件对象,
你点击一下,它就能响应一次点击处理事件。
⑧ Android中Handler的主要作用是什么通俗点,初学。
Handler的使用主要是android中无法在主线程(即UI线程)中访问网络、无法在子线程中访问UI线程元素。
一般是在子线程中访问网络,然后使用Handler发送message通知主线程处理UI更新操作
⑨ C#写Android应用时handler和message要怎么用
handler的方法中有post();里面的参数为Runnable类型,一般在主线程中建立handler,子线程向其发送消息,使其更新UI界面,在主线程中,可以通过post(),将Runnable()中的任务加入主线程的消息队列中;
在子线程中,是没有消息队列的,需要自己创建,在主线程中,系统会帮我们创建一个消息队列;
Looper负责消息的传递
这样子线程就可以用post将Runnbale()加入到消息队列中去,这样主线程都可以向子线程发送消息了,如:按钮(点击后发送消息)
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();//Looper准备
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();//让Looper动起来
}
}
原则是:先建立Handler,再发送消息,或者post();
Handler的函数在所有线程中均可使用,利用内部类实现;