注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东东的博客

江南烟雨,同大家一起分享

 
 
 

日志

 
 

Handler应用总结  

2009-10-10 17:02:00|  分类: android相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
                                                                                                                                       (原创,转载请注明出处)


       先从自己之前遇到的一个问题讲起吧:我想在应用里面实现两件事:点击Button后,1)每隔三秒更换一次桌面。2)每隔三秒在ImageView里面更换一张图片(时间与1同步,图片与1相同)。

如图:



    图片是从资源里面随机得到的。想单纯实现换桌面和换图片是容易的,只要调用setWallpaper(bmp);mImageView.setImageDrawable(getResources().getDrawable(bgs[r]));就可以了,但是要周期改变图片就有点小麻烦了。我们最容易想到的就是开个线程来控制,于是就有了如下代码:

mButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                new Thread() {
                    public void run() {

                        while (true) {
                            int r = rand();
                            Bitmap bmp = BitmapFactory.decodeResource(
                                    getResources(), bgs[r]);
                  // mImageView.setImageDrawable(getResources().getDrawable(bgs[r]));

                            try {
                                setWallpaper(bmp);
                                Thread.sleep(3000);
                            } catch (IOException e) {

                                e.printStackTrace();
                            } catch (InterruptedException e) {

                                e.printStackTrace();
                            }
                        }
                    }
                }.start();

            }
        });

   你也可以用timer来实现(其实就是被封装好了的线程):

mButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Timer timer = new Timer();
                TimerTask task = new TimerTask() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        int r = rand();
                        Bitmap bmp = BitmapFactory.decodeResource(
                                getResources(), bgs[r]);
                     // mImageView.setImageDrawable(getResources().getDrawable(bgs[r]));
                        try {
                            setWallpaper(bmp);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                };
                timer.schedule(task, 3000L, 3000L);

            }

        });

    大家会注意到:换图片的的方法被注掉了,因为这样用的话,会抛出CalledFromWrongTreadExeption。为什么会有这样的异常呢?这是因为:像ImagerView这样的View之类的东西只能在UI线程里被调用。而我们的应用的UI线程只有一个,就是当前这个Activity的线程。我们自己开的线程都不是UI线程。这就要用到Handler了。android里面对于异步消息的处理,提供了一套Handler的实现方案。Handler有很多适宜的应用和微妙之处,使它在和Thread以及Service等一起使用的时候达到很好的效果。Handler与调用者处于同一线程,如果Handler里面做耗时的动作,调用者线程会阻塞。Android UI操作不是线程安全的,并且这些操作必须在UI线程中执行。Android提供了几种基本的可以在其他线程中处理UI操作的方案,包括Activity runOnUiThread(Runnable),Viewpost以及1.5版本的工具类AsyncTask等方案都采用了 HandlerHandlerpost对线程的处理也不是真正start一个新的线程,而是直接调用了线程的run方法,这正是google煞费苦心 搞一套Handler的用意。

     一个Handler允许你传递和执行结合了一个线程的消息队列的Message类或Runnable类的对象。每一个Handler的实例被结合于一个单独的线程和一个线程的消息队列。当你创建一个新的Handler时,它被绑定到一个正在创建它的线程的线程/消息队列--从这一点来看,当messagesrunnables出了消息队列时,这个Handler将传递这些messagesrunnables到那个消息队列并执行它们。

    Handler有两个重要的作用:1)安排messagesrunnables在将来被作为一些元素来执行。2)把一个将要被执行,并且与你当前的线程不同的action入队。

    我们处理messages一般用到如下方法:post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), sendMessageDelayed(Message, long) 当一些将要被消息队列调用的Runnable对象被得到时,post形式的方法允许你把这些Runnable对象入队。而如果一个Message对象绑定了一些将要被HandlerhandleMessage(Message)方法所处理的数据,那么sendMessage形式的方法允许你把这样的Message对象入队(要求你必须实现一个Handler的子类)。

