两个小时在Android上写个小应用(上)

那天酒精同学跑来问我要一个Android应用:在晚间能够让特定的短信不发出声响。

当时我的第一反应是短信屏蔽。

查阅过相关文档后我发现短信屏蔽功能在Android上是无法在应用层实现的,因为系统在接收SMS后会发送一条广播,Android SDK在M5之后改变了SMS广播的播送方式,使得广播无法在处理过程中取消,应用程序便无法干预这条广播的传递了。

那么我们就改变一下屏蔽方式,关闭系统的Message程序的声音和震动,把提醒功能交给我们的程序来做,这样虽然不是一个纯粹意义上的短信屏蔽程序,但是正好可以满足酒精同学的需求。

那么我们要做的程序就非常简单了:监听系统的SMS广播 -> 过滤SMS -> 提醒

新建一个Android项目,建立一个BroadcastReceiver子类SmsReceiver。

要让SmsReceiver接收到系统的广播,还需要在AndroidManifest.xml中注册一下,并且添加接收短信的权限(要接收短信需要添加相应的权限。这里我们也顺便把后面用到的震动权限也添加了):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        ....
        <receiver android:name=".SmsReceiver">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>    

    </application>
    <uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
</manifest>

这里的"android.provider.Telephony.SMS_RECEIVED"就是SMS广播的消息名称(ACTION_NAME),像这样的信息在哪里可以找到呢?别忘了Android是一个开源项目,Message程序也是开源的。你可以在http://android.git.kernel.org/找到相关的代码。

然后我们跳过过滤SMS,实现一个提醒功能。这里我们创建一个Activity,他做的唯一一件事情就是发送提醒,然后退出。所以他没有界面。建立一个Activity的子类Notify:

static final int NOTIFICATION_ID = 12;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	Notification n = new Notification();
	PendingIntent pendIntent = PendingIntent.getActivity(this, 0,
		new Intent(this, Setting.class), Intent.FLAG_ACTIVITY_NEW_TASK);
	n.setLatestEventInfo(this, "Sms Filter", "Please ignore me!!",
		pendIntent);
	n.defaults |= n.DEFAULT_VIBRATE | n.DEFAULT_SOUND;
	n.flags |= Notification.FLAG_SHOW_LIGHTS;
	n.ledARGB = 0xff00ff00;
	n.ledOnMS = 500;
	n.ledOffMS = 2000;
	NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
	nm.notify(NOTIFICATION_ID, n);
	finish();
}

上面的onCreate方法在最后一行调用finish()直接退出,所以系统消息栏并不会显示消息,但是提示声、震动和闪烁灯都被激活了。这里的提示音和震动都是系统默认的,后面我们还将会加入提示音选择功能。

接着打开SmsReceive.java,当接收到消息提示的时候,启动Notify就可以了。

@Override
public void onReceive(Context context, Intent intent) {
	Intent i = new Intent(context, Notify.class);
	i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	context.startActivity(i);
}

此时就可以运行程序测试其效果了。如果你只有模拟器的话,可以在Eclipse里打开DDMS(没有看到?打开Window->Open Perspective->Others...)中的Emulator Control中模拟一条SMS。不过你感收不到震动和提示音。

程序的第一部分就完成了,剩下的事情就是过滤SMS了,下面我们要做的是实现一个PreferenceActivity,让用户制定黑名单、选择屏蔽的时间段,以及定制提示音。

sms_filter

欲知如何实现,请听下一小时的课程。

如果等不及了,那也可以直接下载程序的源代码APK

Android版的大众点评网手机应用

经过半个月的设计和开发,Android版的大众点评网手机应用发布了。

为什么要叫做Android版,是因为我们还准备相继发布更多的版本,除了现有的Nokia Widget版,还会有Windows Mobile版等

主要功能还是集中在餐馆搜索上,毕竟这个是我们的强项。

第一页,搜索框和热门优惠券

dpv1_sc1

第二页,通过AGPS尝试定位你当前的位置,然后搜索附近的餐馆
dpv1_sc2

不管是关键字搜索还是附近搜索都会得到餐馆列表,翻页只需要不断的往下拖动屏幕即可。
dpv1_sc3

还可以根据菜系和价格进行筛选。
dpv1_sc4

选中合适和餐馆后,不仅可以查看餐馆的具体地址、电话等信息,可以直接拨打电话,在地图上查看餐馆位置,还能将餐馆信息发给你的朋友。
dpv1_sc5

想了解餐馆的具体信息,可以查看相关的点评。
dpv1_sc6

餐馆找找了,可以看看有没有相关的优惠券,输入你的手机号,就能通过短信下载优惠
dpv1_sc7

可以查看热门的优惠券
dpv1_sc8

如果有需要下载的用户,可以用条码扫描软件扫描便可直接转向到Market下载。当然直接搜索dianping或者大众点评都能找到。

market_qrcode

如何识别搜索引擎爬虫的真伪

