论坛首页 移动开发技术论坛

垃圾书:杨丰盛的《Android应用开发揭秘》

浏览 119392 次
该帖已经被评为精华帖
作者 正文
   发表时间:2011-03-31  
starboy 写道
我觉得适可而止吧,不用纠住不放了。

写本书是很不容易。也有编辑约我写书,也曾想下手,最后想想要顾及的地方太多,所有的例子都要亲自验证,还要尽可能挑最正确的写法。劳神耗时,而版费一年下来正常销量的话也就小几万。想想还是放弃了。

楼主贴的那个循环代码确实没啥用处,但也不会造成什么问题就是,属画蛇添足。所以论严重性的话,正如楼上所说,只能算Minor Bug。因为只看产品功能不看代码的话,测试会让它通过的。只是代码写法不是太好。

从作者角度讲,被人纠住个有点低级的代码错误,确实有点尴尬。我们自己写代码其实也是啊,所以善意提醒一下即可。


我已经打算放手了,这几天赶手头的项目,所以也没怎么顾回复了。

不过楼下应该看到作者问我“怎么不回复了”?
0 请登录后投票
   发表时间:2011-03-31  
nokiaguy 写道
书中的代码只是为了演示功能的。一般并不会太健壮。任何作者都不会像做项目一样做例子的,否则代码会很多。国外的书的代码也是一样。只是为了演示一下功能而已。容错性并不好。如果要求太完美,恐怕会很失望的。如果楼主水平很高的话。不需要再买书了。直接看官方文档更好。


错了,我还是很喜欢买书的。
尤其是少数国内作者的图书。
0 请登录后投票
   发表时间:2011-03-31   最后修改:2011-03-31
kangfu 写道
I just downloaded this bluetooth discovery source code, here is how to start the thread:
		/* 显示一个对话框,正在搜索蓝牙设备 */
                SamplesUtils.indeterminate(DiscoveryActivity.this, _handler, "Scanning...",
                    _discoveryWorkder, new OnDismissListener() {
			public void onDismiss(DialogInterface dialog)
			{

				for (; _bluetooth.isDiscovering();)
				{

					_bluetooth.cancelDiscovery();
				}

				_discoveryFinished = true;
			}
		}, true);


it seems we need to keep bluetooth discovery thread alive during discovering. if there is no that loop, the message "scanning" will not be shown or be shown in very short time.

Is there other person interested in testing this case in your android phone? first test the code with loop, then comment out that loop and try again.



看到你的回复,很为你的执着感到“苦恼”,因为你的技术层次决定了和你讨论这个问题十分艰难,你似乎没有任何多线程知识。我已经建议了你先自行阅读多线程的知识。因为我不想做老师。

