请先允许我对网上某些没经过亲自实践人云亦云的同志呵呵。。。
那么开始正文,首先“阻塞”这个词本身就存在理解上的差异!
一般我们理解的阻塞,是阻塞了某个线程,即代码执行到这里后等待这个函数块执行完毕,才能继续向下运行。比如常见的控制台输入函数,必须要求用户输入一个值才能继续,否则等待。
而在Android里,一部分人对阻塞做了另外的解释:锁死了其它UI,只有当前这个模块可以被响应。具体什么意思呢?比如原本点击屏幕,会弹出一个Toast。那么好,现在我弹出一个UI,用户只能在这个UI操作,他再去点击这个UI外围的屏幕,将触发不了“弹出Toast”这个事件,那么就认为这个UI“阻塞”了应用。
好,现在我们着重分析第二种看法。乍一看貌似没问题,原本应该执行的操作,因为另一个操作没结算完毕而不能发生,这不就是“阻塞”了么?然而事实是,这种“阻塞”实质上只是屏蔽了控制弹出Toast的代码块的触发条件:点击UI。准确的说,是把点击UI这个操作给截获了。但如果这个事件是在这个线程里顺序执行的,他并不需要事件驱动呢?想要测试也很简单,探出一个PopupWindow,紧接着在下面(不是某个UI的监听器里)写一个Log.v();呵呵哒,看到了吧,不等你关掉弹窗,Log.v里面的内容已经被打印了。。。
可见,PopupWindow的“阻塞”,其实只是一种屏蔽。它仅仅是使得其它控件不可被操作罢了。说它是“阻塞的”,没问题,就是容易误导;但说它是“线程阻塞”的就呵呵了。另外面对这个问题,网上还有一种退而求其次的建议:把要做的东西放到onClick();里面。这样也能一定程度的解决问题,但需要把原本连贯的一个过程拆分开。虽然不可否认,这本就更符合Android的设计框架的思想,但如果是在流程已经设计好了,无法改动的情况下就行不通了。
总结:PopupWindow的”阻塞”并不能使你的线程wait。它完全取得了用户操作的响应处理权限,从而使其它UI控件不被触发,仅此而已。无论AlertDialog还是PopupWindow,都不能做到传统意义上的线程阻塞。想要根据用户的某个操作来决定程序流程(否则不继续执行),只能把主线程wait掉。但这样会导致ANR,所以取巧的方法是while([某个值没有被改变]) sleep(100);是的,间歇性sleep主线程,告诉Android,咱每100ms有一次响应,你别给我ANR了啊。
附上我的小游戏的源码链接,就是在这里面遇到的问题: GitHub