相信不少网站对搜索引擎爬虫都是又爱又恨,因为其中不仅有些爬虫不守规矩,还有人冒充爬虫对网站进行疯狂的扫描。

做的比较好的爬虫抓取频率都比较合理,对网站资源消耗比较少,像Google Spider会根据网页的下载速度等因素进行抓取速度的动态调整,而且还能通过Webmaster Tools来调整Spider的抓取速度。

Google_Webmaster_Tools_Settings

很多糟糕的网络爬虫,经常并发几十上百个请求循环重复抓取。曾经见证过一个“爬虫”先是将PageNo递增到无穷大——被封,过了4个小时,“爬虫”又回来了,这次程序倒是改进了不少,通过分析网页内部的链接进行抓取,可是没过多久发现总是抓取那几个特定的页面,原来被网页内部链接套住,程序进入了死循环,我只能封杀。

网上也出现了很多如何封杀恶意爬虫的方法。常见的就是根据UserAgent中的标识进行识别封杀,但是道高一尺魔高一丈,接下来就有人伪造User-Agent,伪装成各大搜索引擎的爬虫进行抓取。

目前大众点评网的做法是根据UserAgent进行判断,如果是真正的搜索引擎爬虫,那么就放过;如果发现是伪造的就坚决封杀。剩余的正常UserAgent的访问则通过限制IP并发请求次数来限制。

那么问题就出现了,如何才能正确识别搜索引擎爬虫的真伪,其实一些大型的搜索引擎商都已经提供了相关的方法,那就是反向DNS验证(Reverse DNS Lookup)。

拿Google Spider举个例子:

Google:http://www.google.com/support/webmasters/bin/answer.py?answer=80553

Yahoo:http://www.ysearchblog.com/2007/06/05/yahoo-search-crawler-slurp-has-a-new-address-and-signature-card/

Bing(MSN):http://cn.bing.com/community/blogs/search/archive/2006/11/29/search-robots-in-disguise.aspx

可喜可贺的是baidu的2个月前爬虫也开始遵守这一“潜规则”,虽然没有在任何网页公开此消息,但经过测试,实际上是可行的。

P.S.记得大约是09年2月,曾经就此事给百度的Webmaster@baidu.com写过邮件,结果石沉大海。然后尝试通过百度空间给李彦宏留言,一样渺无音讯。今天还给soso和sougou写了类似的邮件,不知道是不是有消息。

.NET WAP开发-WAP2.0篇

WAP1.1时代是否结束这个不可下定论。但WAP2.0的大面积使用应该已经成熟。DianPing网的WAP站点也基本上迁移到WAP2.0
从构建WAP网站的过程来看,WAP2.0和WAP1.1并没有什么很大的区别。
可以这么说wap2.0其实就是xhtml的网站,而wap1.1是wml的网站。
相比WML受到的限制,WAP2.0网站可以直接在PC上显示。CSS的有限支持。大大丰富了网页在手机上的展示,提供了更丰富的用户体验。WAP 2.0 可以简单的概括为 XHTML MP + WAP CSS
Read the rest of this entry »

多变的this

最近比较流行的大片当属变形金刚2了,今天我们要聊的也是一个多变的家伙--this。上篇文章大概提到了js里面的几个常用的知识点,本篇文章详细介绍下javascript语言里面的this,熟悉js的同学基本都知道,这个this是个多变的家伙,跟传统的 java,c#等语言里面的this有所不同。就连adobe最新的actionscript3.0都对this这个关键字采取了措施,可是我们可怜的 javascript还是不能用到最新的特性(javascript可能要哭了,我跟actionscript本是同根生,怎么我不能)。恩,我们聪明的程序员该大显身手了,先看几个实例:

1.element绑定事件中的this

  1. document.getElementById('a').onclick = function() {
  2.      //some code
  3.      alert(this);
  4.  }

这里的this,不管你的function是在什么地方定义的,始终是指向元素本身,这也是我们最经常用到的。

2.对象方法中的this

  1. var obj={
  2.     a:function(){
  3.          //some code
  4.          alert(this);
  5.     }
  6. }

当我们调用obj.a()的时候,this是指向obj这个对象的。一般我们定义的函数都是在window这个对象下面,所以this一般情况下指向window对象。

3.inner function中的this

  1. (function out(){
  2.     //some code
  3.     var a=function(){
  4.         alert(this)
  5.     }
  6.     a();
  7. })();

内联函数中的this一般指向window。

可以看出,同一个函数在不同的场景中this的指向也是不断变化的,为了减少开发人员的苦恼,目前流行的javascript framework中都有了关于函数的bind的实现,具体的原理就是利用closure。

在这里我们来简单实现一个bind方法:

  1. Function.prototype.bind=function(obj){
  2.     var fn=this;
  3.     return function(){
  4.         return fn.apply(obj,arguments);
  5.     }
  6. }

