android中handler的基本使用方法以及运行原理。
最近看mars的android重置版第二季的视频关于handler的讲解,让我对于这个以前知道怎么用,却不是很明白原理的组件的理解瞬间加深了无数倍。mars真的讲的很好,视频真的都蛮不错的。下面我写写自己学习到的知识,以及自己的了解。
handler的基本运行原理
handler怎样从worker thread传输数据到main thread
handler怎样从main thread传输数据到worker thread
handler的post()方法
handler的基本运行原理
为什么我们需要一个handler?我想这是一个最重要的问题,也就是说handler的作用到底是什么?handler主要是用于线程间的通信,那么问题又来了,为什么一个app中需要多个线程,而不是只有一个UI主线程就可以了呢?
假如app中只有一个UI主线程,那么,当需要进行网络连接,网络下载这些等待耗时较长的任务时,android系统就会检测到UI主线程长时间没有响应,就会发出一个 application not response的异常警告,简称ANR问题。所以,在UI主线程中,是要与用户实时交互的,不能出现长时间的等待问题。于是,这些任务必须在worker thread中进行。
然而根据android的设定,UI主线程之外的线程,(除了特别的控件,例如progressbar)不能修改UI里的控件的,这样又出现了新的问题,我们在子线程获得的数据,该如何反应的UI上与用户进行交互?这样,就出现了这个巧妙的组件,handler!
那么,handler到底是如何运行的呢?handler对象首先取出一个消息对象,存入到一个消息队列messagequeue中,然后在另外一端,有一个looper对象,循环的从消息队列中取出消息对象再交给handler去处理。
handler怎样从worker thread传输数据到main thread
public class MainActivity extends ActionBarActivity { private Handler handler; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.cancleButton); // 点击button启动新线程 button.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { Thread thread = new Mythread(); thread.start(); } }); handler = new Myhandler(); } // 复写hanlder中的handlerMessage方法,处理从消息队列中得到的消息 class Myhandler extends Handler{ @Override public void handleMessage(Message msg) { super.handleMessage(msg); String s = msg.obj.toString(); System.out.println("在当前线程中"+Thread.currentThread().getName()+"获得来自这个线程的消息"+s); } } // 在worker thread中使用handler.obtainMessage()方法得到一个Message对象,再把消息存入message中,发入消息队列 class Mythread extends Thread{ @Override public void run() { Message msg = handler.obtainMessage(); msg.obj = currentThread().getName(); handler.sendMessage(msg); } } }
通过这个例子,我们可以看到,handlerMessage()方法是运行在主线程中的,而他可以得到来自worker thread的消息,这样,就可以将消息在UI界面更新了。
为什么只是初始化了一个handler对象,就会自动调用他的handleMessage方法?是因为在android.os.Handler类中有一个looper对象,会循环的从消息队列中取出消息,调用handleM而是撒个方法。
handler怎样从main thread传输数据到worker thread
public class MainActivity extends ActionBarActivity { private Handler handler; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.cancleButton); // 每点击一次button,给worker thread 发送一个消息 button.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { // 在main中使用handler.obtainMessage()方法得到一个Message对象,再把消息存入message中,发入消息队列 Message msg = handler.obtainMessage(); msg.obj = Thread.currentThread().getName(); handler.sendMessage(msg); } }); Thread thread = new Mythread(); thread.start(); } // 复写hanlder中的handlerMessage方法,处理得到的消息 class Myhandler extends Handler{ @Override public void handleMessage(Message msg) { super.handleMessage(msg); String s = msg.obj.toString(); System.out.println("在当前线程中"+Thread.currentThread().getName()+"获得来自这个线程的消息"+s); } } // work thread 接受这个消息,并调用handleMeesage()方法处理消息 class Mythread extends Thread{ @Override public void run() { // looper对象的loop方法从消息队列中取出消息,调用handleMeesage()方法处理消息 Looper.prepare(); handler = new Myhandler(); Looper.loop(); } } }
通过运行结果可以知道,handleMessage()方法运行在worker thread中,这样就可以在worker thread中处理来自主线程的消息,实现了进程间的通信。
handler的post()方法
post方法通过生成一个message,然后把Runnable对象放在message中,再把message放在消息队列中,然后在主线程中取出这个Runnable对象,在主线程中执行。
public class MainActivity extends ActionBarActivity { private Handler handler; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.cancleButton); // 初始化handler,处理得到的Runnable对象 handler = new Handler(); // 点击按钮执行worker thread button.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { Thread thread = new Mythread(); thread.start(); } }); } class Mythread extends Thread{ @Override public void run() { // 在worker thread 中初始化一个Runnable对象 Runnable runnable = new Runnable() { public void run() { // 打印出该Runnable方法执行的线程 System.out.println("当前线程名"+Thread.currentThread().getName()); } }; // post该Runnable对象 handler.post(runnable); } } }
最后的结果,是这个Runnable对象执行在main线程中。有了post()方法,我们可以直接在worker thread中先生成一个Runnable对象,然后在其中写上更新UI的代码,直接用post方法即可更新UI。