amp@java

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  99 随笔 :: 0 文章 :: 228 评论 :: 0 Trackbacks

#

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里面有个人对这个问题解释得比较清楚:
http://stackoverflow.com/questions/8768142/java-capturedevicemanagergetdevicelist-is-empty


虽然问题解决了,但是还是不明白为何在Eclipse中可以正常运行,导出jar后运行却找不到摄像头,即使把JMF所有jar和lib目录都加入系统的CLASSPATH环境变量里还是不行。


另外,JMF安装程序会自动把它的jar和lib目录加入系统的%CLASSPATH%环境变量,但是如果你卸载了再重新安装到其他目录,并不会改变%CLASSPATH%的值,需要手动修改。不过这个环境变量似乎没啥用处。
最好不要把JMF安装到默认的Program Files目录,可能会运行不了,安装到短目录会比较保险,它似乎还是只认Dos时代的8.3目录结构,但偏偏又默认安装到Program Files里面。
posted @ 2014-07-01 10:33 amp@java 阅读(7265) | 评论 (0)编辑 收藏

其实我也搞不懂Windows的域,反正能用就行了。
但是最近有一台客户端的时间改不了,总是提示特权级不够,按理说应该是组策略限制了,但是我把那台计算机从包含该组策略的OU中移出来,还是不行,这就奇怪了,难道组策略不是指针对OU里面的成员的吗?百思不得其解啊,最后只能在BIOS里面把时间改了。
今天发现我自己的电脑设置不了屏幕保护,也是组策略限制了,然后把我的用户和计算机都移出了组策略应用的OU,结果发现还是设置不了,这下肯定是组策略的应用上有问题了。
搜索了半天发现有个叫rsop.msc的管理工具,可以看到某用户在某计算机上应用的组策略,结果发现我还是应用之前的组策略,但是计算机配置和用户配置前面都有个红叉,右键-属性-错误信息里面显示:
Title
由于下面列出的错误,组策略结构 失败。

系统找不到指定的路径。

注意: 由于 GP Core 失败,其它组策略组件没有一个处理了它们的策略。因此,其它组件的状态信息不可用。
好像是有某个组策略找不到,所以不能应用的意思。
然后想起来在域名下面有个“新建组策略”,但是没有做过任何配置,应该是有人手贱点了一下新建按钮加进去的,于是把它删除,还是不行。
重启了一下客户端,居然好了,时间也可以改了,屏幕保护也可以改了,一切都按计划进行。


莫名其妙~~
posted @ 2014-06-23 16:11 amp@java 阅读(1334) | 评论 (0)编辑 收藏

现在的手机摄像头动辄几百万上千万像素,如果电脑需要用到摄像头又没有的话,不妨用手机的摄像头代替。

我是在做一个电脑二维码识别器的时候,因为原来的摄像头太差,从而想到用一台淘汰的Android手机来代替。

这类应用应该不少,我首先找到的是一个叫DraoidCam的应用,装好之后发现免费版没法调整分辨率,于是放弃之。

然后又找到了一个国内做的免费软件,叫魅色,非常简单,支持USB和WiFi连接方式,如果是USB连接的话,打开USB调试模式之后,运行电脑的客户端,手机上就自动装上了App并且自动运行,可以调整分辨率,不过最高只有640*480,帧率不到10,不过已经能够满足我的需求了。

然后就可以像普通PC摄像头一样使用了,在JMF里面也能找到,于是就可以被Java调用了。经测试,效果比原来的PC摄像头好多了。

软件主页:http://www.libfetion.org/meise/
posted @ 2014-06-05 15:35 amp@java 阅读(1711) | 评论 (4)编辑 收藏

     摘要: TabActivity在API 13(Android 3.2)被标记为过期,需要使用Fragment来实现,Fragment是Android 3.0引入的一个概念,主要就是为了适应各种不同的屏幕大小(手机、平板电脑)。Android 4.1发布时,google还发布了一个Android Support v4的包,用于Android 1.6以上的系统兼容新的特性,其中包括Fragment。为了在低于...  阅读全文
posted @ 2012-12-27 19:07 amp@java 阅读(15628) | 评论 (0)编辑 收藏

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 提供程序 'MSDAORA' 报错。

[OLE/DB provider returned message: 未找到 Oracle 客户端和网络组件。这些组件是由 Oracle 公司提供的,是 Oracle 8i (或更高) 客户软件安装的一部分。

 

在安装这些组件之前,将无法使用此提供程序。]