当把一个Message“posting”或“sending”到一个Handler时,你可以或者一旦消息队列准备好处理消息时就处理这个项目,或者在它被处理之前指定一个延时或指定一个绝对时间来处理它。后者的两个方法允许你实现延时“设定、读秒”和一些其它的基于时间的行为。

    当你的应用创建了一个进程。就意味着线程被献身于运行一个消息队列。这个消息队列关心的是:管理高级的应用对象(activitiesbroadcast receivers等)和任何它们所创建的窗口。

你可以创建自己的线程,并且通过一个Handler与主应用线程返回通信。返回通信是这样被做到的:从你自己new的线程里,调用同样的post或者sendMessage方法。所给的RunnableMessage将被安排在Handler的消息队列并且在适当的时候被处理。

   下面就看看怎么利用Handler解决一开始提到的问题吧,首先在自己开的线程中把消息发出去:


mButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Timer timer = new Timer();
                TimerTask task = new TimerTask() {
                   
                    public void run() {

//                        Message message = Message.obtain(mHandler,
//                                EVENT_TIME_TO_CHANGE_IMAGE);
 
                        Message message = mHandler.obtainMessage(EVENT_TIME_TO_CHANGE_IMAGE);                                                

                        mHandler.sendMessage(message);

                    }
                };
                timer.schedule(task, 3000L, 3000L);

            }

        });


   被注掉的方法和它下面得到message的方法效果是一样的。然后要在主线程里new一个Handler来接受消息并处理事件:

private Handler mHandler = new Handler() {
       
        public void handleMessage(Message msg) {

            switch (msg.what) {

            case EVENT_TIME_TO_CHANGE_IMAGE:

                int r = rand();

                Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                        bgs[r]);

                try {

                    setWallpaper(bmp);
//换桌面
                    changeImg(r);      //图片
                } catch (IOException ie) {

                    ie.printStackTrace();
                } catch (Exception e) {

                    e.printStackTrace();

                }

                break;
            }
        }
    };


   这样,就不会出现CalledFromWrongTreadExeption异常了。最后,给出完整的代码清单:

package com.li.android.timer;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class TimerChange extends Activity {

    private Button mButton;
    private ImageView mImageView;
    private static int[] bgs = { R.drawable.girl001, R.drawable.girl002,
            R.drawable.girl003, R.drawable.girl004 };

    private static final int EVENT_TIME_TO_CHANGE_IMAGE = 100;

    private Handler mHandler = new Handler() {
       
        public void handleMessage(Message msg) {

            switch (msg.what) {

            case EVENT_TIME_TO_CHANGE_IMAGE:

                int r = rand();

                Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                        bgs[r]);

                try {

                    setWallpaper(bmp);
                    changeImg(r);
                } catch (IOException ie) {

                    ie.printStackTrace();
                } catch (Exception e) {

                    e.printStackTrace();

                }

                break;
            }
        }
    };

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

        mButton = (Button) findViewById(R.id.Button01);
        mImageView = (ImageView) findViewById(R.id.ImageView01);
        mImageView.setImageDrawable(getResources().getDrawable(bgs[0]));

        mButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Timer timer = new Timer();
                TimerTask task = new TimerTask() {
                   
                    public void run() {

//                        Message message = Message.obtain(mHandler,
//                                EVENT_TIME_TO_CHANGE_IMAGE);
 
                        Message message = mHandler.obtainMessage(EVENT_TIME_TO_CHANGE_IMAGE);                                               

                        mHandler.sendMessage(message);

                    }
                };
                timer.schedule(task, 3000L, 3000L);

            }

        });

    }

    private void changeImg(int r) {
        mImageView.setImageDrawable(getResources().getDrawable(bgs[r]));
    }

    private int rand() {
        int result = 0;
        result = (int) (Math.random() * 4);
        return result;
    }
}

  评论这张
 
阅读(1019)| 评论(4)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017