Handler/HandlerThread的使用

来源:互联网 发布:海报打印机 知乎 编辑:程序博客网 时间:2024/06/05 08:13

Handler与HandlerThread的理解
1.什么是Handler:
Handler是android给我们提供用来更新UI的一套机制(某一点),也是一套消息处理的机制,我们可以发送消息,也可以通过它来处理消息。

    首先我们来看下我们平时在子线程中发送消息给UI线程更新我们的UI组件。
public class MainActivity extends AppCompatActivity {    private TextView textView=null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        textView=new TextView(this);        textView.setTextSize(20);        setContentView(textView);        new mThread().start();    }    private Handler handler=new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            String str = (String) msg.obj;            textView.setText(str);        }    };    class mThread extends Thread{        @Override        public void run() {            super.run();            try {                Thread.sleep(2000);                Message message = handler.obtainMessage();                message.obj="hello";                handler.sendMessage(message);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
很简单,这就是我们平时利用handler来更新UI的代码。

我们要讲的是我们的handler在这里是怎么处理我们发送的消息的。这里就涉及到了一个叫做Looper的对象,那么它是怎么做的呢?我们用一张图片来展示。
这里写图片描述

可以看到我们通过handler来发送我们的消息到MessageQueue(消息队列)中,然后我们的Looper通过loop()方法不断的去取出我们MessageQueue中的消息,然后再交给handler自己处理。这就是Handler的一个主要工作过程;

到这里,我们就对我们的子线程通过handler发送给主线程更新ui的过程有一个大概的理解了。由于我们上面的代码的handler是在我们的主线程中创建了,根本看不到Looper的身影,那么这是为什么呢?因为我们UI线程的特殊性,其内部已经对Looper有了一个封装(感兴趣的可以去跟踪下源码)。接下来我们就来在子线程中创建handler,看看怎么使用我们的Looper;

public class MainActivity extends AppCompatActivity {    private TextView textView = null;    private mThread thread;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        textView = new TextView(this);        textView.setText("hello");        setContentView(textView);        thread = new mThread();        thread.start();        try {            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        thread.handler.sendEmptyMessage(0);    }    class mThread extends Thread {        Handler handler;        @Override        public void run() {            Looper.prepare();            handler = new Handler() {                @Override                public void handleMessage(Message msg) {                    super.handleMessage(msg);//                    Toast.makeText(MainActivity.this,Thread.currentThread()+"",Toast.LENGTH_SHORT).show();                    Log.i("xy", "current:" + Thread.currentThread());                }            };            Looper.loop();        }    }}

这样我们就将handler作用在了我们的子线程上了。
注意我们onCreate()里面的Thread.sleep(500),这里如果不这样做就会报出一个空指针的异常,原因:

子线程中 handler一开始是没有实例化的 实例化在start()中进行,所以在执行thread.start()后,直接执行thread.handler.send...方法此时也许thread.start()中还未执行到给handler实例化的那一步,自然抛出异常,解决方法之二就是在thread中定义handler时候直接实例化。

OK,接着我们在主线程中再来创建一个handler,但是我们的Looper对象是我们刚才的子线程。

public class MainActivity extends AppCompatActivity {    private TextView textView = null;    private mThread thread;    private Handler handlers;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        textView = new TextView(this);        textView.setText("hello");        setContentView(textView);        thread = new mThread();        thread.start();        //这里我们的handler是运行在主线程中的,同理,我们的Looper也就运行在主线程中的handler里面了        handlers=new Handler(thread.looper){            @Override            public void handleMessage(Message msg) {                super.handleMessage(msg);                System.out.println(msg);            }        };        //主线程发送消息到子线程中的Looper里面        handlers.sendEmptyMessage(1);    }    class mThread extends Thread {        Handler handler;        Looper looper;        @Override        public void run() {            Looper.prepare();            looper=Looper.myLooper();            handler = new Handler() {                @Override                public void handleMessage(Message msg) {                    super.handleMessage(msg);//                    Toast.makeText(MainActivity.this,Thread.currentThread()+"",Toast.LENGTH_SHORT).show();                    Log.i("xy", "current:" + Thread.currentThread());                }            };            Looper.loop();        }    }}
我们运行我们的程序会发现,此时我们的程序崩溃了。这是因为当多线程对Looper作用的时候,由于我们的Looper是在子线程中创建的,而我们的主线程现在要作用在其之上,可是此时我们的Looper对象还没有创建,这样当然就会抛出一个空指针的异常。(其實解決這個問題只需要在.start()方法之后給其一個緩存的方法。Thread.sleep(500)就可以了,和上面的那個情況差不多)在我们自定义Looper时会经常碰到这样的问题,那么我们怎样去处理这个问题呢?这里就要用到我们的HandlerThread了。由于篇幅过长,我们将在下一张中来对我们HandlerThread做一个详细的讲解。
0 0
原创粉丝点击