我们再来看杨丰盛这个案例中SamplesUtils类中的代码:
	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()
		{
[b]			runnable.run();[/b]

			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去做。

不想多说了,建议你和作者先阅读什么叫“多线程编程”。说多了免得被别人说我“揪住不放”了。

老实说,我来回帖已经很累了,买了一本书还要付出这么多额外的劳动来“传道、授业”,我觉得累了。
也许我以后又潜水了。
0 请登录后投票
   发表时间:2011-03-31   最后修改:2011-03-31
yarin 写道
我不知道何种原因,cloixio兄现在不出来回帖了!
因为cloixio兄始终对这个问题纠结着,我30日找到以前的代码运行测试了N次,结果和kangfu兄说的情况一样。
鉴于此次cloixio兄的“炮轰”,对作者及出版社影响甚大,在我得测试结果之后,我并没有上来回帖,而是联系了出版社的编辑,希望编辑能先私下联系cloixio兄本人,同时(编辑也另外又找了几个Android方面比较有经验的朋友进行了测试,结果都是不能按照cloixio兄的做法来去掉那个所谓的“多余的循环”),再上来解决此问题,但是到目前为止未果。
我一直关注着此贴的最新消息,现在是在忍受不了了,加上kangfu兄也再次验证了正确无误的结果,所以我得上来回复了,希望cloixio兄能够出现回答此问题,否则会误导其他读者。
另外,正如编辑所说的,本书并不一定是完美的,但也不至于完全没有任何价值,也不是cloixio兄所谓的,javaeye上大部分都是人云亦云的“鹦鹉”,我一直知道javaeye上有着很多国内外知名的大师。
最后感谢kangfu兄以及所有为正确结果而讨论验证的师兄弟,包括对技术非常认真严肃的cloixio兄。


引用
也不是cloixio兄所谓的,javaeye上大部分都是人云亦云的“鹦鹉”,我一直知道javaeye上有着很多国内外知名的大师。

  不用拿这句话来给我施压。既然我在第一帖已经就把矛头直指“那一群鹦鹉”,就知道我对这句话免疫。当然我并不是说javaeye上的所有人都是鹦鹉,任何一个地方上总有真正的高手,但真正的高手也许早就发现你的问题懒得说,也许根本没有参与你的数的讨论,因为浪费时间,比如这件事情就浪费了我大量的时间。

2. 希望cloixio兄能够出现回答此问题。
   我已经上来回答该问题了。希望你好自为之,如果我愿意,我可以列出你书中更多“与此类似”的代码,这些代码可能会让你更加难堪。
   一来我累了,二来也是与人为善。算了。

最后补充一下:
我已经在motorola me525、HTC Desire g7两台机器上测试这个程序。
0 请登录后投票
   发表时间:2011-04-01  
可以输入中文了。

首先这个例子来自
http://code.google.com/p/backport-android-bluetooth/source/browse/trunk/backport-android-bluetooth/src/backport/android/bluetooth/samples/?r=39
好像是日本人写的。

其次我们就是要讨论循环有没有用,这是你贴过的代码
	private static void indeterminateInternal(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(); //here is start()
	}

如果没有循环,runnable.run()马上返回, dialog.dismiss()立刻调用, "scanning"也立刻消失了,这显然不是我们想要的,我们是想所有的蓝牙设备都找到了,"Scanning"才消失吧。

还有就是如何启动线程,一般java书是像你所说的
new Thread(runnable).start()
其实这个例子也是这么做的,只不过创建了一个新线程,然后重载run(),在这里调用了runnable.run()函数。其实本质是一样的。

关于你在手机上的测试,你删掉循环后真的看到"Scanning"了吗,看到了多长时间?

最后,我们这里纯讨论技术问题,我的所有发言中没有对你本人有任何评论,完全以礼相待。而你却认为我是一个不懂多线程,层次不高,让你很苦恼的人。无论怎样,我都认为那个循环不是没有用。最好有除了编辑,本书作者外,其他兄弟来验证一下。
0 请登录后投票
   发表时间:2011-04-01   最后修改:2011-04-01
kangfu 写道
可以输入中文了。

首先这个例子来自
http://code.google.com/p/backport-android-bluetooth/source/browse/trunk/backport-android-bluetooth/src/backport/android/bluetooth/samples/?r=39
好像是日本人写的。

其次我们就是要讨论循环有没有用,这是你贴过的代码
	private static void indeterminateInternal(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(); //here is start()
	}

如果没有循环,runnable.run()马上返回, dialog.dismiss()立刻调用, "scanning"也立刻消失了,这显然不是我们想要的,我们是想所有的蓝牙设备都找到了,"Scanning"才消失吧。

还有就是如何启动线程,一般java书是像你所说的
new Thread(runnable).start()
其实这个例子也是这么做的,只不过创建了一个新线程,然后重载run(),在这里调用了runnable.run()函数。其实本质是一样的。

关于你在手机上的测试,你删掉循环后真的看到"Scanning"了吗,看到了多长时间?

最后,我们这里纯讨论技术问题,我的所有发言中没有对你本人有任何评论,完全以礼相待。而你却认为我是一个不懂多线程,层次不高,让你很苦恼的人。无论怎样,我都认为那个循环不是没有用。最好有除了编辑,本书作者外,其他兄弟来验证一下。



看来你就是作者了,昨晚我发完回复后大约1小时内,应机工的编辑之邀,与他联系了一下,编辑说会通知你来回复,相信你就是作者了。

澄清这样几个问题:

1. 如果这个例子不是你写的,你是直接copy了别人的例子。那我一样会说,写这个例子的人其实只是一个入门级的用户。而你作为一个作者,抄袭别人的例子我就不说你了(估计这也是为何你书中的案例与李宁书中的案例完全相同的原因),但你抄了别人的例子,连最基本的代码review都不做、连最基本的去伪存真都不做,直接就复制到书中就来“忽悠”读者,这太不负责了吧?


2. 至于我说你技术层次不高,其实相信这不是我个人的看法。包括机工编辑说要请XXX来鉴定,如果他是真正的高手、不是人云亦云的鹦鹉,不党同伐异!相信他一样会得到这个结论。包括作者写的代码。
我是纯粹站在技术层面讨论这个问题。

3. 请注意我所讨论的是代码质量问题。
   请注意runnable.run();——这种代码是一个真正的程序员应该写的代码吗?启动多线程应该真么干吗?这就是我让你去看看多线程的书再来讨论问题的原因。忠言逆耳利于行啊。
   看作者之前发的回复:
  
引用
只能说明这位仁兄喜欢自己的设备的CPU使用率永远都是100%的。
   最大限度的发挥设备的能力。
   帮助用户消耗一部分电量。
   非常抱歉,本书没有满足你上诉要求!


   ——看来这就是作者设计这段死循环的目的。但实际上,这段代码根本达不到这样的效果,它就是一堆垃圾。正如我之前回复的:
 
引用
这个程序定义了一个线程来执行蓝牙搜索,这条线程只做了2件事情:
   1. _bluetooth.startDiscovery();    ——这条代码是个耗时操作。
   2. 死循环。

   第一种假设:假如_bluetooth.startDiscovery(); 是同步执行的,也就是程序必须等这条代码执行完成后,才会去执行死循环,那死循环能暂停_bluetooth.startDiscovery();这个耗时操作吗?能让CPU空闲出来吗?
 
   幸好Android没有这么SB!因为这个操作完全可能会搜索1~3分钟。这里是异步执行的——也就是说死循环与_bluetooth.startDiscovery();其实是并发执行的。那么根据多线程的“基础知识”:当死循环线程
执行Thread.sleep(100)时,系统完全可能会被调度到去执行 _bluetooth.startDiscovery();这个耗时操作,那么死循环有意义吗?
  
    等你认真学习以下多线程之后再从技术的角度来判断,谁的做法更好。
  
4. 至于你说的“scaning”对话框会消失,那是因为你之前写的代码太垃圾了。换句话来说,
   就像你之前的回复“for expert, of cause, loop is not needed, expert might handle call back function to show the bluetooth device one by one. but it is different story.”我要告诉你的是,其实BroadcastRecevier本身就已经是回调了,它会在蓝牙搜索结束时被回调,所以dialog.dismiss();应该放在交给它去执行。其实一个稍微懂点Android的人、懂点多线程的人都知道应该这么干。不需要什么expert,看来你对expert的要求太低级了。——我认为这这是一个普通中级程序员的要求,等你到了你所谓的“expert”阶段,再来对比一下:到底哪种做法更简单、搞笑?看看你的死循环是不是垃圾?
   再次重复:现在我给你列出的DiscoveryActivity.java、SamplesUtils.java、以及你书中大量java代码,任何一个有2~3年经验的人看了, 都会不忍卒读;如果我在做代码review时发现这种垃圾代码,肯定是要改的,次数多了,就会把他调走!



0 请登录后投票
   发表时间:2011-04-01  
sorry, I can't write Chinese now.

I am not the writer. Before I discuss this topic to you, I didn't read this book and example.

you didn't answer my question, did you see "Scanning" in the phone after you remove the loop?

Our topic is "do we need the loop in this bluetooth discovery code"

here is your first message:

接下来那段死循环就纯属多余!!代码判断_discoveryFinished为true时结束死循环,但这个死循环什么都没做啊。
事实上,完全可以把这段垃圾代码删除。

0 请登录后投票
   发表时间:2011-04-01  
yarin 写道
我不知道何种原因,cloixio兄现在不出来回帖了!
因为cloixio兄始终对这个问题纠结着,我30日找到以前的代码运行测试了N次,结果和kangfu兄说的情况一样。
鉴于此次cloixio兄的“炮轰”,对作者及出版社影响甚大,在我得测试结果之后,我并没有上来回帖,而是联系了出版社的编辑,希望编辑能先私下联系cloixio兄本人,同时(编辑也另外又找了几个Android方面比较有经验的朋友进行了测试,结果都是不能按照cloixio兄的做法来去掉那个所谓的“多余的循环”),再上来解决此问题,但是到目前为止未果。
我一直关注着此贴的最新消息,现在是在忍受不了了,加上kangfu兄也再次验证了正确无误的结果,所以我得上来回复了,希望cloixio兄能够出现回答此问题,否则会误导其他读者。
另外,正如编辑所说的,本书并不一定是完美的,但也不至于完全没有任何价值,也不是cloixio兄所谓的,javaeye上大部分都是人云亦云的“鹦鹉”,我一直知道javaeye上有着很多国内外知名的大师。
最后感谢kangfu兄以及所有为正确结果而讨论验证的师兄弟,包括对技术非常认真严肃的cloixio兄。

实现了功能不代表代码质量高,专家和初学者一样能完成某个功能,但是写出来的代码迥然不同
你既然写书,就不要用这种垃圾代码来误导读者.
你这种测试就相当于黑盒测试,能测试出代码的优劣来?垃圾代码不代表错误~
0 请登录后投票
   发表时间:2011-04-01  
  我国大部分作者就是这样相互抄袭。口头指示产权保护的很好。在了法律上。甚至比美国还有严格,就是实施上。。。。狗屁不做。。

 
0 请登录后投票
   发表时间:2011-04-01  
作者连最基本的java,android变量命名规则都不懂,应该是用c++用习惯了,n久不用java了吧?
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics