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做一个详细的讲解。