在handler
的简单用法中,我们自己简单new出一个handler
然后调用它的sendMessage方法发出一条消息。然后在handler
类重写了handler
的handler
Message方法来进行处理。看似就是这么简单的俩步,其实背后隐藏了很多我们不知道的流程。
在介绍这个之前,我先介绍几个概念
1。Message 这个应该很清楚吧 就是我们发送的消息 介绍一个里面的一个方法Message.obtain函数。作用是从Message
Pool中取出一个Message,如果Message
Pool中已经没有Message可取则新建一个Message返回,同时用对应的参数给得到的Message对象赋值。 message Pool
我的理解就是一个缓存区。就是把用过的Message放进这里面为了以后用而已。要不每次都要new一个message起步麻烦。这个应该跟String
pool的原理一样。姑且我们把它视为同一个作用的东西。
2.MessageQueue
顾名思义就是消息队列,干什么用的 当然是存放消息用的
3。Looper
我暂且叫他循环体吧。 主要就是从MessageQueue中读取消息。
4.handler
当然就是处理发来的消息了
下面我就把这个四个联系起来,看看他们在内部到底怎么执行。
首先通过handler
发出一条消息,发到哪呢
肯定是MessageQueue里,最终会调用MessageQueue的
enqueueMessage函数,enqueueMessage根据上面的接收的Message的队列的构造把接收到的Message放入队列中。
MessageQueue的removeMessages函数根据上面的接收的Message的队列的构造把接收到的Message从队列中删除,并且调
用对应Message对象的recycle函数把不用的Message放入Message
Pool中。通过Loop从MessageQueue中从前往后取出Message,然后通过Handler的dispatchMessage函数进行消
息的处理(可见消息的处理是Handler负责的),消息处理完了以后通过Message对象的recycle函数放到Message
Pool中,以便下次使用,通过Pool的处理提供了一定的内存管理从而加速消息对象的获取。至于如何处理就看你的handler
如
何定义了由你指定(三个方法,优先级从高到低:Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工
作;Handler里面的mCallback指向的一个实现了
Callback接口的对象,里面的handleMessage进行处理;处理消息Handler对象对应的类继承并实现了其中
handleMessage函数,通过这个实现的handleMessage函数处理消息)。
大致流程就是handler
------->>发送message---->>MessageQueue
Looper--->取出message从messagequeue中----->>在触发handler
的消息分发函数----调用handler
中定义的方法.
这里有个疑问那looper
和messagequeue什么时候生成呢。其实messagequeue在Looper创建的时候就生成了。那Looper什么时候生成呢?其实
Looper是跟一个线程关联的。而主线程会自动调用prepareMainLooper生成自己的Looper,但其他线程则不会自己创建了。待会再
说。
先来看看我们上次的简单handler
例子。这下应该知道他们内部的流程了吧。其实我们在Hander handler
=new
Handler();其实就已经把主线程的Looper关联上来了,有了Looper我们也就有了MessageQueue
所以我们在调用sendMessage的时候就把这个Message发送到由Looper创建的MessageQueue里。Looper有主线程创建
的,当然消息会在主线程处理了。这样就实现了简单的子线程到主线程的通信了。
那好,如果现在我要创建子线程的Looper呢 然后怎么把这个Looper绑定Handler上呢。其实很简单
在子线程调用Looper.prepare()就可以创建子线程的Looper
然后通过Looper.myLooper()就可以拿到这个Looper对象,最后就是把这个Looper 跟Handler绑定起来。其实在构建handler
对
象的时候我们除了我默认无参构造方法(这个就是我们上次那个例子用的)还有有参的构造方法,就是传Looper的。好了,这样就可以把Looper跟
Handler绑定起来了。这你在主线程调用Handler.sendMessage就是把message发到子线程里来了。这样就实现主线程到子线程的
通信了。以此类推各种样式的通信都是可以的。大家回去不妨试一下。
来自:http://www.eoeandroid.com/forum-viewthread-tid-35202-highlight-handler.html
一、提问之前的准备
首先,最重要的是,你自己一开始就应该想清楚:
1. 需要新员工完成什么样的任务?
2. 怎样的人能完成这样的任务?
3. 哪些途径和方法可以发现这样的人?
只有明确这些根本性的问题,才能正确高效地完成面试。
二、提问的原则
假定你对上一节的三个问题,已经有了清晰的想法,那么接下来就可以设计如何提问了。
有一些提问的原则,是你应该遵循的:
每一个面试问题都有明确的目的。你不仅自己了解,还能向其他面试官解释清楚。
多提一些开放性(Open-ended)的问题,而不是那种用Yes/No就可以回答的问题。这样做使你有机会与面试者展开讨论,并且提出后续的问题,尽可能多地了解对方。
不要问宗教、家庭、健康、个人隐私等方面的问题。
不要问太复杂的问题。因为面试者没有太多思考时间,所以无法周全地回答,你也就无从判断他的能力了。
三、考察专业能力
为了确认面试者是胜任的,你可以问一些与职位相关的专业方面的问题。(不过通常来说,一次面试不足以看出一个人的专业能力。)
比如,你的招聘职位是系统管理员,你可以问"如何快速地在50台机器上部署Linux?"(提示:正确答案不是刻录50张安装光盘。)
另外,你还应该向面试者了解他的过去,因为过去是未来的最好预测依据。不过,提问的重点不要仅仅是他过去的成果,更要关注在当时的环境中,他是如何决策和实施的。
四、考察综合素质
因为人是会发展的,所以某种程度上,面试者的综合素质要比他的专业能力更重要。
所以,具体的技术问题(如何调用API、什么是设计模式、编程语言的语法等等)可以少问一些,更应该关注面试者的事业心、对工作的热情、进取心、自律能力、毅力等方面。
下面是一些典型问题:
Why did you get into development?
你为什么开发软件?
How many technical books did you read in the past year?
去年你读了几本技术书籍?
What was your favorite technical book in the past year? What did you learn from it?
去年你最喜欢的技术书籍是哪本?你从中学到了什么?
What websites do you read regularly, related to development?
平时你经常访问哪些编程类网站?
Do you maintain any open-source projects?
你有自己的开源项目吗?
Do you code in your spare-time?
业余时间你编程吗?
Do you love programming, or do you do it for the money?
对于你来说,编程是一种爱好,还是一种谋生手段?
Have you accomplished anything important in your career yet? Do you want to?
你的职业生涯之中有什么重要的成就?它是你主导的吗?
What would make you feel that you have done something important?
什么事情会让你很有成就感?
五、考察理性思维
某些情况下,你可能需要了解面试者的分析判断能力,看他能否全面地思考问题、客观地评价自己。
那么,你可以依次提出这样三个问题:
What's your favorite programming language? Why?
你最喜欢的编程语言是哪种?为什么?
If you could add one feature to your favorite language, what would it be? Why?
如果允许你为这种语言加一种功能,你会加什么功能?为什么?
If you could remove one feature from it, what would it be? Why?
如果允许你取消一种功能,会是什么功能?为什么?
这里的重点是,让面试者从正反两方面评价一件自己熟悉的东西,看看他的思维是否片面。答案无所谓对错,只要面试者有一个明确的立场,能够从正反两方 面说出令人信服的理由,就可以了。比如,某个软件的口碑不好,但是面试者说他很喜欢,而且说得出一大堆理由,清楚地解释了这种软件的优点和缺点在哪里,这 样就很好。
你还可以把这些问题,套用在其他东西上面,比如操作系统、文字编辑器等等。
原文出自:http://www.eoeandroid.com/viewthread.php?tid=1729
eoeandroid社区是国内最火的android社区。
最近在学习AppWidget,想做一个像GoogleSearch那样带有输入框的Widget练习。
可是,Dev Guide关于AppWidget的讲解明确指出,在App Widget中只能用FrameLayout,LinearLayout,RelativeLayout三种Layout和AnalogClock,Button,Chronometer,ImageButton,ImageView,ProgressBar,TextView这几种Widget,而且它们的子类也不能用。
不管怎样还是用先用EditText看看。编译和安装都没有问题。但是在向桌面加入AppWidget的时候,就会出现“Problem loading widget”错误。
看来真的只能用TextView了。
虽然通过修改TextView的属性,可以让TextView看起来象EditText,而且也可以输入,但是至少有两个问题:
1.光标不能在文本框内移动 -
按左右箭头时,焦点会跳到其它的Item上,而不是像EditText那样在字符间移动。看了一下EditText是通过Override TextView的getDefaultMovementMethod这个方法设置箭头按键的移动方式的。而TextView中虽然也有setMovementMethod方法,但是搞了半天也没办法从RemoteViews中拿到TextView的实例;
2.这一点比较重要:不知道该如何从RemoteViews中获得TextView的输入的结果?
可是GoogleSearch上明明就有输入框。它是怎么实现的呢?
在网上查了一下,结论是:GoogleSearch并不是用普通AppWidget方法实现的Widget,而是在Home(Launcher)中独立实现,是属于Launcher的一部分。
翻出Launcher的代码(/packages/apps/Launcher),果然看到了GoogleSearch的实现在Search.java,它的Layout定义在widget_search.xml。其中的输入框是Launcher封装了的AutoCompleteTextView(即SearchAutoCompleteTextView)。
那么Launcher是怎样区别加载GoogleSearch和其它普通的AppWidget的呢?
在Launcher中有一个static成员LauncherModel,它主要负责维护Launcher的状态和提供一些更新Launcher数据库状态的API。LaunchModel中用不同的ArrayList记录ItemInfo和LauncherAppWidgetInfo的信息(ITEM_TYPE_APPLICATION, ITEM_TYPE_USER_FOLDER, ITEM_TYPE_LIVE_FOLDER, ITEM_TYPE_WIDGET_SEARCH这些类型的Item都被记录在ItemInfo类型中)。
具体的加载过程大概是:在Launcher的onCreate和onResume中都调用了LauncherModel::loadUserItems方法。之后的顺序是LauncherModel::loadUserItems->Launcher::onDesktopItemsLoaded->Launcher::bindDesktopItems->…->最后在Launcher::DesktopBinder::handleMessage中通过Launcher::bindItems方法加载了Widget Search到workspace(控制桌面显示区域的class)上,而通过Launcher::bindAppWidgets加载了普通的AppWidgets。
再看一下Widget添加的过程吧。Launcher通过addSearch直接用inflate的方法产生一个GoogleSearchWidget的View,并添加到workspace;而普通的AppWidget则是通过completeAddAppWidget中产生并添加一个AppWidgetHostView来实现的。