|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
对于一个大型项目,如果用java来作,可能需要9个月,并且可能需要翻阅10本以上的书,但如果用ruby来作,3个月,3本书就足够了,而.net网页编程也不过3,4本书足以,这就是区别。每个进修Android的同砚城市以为Handler是一个奇妙的工具,我也一样,入手下手我觉得我懂了Handler的机制,厥后发明本人是一孔之见,今天想一想,我可否本人完成一个Handler,让子线程与ActivityUI线程通讯,假如可以本人完成一个Handler,那一定是对Handler的动静传送机制了解浸透了。
1、引进
Android的UI是单线程把持的,实践上,乐成的UI框架都是基于单线程的,多线程的UI框架常常由于办理并发和逝世锁的困难而胎逝世腹中。只要UI线程能把持界面控件,但我们老是但愿子线程的数据能更新到UI上,因而就有了Handler,它匡助我们完成了非UI线程向UI线程之间的通讯,Handler的利用十分复杂。
一个复杂的示例,让一个TextView静态显现秒数:
- 1publicclassMainActivityextendsActivity{2privatestaticfinalintUPDATE_TAG=0x01;3privateTextViewtextView;45@Override6protectedvoidonCreate(BundlesavedInstanceState){7super.onCreate(savedInstanceState);8setContentView(R.layout.activity_main);9textView=(TextView)findViewById(R.id.textview);10//启动一个线程11newThread(newRunnable(){1213@Override14publicvoidrun(){15intcount=1;16while(true){17//发送计数值到handler18mHandler.obtainMessage(UPDATE_TAG,String.valueOf(count))19.sendToTarget();20try{21TimeUnit.SECONDS.sleep(1);22}catch(InterruptedExceptione){23e.printStackTrace();24}25}26}2728}).start();29}3031publicHandlermHandler=newHandler(){32publicvoidhandleMessage(Messagemsg){33switch(msg.what){34caseUPDATE_TAG:35//显现计数值36textView.setText((String)msg.obj);37break;38}39}40};41}
复制代码
经由过程开启一个线程,线程每隔一秒发送一次计数给handler,让handler来更新TextView的内容,新开的子线程内里不克不及间接操控TextView,由于这违背了UI线程了单线程把持标准,假如你真要这么做,一运转就会失掉CalledFromWrongThreadException非常。
2、这不就是一个察看着形式么?
最后本人了解的Handler就是一个典范的察看着形式。sendToTarget()这个办法必定以某种体例挪用了Handler的handleMessage(Messagemsg)办法,从而完成了我们指定的义务,因而我写了上面如许一个Handler和Message
- /****摹拟Android的Handler,声名一个供子类掩盖的办法和多个天生动静的办法*/publicclassHandler{/****子类掩盖本办法,完成想要的操纵**@parammsg*/protectedvoidhandleMessage(Messagemsg){}publicMessageobtainMessage(intwhat){Messagemsg=newMessage(this,what,-1,-1,null);returnmsg;}publicMessageobtainMessage(intwhat,Objectobj){Messagemsg=newMessage(this,what,-1,-1,obj);returnmsg;}publicMessageobtainMessage(intwhat,intarg1,intarg2,Objectobj){Messagemsg=newMessage(this,what,arg1,arg2,obj);returnmsg;}}
复制代码
上去就是Message类:
- /****摹拟Android的Message,这里为便利演示,只写了一个机关办法。机关办法中绑定了一个Handler*/publicclassMessage{privatefinalHandlertarget;publicfinalintwhat;publicfinalintarg1;publicfinalintarg2;publicfinalObjectobj;publicMessage(Handlertarget,intwhat,intarg1,intarg2,Objectobj){this.target=target;this.arg1=arg1;this.arg2=arg2;this.what=what;this.obj=obj;}/****使用OOP的多态,挪用子类的掩盖办法*/publicvoidsendToTarget(){target.handleMessage(this);}}
复制代码
测试代码以下:
ViewCode
真想说下面的代码表现了一个复杂的察看着形式,下面的测试代码能运转。可是,可是如许的Handler能取代Android的Handler在Activity中利用吗,用下面的Handler往替换Android的handler,了局失掉是CalledFromWrongThreadException。
这很明显的,下面的Handler能够只仿照到AndroidHandler的形,没有仿照到其神,它只是经由过程一个回调仿照了Handler的事情表面,使用多态的手段往挪用子类的handleMessage办法,设法是好的,但这终极相称于让子线程间接挪用了handleMessage,从而让子线程对界面控件举行了操控,违反了UI界面的单线程把持准绳,必需会报CalledFromWrongThreadException的非常。
3、子线程是怎样把动静传送给UI线程
后面仿制的Handler让子线程经由过程Message利用了UI控件,因而会报错,那Android是怎样将子历程的动静发送给UI历程。实践上Handler的事情离不开以下几个组件:
- Message:Handler吸收和处置的对象
- MessageQueue:动静行列,以FIFO的体例办理Message对象
- Looper:办理MessageQueue的对象,不休地从MessageQueue中作废息,并发送该动静对应的Handler举行处置。每一个线程只要一个Looper,UI线程在创立时就已默许创立了一个Looper,因而在Activity中能够间接创立Handler便可发送和处置动静;假如在子线程中创立Handler,必需在创立前挪用Looper.prepare();如许Looper在才干做好筹办,并为以后线程创立MessageQueue,以便承受Handler的Message。能够看一下Looper.prepare()的源码
- publicstaticvoidprepare(){prepare(true);}privatestaticvoidprepare(booleanquitAllowed){if(sThreadLocal.get()!=null){thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");}sThreadLocal.set(newLooper(quitAllowed));}privateLooper(booleanquitAllowed){//公有的机关办法mQueue=newMessageQueue(quitAllowed);mRun=true;mThread=Thread.currentThread();}
复制代码
在子历程创立好Handler后,挪用Looper.loop()处置动静。Looper.loop()是一个逝世轮回,假如不实行quit(),厥后的代码将不会实行。如今看一个例子,我们经由过程点击Button给子线程的Hanlder传送动静。
- publicclassMainActivityextendsActivity{privateMythreadthread;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);thread=newMythread();thread.start(); }classMythreadextendsThread{publicHandlerhandler;@Overridepublicvoidrun(){Looper.prepare();//在子线程中界说Handlerhandler=newHandler(){publicvoidhandleMessage(Messagemsg){Log.i("handleMessage","子线程handler.handleMessage(...)");//接到动静让Looper加入逝世轮回handler.getLooper().quit();}};Toast.makeText(MainActivity.this,"beforeLooper.loop()",Toast.LENGTH_LONG).show();//逝世轮回处置动静Looper.loop();Toast.makeText(MainActivity.this,"afterLooper.loop()",Toast.LENGTH_LONG).show();}};publicvoidonClickButton(Viewv){thread.handler.obtainMessage().sendToTarget();}}
复制代码
能够看到线程启动后,会Toast"beforeLooper.loop()",但不会立即Toast"afterLooper.loop()",只要当我们按下Button后才会显现"afterLooper.loop()",由于按下Button,会给子线程的Handler发送一个空动静,而我们界说Handler抵消息的处置是挪用looper的quit(),从而停止Looper.loop()。注重quit()并非复杂的停止Looper.loop(),而是设置MessageQueue的一个标记,让MessageQueue的next()办法前往null,从而停止Looper.loop(),概况请看MessageQueue源码,这里我们来看看loop()的源码:
- publicstaticvoidloop(){...for(;;){Messagemsg=queue.next();//mightblockif(msg==null){//Nomessageindicatesthatthemessagequeueisquitting.return;}...msg.target.dispatchMessage(msg);...msg.recycle();}}
复制代码
别的跟踪sendToTarget()发明终极挪用的办法是MessageQueue的enqueueMessage(Messagemsg,longwhen),这个办法只是把message放进行列中,并没有挪用动静动静办法,动静的分发处置是在Looper的loop()中举行的。
4、是甚么工具再帮UI线程跑Looper.loop()
如今理清了后面的成绩又来了新的成绩,是谁在帮UI线程跑Looper.loop():
- 假如是其他线程帮它Looper.loop(),那末这分明违反了UI线程的单线程把持标准;
- 假如是UI线程本人在跑,那它的逝世轮回在那边跑着,怎样用光阴往实行onCreate(),onResume()...和我们绑定的各类listener。
假如既要满意UI线程的单线程把持标准,又要让逝世轮回Looper.loop()跑着不遗漏一个动静,还要呼应onCreate()、listener,只要一种举措,那就是对界面的一切的操纵都是由loop来驱动分发的,onCreate(),onResume()...各类listener都是Looper.loop()来挪用。
实践上Android就是这么干的,要理清onCreate等各类办法绑定的Message的历程不简单,可是我们能够很复杂地考证我们的下面的假定,那就是在onCreate(),onResume(),和listener的呼应办法内里激发非常,然后看一下栈信息,我们在onCreate发放中加一句inta=1/0,看看非常的栈信息:
当发明奇妙的Handler本来就是靠一个逝世轮回来保持的,统统就变得名顿开了。
Java到底会发战成什么样,让我们拭目以待吧,我始终坚信着java会更好。以上都是俺个人看法,欢迎大家一起交流. |
|