那个~~谁知道www.ffchina.co0000.co...

最近新部署了一个信息系统,厂家居然没有升级方案,所有数据都要重新输入,包括用户、角色等都要重新配置,真是操蛋。要是一个个录入简直是日狗了,这些用户在其他信息系统早已存在,但是每个都复制粘贴提交一遍也不是办法,于是就想用程序自动完成这些操作。步骤如下:1、从其他信息系统的数据库导出用户信息,也可以直接从其他信息系统的界面把所有用户信息复制下来放在一个文本文件里,反正就是准备好数据源;2、在需要录入用户信息的系统中,用人工操作的方式登录系统,并录入一个用户,同时用Wireshark抓包,查看整个过程要提交一些什么样的表单数据;3、在程序中用httpclient提交同样的数据,完成登录,并从第1步的数据源中读取用户信息,然后循环提交录入用户所需的数据,完成用户的录入;4、新系统没有默认的用户角色,是需要一个个修改的,是根据用户的ID来确定当前修改的用户,并且提交一个角色ID来进行设定,因此需要首先获取用户的ID,然后根据该ID来提交角色ID,而用户ID是通过用户列表页面获取到的,因此还需要通过正则表达式来获取所有用户的ID,然后循环提交角色ID,完成角色设定。花了不少时间才搞定,有几个地方需要注意:1、如果表单数据不包含中文,直接把表单的Name和Value加在HttpPost的URL的?后面即可,不需要专门建立NameValuePair,如下所示:HttpPost&httppost&=&new&HttpPost("http://1.1.1.1/test/adduser?userid=abc&username=efg");httpclient.execute(httppost);但是,如果表单数据包含中文,例如姓名,用这种方式提交的表单数据会出现乱码,即使通过URLEncoder进行编码后再发也不行,必须建立NameValuePair,再加到HttpPost的Entity里面,如下所示:HttpPost&httppost&=&new&HttpPost("http://1.1.1.1/test/adduser?userid=abc");List&NameValuePair&&nvps&=&new&ArrayList&NameValuePair&();nvps.add(new&BasicNameValuePair("username","张三"));httppost.setEntity(new&UrlEncodedFormEntity(nvps,&HTTP.UTF_8));httpclient.execute(httppost);2、用于网页内容查找的正则表达式的使用方式一般为:Pattern&p&=&pile(".*?abc(whattoget)123.*?");Matcher&m&=&p.matcher(line);if(m.matches()){&&&& String&whattoget&=&m.group(1);}".*?abc(whattoget)123.*?"就是一个正则表达式,如果用于匹配一行的时候,由于要查找的内容是在行中间,所以前后需要加上.*?,表示前后可以是任意字符,也可以什么都没有,而表达式中间的(whattoget)就表示一个group,编号为1,编号为0的group是整个匹配的字符串,找到之后提取group(1)即可得到想要的内容。测试正则表达式是一项很麻烦的工作,不过有个很好的软件可以完成此工作:RegexBuddy,支持各种语言的正则表达式的调试。学习正则表达式的宝典是《Mastering Regular Expression》。
今天遇到一个非常奇怪的问题,有台装XP的电脑,插上USB键盘没反应,还以为是键盘坏了,又找来两个不同型号的键盘,依然不行,又以为是USB接口坏了,结果在电脑启动的时候又可以按F2进入BIOS,这样就只有一个原因,Windows的驱动没装上了。幸好这电脑还有传统的PS/2口,而且插上就能识别,否则连Windows都进不去,因为按Ctrl+Alt+Del没反应。进去之后提示***USB键盘驱动,到最后一步提示***失败,原因是拒绝访问。上网搜了一下,***驱动拒绝访问的其中一个原因是注册表有个键的权限设置有问题,改过来即可,但是我打开注册表,连那个键都没找到,不是这个原因。不过从这个解决方案中也知道了驱动***的日志是在Windows目录下的setupapi.log文件里面,于是打开那个文件,发现每次***都有两个拒绝访问的错误,但并没有说是注册表拒绝访问,在拒绝访问之前,还提到一个叫MlCoInst.dll的文件没有签名。上网搜MlCoInst.dll,没有找到任何结果,在System32目录下找到它,看属性,果然没有签名,是个三无文件,不知道为什么每次***驱动都要调用它。日志里面还提到了“共同***程序”,似乎和CoInst有点关联,于是又查了一下,原来***驱动的时候可以通过调用“共同***程序”来实现某些目的,例如修改驱动程序的签名状态,欺骗操作系统,这样就可以只***一次驱动即可,不用每次插入都***一次。于是尝试把MlCoInst.dll删除,提示删除失败。在注册表里面搜索MlCoInst.dll,把所有找到的键值都删除,再次插拔键盘,顺利***完毕,删除MlCoInst.dll,也成功了,果然是它的问题。这个应该是某个USB设备的驱动引进来的,而且修改了usb.inf,每次***任何USB设备都要调用它,但它可能与Windows的签名机制有冲突,所以导致***失败,真是坑爹!
做GUI程序的时候,通常有个后台工作线程在努力工作,但是中间又需要一些暂停,而关闭程序的时候,必须立即结束那个线程,退出程序,也有的时候需要停止后台线程,但不关闭程序。例如,做一个目录监控程序,发现目录中有文件的时候,执行一定的操作,执行完之后没有文件了,就要暂停一下,过几秒或几分钟再次检测,这时候就要对线程进行暂停操作,如果在暂停的时候,用户要关闭程序,就必须马上停止线程,如果用户需要暂停检测,按下某个按钮后,需要让线程马上停止,但再次按下某个按钮,线程又必须马上开始。
以前我都是通过检测停止标记和用Thread.sleep(time)来完成的,后台线程的每次循环都要检查停止标记,如果发现停止标记已设定,就不再循环,退出线程,在线程内部,如果需要暂停,就执行Thread.sleep(time)。通过把线程的setDaemon(true)方法,还可以让线程作为后台线程,当图形界面关闭后,线程也自动退出。
但是,这种方式有个问题,如果我需要在图形界面上点击按钮来停止线程,但并不退出程序,而点击按钮的时候线程正处于sleep状态,就对它没有任何办法,只能让它醒过来再操作,如果sleep的时间比较长,例如1分钟,那么点击按钮之后,用户最多要等1分钟才能把线程停下来。当然,Thread对象有个interrupt方法,但是已经被标记为过期,一般不建议使用了。感谢评论中的提醒,Thread的interrupt()并没有标记为过期,可以按照他的说法来操作,更为简单。
怎么让线程能暂停,又能随时叫醒呢?原来Java里最原始的对象Object就自带此功能。
每个Object都有wait(time)和notify()方法,前者就是让拥有该Obejct的线程处于暂停状态,后者则让线程马上唤醒,通过这两个方法,就能够满足上述的所有要求。
首先,建立一个同步对象:
Object syncObj = new Object();
然后在线程中需要暂停的地方,调用该对象的wait(time)方法:
synchronized (syncObj) {
&& &&& syncObj.wait(60*1000);
在图形界面的按钮***事件中,对该对象执行notify()方法:
&& &&&& button_1.addSelectionListener(new SelectionAdapter() {
&& &&& &&& &@Override
&& &&& &&& &public void widgetSelected(SelectionEvent e) {
&& &&& &&& &&&& thread.setStop(true);
&&& &&& &&& &&& synchronized (syncObj) {
&& &&& &&& &&& &&& &&&& syncObj.notify();
&& &&& &&& &&& & }
&& &&& &&& &&&& //为了等待线程退出,还可以加上以下语句:
&& &&& &&& &&&& thread.join();
&& &&& &&& &}
&& &&& &});
Eclipse有个功能就是把整个项目打包成一个可执行的Jar文件,里面包含了所有项目引用了的库,如果电脑上***了JRE,直接双击就可以启动,看起来很方便,如下图所示:可以选择把所有类库打包进去,也就是Jar里面还包含一堆Jar:还可以生成ant脚本:生成的jar文件,可以直接通过java -jar xx.jar启动,简单快捷。然而,这样导出来的可执行jar,启动速度却非常慢,这跟包的大小有关。有个项目导出来的包有40MB,结果启动需要近一分钟,在性能差的电脑上,甚至要几分钟,就是你执行完命令后,没有任何界面显示,但是查看任务管理器发现java进程的CPU占用率在浮动,说明正在努力启动,过了一段时间之后界面突然显示出来,简直让人崩溃。可是在Eclipse里面运行,却是一点就开。我开始尝试缩小导出的包。但是Eclipse的导出对话框并没有提供需要打包哪些库的选项,都是默认把所有库都打包进去,但是它可以生成ant脚本,可以通过编辑ant脚本的方式来减少不必要的库。经过多次尝试,终于把40MB的包缩成了17MB,启动速度快了一些,但是依然需要半分钟以上。后来觉得,能不能不打包直接运行呢?于是把导出来的包用压缩软件解压,再把里面包含的jar包继续解压,最后得到一堆没有压缩的class文件,再通过指定classpath的方式,直接运行程序入口class,发现启动速度和在Eclipse里面一样,一点就开。打包的好处是部署简单,只需要一个文件,但带来的缺点实在不能忍,打散的方式部署起来稍微难一点,但是启动速度够快,对普通用户来说,这个才是最重要的。当然,还有一种方式是像Eclipse那样,启动时显示一个图片,底下一个进度条显示启动进度,不过这样也加大了工作量,而且每次都要等那进度条,实际上也很烦。
&&&& 摘要: JMF太老了,各种问题得不到解决,Oracle也没再升级过,如果能找到新东西,最好能把它扔掉。最近OpenCV比较火,还有人用Java封装了OpenCV,成立了JavaCV项目,通过改造VideoInput这个基于C语言的项目,能够用Java来调用摄像头,JMF可以扔掉了。如果想测试,非常简单,把那些编译好的jar文件放入Build Path即可,如果是在Windows X86环境下,则只需要把带...&&
其实我觉得用java结合SQL来做同样的事情更简单,但是EXCEL的好处是不用编程,虽然里面有好多陷阱,但是掌握之后能够熟练运用还是比每次都编个程序更简单。VLOOKUP函数的使用比较复杂,搞了好久都不明白,终于找到了下面这篇文章,解决了很多问题。以下是转载文章,原来的出处不知道是哪里,应该是来自但具体的地址不详。VLOOKUP函数是Excel中几个最重函数之一,为了方便大家学习,兰色幻想特针对VLOOKUP函数的使用和扩展应用,进行一次全面综合的说明。本文为入门部分 &&&&&一、入门级 &&&&&&VLOOKUP是一个查找函数,给定一个查找的目标,它就能从指定的查找区域中查找返回想要查找到的值。它的基本语法为: &&&&&&VLOOKUP(查找目标,查找范围,返回值的列数,精确OR模糊查找) 下面以一个实例来介绍一下这四个参数的使用 &&&& 例1:如下图所示,要求根据表二中的姓名,查找姓名所对应的年龄。&&
&&&公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)&& && 参数说明: &&&&&& 1&查找目标:就是你指定的查找的内容或单元格引用。本例中表二A列的姓名就是查找目标。我们要根据表二的“姓名”在表一中A列进行查找。 &&&&&&& 公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)&&& &&&&&&&2&查找范围(VLOOKUP(A13,$B$2:$D$8,3,0)&): 指定了查找目标,如果没有说从哪里查找,EXCEL肯定会很为难。所以下一步我们就要指定从哪个范围中进行查找。VLOOKUP的这第二个参数可以从一个 单元格区域中查找,也可以从一个常量数组或内存数组中查找。本例中要从表一中进行查找,那么范围我们要怎么指定呢?这里也是极易出错的地方。大家一定要注 意,给定的第二个参数查找范围要符合以下条件才不会出错: &&&&&&&&A&查找目标一定要在该区域的第一列。本例中查找表二的姓名,那么姓名所对应的表一的姓名列,那么表一的姓名列(列)一定要是查找区域的第一列。象本例中,给定的区域要从第二列开始,即$B$2:$D$8,而不能是$A$2:$D$8。因为查找的“姓名”不在$A$2:$D$8区域的第一列。 &&&&&&& B&该区域中一定要包含要返回值所在的列,本例中要返回的值是年龄。年龄列(表一的D列)一定要包括在这个范围内,即:$B$2:$D$8,如果写成$B$2:$C$8就是错的。 &&&&&& 3&返回值的列数(B13 =VLOOKUP(A13,$B$2:$D$8, &&& &公式=VLOOKUP("*"&A10&"*",A2:B6,2,0) & &&&&公式说明:VLOOKUP的第一个参数允许使用通配符“*”来表示包含的意思,把*放在字符的两边,即"*" & 字符 & "*"。 &&&二、数字的区间查找 &&&&&&数字的区间查找即给定多个区间,指定一个数就可以查找出它在哪个区间并返回这个区间所对应的值。 &&&&在VLOOKUP入门中我们提示VLOOKUP的第4个参数,如果为0或FALSE是精确查找,如果是1或TRUE或省略则为模糊查找,那么实现区间查找正是第4个参数的模糊查找应用。 &&&&首先我们需要了解一下VLOOKUP函数模糊查找的两个重要规则: &&& 1、引用的数字区域一定要从小到大排序。杂乱的数字是无法准确查找到的。如下面A列符合模糊查找的前题,B列则不符合。& &&&&
&&& 2、模糊查找的原理是:给一定个数,它会找到和它最接近,但比它小的那个数。详见下图说明。 &&&&
&&&最后看一个实例:& &&&&例:如下图所示,要求根据上面的提成比率表,在提成表计算表中计算每个销售额的提成比率和提成额。 &&&&
&& 公式:=VLOOKUP(A11,$A$3:$B$7,2) &&&公式说明: &&& 1、上述公式省略了VLOOKUP最后一个参数,相当于把第四个参数设置成1或TRUE。这表示VLOOKUP要进行数字的区间查找。 &&& 2、图中公式中在查找5000时返回比率表0所对应的比率1%,原因是0和1最接近,但VLOOKUP只选比查找值小的那一个,所以公式会返回0所对应的比率1%。 & &前言:前面我们分别学习了VLOOKUP函数的入门、初级和进阶篇。今天我们学习VLOOKUP函数的高级应用部分-VLOOKUP函数的数组应用。(本文由兰色幻想原创,转载请注明转自) &一、VLOOKUP的反向查找。 &&& 一般情况下,VLOOKUP函数只能从左向右查找。但如果需要从右向右查找,则需要把区域进行“乾坤大挪移”,把列的位置用数组互换一下。 &&&&例1:要求在如下图所示表中的姓名反查工号。 &&&&&
&&&&公式:=VLOOKUP(A9,IF({1,0},B2:B5,A2:A5),2,0) &&&&公式剖析: &&&&&&& 1、这里其实不是VLOOKUP可以实现从右至右的查找,而是利用IF函数的数组效应把两列换位重新组合后,再按正常的从左至右查找。 &&&&&&&
2、IF({1,0},B2:B5,A2:A5)这是本公式中最重要的组成部分。在EXCEL函数中使用数组时(前提时该函数的参数支持数组),返回的结 果也会是一个数组。这里1和0不是实际意义上的数字,而是1相关于TRUE,0相当于FALSE,当为1时,它会返回IF的第二个参数(B列),为0时返 回第二个参数(A列)。根据数组运算返回数组,所以使用IF后的结果返回一个数组(非单元格区域):{"张一","A001";"赵 三","A002";"杨五","A003";"孙二","A004"} &二、VLOOKUP函数的多条件查找。 &&&&& VLOOKUP函数需要借用数组才能实现多条件查找。 &&&&&例2:要求根据部门和姓名查找C列的加班时间。
&&&& 分析:我们可以延用例1的思路,我们的努力方向不是让VLOOKUP本身实现多条件查找,而是想办法重构一个数组。多个条件我们可以用&连接在一起,同样两列我们也可以连接成一列数据,然后用IF函数进行组合。 &&&&公式:{=VLOOKUP(A9&B9,IF({1,0},A2:A5&B2:B5,C2:C5),2,0)} &&&&公式剖析: &&&&&& 1、A9&B9 把两个条件连接在一起。把他们做为一个整体进行查找。 &&&&&& 2、A2:A5&B2:B5,和条件连接相对应,把部分和姓名列也连接在一起,作为一个待查找的整体。 &&&&&& 3、IF({1,0},A2:A5&B2:B5,C2:C5) 用IF({1,0}把连接后的两列与C列数据合并成一个两列的内存数组。按F9后可以查看的结果为: &&&&&& {"销售张一",1;"销售赵三",5;"人事杨五",3;"销售赵三",6} &&&&&& 4、完成了数组的重构后,接下来就是VLOOKUP的基本查找功能了,另外公式中含有多个数据与多个数据运算(A2:A5&B2:B5),,所以必须以数组形式输入,即按ctrl+shift后按ENTER结束输入。 &&&& 三、VLOOKUP函数的批量查找。 &&&&&VLOOKUP一般情况下只能查找一个,那么多项该怎么查找呢? &&&&&例3 要求把如图表中所有张一的消费金额全列出来
&&&&&分析:经过前面的学习,我们也有这样一个思路,我们在实现复杂的查找时,努力的方向是怎么重构一个查找内容和查找的区域。要想实现多项查找,我们可以对查找的内容进行编号,第一个出现的是后面连接1,第二个出现的连接2。。。 &&&& 公式:{=VLOOKUP(B$9&ROW(A1),IF({1,0},$B$2:$B$6&COUNTIF(INDIRECT("b2:b"&ROW($2:$6)),B$9),$C$2:$C$6),2,)} &&&& 公式剖析: &&&&&&& 1、B$9&ROW(A1) 连接序号,公式向下复制时会变成B$9连接1,2,3 &&&&&&&&2、给所有的张一进行编号。要想生成编号,就需要生成一个不断扩充的区域(INDIRECT("b2:b"&ROW($2:$6)),然后在这个逐行扩充的区域内统计“张一”的个数,在连接上$B$2:$B$6后就可以对所有的张一进行编号了。 &&&&&&&3、IF({1,0}把编号后的B列和C组重构成一个两列数组 &&&& 通过以上的讲解,我们需要知道,VLOOKUP函数的基本用法是固定的,要实现高级查找,就需要借助其他函数来重构查找内容和查找数组。 &&&& 至此VLOOKUP函数从入门到高级的四篇VLOOKUP函数使用教程全部结束了,VLOOKUP函数在数组运算中还有着其他应用,但只是配角了,所以本系列不再介绍。由于笔者水平有限,不免有错漏之处,请大家多多指点。
JMF(Java Media Framework)是Java平台使用摄像头、麦克风等媒体设备的应用程序框架,但到了2.1.1e就不再更新,在Windows 7 X64上还能正常运行,只是***的界面让你感觉回到了Windows98的时代。不过年代久远的东西,虽然还能用,但可能会遇到一些奇怪的问题,折腾了两个月,发现了两个比较大的问题:第一个是在Windows 7 x64上提示摄像头初始化失败的问题。这个问题很奇怪,电脑刚开机的时候可以顺利找到一次摄像头并正常操作,但是第二次就会提示摄像头初始化失败。有人提出的解决方法是***一个叫ManyCamera的程序,这个程序可以把一个摄像头供多个程序同时使用,其实就等于中间加了一层转换,效果会有点差别,免费版还会加上水印,要求比较高的人可能会不爽,但是目前找不到其他办法。第二个是在程序中找不到摄像头,不光找不到摄像头,其他媒体设备通通找不到,使用以下语句: vector&=&CaptureDeviceManager.getDeviceList&(&null&)按照文档说明是返回所有媒体设备,但每次vector都是null。在Eclipse中运行又能正常,导出成jar之后运行就会找不到摄像头。原因在于找不到jmf.properities文件,该文件包含所有检测到的媒体设备的信息,最简单的解决方法就是把JMF***目录下lib子目录中的jmf.properties文件复制到最后运行的jar所在的目录,不过如果摄像头改过的话,重新检测后要把新的文件复制到jar目录,因为检测到的媒体设备信息都会存放在JMF***目录里面的jmf.properties文件里。StackOverflow里面有个人对这个问题解释得比较清楚:虽然问题解决了,但是还是不明白为何在Eclipse中可以正常运行,导出jar后运行却找不到摄像头,即使把JMF所有jar和lib目录都加入系统的CLASSPATH环境变量里还是不行。另外,JMF***程序会自动把它的jar和lib目录加入系统的%CLASSPATH%环境变量,但是如果你卸载了再重新***到其他目录,并不会改变%CLASSPATH%的值,需要手动修改。不过这个环境变量似乎没啥用处。最好不要把JMF***到默认的Program Files目录,可能会运行不了,***到短目录会比较保险,它似乎还是只认Dos时代的8.3目录结构,但偏偏又默认***到Program Files里面。
其实我也搞不懂Windows的域,反正能用就行了。但是最近有一台客户端的时间改不了,总是提示特权级不够,按理说应该是组策略限制了,但是我把那台计算机从包含该组策略的OU中移出来,还是不行,这就奇怪了,难道组策略不是指针对OU里面的成员的吗?百思不得其解啊,最后只能在BIOS里面把时间改了。今天发现我自己的电脑设置不了屏幕保护,也是组策略限制了,然后把我的用户和计算机都移出了组策略应用的OU,结果发现还是设置不了,这下肯定是组策略的应用上有问题了。搜索了半天发现有个叫rsop.msc的管理工具,可以看到某用户在某计算机上应用的组策略,结果发现我还是应用之前的组策略,但是计算机配置和用户配置前面都有个红叉,右键-属性-错误信息里面显示:Title由于下面列出的错误,组策略结构 失败。
系统找不到指定的路径。
注意: 由于 GP Core 失败,其它组策略组件没有一个处理了它们的策略。因此,其它组件的状态信息不可用。好像是有某个组策略找不到,所以不能应用的意思。然后想起来在域名下面有个“新建组策略”,但是没有做过任何配置,应该是有人手贱点了一下新建按钮加进去的,于是把它删除,还是不行。重启了一下客户端,居然好了,时间也可以改了,屏幕保护也可以改了,一切都按计划进行。莫名其妙~~
现在的手机摄像头动辄几百万上千万像素,如果电脑需要用到摄像头又没有的话,不妨用手机的摄像头代替。我是在做一个电脑二维码识别器的时候,因为原来的摄像头太差,从而想到用一台淘汰的Android手机来代替。这类应用应该不少,我首先找到的是一个叫DraoidCam的应用,装好之后发现免费版没法调整分辨率,于是放弃之。然后又找到了一个国内做的免费软件,叫魅色,非常简单,支持USB和WiFi连接方式,如果是USB连接的话,打开USB调试模式之后,运行电脑的客户端,手机上就自动装上了App并且自动运行,可以调整分辨率,不过最高只有640*480,帧率不到10,不过已经能够满足我的需求了。然后就可以像普通PC摄像头一样使用了,在JMF里面也能找到,于是就可以被Java调用了。经测试,效果比原来的PC摄像头好多了。软件主页:
&&&& 摘要: TabActivity在API 13(Android 3.2)被标记为过期,需要使用Fragment来实现,Fragment是Android 3.0引入的一个概念,主要就是为了适应各种不同的屏幕大小(手机、平板电脑)。Android 4.1发布时,google还发布了一个Android Support v4的包,用于Android 1.6以上的系统兼容新的特性,其中包括Fragment。为了在低于...&&
SQL Server 2000的导入导出功能还是不错的,支持各种各样的数据库,但是却有好多奇怪的bug,不能直接操作,几乎每一步都要上网搜索,最后搞定了,一定要记下来:
1、在同一台电脑上装好SQL Server 2000的客户端和Oracle 10g的客户端,并分别设置好到源数据库(SQL Server 2000数据库)和目标数据库(Oracle 数据库)的连接,两个数据库都有图形界面的企业管理器,很容易设置好;
2、在控制面板-管理工具-数据源里添加一个DSN,驱动程序选择类似“Oracle in OraClient10g_home1”的,确定之后输入Data Source Name(随意),Description(随意),TNS Service Name(在企业管理器里设置好的连接名),User ID(用户名),然后按Test Connection测试是否连接成功,成功之后点OK;
3、在SQL Server 2000的企业管理器里,在任意一个表上点右键,所有任务,导出数据,在目的里选择“Oracle in OraClient10g_home1”,用户/系统DSN里面就会出现刚才设置好的DSN名字,选中,然后输入用户名密码,点两次下一步就会出现选择源表和视图对话框
4、这里要注意的是,勾上源中的某个表,在目的里面就会出现"用户名"."表名"的默认选项,如果你刚才使用的Oracle用户名是小写的话,这里也会是小写,一定要改成大写,否则会提示该用户名不存在!
目的也可以使用Microsoft OLE DB Provider for Oracle,在属性里面设置服务器名称为Oracle的TNS名称,用户名和密码输入Oracle用户名和密码,测试连接通过即可,后面的步骤都一样。
如果出现以下错误:
[OLE/DB provider returned message:
OLE DB OLE/DB Provider 'MSDAORA' IDBInitialize::Initialize returned 0x:&&
就要修改注册表,有人已经作出了详细的修改说明,在这里可以看到:
我把那个表也贴在这里:
Oracle Client
&Microsoft Windows NT、
Oracle Microsoft Windows 95、
Client Windows 98 和 Windows 98 SE
Microsoft Windows 2000/XP/2003
[HKEY_LOCAL_MACHINE\SOFTWARE
\Microsoft\TransactionServer\Local Computer\My Computer]
"OracleXaLib"="xa73.dll"
"OracleSqlLib"="SQLLib18.dll"
"OracleOciLib"="ociw32.dll
[HKEY_LOCAL_MACHINE\SOFTWARE
Microsoft\MSDTC\MTxOCI]
"OracleXaLib"="xa73.dll"
&"OracleSqlLib"="SQLLib18.dll"
&"OracleOciLib"="ociw32.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
\Microsoft\Transaction Server
\Local Computer\My Computer]
"OracleXaLib"="xa80.dll"
"OracleSqlLib"="sqllib80.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
&\Microsoft\MSDTC\MTxOCI]
&"OracleXaLib"="xa80.dll"
&"OracleSqlLib"="sqllib80.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
\Microsoft\Transaction Server
\Local Computer\My Computer]
"OracleXaLib"="oraclient8.dll"
"OracleSqlLib"="orasql8.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
&\Microsoft\MSDTC\MTxOCI]
"OracleXaLib"="oraclient8.dll"
"OracleSqlLib"="orasql8.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
\Microsoft\Transaction Server
\Local Computer\My Computer]
"OracleXaLib"="oraclient9.dll"
"OracleSqlLib"="orasql9.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
&\Microsoft\MSDTC\MTxOCI]
"OracleXaLib"="oraclient9.dll"
"OracleSqlLib"="orasql9.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
\Microsoft\Transaction Server
\Local Computer\My Computer]
"OracleXaLib"="oraclient10.dll"
"OracleSqlLib"="orasql10.dll"
"OracleOciLib"="oci.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE
&\Microsoft\MSDTC\MTxOCI]
"OracleXaLib"="oraclient10.dll"
"OracleSqlLib"="orasql10.dll"
"OracleOciLib"="oci.dll"
当读写二进制文件,或者要把非标准长度的整数与标准长度的整数互相转换时,就要用到大量的位操作,虽然看起来很简单,实际上里面却有很多细节很容易出错。首先,Java有些标准跟C/C++是不同的:1、Java采用高字节在前的方式读写数据,例如要把一个4字节的int数值写入文件时,它是按照从高字节到低字节的顺序写入的,读取的时候也是这样读出来。而C/C++则采用平台相关的方式,在Windows平台采用低字节在前的方式,在Linux/Unix平台则采用高字节在前的方式。如果Java要读取C/C++创建的二进制文件,就要注意这个问题,最好先搞清楚原来的文件是采用哪种方式创建的。网络通信也要注意。2、Java没有无符号数,无论byte,short,int,long都是有符号整数,而C/C++有个unsigned关键字可以设置一个数值为无符号数。3、Java的整数基本数据类型就是byte,short,int,long这几个,长度分别为1,2,4,8字节,C/C++可以用typedef定义各种数据类型。第二,Java是采用补码来存放整数的。有时候觉得补码的定义有些奇怪,实际上可以这样理解:把一个整数从0一直往上加1,加到溢出就变成了负数的最小值,然后再继续加1,最后又能回到0,实际上就是一个轮回。例如一个byte类型的整数,一共有8位,能表示256个数值,采用补码的话数值范围就是-128~127,表示方法如下:0&&& &&& 1&&& &&& ..126&&& 127&&& -128&& -127&& ..-1&&&&&& 0&&&&&&&& 第三、不同长度的整数转换。如果是从较短的数转成较长的数,很简单,如果是正数就在高字节补0,如果是负数就在高字节补1。 例如byte的127转为short的127:byte:short:11 0111byte的-127转为short的-127byte:short:00 0001如果是从较长的数转成较短的数,实际上就是把高位都截断了,所以转出来的数值可能完全不是一回事了。例如short的256转为byte:short:00 0000byte: 把256变成了0short的-255转成byte:short:00 0001byte:把-255变成了1第四、位运算操作符及它们的优先级Java的位运算操作符包括:~非,|按位或,&按位与,^按位异或,&&左移,&&右移,&&&右移左侧补0各种运算符的优先级如下表所示:优先级
-(负) ~ ++ --
+(加) -(减)
& &= & &= instanceof
= += -= *= /= %= &= |= ^=
从右向左根据该表可以看到,位运算操作符的优先级各有不同,分别为:1、~2、&& && &&&3、&4、^5、|另外需要特别注意的是,除了~,其他位运算操作的优先级都低于加减,所以要记得以下语句是返回32而不是7!1&&2+3还有就是&、^、|的优先级都是低于逻辑操作符的,因此下面的语句会编译出错,幸好Java不像C那样对所有大于1的值都认为是真,否则下面的语句也能编译通过,但可能与你的意图不太一样,可能调试半天才发现。if(3&1&0)如果记不清楚,还是按照你的意图加上括号最保险。第五、字节数组与整数之间的转换为了把一个整数存入文件,或者从文件中读取一个整数,需要经常在字节数组和整数之间转换,这个过程要用到大量的位运算。首先需要记住的是,在参与所有运算前,Java都会把byte、short类型的值都转换成int,然后再对转换后的int进行操作。例如下面的语句会编译出错:byte&a=10,b=20,c;c=a+b;因为a和b在相加前都被转成了int,最后得到的结果是个int类型的值,如果要赋给byte类型的c,必须显式地进行类型转换,即把第二句改为:c=(byte)(a+b)这一点很关键,因为对于一个最高位为1的byte类型的整数(负数),在运算之前它会被强制转换成int类型,根据上面所说的第三点,其实就是往前面的三个高字节补上1,这样一来,它在参与位运算的过程中,就不仅仅是它本身的8个bit参与了,实际上连前3个字节的24个bit(均为1)也参与了。例如有一个整数i=,它的二进制表示为:00 分为4个字节存储,除了第一个字节是正数外,其余3个字节均为负数。假如用a代表最高字节的值,用b代表其他三个字节的值,如果按照通常的理解,你可能会这样得到i的值:i=(a&&24)+(b&&16)+(b&&8)+b如果a和b都是正数,上面的等式是成立的,但是在这个例子里,却是错的,因为上式中的a和b都已经被强制转换成了int类型再参加运算,实际上a=00 b=11 i=00 00 11 00+11 最后得到的结果是,不是原来的值了。为了不让byte在强制转换成int的过程加入了我们不想要的高位1,我们需要把它跟0xff进行与操作,i的值应该这样运算:i&=&(&(&a&&0xff&)&&&&24&)&+(&(&b&&&0xff&)&&&&16&)&+&(&(&b&&&0xff&)&&&&8&)&+&(&b&&&0xff&)注意,因为&和&&的优先级都低于+,所以上面的括号是不能少的。不过由于跟0xff与操作之后,其余24位都变成了0,因此可以把+改为|操作,因为任何值与0进行或操作都得到本身:i&=&(&a&&&0xff&)&&&&24&|&(&b&&&0xff&)&&&&16&|&(&b&&&0xff&)&&&&8&|&(&b&&&0xff&)由于&&的优先级高于|,所以省了一些括号。最高字节可以不与0xff进行与操作,因为它转换成int后左边增加的3个字节都在左移24位时被去掉了:i&=&a&&&&24&|&(&b&&&0xff&)&&&&16&|&(&b&&&0xff&)&&&&8&|&(&b&&&0xff&)把int转为字节数组的时候比较简单,直接右移截断即可:byte[]&b&=&new&byte[4];b[0]&=&(byte)&(i&&&&24);b[1]&=&(byte)&(i&&&&16);b[2]&=&(byte)&(i&&&&8);b[3]&=&(byte)&i;第六、非标准长度整数的存储和读取假如有两个变量,他们的值可以用12个bit来表示,如果我们用16bit的short类型来表示一个变量,那么两个变量就需要4个字节,而实际上它们只需要3个字节就能表示出来,如果存储空间比较有限,写入文件时可以把它们存放在3个字节里面,但是读写过程就需要进行转换。在内存里,它们都是标准的数据类型:short&a,b;写入文件时,我们用第一个字节和第二个字节的前半部分来表示a,把第二个字节的后半部分和第三个字节来表示b,即:1:xxxx xxxx2:xxxx yyyy3:yyyy yyyyx和y都表示一个bit,分别用来存放a和b。写入时先把a和b转为字节数组:byte[]&out&=&new&byte[3];out[0]&=&(byte)&(&a&&&&4&);//把a的高8位放在第一个字节out[1]&=&(byte)&(&a&&&&4&);//先把a左移四位,在右边补上4个0,第二个字节的高4位就是a的低4位了,第二个字节的高4位已经生成,低4位还是0out[1]&|=&(byte)&(&b&&&&8&&&0x0f&);//b右移8位,并与0x0f进行与操作,实际上就只保留了b的高4位,并且是在字节的低4位上,跟第二步得到的字节进行或操作,就生成了第二个字节out[2]&=&(byte)&b;//把b的高4位截断就得到了低8位然后再把这个字节数组写入文件,就可以用3个字节表示两个整数了。读取:a&=(short)( (out[0]&&&0xff)&&&&4&|&(&out[1]&&&0xf0&)&&4);b&= (short)((out[1]&&&0x0f)&&&&8&|&(&out[2]&&&0xff));
AdMob是往手机应用程序里添加广告的最流行的方式,Android程序基本都是靠这个赚钱。看文档似乎很简单,但是操作起来却不是那么回事,今天搞了一上午才弄明白怎么正确添加,网上搜索到的资料都不适合最新的SDK。按照AdMob的官方文档,很简单,只要把AdMob的开发包jar放到Build Path的Libraries里面就行了,这样做编译是没问题的,但是一运行就会出错,提示java.lang.NoClassDefFoundError:com.google.ads.AdView这是因为Google最近更新了ADT到17.0,改变了项目依赖的检测方式,官方的说明在,不过看得不是很懂。有人用图形的方式标了出来,容易理解一些,看。如果不求甚解,就把刚才放到Build Path里面的jar移除,直接在项目目录下建立一个libs目录,然后把那个jar文件放进去就行了。AdMob SDK也更新到了4.3.1,网上搜索到的在XML文件里面设置AdView属性的方法也已过时,现在不需要建立attrs.xml文件,直接增加一个xmlns:ads="/apk/lib/com.google.ads"就可以在AdView标签里面设置ads开头的属性了,关于xml设置AdView属性的官方文档隐藏得比较深,没有在目录中列出来,只能在其他文档里面的链接里进去,在。另外,按照官方说明,要在AndroidManifest.xml里面添加一个Activity的声明:&&& &activity android:name="com.google.ads.AdActivity"&&&&&&&&&&&&& android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/&后面那个属性android:configChanges的最后两个值screenSize|smallestScreenSize是在Android 3.2后面才增加的,这两个值必须填上去,否则运行的时候会报错。如果你使用的SDK是3.2以下的,识别不了这两个值,编译也不会报错。因此你的项目必须使用Android 3.2以上的SDK,也就是项目根目录下的project.properties文件里面的属性target的值必须是android-13以上,例如target=android-15但是可以在AndroidManifest.xml里面设置android:minSdkVersion和android:targetSdkVersion为比13低的值,这样就不需要***Android 3.2以上的手机或平板来运行这个程序,实际上AdMob支持Android 1.5以上的系统,只是开发需要更高版本的SDK而已。这次折腾让我真正体会到Android更新得实在太快了,连官方的文档都来不及更新,开发人员只能自己摸索总结,幸好有强大的搜索工具,只要你遇到的问题不是第一个,就会有人找到解决方案。
SWT里TableEditor的作用是可以在表格里面显示一些控件,例如列表、按钮等,有时候是根据表格的内容在控件上显示不同内容的,如果更新了表格内容,就要同时更新控件,但是表格内容可以通过Table控件的removeAll()来清除,而表格中的控件则无法用这个方法清除,你调用Table的removeAll()方法,往表格里填入新内容后,控件还是上次的控件,但是你一操作那些控件就会出异常,提示那些控件已经disposed。解决方法是显式地调用控件及TableEditor的dispose()方法,在你建立TableEditor的时候,把它的引用保存起来,把里面的控件的引用也保存起来,到整个表格需要的清除的时候,通过引用先把控件dispose掉,再把TableEditor也dispose掉,这样整个表格的内容就真正清除了。例如有一个表格名为table,里面的每一行都有3列,第一列是文本,第二列是Combo,第三列是Button,绘制表格的时候是这样的:TableItem&ti&=&new&TableItem(table,SWT.NONE);ti.setText(0,"some&string");te&=&new&TableEditor(table);Combo&combo&=&new&Combo(table,SWT.NONE);controls.add(combo);te.setEditor(combo,ti,1);Button&button&=&new&Button(table,SWT.NONE);controls.add(button);te.setEditor(button,ti,2);其中te和controls都是成员变量,te的类型是TableEditor,controls的类型是ArrayList&Control&。当整个table要清除内容时,可以这样://删除控件for(Control&control:controls){control.dispose();}//删除TableEditorte.dispose();//删除文本table.removeAll();
mars课程里关于Socket通信那一课说那些程序只能在真机上运行,模拟器模拟不了,实际上是可以的。Android模拟器是通过一个类似路由器的虚拟网络层与电脑相连,可以看作模拟器是处于“内网”当中,每个模拟器都有自己的虚拟路由器,而且虚拟路由器的地址总是10.0.2.1,在模拟器看来,电脑的地址是10.0.2.2,模拟器自己的地址是10.0.2.15,无论你启动多少个模拟器,对于模拟器来说都是这样的地址,模拟器之间不能直接通信。启动模拟器的时候,电脑会给模拟器分配两个端口,通过这两个端口,电脑就能操作模拟器。第一个启动的模拟器的端口是,第二个是,以此类推,最多可以同时启动32个模拟器。第一个端口(偶数端口)可以接受telnet连接,对模拟器进行设置,第二个端口(奇数端口)则接受adb连接,可以用来调试。第一个端口可以在模拟器窗口的标题栏看到,如下图所示:5554表示端口号,t表示模拟器名称。实际上,这些端口也是电脑***的端口,在电脑上通过netstat可以看到本机正在***这些端口,因此通过telnet localhost 5554就能连上第一台模拟器,连上之后通过help命令可以查看操作帮助。为了实现电脑和模拟器上的android程序进行socket通信,需要把程序开启的端口通过端口映射设置到电脑上,这跟家里的路由器端口映射概念是一样的。telnet到模拟器之后,通过redir add tcp:就能把模拟器上的1234端口映射到电脑上,第一个表示电脑端口,第二个表示模拟器程序要使用端口,这两个数字可以相同也可以不同,要映射udp端口就把tcp改为udp即可redir add udp:这样一来,当模拟器的程序打开1234端口时,在电脑上也打开了对应的端口,只要通过电脑连接127.0.0.1的对应端口,就连上了模拟器的程序端口,就可以通过电脑上的client向模拟器的server发送数据,不需要通过真机运行。如果要让第一个模拟器向第二个模拟器发送数据,也可以把第二个模拟器的端口映射到电脑上,然后在第一个模拟器程序中向10.0.2.2的对应端口发送数据即可。模拟器还有一个很有意思的功能,每个模拟器默认的***号码就是它的第一个端口号,例如开了两个模拟器,第一个拨打5556,第二个就会显示5554来电,还能接通,发短信也可以,这样就能模拟***和短信功能。详细的信息可以看Dev Guide的模拟器部分:
前天是情人节,虽然结婚好多年了,但是老婆一直都喜欢惊喜的浪漫,可惜我却是个木讷的呆子,做不出那些轰动的事情。那天下午马上就要下班回家了,突然在微博上看到有人谈到geek的情人节礼物,虽然我不是geek,但是最近在学Android,老婆的手机也是Android系统的,何不专门做个程序给她?想法可嘉,但是动起手来却不是那么回事。学了那么多天,真正派上用场的还没学到。时间只剩下不到一个小时了,我会的只是在屏幕上显示几个大字:XXX,我爱你!后来想想似乎太单调,如果能够加上点背景音乐可能好点,但是还没学会怎么使用,上网搜了一下,幸好很简单,用MediaPlayer就可以了,几条语句就能搞定。音乐文件怎么来呢?通过网络在线播放是最简单的,于是就到百度MP3搜了一下“情人节快乐”,我记得有一首歌里面一直在喊“情人节快乐”的,结果最后发现那首歌名字叫《没有情人的情人节》……算了,管它呢,有老婆就行了,没有情人照样过情人节,打开发现链接居然是百度的,以前百度不是说它只负责搜索,不负责存放吗,怎么现在的MP3都放在百度的服务器了?把链接复制下来,在模拟器上运行还是挺好的,因为它用的是电脑的宽带,呵呵。不过过了一会提示下载失败,把那个地址往浏览器一贴,果然打不开了,原来百度这种下载链接是有有效期的,只能让你试听一下,然后下载,不是长期有效的。这就麻烦了,到时候装在手机上没声音岂不是很糗?再搜索一下,还好,可以把MP3文件放在assets里面,发布程序的时候把它包含在apk里面就行了,不用联网了。现在可以在显示大字的同时播放《没有情人的情人节》了。看了一下效果,还是有点怪异,手机的状态栏和程序的标题跟黑色的背景,红色的大字似乎不太搭配,于是继续搜索全屏代码,哈哈,两句搞定,这样炫多了。不过一直看着那几个字没任何反应,似乎太单调了,于是就想让它们不断变色,或者动一下也好,但是无论怎么弄都搞不定,下班时间到了,要去接老婆了,就这样吧。之前都是在模拟器上运行,或者接个USB在手机上运行,还不知道怎么打包成apk呢,这下居然没搜索到,可能太简单了,大家都没说。于是在项目上点右键,果然看到导出apk的菜单,我选择了unsigned方式导出,在手机上居然***不了。再搜索一下,哦,原来是要导出成signed apk才能装的,但是我没有***,怎么signed呢?没想到ADT还可以生成***,一下就搞定了,这比Symbian那种签名简单多了,但是可能也是导致Android恶意软件泛滥的原因之一。去接老婆的时候通过蓝牙把apk发到她手机上,装上,运行,从她表情上看出,我的努力没有白费。不过最后还是发现了个严重的bug,那首歌还没放完,另外一个声音已经重新开始了,形成了“二重唱”的效果,而且程序退出之后还在唱,赶工造成的悲剧啊。下面是代码:public&class&LoveActivity&extends&Activity&{&&&&TextView&&&&&/**&Called&when&the&activity&is&first&created.&*/&&&&@Override&&&&public&void&onCreate(Bundle&savedInstanceState)&{&&&&&&&&super.onCreate(savedInstanceState);&&&&&&&&getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,&&&&&&&&&&&WindowManager.LayoutParams.FLAG_FULLSCREEN);&&&&&&&&&&requestWindowFeature(Window.FEATURE_NO_TITLE);&&&&&&&&&&setContentView(R.layout.main);&&&&&&&&&MediaPlayer&mp&=&new&MediaPlayer();&&&&&&&&try{&&&&&&&&&&&&AssetManager&assetManager&=&getAssets();&&&&&&&&&&&&AssetFileDescriptor&afd&=&assetManager.openFd("a.mp3");&&&&&&&&&&&&mp.setDataSource(afd.getFileDescriptor(),&afd.getStartOffset(),&afd.getLength());&&&&&&&&&&&&mp.prepare();&&&&&&&&&&&&mp.start();&&&&&&&&}&&&&&&&&catch&(Exception&e)&{&&&&&&&&&&&&e.printStackTrace();&&&&&&&&}&&&&}}main.xml:&?xml&version="1.0"&encoding="utf-8"?&&LinearLayout&xmlns:android="/apk/res/android"&&&&android:orientation="vertical"&&&&android:layout_width="fill_parent"&&&&android:layout_height="fill_parent"&&&&&&&&&&TextView&&&&&android:id="@+id/textView1"&&&&&android:text="@string/loveyou"&&&&&android:layout_width="match_parent"&&&&&android:layout_height="match_parent"&&&&&android:gravity="center"&&&&&android:textColor="#ff0000"&&&&android:textStyle="bold"&&&&android:textSize="50dip"&&&&/&&&&&&&&&/LinearLayout&strings.xml:&?xml&version="1.0"&encoding="utf-8"?&&resources&&&&&&string&name="hello"&Hello&World,&LoveActivity!&/string&&&&&&string&name="app_name"&Love&/string&&&&&&string&name="loveyou"&XXX\n我爱你&/string&&/resources&再把那首mp3放到assets里,改名为a.mp3即可。希望明年能做出个更好的。
昨天在调试一段Android程序的时候发现总是出现NullPointerException,是来自一句System.out.println(),但是把里面的内容分拆了几次都找不到哪里有null,最后发现居然是因为最终输出的字符串是null!一直以来,在JavaSE里,如果字符串本身是null,System.out.println()打印该字符串,会在终端输出“null”,而在Android里却是直接抛出NullPointerException,整个程序都会被终止。大家可以测试一下下面的语句在两种环境下的运行结果:1&String&s&=&null;2&System.out.println(s);
这是mars课程里面关于handler和线程的一个例子:package&mars.import&android.app.Aimport&android.os.Bimport&android.os.Hpublic&class&HandlerTest&extends&Activity&{&&&&Handler&handler&=&new&Handler();&&&&/**&Called&when&the&activity&is&first&created.&*/&&&&@Override&&&&public&void&onCreate(Bundle&savedInstanceState)&{&&&&&&&&super.onCreate(savedInstanceState);&&&&&&&&System.out.println("1");&&&&&&&&handler.post(r);&&&&&&&&System.out.println("2");&&&&&&&&setContentView(R.layout.main);&&&&&&&&System.out.println("activity----&"+Thread.currentThread().getId());&&&&&&&&System.out.println("activity&name---&"+Thread.currentThread().getName());&&&&}&&&&&&&&Runnable&r&=&new&Runnable()&{&&&&&&&&&&&&&&&&@Override&&&&&&&&public&void&run()&{&&&&&&&&&&&&//&TODO&Auto-generated&method&stub&&&&&&&&&&&&System.out.println("handler----&"+Thread.currentThread().getId());&&&&&&&&&&&&System.out.println("handlername----&"+Thread.currentThread().getName());&&&&&&&&&&&&try&{&&&&&&&&&&&&&&&&Thread.sleep(10000);&&&&&&&&&&&&}&catch&(InterruptedException&e)&{&&&&&&&&&&&&&&&&//&TODO&Auto-generated&catch&block&&&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&&&}&&&&&&&&&&&&System.out.println("3");&&&&&&&&}&&&&};}根据mars的解释,handler所在的线程跟Activity的线程是同一个线程,所以在handler.post(r);语句后,执行的是Runnable里面的run函数,这个函数没有在新开的线程中执行,只是简单地调用了run函数,所以这个app在模拟器运行时要过10秒才会显示界面,因为run函数里面睡眠了10秒,等它返回后才执行setContentView函数设置界面元素。根据实际运行结果,的确是过了10秒才能显示界面。但是奇怪的是System.out语句似乎没有受到影响,下面是日志:log02-09 11:12:43.553: INFO/System.out(591): 102-09 11:12:43.553: INFO/System.out(591): 202-09 11:12:43.674: INFO/System.out(591): activity----&102-09 11:12:43.674: INFO/System.out(591): activity name---&main02-09 11:12:43.713: INFO/System.out(591): handler----&102-09 11:12:43.713: INFO/System.out(591): handlername----&main02-09 11:12:53.775: INFO/System.out(591): 3从日志可以看出,除了run函数里面睡眠后才执行的打印函数推迟了10秒才执行之外,其他都是没有受到任何延时,顺序执行的,在handler.post(r);语句前后的打印函数都被按顺序执行了,唯独setContentView(R.layout.main);需要在run函数返回后才执行,这是什么道理?难道打印函数的优先级更高,不会堵塞?如果是这样的话为什么在run函数里面还是要等睡眠结束才执行呢?
很想搞点Android的小程序玩玩,但是却万事开头难,不知道从哪里开始,看了官方的文档,结果一天都看不了几段,还是英文的,比较痛苦。找了些电子书,也是看过目录就不知道放哪里了。这种编程的入门没有强大的决心真的很难静下心来学习。前几天又心血来潮,搜索了一下android开发的网站,发现了一些视频,看起来还挺有意思,连续看了几个,慢慢地也摸着一点门路了,以前没有试过用这种方法学习,都是看书,现在发现看视频似乎更高效,起码眼睛没那么累,有人在念,很多时候只要用耳朵听就行了,而且所有软件的界面、步骤都很清楚,这些东西通过书是没法表现出来的。现在学会了让一个Activity显示出来,放上点控件,处理一下点击,页面布局等,算是入门了,但很多东西还要继续看,那些视频还有好多。入门系列视频地址:http://www.marsdroid.org/还有一个深入浅出系列:/thread--1.html由于没有入门,所以还在看第一个系列,第二个系列只看了两个。到现在发现android界面的构建很像web界面,android是通过layout来排布控件,而web是通过css,android可以通过java来操纵控件,而web则是通过javascript操纵控件,回调函数则跟JavaSE一样。不过有时候很容易忘记了一个步骤导致程序运行出错,一般来说,要让一个Activity成功运行,需要做以下步骤:1、有一个继承与Activity的类2、有一个layout文件,里面是各种控件的布局,在Activity里面应该用setContentView加载这个layout3、有一个strings文件,里面是界面的各种字符串,用于国际化4、在AndroidManifest里面加入这个Activity第4步很容易忘记。
前段时间听了一家公司介绍分布式存储产品,号称性能超过传统的磁盘阵列+小型机,但价格却比这种组合低,而且具有维护简单、数据安全等优点,其核心就是把一些PC服务器通过网络连接起来,把数据分散存储在这些服务器上,查找的时候把任务分配到这些服务器上,让它们分别完成各自的小任务,最后再汇合出结果,核心就是:每个节点都是一个数据存储单元和运算单元的结合,这些节点性能要求不高,可以是各种各样的配置,只要在上面运行集群要求的软件即可,一台挂了不要紧,换上去一台就能自动恢复,增加一台就能提高性能,减少一台也不会有很大影响,只是性能稍微下降,每份数据都有多个备份,能够平衡分布在各服务器上。这种架构的缺点是,只要用上了这套东西,所有的软件就必须从这家公司购买,因为整个集群的控制和访问接口都是他们提供的。该公司也坦言这其实就是google的服务器应用技术,实际上就是google提出来的云计算。今天看了一些文章介绍,发现上面介绍的东西实际上已经通过Apache的一个项目Hadoop实现,不知道那家公司是不是就是简单包装了一下这个项目。Hadoop包含两个主要的模块,分别是HDFS分布式文件系统和MapReduce集群计算机制。刚刚发布了1.0.0版本。主页: blogjava有位高手已经翻译了HDFS的架构说明:,但对应的是上一个版本0.20的,里面说到了很多没有实现的东西,不知道是否已经在1.0版本实现,目前官方网站上该文章的版本还是0.20的。这里有三篇文章介绍Hadoop在单机环境、多机环境下的***和配置,还有应用程序的开发:看起来还是挺有意思的,以前就曾经有过想法,把单位淘汰下来的那一大堆台式电脑组成一个存储或者计算的小集群,也许能够代替一两台PC服务器,现在看来可以试试,以后的趋势就是云计算了,先自己搞点小云看看效果如何。
这个不仅仅是IE6的错,而是所有IE的错!!
IE有一个特别随意的功能,就是能够通过Element的name来操作一个Element,有些人觉得这个功能很方便,实际它不仅不符合标准,还会导致IE自己变得莫名其妙。
假如你的Form有一个提交按钮的name="submit",那么,很遗憾,你这个form无论如何都不能通过Javascript来提交,只要你一调用了这个form的submit()方法,IE就会告诉你它不支持这个方法!这不是搞笑吗?哪个浏览器会不支持form的submit()方法?虽然IE不标准,也不至于这样吧?对不起,就是这样。
因为当你调用form的方法submit(),它首先想到的是你的提交按钮!
theForm.submit()
这个语句在IE看来并不是调用theForm的submit方法,而是调用了名字为submit的提交按钮!如果你在某个元素对象后面加个括号,会有什么效果?当然就是出错。在IE的独特视角下,上面这个语句与下面这个语句的效果一样:
(theForm.submit)();
前一个括号代表了名称为submit的按钮对象,后面那个括号就无法理解了,所以IE告诉你不支持这个方法。
IE整个家族都是如此的丑陋!
一直都看到很多人说,IE6是Web开发人员的恶梦,以前我单位的内部网络,所有电脑装的都是IE6,我只针对IE6开发,似乎没什么感觉,反正在我的电脑上看到什么样的,其他电脑上看到也是一样的。
后来因为某公司给我们做的一个系统运行速度实在太慢,我把自己的电脑更新到IE8,发现速度快了很多,但是有些东西不兼容,我对那些不兼容的功能使用得比较少,就不管了。
终于,我自己又要开发一个小项目,用了一个网上下载的CSS模板,发现里面很多针对IE的注释,从IE 5到IE 8都有,反正我电脑上看着效果不错,于是就用了。
辛苦了好几天,我那项目基本完工了,想在IE6上看看效果,Shit,本来显示在页面右方主要区域的表格掉在了左边导航栏的下面,表格里面一些DIV的下划线莫名其妙地不见了,这些东西在我的电脑上显示得好好的,也没用到什么特别的东西,怎么差别会这么大呢?
一个个问题排查:
表格问题,在IE6上表现得有些诡异,显示完之后表格是在下面的,但是鼠标晃过导航栏里面的链接,表格又会自动跳到右方区域,真见鬼。改了一下布局的padding,一个表格好了。另外一个却还是掉下去,仔细研究了一下,把表格的宽度减少10px,好了。
下划线问题,我用的是:
border-bottom:1px&solid&grey
结果IE6不会显示出这条下划线。搜索一下才知道这是IE6的bug,它理解不了这么长的句子!必须写成这样:
border-bottom-width:1
border-bottom-style:
border-bottom-color:
还有比这更傻逼的吗?有!
它显示出的线是黑色的,不是grey的!而且根据DIV里面内容的颜色不同,它还会变色!如果里面是红色的字,那么它下面的线也是红色,如果是绿色的字,下面的线也是绿色,如果没有指定颜色,它就是黑色,非常智能,但就是不显示你要的颜色!
后来知道原来它根本不知道grey的意思,必须指定颜色代码才能解决。
这就是IE6,没想到微软这么大一个公司还出了这么一个垃圾,而且出了那么多年,至今还占据中国浏览器市场的半壁江山!
有一台WIN2003的服务器,在单位的局域网内,与互联网是物理隔离的,最近上面运行的一个WEB服务器经常出错,查看日志发现是因为数据库不能连接,因为系统的所有端口都已经被占用完。使用netstat -abn查看发现svchost.exe开启了大量状态为SYN_SENT的连接,目标端口都是445,但是连接的IP各种各样的都有,由于机器不能建立Internet连接,所以状态都是SYN_SENT,重启一下这些连接都没有了,但是过一会又会迅速建立起来,很快就把系统的所有端口都占用了。
根据端口找出哪个服务真不容易,通过netstat -abn只能查到是svchost.exe,最多还能得到一个PID,确定是哪个svchost.exe,然后通过tasklist /svc可以查到那个svchost对应了哪些服务,但是一看,很多服务都是使用那个svchost,包括Server,Workstation等等,根本不知道是哪个产生的连接。
找了半天发现有人和我一样:,讨论了半天最后也找到了解决方法:,原来是W32.Downadup这个病毒惹的祸,下载了专杀工具回来查了一下,果然找到了两个被感染的文件,一个是jpg文件,在IE的缓存里,一个是dll文件,在system32里。
根据dll文件名在注册表里查到了它注册的服务,原来又是之前处理过的那种,服务名随机、服务描述为空、启动类型为自动、状态为未启动、dll名随机,但是我记得这台服务器已经打过补丁,也没有出现svchost错误,所以就忽略了服务的检查,没想到这种东西还有不同的症状。
这个病毒利用的是KB958644的漏洞,到微软下载了补丁回来,一看才发现原来那台服务器以前已经装过这个补丁。补丁的作用也许就是只能防止再出问题,但不能解决已有的问题,所以那台服务器虽然装了补丁,但是可能已经被感染了,于是就没治好。
把APE、FLAC等无损压缩音频文件刻录成CD的软件有很多,搜索一把,出现频率最多的是用NERO+插件,但是现在的NERO体积实在庞大,我尝试下载一个NERO 10,大小不过200多M,结果***的时候解压到临时文件夹,我的C盘1G多的空间都不够它解压,根本就***不了,为了这么一点事情用这么大一个软件实在没必要,仔细搜索一下,刻录的软件其实有很多,都能自动地把APE刻录到CD上,方法远比NERO简单。
第一个软件是。
Burrrn是个专门干这事的软件,它支持的文件包括ape、flac、mp3、ogg等,实际上也是通过插件来完成编码解码工作的,不过这些插件都是内置在程序包里,不用再逐个下载。它的界面非常简单,使用也非常简单,基本一打开就会使用。
第二个软件是。
这个软件比较强大,不但能够刻录APE,还可以把光盘提取成镜像、把文件或文件夹生成镜像、把文件或文件夹刻录到光盘上、把镜像刻录到光盘上,基本上NERO常用的功能都有了,软件只有几MB,十分环保。我下载这个软件的时候只是想使用它的生成镜像功能,因为下载下来一些蓝光原盘需要制作成ISO文件才能用POWERDVD播放。后来发现有人说这个软件还可以刻录APE,不过也需要使用相关的解码器,只是这些解码器在***常用的播放器的时候一般都已经***过了,例如我以前装过终极解码,其中包含APE解码器,就不需要另外***了。
使用的时候只需要选择刻录镜像到光盘功能,选中与APE相关的cue文件,然后就可以分轨刻录了。
这两个软件的体积都很小,而且都是免费软件,不但环保还合法。
第一次使用Burrrn刻录APE的时候,用KMPlayer播放,发现直接播放APE的效果跟播放刻录出来的CD效果不一样,CD的效果动态范围明显不如直接播放APE,我以为是刻录软件的问题,后来使用ImgBurn刻录,也是一样的效果。仔细对比之后发现KMP播放的时候是使用不同的滤镜,可能是这个原因导致效果不同,但是播放APE和播放CD又不可能使用相同的滤镜,所以到底是什么原因也很难说得清楚,不过CD机上不认APE,也只能这样了。
1、服务命名。Oracle的服务命名就跟计算机的名称一样。一般来说,在局域网里面,计算机名称是与IP一一对应的,通信的时候需要使用IP,所以就有了DNS,把计算机名翻译成IP。同样的道理,在Oracle体系里,服务命名对应计算机名,服务名(SID)+IP+端口+协议(TCP/IP)就对应了计算机的IP,Oracle体系里的DNS其实就是一个配置文件,把服务命名翻译成可以用于通信的服务名(SID)+IP+端口+协议(TCP/IP)。有趣的是,与计算机里的ping命令一样,Oracle里面也有个TNSPing命令,通过“TNSPing 服务命名”,就会得到像ping命令相似的结果,验证该命名对应的数据库是否有效。
2、主机身份验证。Oracle的一些维护工作往往需要输入主机身份验证信息,但是默认情况下,即使输入了正确的用户名和密码,系统也会提示“用户口令错误”,让人十分困惑。其实真实的原因是,你输入的用户必须在“作为批处理作业登录”里面,否则就会出现上述错误。操作方法如下:运行-gpedit.msc-计算机配置-Windows设置-安全设置-本地策略-用户权利指派-作为批处理作业登录-添加用户或组...-加入要登录的用户。
执行数据库迁移操作的时候,可能需要在源数据库主机和目标数据库主机都进行上述操作才能成功。
更多问题待续
9月10号,CHDBits开放了注册权限,赶紧注册了一个帐户,这是我第一次登录PT站。每个文件都有几个甚至几十个种子在等待下载者,真是“僧多粥少”。下载速度果然很猛,下了几个文件,基本上可以达到ADSL的上限,甚至遇到了前所未有的极速,不过持续时间较短,但是平均速度都接近上限。
然而,ADSL小水管终究不是玩PT的料,严格的分享率要求和ADSL龟速的上传带宽使得我两天之后就变成了冰人,如果20天之内再不提高分享率,我的帐户将会被封禁。仔细考虑了一下,我还是“过把瘾就死”算了,因为以我这8:1的上传和下载带宽,要长期达到要求基本上是不可能的事情,如果要我的分享率达到1:1,那我4M的下载带宽就等于缩水成和上传带宽一样,只有512K了,我装这4M的宽带还有什么意义?
其实在PT站外下载,速度也是不错的,无论是emule还是BT都能达到上限的80%以上,当然,是在种子刚刚放出的一段时间,只要热度一过,速度马上下降,这是与PT没法比的。
还是等到哪一天光纤到户再玩PT吧,现在的任务就是趁着20天没过,赶紧“过瘾”,嘿嘿!
VISTA和WIN7都有一种OEM激活法,该激活方式需要以下三个条件:
1、BIOS中有相应厂商的SLIC,VISTA要求SLIC 2.0,WIN7则要求SLIC 2.1。一般来说,品牌机的BIOS里面本来都带有SLIC,不过有的没打开(例如DELL的OPTIPLEX系列),需要用一些小工具打开(例如Asset);有的版本是2.0的,只能用来激活VISTA,如果要激活WIN7,需要更新SLIC,但更新官方的BIOS并不会更新SLIC,因此还需要找到专门的修改过的BIOS文件来更新。
2、***的VISTA或者WIN7导入了相应的OEM厂商的***,如果***的系统是OEM版的,***完之后***就在里面了;如果***的是普通版本的,还需要手动导入,命令为:
slmgr.vbs -ilc &***路径&
一般每个厂商都只有一个***,而且VISTA和WIN7的***是相同的,也就是说相同的***可同时用于VISTA或者WIN7。
3、所***的VISTA或WIN7的key,与***不同,key是每个版本的Windows一个,HomeBasic,HomePremium,Business,Ultimate等版本分别有各自的key,VISTA和WIN7的key也是不同的。导入key的方式是运行以下命令:
slmgr.vbs -ipk&&key&
如果***的时候输入了相应的key就不用这一步了。
同时具备了上述条件的VISTA和WIN7就被激活了,这些条件不需要按顺序来准备,只要具备即可,也就是说系统***后再刷BIOS,或者系统***前刷BIOS都是可以的。
&关于BIOS的信息,可浏览:&
关于Windows的信息,可浏览:
jQuery UI里面只有一个DatePicker,只能选择日期,不能选择时间,有人做了一个可以选择时间的DateTimePicker,在这里()可以看到,把jquery.js,jquery-calendar.js,jquery-calendar.css下回来之后就可以用了。但是有几个Bug需要自己修改:1、当输入框里面的时间是0点时,控件显示不完整,这是因为有个函数有bug,如下所示:
Ensure numbers are not treated as octal.
trimNumber:
(value.charAt(
value.substring(
这一句,如果是0点的话,最终会出错,因为它的长度最后是1,不能执行substring(1),改成下面就好了:
Ensure numbers are not treated as octal.
trimNumber:
(value.charAt(
value.length
value.substring(
popUpCal.selectDate(); //$('.calendar_daysRow td a').hover( // highlight current day 2
$('.calendar_daysRow td').hover( // highlight current day 3
function() { 4
$(this).addClass('calendar_daysCellOver'); 5
}, function() { 6
$(this).removeClass('calendar_daysCellOver'); 7
//$('.calendar_daysRow td[a]').click(function() { // select day 9
$('.calendar_daysRow td a').click(function() { // select day popUpCal.selectDate();

参考资料

 

随机推荐