Android中Handler的使用方法有哪些?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中Handler的使用方法有哪些?相关的知识,希望对你有一定的参考价值。

我通过看教程知道Handler相当于线程的作用,那我可不可以像Java中那样(没有Handler),直接继承Thread或实现Runnable创建线程呢?我觉得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();
参考技术A Android之Handler用法总结

方法一:(java习惯,在android平台开发时这样是不行的,因为它违背了单线程模型)

刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问题

new Thread( new Runnable()
public void run()
myView.invalidate();

).start();

可以实现功能,刷新UI界面。但是这样是不行的,因为它违背了单线程模型:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

方法二:(Thread+Handler)

查阅了文档和apidemo后,发觉常用的方法是利用Handler来实现UI线程的更新的。

Handler来根据接收的消息,处理UI更新。Thread线程发出Handler消息,通知更新UI。

Handler myHandler = new Handler()
public void handleMessage(Message msg)
switch (msg.what)
case TestHandler.GUIUPDATEIDENTIFIER:
myBounceView.invalidate();
break;

super.handleMessage(msg);

;

class myThread implements Runnable
public void run()
while (!Thread.currentThread().isInterrupted())
Message message = new Message();
message.what = TestHandler.GUIUPDATEIDENTIFIER;
TestHandler.this.myHandler.sendMessage(message);
try
Thread.sleep(100);
catch (InterruptedException e)
Thread.currentThread().interrupt();





以上方法demo看:http://rayleung.javaeye.com/blog/411860

方法三:(java习惯。Android平台中,这样做是不行的,这跟Android的线程安全有关)

在Android平台中需要反复按周期执行方法可以使用Java上自带的TimerTask类,TimerTask相对于Thread来说对于资源
消耗的更低,除了使用Android自带的AlarmManager使用Timer定时器是一种更好的解决方法。 我们需要引入import
java.util.Timer; 和 import java.util.TimerTask;

public class JavaTimer extends Activity
Timer timer = new Timer();
TimerTask task = new TimerTask()
public void run()
setTitle("hear me?");

;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
timer.schedule(task, 10000);



方法四:(TimerTask + Handler)

通过配合Handler来实现timer功能的!

public class TestTimer extends Activity
Timer timer = new Timer();
Handler handler = new Handler()
public void handleMessage(Message msg)
switch (msg.what)
case 1:
setTitle("hear me?");
break;

super.handleMessage(msg);

;
TimerTask task = new TimerTask()
public void run()
Message message = new Message();
message.what = 1;
handler.sendMessage(message);

;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
timer.schedule(task, 10000);



方法五:( Runnable + Handler.postDelayed(runnable,time) )

在Android里定时更新 UI,通常使用的是 java.util.Timer, java.util.TimerTask, android.os.Handler组合。实际上Handler 自身已经提供了定时的功能。

private Handler handler = new Handler();
private Runnable myRunnable= new Runnable()
public void run()

if (run)
handler.postDelayed(this, 1000);
count++;

tvCounter.setText("Count: " + count);

;

然后在其他地方调用

handler.post(myRunnable);

handler.post(myRunnable,time);

知识点总结补充:

很多初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有
HandlerThread、java.util.concurrent、Task、AsyncTask由于目前市面上的书籍等资料都没有谈到这些问题,
今天就这一问题做更系统性的总结。我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。但是在操作一些耗时操作时,比如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑使用Thread线程来解决。

对于从事过J2ME开发的程序员来说Thread比较简单,直接匿名创建重写run方法,调用start方法执行即可。或者从Runnable接口继承,但对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,这点Google在设计Android时倒是参考了下Win32的消息处理机制。

1. 对于线程中的刷新一个View为基类的界面,可以使用postInvalidate()方法在
线程中来处理,其中还提供了一些重写方法比如postInvalidate(int left,int top,int right,int
bottom) 来刷新一个矩形区域,以及延时执行,比如postInvalidateDelayed(long
delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int
left,int top,int right,int bottom) 方法,其中第一个参数为毫秒

2. 当然推荐的方法是通过一个Handler来处理这些,可以在一个线程的
run方法中调用handler对象的
postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮训处理这些,如果你是Win32程序员可以
很好理解这些消息处理,不过相对于Android来说没有提供 PreTranslateMessage这些干涉内部的方法。

3. Looper又是什么呢?
,其实Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列,但是Looper和
Handler没有什么关系,我们从开源的代码可以看到Android还提供了一个Thread继承类HanderThread可以帮助我们处理,在
HandlerThread对象中可以通过getLooper方法获取一个Looper对象控制句柄,我们可以将其这个Looper对象映射到一个
Handler中去来实现一个线程同步机制,Looper对象的执行需要初始化Looper.prepare方法就是昨天我们看到的问题,同时推出时还要
释放资源,使用Looper.release方法。

4.Message 在Android是什么呢? 对于Android中Handler可以传递一些内容,通过Bundle对象可以封装String、Integer以及Blob二进制对象,我们通过在线程中使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器。对于Handler类提供了重写方法handleMessage(Message msg) 来判断,通过msg.what来区分每条信息。
将Bundle解包来实现Handler类更新UI线程中的内容实现控件的刷新操作。相关的Handler对象有关消息发送sendXXXX相关方法如
下,同时还有postXXXX相关方法,这些和Win32中的道理基本一致,一个为发送后直接返回,一个为处理后才返回 .

