技术开发 频道

Android开发案例:多线程中的Handler

  【IT168技术】在案例程序代码中用到了一个android.os.Handler类的对象—handler,android.os.Handler是Android中多个线程间消息传递和计划任务的“工具”类。Handler会在多个线程之间发送Message、执行Runnable。使用这些类可以对运行在不同线程中的多个任务进行排队。

  Handler工具类在多线程中有两方面的应用:

  发送消息,在不同的线程间发送消息,使用的方法为sendXXX();

  计划任务,在未来执行某任务,使用的方法为postXXX()。

  1、发送消息

  android.os.Handler对象通过下面的方法发送消息的:

  l sendEmptyMessage(int),发送一个空的消息;

  sendMessage(Message),发送消息,消息中可以携带参数;

  l sendMessageAtTime(Message, long),未来某一时间点发送消息;

  l sendMessageDelayed(Message, long),延时Nms发送消息。

  一个线程发出消息后,另外的线程要接收消息,接收消息通过重写Handler类的handleMessage(Message)方法实现,如下代码所示:

handler = new Handler() {

        @Override
        
public void handleMessage(Message msg) {
            switch (msg.what) {
            
case 0:
                labelTimer.setText(
"逝去了 " + msg.obj + "");
            }
        }

    };

  2、计划任务

  android.os.Handler对象通过下面的方法执行计划任务:

  l post(Runnable),提交计划任务马上执行;

  l postAtTime(Runnable, long),提交计划任务在未来的时间点执行;

  l postDelayed(Runnable, long),提交计划任务延时Nms执行。

  通过Handler的postXXX()方法提交计划任务,那么谁来完成这个任务呢?可以通过实现Runnable接口的run()方法:

Runnable r = new Runnable() {
    
public void run() {
        ... ...
    }
};

  代码清单8-7所示是把案例修改成计划任务方式的代码,完整代码请参考chapter8_6工程中 chapter8_6代码部分。

  【代码清单8-7】

public class chapter8_6 extends Activity {    

    
private String TAG = "chapter8_6";
    
private Button btnEnd;
    
private TextView labelTimer;
    
private boolean isRunning = true;
    
private Handler handler;
    
private int timer = 0;

    @Override
    
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btnEnd
= (Button) findViewById(R.id.btnEnd);
        btnEnd.setOnClickListener(
new OnClickListener() {
            @Override
            
public void onClick(View v) {
                isRunning
= false;
            }
        });
        
        handler
= new Handler();
        
        Runnable r
= new Runnable() {
            
public void run() {
                
if (isRunning) {
                    labelTimer.setText(
"逝去了 " +timer + "");
                    
timer++;
                    handler.postDelayed(this,
1000);
                }

            }
        };
        handler.postDelayed(r,
1000);

        labelTimer
= (TextView) findViewById(R.id.labelTimer);

    }
    }

  运行一次handler.postDelayed(this, 1000) 只能向线程提交一次消息,如果想反复运行线程体(run()方法),就要在run()方法的后面再次提交,这样就会达到每1s执行一次线程体(run()方法)的效果了。

  发送消息和计划任务有什么不同?发送消息可以向一个线程通信请求,请求它执行某些处理,并可以携带数据,这些数据被封装在Message对象中,发送消息的线程处理方法就是重写handleMessage()方法,代码如下:

handler = new Handler() {

    @Override
    
public void handleMessage(Message msg) {
        ... ...
    }

};

  计划任务也可以向一个线程通信发请求,请求它执行某些处理,但不可以携带数据,计划任务的线程处理方法就是重写run()方法,代码如下:

Runnable r = new Runnable() {
    
public void run() {
           ... ...
    }
};

  消息发送和计划任务提交之后,它们都会进入目标线程的消息队列中,目标线程并不区分是主线程还是子线程。图8-12所示是消息发送示意图,线程2就是目标线程。图8-13所示是计划任务提交示意图,线程2就是目标线程,计划任务也是有消息队列维护的。

Android开发案例:多线程中的Handler
▲图8-12 消息发送

Android开发案例:多线程中的Handler
▲图8-13 计划任务

  无论是消息发送还是计划任务都可以实现“计时器”案例,使用那一种方式可以根据自己的喜好选择。但是由于UI控件labelTimer是在主线程中声明和创建的,因此更新labelTimer操作必须在主线程中处理,也就是说更新UI的主线程必须作为目标线程。

Android开发案例:多线程中的Handler
▲图书参考

0
相关文章