看到javaeye很多人在吹嘘、推荐杨丰盛的《Android应用开发揭秘》,个人就买了一本。
首先拿到书时,再次感受到机工出版社的书的纸张独有的“薄如蝉翼、黄如粪便”的特征,不过想着javaeye一众人对书中内容的推荐,纸张的质量我忍了。
接着看书,不过我慢慢发现书中一堆晦涩不清的表述——这种表述可能是我自己的中文理解问题,算了不说了。
但书中还充斥着一堆垃圾代码,看下面书中代码(P270,免得说我诬陷):
private Runnable _discoveryWorkder = new Runnable() { public void run() { /* 开始搜索 */ _bluetooth.startDiscovery(); for (;;) { if (_discoveryFinished) { break; } try { Thread.sleep(100); } catch (InterruptedException e){} } } };
上面_bluetooth.startDiscovery();就是开始进行蓝牙搜索了,
接下来那段死循环就纯属多余!!代码判断_discoveryFinished为true时结束死循环,但这个死循环什么都没做啊。
事实上,完全可以把这段垃圾代码删除。
我不确定杨丰盛到底会不会Android,但我觉得这java代码写得也太垃圾了。
书中大量这种的代码,让人不堪入目。前几章,看过也就算了,后来发现越来越多
上来发发牢骚。
1 楼 wdjezym 2011-03-23
没看过书,不懂蓝牙的菜鸟飘过
那段是等待蓝牙连接完成吧
连接完成前一直sleep
那段是等待蓝牙连接完成吧
连接完成前一直sleep
2 楼 yarin 2011-03-24
只能说明这位仁兄喜欢自己的设备的CPU使用率永远都是100%的。
最大限度的发挥设备的能力。
帮助用户消耗一部分电量。
非常抱歉,本书没有满足你上诉要求!
最大限度的发挥设备的能力。
帮助用户消耗一部分电量。
非常抱歉,本书没有满足你上诉要求!
3 楼 yarin 2011-03-24
就在javaeye上给你转一段过来你看看:
你把sleep删掉在Windows上跑跑然后打开任务管理器看看CPU是不是100%,加上sleep()是不是立刻变成0%-1%
不需要Android,随便写个Java程序就可以测试
你把sleep删掉在Windows上跑跑然后打开任务管理器看看CPU是不是100%,加上sleep()是不是立刻变成0%-1%
不需要Android,随便写个Java程序就可以测试
4 楼 yarin 2011-03-24
你要“污蔑”作者一个人无关紧要,javaeye上如此多高手总不能被你一竿子解决了吧。
5 楼 cloixio 2011-03-28
yarin 写道
只能说明这位仁兄喜欢自己的设备的CPU使用率永远都是100%的。
最大限度的发挥设备的能力。
帮助用户消耗一部分电量。
非常抱歉,本书没有满足你上诉要求!
最大限度的发挥设备的能力。
帮助用户消耗一部分电量。
非常抱歉,本书没有满足你上诉要求!
既然作者用这么NB哄哄的口吻来解释,
我就再发表一下我的看法:
看来作者认为这个死循环是可以让_bluetooth.startDiscovery();这个耗时操作暂停下来,让CPU空闲出来。
看来有必要补充一下多线程的知识了:
这个程序定义了一个线程来执行蓝牙搜索,这条线程只做了2件事情:
1. _bluetooth.startDiscovery(); ——这条代码是个耗时操作。
2. 死循环。
第一种假设:假如_bluetooth.startDiscovery(); 是同步执行的,也就是程序必须等这条代码执行完成后,才会去执行死循环,那死循环能暂停_bluetooth.startDiscovery();这个耗时操作吗?能让CPU空闲出来吗?
幸好Android没有这么SB!因为这个操作完全可能会搜索1~3分钟。这里是异步执行的——也就是说死循环与_bluetooth.startDiscovery();其实是并发执行的。那么根据多线程的“基础知识”:当死循环线程
执行Thread.sleep(100)时,系统完全可能会被调度到去执行 _bluetooth.startDiscovery();这个耗时操作,那么死循环有意义吗?
6 楼 yarin 2011-03-31
我不知道何种原因,cloixio兄现在不出来回帖了!
因为cloixio兄始终对这个问题纠结着,我30日找到以前的代码运行测试了N次,结果和kangfu兄说的情况一样。
鉴于此次cloixio兄的“炮轰”,对作者及出版社影响甚大,在我得测试结果之后,我并没有上来回帖,而是联系了出版社的编辑,希望编辑能先私下联系cloixio兄本人,同时(编辑也另外又找了几个Android方面比较有经验的朋友进行了测试,结果都是不能按照cloixio兄的做法来去掉那个所谓的“多余的循环”),再上来解决此问题,但是到目前为止未果。
我一直关注着此贴的最新消息,现在是在忍受不了了,加上kangfu兄也再次验证了正确无误的结果,所以我得上来回复了,希望cloixio兄能够出现回答此问题,否则会误导其他读者。
另外,正如编辑所说的,本书并不一定是完美的,但也不至于完全没有任何价值,也不是cloixio兄所谓的,javaeye上大部分都是人云亦云的“鹦鹉”,我一直知道javaeye上有着很多国内外知名的大师。
最后感谢kangfu兄以及所有为正确结果而讨论验证的师兄弟,包括对技术非常认真严肃的cloixio兄。
现在已经越来越多的人测试出结果,如果按你说的去掉循环,搜索对话框根本就弹不出来,或者是只弹出很短的时间。
因为cloixio兄始终对这个问题纠结着,我30日找到以前的代码运行测试了N次,结果和kangfu兄说的情况一样。
鉴于此次cloixio兄的“炮轰”,对作者及出版社影响甚大,在我得测试结果之后,我并没有上来回帖,而是联系了出版社的编辑,希望编辑能先私下联系cloixio兄本人,同时(编辑也另外又找了几个Android方面比较有经验的朋友进行了测试,结果都是不能按照cloixio兄的做法来去掉那个所谓的“多余的循环”),再上来解决此问题,但是到目前为止未果。
我一直关注着此贴的最新消息,现在是在忍受不了了,加上kangfu兄也再次验证了正确无误的结果,所以我得上来回复了,希望cloixio兄能够出现回答此问题,否则会误导其他读者。
另外,正如编辑所说的,本书并不一定是完美的,但也不至于完全没有任何价值,也不是cloixio兄所谓的,javaeye上大部分都是人云亦云的“鹦鹉”,我一直知道javaeye上有着很多国内外知名的大师。
最后感谢kangfu兄以及所有为正确结果而讨论验证的师兄弟,包括对技术非常认真严肃的cloixio兄。
现在已经越来越多的人测试出结果,如果按你说的去掉循环,搜索对话框根本就弹不出来,或者是只弹出很短的时间。
7 楼 cloixio 2011-03-31
我们再来看杨丰盛这个案例中SamplesUtils类中的代码:
Java代码
private static void indeterminateInternal(final Context context, final Handler handler, String message, final Runnable runnable,
OnDismissListener dismissListener, boolean cancelable)
{
final ProgressDialog dialog = createProgressDialog(context, message);
dialog.setCancelable(cancelable);
if (dismissListener != null)
{
dialog.setOnDismissListener(dismissListener);
}
dialog.show();
new Thread() {
@Override
public void run()
{
runnable.run();
handler.post(new Runnable() {
public void run()
{
try
{
dialog.dismiss();
}
catch (Exception e)
{
; // nop.
}
}
});
};
}.start();
}
注意粗体字代码部分,这行代码仿佛“神来一笔”,杨丰盛执行线程的方法居然是调用Runnable对象的run方法。
接着再看dialog.dismiss(); 这行代码,就是这行代码,它会让“scanning”对话框消息消失。这就是典型的“用单线程思维编写多线程代码”~
正确的做法:这里直接调用new Thread(runnable).start();启动多线程——把dialog.dismiss();交给监听蓝牙搜索结束的BroadcastRecevier去做。
Java代码
private static void indeterminateInternal(final Context context, final Handler handler, String message, final Runnable runnable,
OnDismissListener dismissListener, boolean cancelable)
{
final ProgressDialog dialog = createProgressDialog(context, message);
dialog.setCancelable(cancelable);
if (dismissListener != null)
{
dialog.setOnDismissListener(dismissListener);
}
dialog.show();
new Thread() {
@Override
public void run()
{
runnable.run();
handler.post(new Runnable() {
public void run()
{
try
{
dialog.dismiss();
}
catch (Exception e)
{
; // nop.
}
}
});
};
}.start();
}
注意粗体字代码部分,这行代码仿佛“神来一笔”,杨丰盛执行线程的方法居然是调用Runnable对象的run方法。
接着再看dialog.dismiss(); 这行代码,就是这行代码,它会让“scanning”对话框消息消失。这就是典型的“用单线程思维编写多线程代码”~
正确的做法:这里直接调用new Thread(runnable).start();启动多线程——把dialog.dismiss();交给监听蓝牙搜索结束的BroadcastRecevier去做。
8 楼 zhaopian16 2011-04-02
呵呵,这兄弟挺有意思!上来就炮轰!android垃圾书多了去了,为什么不去轰那些直接翻译API,粘贴API里Demo凑页数的书?非要挑一本写的不错的的来轰?想出名?搞炒作?赚点击率?
人尚且无完人,人家写的是“书”不是宪法,你搞搞清楚!!!
cloixio您老人家晚上好好睡一觉,酝酿一下,明早早起去炮轰红楼、三国、水浒……这样来的快些.