5.
java.util.concurrent对象分析,对于过去从事Java开发的程序员不会对Concurrent对象感到陌生吧,他是JDK
1.5以后新增的重要特性作为掌上设备,我们不提倡使用该类,考虑到Android为我们已经设计好的Task机制,这里不做过多的赘述,相关原因参考下
面的介绍:

6. 在Android中还提供了一种有别于线程的处理方式,就是Task以及AsyncTask,从开源代码中可以看到是针对Concurrent的封装,开发人员可以方便的处理这些异步任务。
参考技术B 1、调用 函数getOf_getOn();
2、异步获取数据
public void getOf_getOn()
new Thread(new Runnable()
@Override
public void run()

List<HashMap<String, String>> listOut = new ArrayList<HashMap<String, String>>();
// 从数据库中异步获取数据
listOut = paymentManager.checkPremissions(errorlist_menu.this,
userID, txtTitle.getText().toString());
Message msg = new Message();
msg.obj = listOut;
msg.what = 1;
handlerinformationtest.sendMessage(msg);

).start();

3、异步接收数据
Handler handlerinformationtest = new Handler()
@Override
public void handleMessage(Message msg)
// TODO Auto-generated method stub
super.handleMessage(msg);

if (msg.what == 1)
List<HashMap<String, String>> list = (List<HashMap<String, String>>) msg.obj;
if (list.size() > 0)
HashMap<String, String> hashMapOut = new HashMap<String, String>();
hashMapOut = list.get(0);
gsft_id = hashMapOut.get("Gsft_id");
gsft_flag = hashMapOut.get("Gsft_flag");


参考技术C 选择3G培训机构,要最起码的了解一些情况比如师资是否真的做过这方面的开发?是否有线上真实的应用?教学设备如何?是不是真正的先 就 业后 付款?
我知道的比较好的就是华夏 博大3G学 院,基本情况都很好,你可以了解一下!\
参考技术D 你可以直接创建自己的thread来完成一些工作。
Handler主要是用来跟UI主线程交互用。 比如:
1、你用handler发送一个message,然后在handler的线程中来接收、处理该消息,以避免直接在UI主线程中处理事务导致影响UI主线程的其他处理工作。
2、你可以将handler对象传给其他进程,以便在其他进程中通过handler给你发送事件。
3、通过handler的延时发送message,可以延时处理一些事务的处理本回答被提问者和网友采纳

Android--Handler的使用方法:在子线程中更新界面

本文主要介绍Android的Handler的使用方法。Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列。每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联。

  1.     Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器。2)线程间通信。在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息。当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Handler对象,就可以通过该对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。

◆ 通过Runnable在子线程中更新界面的例子

在onCreate中创建Handler
public class HandlerTestApp extends Activity { 
        Handler mHandler; 
        TextView mText; 
        /** Called when the activity is first created. */ 
       @Override 
       public void onCreate(Bundle savedInstanceState) { 
           super.onCreate(savedInstanceState); 
           setContentView(R.layout.main); 
           mHandler = new Handler();//创建Handler 
           mText = (TextView) findViewById(R.id.text0);//一个TextView 
       }
构建Runnable对象,在runnable中更新界面,此处,我们修改了TextView的文字.此处需要说明的是,Runnable对象可以再主线程中创建,也可以再子线程中创建。我们此处是在子线程中创建的。

Runnable mRunnable0 = new Runnable() 
    { 
                @Override 
                public void run() { 
                        // TODO Auto-generated method stub 
                        mText.setText("This is Update from ohter thread, Mouse DOWN"); 
                } 
    };

 创建子线程,在线程的run函数中,我们向主线程的消息队列发送了一个runnable来更新界面。
private void updateUIByRunnable(){ 
          new Thread()  
         {  
               //Message msg = mHandler.obtainMessage();  
              public void run()  
             { 

                   //mText.setText("This is Update from ohter thread, Mouse DOWN");//这句将抛出异常 
                   mHandler.post(mRunnable0);  
             }  
         }.start();

     }

◆ 用Message在子线程中来更新界面

  1.     用Message更新界面与Runnable更新界面类似,只是需要修改几个地方。
实现自己的Handler,对消息进行处理

    private class MyHandler extends Handler 
    {

        @Override 
        public void handleMessage(Message msg) { 
            // TODO Auto-generated method stub 
            super.handleMessage(msg); 
            switch(msg.what) 
            { 
            case UPDATE://在收到消息时,对界面进行更新 
                mText.setText("This update by message"); 
                break; 
            } 
        } 
    }

在新的线程中发送消息     
    private void updateByMessage() 
    { 
        //匿名对象 
         new Thread() 
         { 
                public void run() 
                { 
                    //mText.setText("This is Update from ohter thread, Mouse DOWN");

                    //UPDATE是一个自己定义的整数,代表了消息ID 
                    Message msg = mHandler.obtainMessage(UPDATE); 
                    mHandler.sendMessage(msg); 
                } 
         }.start(); 
    }



以上是关于Android中Handler的使用方法有哪些?的主要内容,如果未能解决你的问题,请参考以下文章

Android---Handler体系

Handler

Handler

Handler

如何在 Android 上更好地对 Looper 和 Handler 代码进行单元测试?

Android消息机制Handler的实现原理解析