Andorid Handler原理及使用

来源:互联网 发布:怎么剔除异常数据 编辑:程序博客网 时间:2024/05/22 13:47
  • 客户端发送http请求至服务器,如果请求成功,响应码为200,服务器会通过流向客户端返回请求的数据
  • 主线程阻塞,应用会停止刷新界面,停止响应用户任何操作,用户体验非常差
  • 耗时操作不要写在主线程

ANR异常

  • Application not responding

消息队列

  • 只有主线程可以刷新ui
  • 主线程创建时,同时也会创建MessageQueue(消息队列)和Looper(消息轮询器)对象
  • 如果需要使用消息队列机制,程序员需要自行创建Handler(消息处理器)
  • 轮询器不断检测消息队列中是否有消息,如果有,就会把消息取出,交给Handler对象
  • Handler对象拿到消息之后,就会在主线程执行handleMessage()
  • 也就是说子线程,只要往消息队列中发送消息,主线程立刻执行handleMessage()
  • 主线程不能被阻塞
  • 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差
  • 主线程阻塞时间过长,系统会抛出ANR异常
  • ANR:Application Not Response;应用无响应
  • 任何耗时操作都不可以写在主线程
  • 因为网络交互属于耗时操作,如果网速很慢,代码会阻塞,所以网络交互的代码不能运行在主线程

只有主线程能刷新ui

  • 刷新ui的代码只能运行在主线程,运行在子线程是没有任何效果的
  • 如果需要在子线程中刷新ui,使用消息队列机制
  • 主线程也叫ui线程

消息队列

  • 主线程创建时,系统会同时创建消息队列对象(MessageQueue)和消息轮询器对象(Looper)
  • 轮询器的作用,就是不停的检测消息队列中是否有消息(Message)
  • Looper一旦发现Message Queue中有消息,就会把消息取出,然后把消息扔给Handler对象,Handler会调用自己的handleMessage方法来处理这条消息
  • handleMessage方法运行在主线程
  • 主线程创建时,消息队列和轮询器对象就会被创建,但是消息处理器对象,需要使用时,自行创建

    //消息队列Handler handler = new Handler(){    //主线程中有一个消息轮询器looper,不断检测消息队列中是否有新消息,如果发现有新消息,自动调用此方法,注意此方法是在主线程中运行的    public void handleMessage(android.os.Message msg) {    }};
  • 在子线程中使用Handler对象往消息队列里发消息

    //创建消息对象Message msg = new Message();//消息的obj属性可以赋值任何对象,通过这个属性可以携带数据msg.obj = bm;//what属性相当于一个标签,用于区分出不同的消息,从而运行不能的代码msg.what = 1;//发送消息handler.sendMessage(msg);
  • 通过switch语句区分不同的消息

    public void handleMessage(android.os.Message msg) {    switch (msg.what) {    //如果是1,说明属于请求成功的消息    case 1:        ImageView iv = (ImageView) findViewById(R.id.iv);        Bitmap bm = (Bitmap) msg.obj;        iv.setImageBitmap(bm);        break;    case 2:        Toast.makeText(MainActivity.this, "请求失败", 0).show();        break;    }       }
public class MainActivity extends Activity {    Handler handler = new Handler(){        //只要消息队列有消息,此方法就会在主线程执行        public void handleMessage(android.os.Message msg) {            //在这里刷新ui            switch (msg.what) {            case 1:                ImageView iv = (ImageView) findViewById(R.id.iv);                iv.setImageBitmap((Bitmap)msg.obj);                break;            case 2:                Toast.makeText(MainActivity.this, "请求失败o(╯□╰)o", 0).show();                break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void click(View v){        final String path = "http://169.254.244.136:8080/dd.jpg";        final File file = new File(getCacheDir(), getNameFromPath(path));        if(file.exists()){            System.out.println("从缓存获取");            Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());            Message msg = new Message();            msg.obj = bm;            msg.what = 1;            handler.sendMessage(msg);//          ImageView iv = (ImageView) findViewById(R.id.iv);//          iv.setImageBitmap((Bitmap)msg.obj);        }        else{            Thread t = new Thread(){                @Override                public void run() {                    System.out.println("从网络获取");                    //发送http请求                    try {                        //1.使用网址构造一个URL对象                        URL url = new URL(path);                        //2.获取连接对象                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();                        //3.设置一些属性                        //设置请求方式,注意大写                        conn.setRequestMethod("GET");                        //设置请求超时                        conn.setConnectTimeout(8000);                        //设置读取超时                        conn.setReadTimeout(8000);                        //4.发送请求,建立连接//                      conn.connect();                        //5.判断请求是否成功                        if(conn.getResponseCode() == 200){                            //获取服务器返回的流,流里就是客户端请求的数据                            InputStream is = conn.getInputStream();                            //我们自己读取流里的数据,读取1k,就把1k写到本地文件缓存起来                            byte[] b = new byte[1024];                            int len;                            FileOutputStream fos = new FileOutputStream(file);                            while((len = is.read(b)) != -1){                                fos.write(b, 0, len);                            }                            fos.close();    //                      因为缓存时已经把流里数据读取完了,此时流里没有任何数据    //                      Bitmap bm = BitmapFactory.decodeStream(is);                            Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());                            //当子线程需要刷新ui时,只需发送一条消息至消息队列                            Message msg = new Message();                            //消息对象本身是可以携带数据的                            msg.obj = bm;                            //使用what标注消息是什么类型的                            msg.what = 1;                            handler.sendMessage(msg);                        }                        else{                            //如果消息池有消息,取出消息池第一条消息,返回,如果没有,就new一个消息返回    //                      Message msg = handler.obtainMessage();    //                      msg.what = 2;    //                      handler.sendMessage(msg);                            handler.sendEmptyMessage(2);                        }                    } catch (Exception e) {                        e.printStackTrace();                    }                }            };            t.start();        }    }    public String getNameFromPath(String path){        int index = path.lastIndexOf("/");        return path.substring(index + 1);    }}

参考:Android Handler

原创粉丝点击