OLE DB 错误跟踪[OLE/DB Provider 'MSDAORA' IDBInitialize::Initialize returned 0x80004005:  


就要修改注册表,有人已经作出了详细的修改说明,在这里可以看到:
http://www.cnblogs.com/autumn/articles/splinkedserver.html

我把那个表也贴在这里:
Oracle Client  Microsoft Windows NT、
Oracle Microsoft Windows 95、
Client Windows 98 和 Windows 98 SE
Microsoft Windows 2000/XP/2003
7.x [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"
 
8.0 [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"
8.1 [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"
 
9.0 [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"
 
10.0 [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"
 
posted @ 2012-04-28 10:22 amp@java 阅读(2560) | 评论 (0)编辑 收藏

当读写二进制文件,或者要把非标准长度的整数与标准长度的整数互相转换时,就要用到大量的位操作,虽然看起来很简单,实际上里面却有很多细节很容易出错。

首先,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        0000 0000
1        0000 0001
.
.
126    0111 1110
127    0111 1111
-128   1000 0000
-127   1000 0001
.
.
-1       1111 1111
0         0000 0000

第三、不同长度的整数转换。
如果是从较短的数转成较长的数,很简单,如果是正数就在高字节补0,如果是负数就在高字节补1。
例如byte的127转为short的127:
byte:0111 1111
short:0000 0000 0111 0111
byte的-127转为short的-127
byte:1000 0001
short:1111 1111 1000 0001
如果是从较长的数转成较短的数,实际上就是把高位都截断了,所以转出来的数值可能完全不是一回事了。
例如short的256转为byte:
short:0000 0001 0000 0000
byte: 0000 0000
把256变成了0
short的-255转成byte:
short:1111 1111 0000 0001
byte:0000 0001
把-255变成了1

第四、位运算操作符及它们的优先级
Java的位运算操作符包括:~非,|按位或,&按位与,^按位异或,<<左移,>>右移,>>>右移左侧补0
各种运算符的优先级如下表所示:
优先级
运算符
结合性
1
() [] .
从左到右
2
! +(正) -(负) ~ ++ --
从右向左
3
* / %
从左向右
4
+(加) -(减)
从左向右
5
<< >> >>>
从左向右
6
< <= > >= instanceof
从左向右
7
== !=
从左向右
8
&(按位与)
从左向右
9
^
从左向右
10
|
从左向右
11
&&
从左向右
12
||
从左向右
13
?:
从右向左
14
= += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
从右向左
根据该表可以看到,位运算操作符的优先级各有不同,分别为:
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=1082163328,它的二进制表示为:
01000000 10000000 10000000 10000000
分为4个字节存储,除了第一个字节是正数外,其余3个字节均为负数。假如用a代表最高字节的值,用b代表其他三个字节的值,如果按照通常的理解,你可能会这样得到i的值:
i=(a<<24)+(b<<16)+(b<<8)+b

如果a和b都是正数,上面的等式是成立的,但是在这个例子里,却是错的,因为上式中的a和b都已经被强制转换成了int类型再参加运算,实际上
a=00000000 00000000 00000000 01000000
b=11111111 11111111 11111111 10000000
i=01000000 00000000 00000000 00000000+11111111 10000000 00000000 00000000+11111111 11111111 10000000 00000000+11111111 11111111 11111111 10000000
最后得到的结果是1065320320,不是原来的值了。
为了不让byte在强制转换成int的过程加入了我们不想要的高位1,我们需要把它跟0xff进行与操作,i的值应该这样运算:
= ( ( a& 0xff ) << 24 ) +( ( b & 0xff ) << 16 ) + ( ( b & 0xff ) << 8 ) + ( b & 0xff )

注意,因为&和<<的优先级都低于+,所以上面的括号是不能少的。不过由于跟0xff与操作之后,其余24位都变成了0,因此可以把+改为|操作,因为任何值与0进行或操作都得到本身:
= ( a & 0xff ) << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )

由于<<的优先级高于|,所以省了一些括号。最高字节可以不与0xff进行与操作,因为它转换成int后左边增加的3个字节都在左移24位时被去掉了:
= 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 xxxx
2:xxxx yyyy
3:yyyy yyyy
x和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位还是0
out[1|= (byte) ( b >> 8 & 0x0f );//b右移8位,并与0x0f进行与操作,实际上就只保留了b的高4位,并且是在字节的低4位上,跟第二步得到的字节进行或操作,就生成了第二个字节
out[2= (byte) b;//把b的高4位截断就得到了低8位
然后再把这个字节数组写入文件,就可以用3个字节表示两个整数了。
读取:
=(short)( (out[0& 0xff<< 4 | ( out[1& 0xf0 )>>4);
= (short)((out[1& 0x0f<< 8 | ( out[2& 0xff));
posted @ 2012-04-08 16:56 amp@java 阅读(1815) | 评论 (2)编辑 收藏

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="http://schemas.android.com/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更新得实在太快了,连官方的文档都来不及更新,开发人员只能自己摸索总结,幸好有强大的搜索工具,只要你遇到的问题不是第一个,就会有人找到解决方案。



posted @ 2012-03-25 19:23 amp@java 阅读(3687) | 评论 (7)编辑 收藏

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();
}
//删除TableEditor
te.dispose();
//删除文本
table.removeAll();
posted @ 2012-03-09 11:09 amp@java 阅读(3840) | 评论 (0)编辑 收藏

mars课程里关于Socket通信那一课说那些程序只能在真机上运行,模拟器模拟不了,实际上是可以的。
Android模拟器是通过一个类似路由器的虚拟网络层与电脑相连,可以看作模拟器是处于“内网”当中,每个模拟器都有自己的虚拟路由器,而且虚拟路由器的地址总是10.0.2.1,在模拟器看来,电脑的地址是10.0.2.2,模拟器自己的地址是10.0.2.15,无论你启动多少个模拟器,对于模拟器来说都是这样的地址,模拟器之间不能直接通信。
启动模拟器的时候,电脑会给模拟器分配两个端口,通过这两个端口,电脑就能操作模拟器。第一个启动的模拟器的端口是5554和5555,第二个是5556和5557,以此类推,最多可以同时启动32个模拟器。第一个端口(偶数端口)可以接受telnet连接,对模拟器进行设置,第二个端口(奇数端口)则接受adb连接,可以用来调试。第一个端口可以在模拟器窗口的标题栏看到,如下图所示:

5554表示端口号,t表示模拟器名称。
实际上,这些端口也是电脑监听的端口,在电脑上通过netstat可以看到本机正在监听这些端口,因此通过telnet localhost 5554就能连上第一台模拟器,连上之后通过help命令可以查看操作帮助。
为了实现电脑和模拟器上的android程序进行socket通信,需要把程序开启的端口通过端口映射设置到电脑上,这跟家里的路由器端口映射概念是一样的。telnet到模拟器之后,通过
redir add tcp:1234:1234
就能把模拟器上的1234端口映射到电脑上,第一个表示电脑端口,第二个表示模拟器程序要使用端口,这两个数字可以相同也可以不同,要映射udp端口就把tcp改为udp即可
redir add udp:1234:1234
这样一来,当模拟器的程序打开1234端口时,在电脑上也打开了对应的端口,只要通过电脑连接127.0.0.1的对应端口,就连上了模拟器的程序端口,就可以通过电脑上的client向模拟器的server发送数据,不需要通过真机运行。
如果要让第一个模拟器向第二个模拟器发送数据,也可以把第二个模拟器的端口映射到电脑上,然后在第一个模拟器程序中向10.0.2.2的对应端口发送数据即可。


模拟器还有一个很有意思的功能,每个模拟器默认的电话号码就是它的第一个端口号,例如开了两个模拟器,第一个拨打5556,第二个就会显示5554来电,还能接通,发短信也可以,这样就能模拟电话和短信功能。

详细的信息可以看Dev Guide的模拟器部分:http://developer.android.com/guide/developing/devices/emulator.html
posted @ 2012-02-24 10:37 amp@java 阅读(2406) | 评论 (0)编辑 收藏

前天是情人节,虽然结婚好多年了,但是老婆一直都喜欢惊喜的浪漫,可惜我却是个木讷的呆子,做不出那些轰动的事情。那天下午马上就要下班回家了,突然在微博上看到有人谈到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 text;
    
/** 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="http://schemas.android.com/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即可。




希望明年能做出个更好的。
posted @ 2012-02-16 11:06 amp@java 阅读(2280) | 评论 (2)编辑 收藏

仅列出标题
共10页: 上一页 1 2 3 4 5 6 7 8 9 下一页 Last