Handler/HandlerThread的使用

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做一个详细的讲解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值