【Android】Android实现Handler异步详解
方式不止一种,这里使用的是Timer类,创建一个定时器。我们经常需要获得移动设备端口的显示屏信息,但是onCreate()方法执行的时候,OnShow()方法不一定执行了,也就是说,在执行Oncreate()时候屏幕还没加载出来,所以这时候可以应用一个异步机制获取数据。
import android.app.Activity; import android.os.Handler; import android.os.Message; import android.view.View; import java.util.Timer; import java.util.TimerTask; /** * Created by Lenovo on 2017/6/2. */ public abstract class MyActivity extends Activity{ protected abstract void ViewAfterShow(int width,int hight); /** * 使用线程异步,获取视图上的数据,比如高和宽 * @param viewID 视图ID * @param msgID 消息ID */ protected void ViewShowListen(final int viewID,final int msgID){ //always make sure that schedule is running from main thread if(Looper.getMainLooper() == Looper.myLooper()) runTimeSchedule(viewID,msgID); else new Handler(getMainLooper()).post(new Runnable() { @Override public void run() { runTimeSchedule(viewID,msgID); } }); } public void runTimeSchedule(final int viewID,final int msgID){ final int f_viewID = viewID; final int f_msgID = msgID; final Timer f_timer = new Timer(); final Handler f_handler = new Handler(){ @Override public void handleMessage(Message msg){ if(msg.what == f_msgID){ View v = (View)findViewById(f_viewID); if(v.getWidth() != 0 && v.getHeight() != 0){ f_timer.cancel();//取消 ViewAfterShow(v.getWidth(),v.getHeight());//回调信息 } } } }; //这里之所以不在该run()方法里进行操作,是因为里面的数据是最终的,所以这里应用了一个消息发送机制。 TimerTask task = new TimerTask() { @Override public void run() { Message message = new Message(); message.what = f_msgID; f_handler.sendMessage(message);//发送消息 } }; //延迟每次延迟10毫秒 隔500毫秒执行一次 f_timer.schedule(task,10,500); } }
上面是关于TimerTask和Handler的一种用法,上面调用的是Handler的 sendMessage(Message msg) ,除了sendMessage方法,还有 handleMessage(Message msg) 方法,注意handleMessage方法和sendMessage方法的效果是不一样的,sendMessage是handler在主线程中执行;但是handlerMessage则不会,所处理的Handler还是在Timer线程中。
下面详细介绍一下TimerTask类和Handler类,TimerTask中创建的线程是一个单独的线程,命名通常以 timer+数字 表示,一帮数字从0开始。而Hanler不会创建新的线程,如果不使用Looper标识,那么Handler处于的线程将会是在main(主)线程中,比如:
public class MainActivity extends Activity { Context context; LinearLayout layout; int f_msgID = 2; final Timer f_timer = new Timer(); final Handler f_handler = new Handler(){ @Override public void handleMessage(Message msg){ if(msg.what == f_msgID){ Log.e("d", Thread.currentThread().getName());//main } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context=this; layout=(LinearLayout)findViewById(R.id.mainlayout); Log.e("a",Thread.currentThread().getName());//main new Thread(new Runnable() { @Override public void run() { Log.e("b", Thread.currentThread().getName());//thread-11840 TimerTask task = new TimerTask() { @Override public void run() { Message message = new Message(); message.what = f_msgID; f_handler.sendMessage(message); Log.e("c", Thread.currentThread().getName());//timer-0 } }; f_timer.schedule(task,10,10000); } }).start(); } }
笔者在上面的代码上中,标识出了各个线程中运行的线程名称,一共有三个线程,可以发现Handler所处的线程是在主线程中的。
接下来如果是使用Looper的话,Handler所处的线程为Looper所处的线程,比如:
public class MainActivity extends Activity { Context context; LinearLayout layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; layout = (LinearLayout) findViewById(R.id.mainlayout); Log.e("a", Thread.currentThread().getName());// main new Thread(new Runnable() { @Override public void run() { Log.e("b", Thread.currentThread().getName());// thread-11899 final int f_msgID = 2; Looper.prepare();// looper begin final Timer f_timer = new Timer(); final Handler f_handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == f_msgID) { Log.e("c", Thread.currentThread().getName());//thread-11899 } } }; TimerTask task = new TimerTask() { @Override public void run() { Message message = new Message(); message.what = f_msgID; f_handler.sendMessage(message); Log.e("d", Thread.currentThread().getName());// timer-0 } }; f_timer.schedule(task, 10, 10000); Looper.loop();// looper end } }).start(); } }
从这个过程中我们可以看出,Handler和 Log.e("b", Thread.currentThread().getName()) 所处的线程都在Thread-11899中,这个线程编号是程序自动指定的。
上面我们介绍这个Handler和TimerTask的比较。视图组件有一个特性,就是修改该组件只能在创建该组件的原始线程中完成,如果创建的视图组件的线程和修改视图组件的线程不在同一个线程中,那么就会报错。而有时候,我们又希望在非创建组件的线程中修改组件,那么这时候,就可以应用上的特性。