用法:

  1. function a(){
  2.     alert(this);
  3. }
  4. var b=a.bind(obj);//obj为你要绑定到的对象
  5. b(); //调用b就可以了

这里我们用了一个简单的闭包,巧妙的转化了this关键字,使this始终指向obj,就聊到这里吧。

Javascript编程基础

1.null 与 undefined

* 从一个对象中获取某个属性,如果该对象及其 prototype 链 中的对象都没有该属性的时候,该属性的值为 undefined 。
* 一个 function 如果没有显式的通过 return 来返回值给其调用者的话,其返回值就是 undefined 。有一个特例就是在使用new的时候。
* JavaScript 中的 function 可以声明任意个形式参数,当该 function 实际被调用的时候,传入的参数的个数如果小于声明的形式参数,那么多余的形式参数的值为 undefined 。
* null为空对象,注意与空的对象({})的区别。


2.if 表达式

* Null总是为假(false)
* Undefined总是为假(false)
* Number+0,-0 或是 NaN 的时候为假,其它值为真
* String空字符串的时候为假,其它值为真
* Object总是为真(true)

3.Array

JavaScript 中的数组(Array)和通常的编程语言,如 Java 或是 C/C++ 中的有很大不同。在 JavaScript 中的对象就是一个无序的关联数组,而 Array 正是利用 JavaScript 中对象的这种特性来实现的。在 JavaScript 中,Array 其实就是一个对象,只不过它的属性名是整数,另外有许多额外的属性(如 length)和方法(如 splice)等方便地操作数组。 Read the rest of this entry »

使用.NET API加密Config文件片段

有时候为了保护.config文件中的敏感信息,我们需要对其中的部分内容进行加密。在MSDN的一篇文档里,提供了一个使用命令行工具通过DPAPI进行配置文件加密的办法。这篇文章里提供另一个通过.NET API的方法加密配置文件的途径。

所需要编写的代码其实非常简单,如下是一个简单的示例:

  1. Configuration myConfig = WebConfigurationManager.OpenWebConfiguration("/");
  2. ConfigurationSection mySection = myConfig.GetSection("appSettings");
  3. mySection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
  4. myConfig.Save();

主要使用了ProtectSection这个方法来对指定的配置项进行加密。解密的过程也非常简单,只要调用UnprotectSection方法即可,示例代码如下:

  1. Configuration myConfig = WebConfigurationManager.OpenWebConfiguration("/");
  2. ConfigurationSection mySection = myConfig.GetSection("appSettings");
  3. mySection.SectionInformation.UnprotectSection();
  4. myConfig.Save();

或许你有更多更好的保护配置文件中敏感信息的策略和方法,欢迎与我们交流 ^_^

C# 邮件批量发送程序

前一段时间使用 System.Net.Mail.MailMessage 类写了一个邮件批量发送的程序,在调试和测试中遇到的一些问题和大家共享一下,希望能够对大家有所帮助。

用MailMessage 类发送邮件的方法有很多,但我推荐使用异步方式发送邮件,尤其是发送批量邮件,这是因为程序在向邮件服务器提交多个邮件时,同步方式是等到上一封邮件提交完成并且有发送状态返回,才开始发送下一封,如果这时连接邮件服务器的网络比较慢,没有及时响应,那么程序一直处于等待状态,会影响后面的发送,有时还会产生重复提交,使收件人收到多封重复邮件。

下面是一个异步发送的实例。
Read the rest of this entry »

FOR XML PATH 语句的应用

大家都知道在SQL Server中利用 FOR XML PATH 语句能够把查询的数据生成XML数据,下面是它的一些应用示例。

DECLARE @TempTable table(UserID int , UserName nvarchar(50));
insert into @TempTable (UserID,UserName) values (1,'a')
insert into @TempTable (UserID,UserName) values (2,'b')
 
select UserID,UserName from @TempTable FOR XML PATH

运行这段脚本,将生成如下结果:
Read the rest of this entry »

在HTML页面中嵌入Flash元素的三个常见问题

1.Flash在form中与JavaScript通信

在HTML页面中嵌入Flash对象,并使用JavaScript与其进行通信(例如调用Flash中的某个方法)时,页面加载Flash之后,在IE浏览器中可能会出现这样的错误:‘flashObjectId’ 未定义。(其中flashObjectId是嵌入flash对象的id)。

这是因为Flash是通过ExternalInterface来与JavaScript进行通信的,当在form标签中使用Flash对象的 ExternalInterface时,是通过window.flashObjectId来获取Flash 对象在JavaScript中的引用的。

但是上面的代码只能获得不在form标签中的Flash对象,而form元素里面的Flash对象只能通过这样的代码来获得:document.forms[0].flashObjectId

Adobe官方提供了一个解决方案:

嵌入Flash对象之后,在页面中加入以下脚本:

window.flashObjectId = document.forms[0].flashObjectId;

2.flash遮挡页面中元素
Read the rest of this entry »