人尚且无完人,人家写的是“书”不是宪法,你搞搞清楚!!!
cloixio您老人家晚上好好睡一觉,酝酿一下,明早早起去炮轰红楼、三国、水浒……这样来的快些.
9 楼 cczlg 2012-03-28
这本书我没看过,不能随便说好坏。但你提到的这个例子我觉得它有可取之处。且不考虑CPU和耗电量,就从实现功能上说。我在做一个功能,发现蓝牙设备之后才能进行下一步操作,典型的单线程同步思维。当初Android团队可能是考虑为了不影响UI主线程与用户交互,把startDiscovery做成一个异步方法。那么我这个需求,怎么实现呢?可能还有其它方法能实现,但我觉得杨先生这个方法简单、粗暴、有效。
另外,别有事没事就“炮轰”,人家就写本书而已,有那么大仇么。
另外,别有事没事就“炮轰”,人家就写本书而已,有那么大仇么。
10 楼 cczlg 2012-03-28
再补充一句,既然对技术要求这么严谨,那么,严谨的说:BroadcastRecevier不是监听蓝牙搜索结束的,而是每发现一个设备就调用一次。但是可以在这里判断action是否等于BluetoothAdapter.ACTION_DISCOVERY_FINISHED来得知搜索过程是否结束。前提还得是注册过BluetoothAdapter.ACTION_DISCOVERY_FINISHED的IntentFilter。
我猜_discoveryFinished就是通过这种方法设置为true的。
我猜_discoveryFinished就是通过这种方法设置为true的。