??xml version="1.0" encoding="utf-8" standalone="yes"?> add_months(d,n) 日期d加n个月 Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q- Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?br>SQL> select to_char(sysdate,'yyyy-mm-dd hh:mi:ss am') from dual; 在oracle中有很多关于日期的函敎ͼ? 1、add_months()用于从一个日期值增加或减少一些月?/p>
date_value:=add_months(date_value,number_of_months) ? SQL> select add_months(sysdate,12) "Next Year" from dual; Next Year ---------- 13-11?04 SQL> select add_months(sysdate,112) "Last Year" from dual; Last Year ---------- 13-3?-13 SQL> 2、current_date()q回当前?x)放时区中的当前日?/p>
date_value:=current_date SQL> column sessiontimezone for a15 SQL> select sessiontimezone,current_date from dual; SESSIONTIMEZONE CURRENT_DA --------------- ---------- +08:00 13-11?03 SQL> alter session set time_zone='-11:00' 2 / ?x)话已更攏V?/p>
SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP --------------- ------------------------------------ -11:00 12-11?03 04.59.13.668000 下午 -11: 00 SQL> 3、current_timestamp()以timestamp with time zone数据cdq回当前?x)放时区中的当前日?/p>
timestamp_with_time_zone_value:=current_timestamp([timestamp_precision]) SQL> column sessiontimezone for a15 SQL> column current_timestamp format a36 SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP --------------- ------------------------------------ +08:00 13-11?03 11.56.28.160000 上午 +08: 00 SQL> alter session set time_zone='-11:00' 2 / ?x)话已更攏V?/p>
SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP --------------- ------------------------------------ -11:00 12-11?03 04.58.00.243000 下午 -11: 00 SQL> 4、dbtimezone()q回时区 varchar_value:=dbtimezone SQL> select dbtimezone from dual; DBTIME ------ -07:00 SQL> 5、extract()扑և日期或间隔值的字段?/p>
date_value:=extract(date_field from [datetime_value|interval_value]) SQL> select extract(month from sysdate) "This Month" from dual; This Month ---------- 11 SQL> select extract(year from add_months(sysdate,36)) "3 Years Out" from dual; 3 Years Out ----------- 2006 SQL> 6、last_day()q回包含?jin)日期参数的月䆾的最后一天的日期 date_value:=last_day(date_value) SQL> select last_day(date'2000-02-01') "Leap Yr?" from dual; Leap Yr? ---------- 29-2?-00 SQL> select last_day(sysdate) "Last day of this month" from dual; Last day o ---------- 30-11?03 SQL> 7、localtimestamp()q回?x)话中的日期和时?/p>
timestamp_value:=localtimestamp SQL> column localtimestamp format a28 SQL> select localtimestamp from dual; LOCALTIMESTAMP ---------------------------- 13-11?03 12.09.15.433000 下午 SQL> select localtimestamp,current_timestamp from dual; LOCALTIMESTAMP CURRENT_TIMESTAMP ---------------------------- ------------------------------------ 13-11?03 12.09.31.006000 13-11?03 12.09.31.006000 下午 +08: 下午 00 SQL> alter session set time_zone='-11:00'; ?x)话已更攏V?/p>
SQL> select localtimestamp,to_char(sysdate,'DD-MM-YYYY HH:MI:SS AM') "SYSDATE" from dual; LOCALTIMESTAMP SYSDATE ---------------------------- ------------------------ 12-11?03 05.11.31.259000 13-11-2003 12:11:31 下午 下午 SQL> 8、months_between()判断两个日期之间的月份数?/p>
number_value:=months_between(date_value,date_value) SQL> select months_between(sysdate,date'1971-05-18') from dual; MONTHS_BETWEEN(SYSDATE,DATE'1971-05-18') ---------------------------------------- 389.855143 SQL> select months_between(sysdate,date'2001-01-01') from dual; MONTHS_BETWEEN(SYSDATE,DATE'2001-01-01') ---------------------------------------- 34.4035409 SQL> 9、next_day()l定一个日期|q回q二个参数指出的日子第一ơ出现在的日期?应返回相应日子的名称字符? 说明: 单行日期函数 单行日期函数操作data数据cdQ绝大多数都有data数据cd的参敎ͼl大多数q回的也是data数据cd的倹{?/p>
add_months(,) q回日期d加上i个月后的l果。i可以使Q意整数。如果i是一个小敎ͼ那么数据库将隐式的他转换成整敎ͼ会(x)截去数点后面的部分?/p>
last_day() 函数q回包含日期d的月份的最后一?/p>
months_between(,) q回d1和d2之间月的数目,如果d1和d2的日的日期都相同Q或者都使该月的最后一天,那么返回一个整敎ͼ否则?x)返回的l果包含一个分数?/p>
new_time(,,) d1是一个日期数据类型,当时区tz1中的日期和时间是dӞq回时区tz2中的日期和时间。tz1和tz2时字W串?/p>
next_day(,) q回日期d后由dowl出的条件的W一天,dow使用当前?x)话中给出的语言指定?jin)一周中的某一天,q回的时间分量与d的时间分量相同?/p>
select next_day(''01-jan-2000'',''monday'') "1st monday",next_day(''01-nov-2004'',''tuesday'')+7 "2nd tuesday") from dual;1st monday 2nd tuesday03-jan-2000 09-nov-2004 round([,]) 日期d按照fmt指定的格式舍入,fmt为字W串?/p>
syadate 函数没有参数Q返回当前日期和旉?/p>
trunc([,]) q回由fmt指定的单位的日期d. 单行转换函数 单行转换函数用于操作多数据类型,在数据类型之间进行{换?/p>
chartorwid() c 使一个字W串Q函数将c转换为rwid数据cd?/p>
select test_id from test_case where rowid=chartorwid(''aaaa0saacaaaaliaaa'') convert(,[,]) c֭W串Qdset、sset是两?a class=bluekey target=_blank>字符?/font>Q函数将字符串c由sset字符集{换ؓ(f)dset字符集,sset的缺省设|ؓ(f)数据库的字符集?/p>
hextoraw() x?6q制的字W串Q函数将16q制的x转换为raw数据cd?/p>
rawtohex() x是raw数据cd字符Ԍ函数raw数据c{换ؓ(f)16q制的数据类型?/p>
rowidtochar() 函数rowid数据cd转换为char数据cd?/p>
to_char([[,) x是一个data或number数据cdQ函数将x转换成fmt指定格式的char数据cdQ如果x为日期nlsparm=nls_date_language 控制q回的月份和日䆾所使用的语a。如果x为数字nlsparm=nls_numeric_characters 用来指定数位和千分位的分隔W,以及(qing)货币W号?/p>
nls_numeric_characters ="dg", nls_currency="string" to_date([,[,) c表示字符Ԍfmt表示一U特D格式的字符丌Ӏ返回按照fmt格式昄的c,nlsparm表示使用的语a。函数将字符串c转换成date数据cd?/p>
to_multi_byte() c表示一个字W串Q函数将c的担子截字符转换成多字节字符?/p>
to_number([,[,) c表示字符Ԍfmt表示一个特D格式的字符Ԍ函数q回值按照fmt指定的格式显C。nlsparm表示语言Q函数将q回c代表的数字?/p>
to_single_byte() 字W串c中得多字节字W{化成{h(hun)的单字节字符。该函数仅当数据库字W集同时包含单字节和多字节字W时才用。Oracle关于旉/日期的操?/p>
1.日期旉间隔操作 当前旉减去7分钟的时?/p>
select sysdate,sysdate - interval '7' MINUTE from dual 当前旉减去7时的时?/p>
select sysdate - interval '7' hour from dual 当前旉减去7天的旉 select sysdate - interval '7' day from dual 当前旉减去7月的旉 select sysdate,sysdate - interval '7' month from dual 当前旉减去7q的旉 select sysdate,sysdate - interval '7' year from dual 旉间隔乘(sh)一个数?/p>
select sysdate,sysdate - 8 *interval '2' hour from dual 2.日期到字W操?/p>
select sysdate,to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual select sysdate,to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual select sysdate,to_char(sysdate,'yyyy-ddd hh:mi:ss') from dual select sysdate,to_char(sysdate,'yyyy-mm iw-d hh:mi:ss') from dual 参考oracle的相兛_文档(ORACLE901DOC/SERVER.901/A90125/SQL_ELEMENTS4.HTM#48515) 3. 字符到日期操?/p>
select to_date('2003-10-17 21:15:37','yyyy-mm-dd hh24:mi:ss') from dual 具体用法和上面的to_char差不多?/p>
4. trunk/ ROUND函数的?/p>
select trunc(sysdate ,'YEAR') from dual select trunc(sysdate ) from dual select to_char(trunc(sysdate ,'YYYY'),'YYYY') from dual 5.oracle有毫U的数据类?/p>
--q回当前旉 q月日小时分U毫U?/p>
select to_char(current_timestamp(5),'DD-MON-YYYY HH24:MI:SSxFF') from dual; --q回当前 旉的秒毫秒Q可以指定秒后面的精?最?9) select to_char(current_timestamp(9),'MI:SSxFF') from dual; 6.计算E序q行的时?ms) declare type rc is ref cursor; l_rc rc; l_dummy all_objects.object_name%type; l_start number default dbms_utility.get_time; begin for I in 1 .. 1000 loop open l_rc for 'select object_name from all_objects '|| 'where object_id = ' || i; fetch l_rc into l_dummy; close l_rc; end loop; dbms_output.put_line ( round( (dbms_utility.get_time-l_start)/100, 2 ) || ' seconds...' ); end;
V_RETURN DATE;
V_ISSUE VARCHAR2(20) :=ISSUE;
V_DATE_TYPE VARCHAR2(20) := DATE_TYPE;
V_ISSUE_TYPE VARCHAR2(20) :=SUBSTR(ISSUE,1,1);
begin
IF V_DATE_TYPE = '0' THEN
CASE
WHEN V_ISSUE_TYPE = '1' Q-q?br> THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');
WHEN V_ISSUE_TYPE = '2' Q-?br> THEN SELECT DECODE( SUBSTR(V_ISSUE,6,2),
'01',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'),
'02',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0401','YYYY-MM-DD'),
'03',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0701','YYYY-MM-DD'),
'04',TO_DATE(SUBSTR(V_ISSUE,2,4)||'1001','YYYY-MM-DD'),TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'))
INTO V_RETURN
FROM DUAL;
WHEN V_ISSUE_TYPE = '3' Q-?br> THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD');
WHEN V_ISSUE_TYPE = '4' Q-?br> THEN SELECT AA INTO V_RETURN FROM (
SELECT aa ,ROWNUM BB
FROM (
SELECT (TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd') + ROWNUM - 1) aa ,rownum cc
FROM all_objects
WHERE ROWNUM < TO_DATE(TO_CHAR(last_day(TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd')),'YYYYMMDD'),'YYYY-MM-DD') - TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd') + 1) bb
WHERE MOD (TO_CHAR (aa, 'dd'), 10) = 1 and to_char(aa,'dd') <> 31 )
WHERE BB = TO_NUMBER(SUBSTR(V_ISSUE,8,2));
WHEN V_ISSUE_TYPE = '5' Q-?br> THEN SELECT MONDAY INTO V_RETURN FROM (
select
MONDAY.the_week,decode(sign(MONDAY.the_day-SUNDAY.the_day),-1,MONDAY.the_day,MONDAY.the_day-7) MONDAY,SUNDAY.the_day SUNDAY
from
(select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day
from (
select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm
from user_objects
where rownum < 366
)
where to_char(wwm,'D')=2 ) MONDAY,
(select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day
from (
select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm
from user_objects
where rownum < 366
)
where to_char(wwm,'D')=1 ) SUNDAY
where MONDAY.the_week=SUNDAY.the_week)
WHERE THE_WEEK = SUBSTR(V_ISSUE,6,2);
WHEN V_ISSUE_TYPE = '6' Q-?br> THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,8),'YYYY-MM-DD');
ELSE
V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');
END CASE;
ELSE
CASE
WHEN V_ISSUE_TYPE = '1'
THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'1231','YYYY-MM-DD');
WHEN V_ISSUE_TYPE = '2'
THEN SELECT DECODE( SUBSTR(V_ISSUE,6,2),
'01',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0331','YYYY-MM-DD'),
'02',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0630','YYYY-MM-DD'),
'03',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0930','YYYY-MM-DD'),
'04',TO_DATE(SUBSTR(V_ISSUE,2,4)||'1231','YYYY-MM-DD'),
TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'))
INTO V_RETURN
FROM DUAL;
WHEN V_ISSUE_TYPE = '3'
THEN V_RETURN := TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD');
WHEN V_ISSUE_TYPE = '4'
THEN SELECT DECODE( SUBSTR(V_ISSUE,8,2),
'01',TO_DATE(SUBSTR(V_ISSUE,2,6)||'10','YYYY-MM-DD'),
'02',TO_DATE(SUBSTR(V_ISSUE,2,6)||'20','YYYY-MM-DD'),
'03',TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD'),
TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD'))
INTO V_RETURN
FROM DUAL;
WHEN V_ISSUE_TYPE = '5'
THEN SELECT SUNDAY INTO V_RETURN FROM (
select
MONDAY.the_week,decode(sign(MONDAY.the_day-SUNDAY.the_day),-1,MONDAY.the_day,MONDAY.the_day-7) MONDAY,SUNDAY.the_day SUNDAY
from
(select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day
from (
select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm
from user_objects
where rownum < 366
)
where to_char(wwm,'D')=2 ) MONDAY,
(select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day
from (
select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm
from user_objects
where rownum < 366
)
where to_char(wwm,'D')=1 ) SUNDAY
where MONDAY.the_week=SUNDAY.the_week)
WHERE THE_WEEK = SUBSTR(V_ISSUE,6,2);
WHEN V_ISSUE_TYPE = '6'
THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,8),'YYYY-MM-DD');
ELSE
V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');
END CASE;
END IF;
return(V_RETURN);
end TF_ISSUE_DATE;
dd number 12
dy abbreviated fri
day spelled out friday
ddspth spelled out, ordinal twelfth
Month:
mm number 03
mon abbreviated mar
month spelled out march
Year:
yy two digits 98
yyyy four digits 1998
24时格式下时间范围ؓ(f)Q?0:00:00 - 23:59:59....
12时格式下时间范围ؓ(f)Q?1:00:00 - 12:59:59 ....
1.
日期和字W{换函数用法(to_date,to_charQ?
2.
select to_char( to_date(222,'J'),'Jsp') from dual
昄Two Hundred Twenty-Two
3.
求某天是星期?
select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual;
星期一
select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;
monday
讄日期语言
ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';
也可以这?
TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American')
4.
两个日期间的天数
select floor(sysdate - to_date('20020405','yyyymmdd')) from dual;
5. 旉为null的用?
select id, active_date from table1
UNION
select 1, TO_DATE(null) from dual;
注意要用TO_DATE(null)
6.
a_date between to_date('20011201','yyyymmdd') and to_date('20011231','yyyymmdd')
那么12?1号中?2点之后和12?L(fng)12点之前是不包含在q个范围之内的?
所以,当时间需要精的时候,觉得to_charq是必要?
7. 日期格式冲突问题
输入的格式要看你安装的ORACLE字符集的cd, 比如: US7ASCII, date格式的类型就? '01-Jan-01'
alter system set NLS_DATE_LANGUAGE = American
alter session set NLS_DATE_LANGUAGE = American
或者在to_date中写
select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;
注意我这只是举了(jin)NLS_DATE_LANGUAGEQ当然还有很多,
可查?
select * from nls_session_parameters
select * from V$NLS_PARAMETERS
8.
select count(*)
from ( select rownum-1 rnum
from all_objects
where rownum <= to_date('2002-02-28','yyyy-mm-dd') - to_date('2002-
02-01','yyyy-mm-dd')+1
)
where to_char( to_date('2002-02-01','yyyy-mm-dd')+rnum-1, 'D' )
not
in ( '1', '7' )
查找2002-02-28?002-02-01间除星期一和七的天?
在前后分别调用DBMS_UTILITY.GET_TIME, 让后结果相?得到的是1/100U? 而不是毫U?.
9.
select months_between(to_date('01-31-1999','MM-DD-YYYY'),
to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;
1
select months_between(to_date('02-01-1999','MM-DD-YYYY'),
to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;
1.03225806451613
10. Next_day的用?
Next_day(date, day)
Monday-Sunday, for format code DAY
Mon-Sun, for format code DY
1-7, for format code D
11
select to_char(sysdate,'hh:mi:ss') TIME from all_objects
注意Q第一条记录的TIME 与最后一行是一L(fng)
可以建立一个函数来处理q个问题
create or replace function sys_date return date is
begin
return sysdate;
end;
select to_char(sys_date,'hh:mi:ss') from all_objects;
12.
获得时?
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 2:38:40') from offer
SQL> select sysdate ,to_char(sysdate,'hh') from dual;
SYSDATE TO_CHAR(SYSDATE,'HH')
-------------------- ---------------------
2003-10-13 19:35:21 07
SQL> select sysdate ,to_char(sysdate,'hh24') from dual;
SYSDATE TO_CHAR(SYSDATE,'HH24')
-------------------- -----------------------
2003-10-13 19:35:21 19
获取q月日与此类?
13.
q月日的处理
select older_date,
newer_date,
years,
months,
abs(
trunc(
newer_date-
add_months( older_date,years*12+months )
)
) days
from ( select
trunc(months_between( newer_date, older_date )/12) YEARS,
mod(trunc(months_between( newer_date, older_date )),
12 ) MONTHS,
newer_date,
older_date
from ( select hiredate older_date,
add_months(hiredate,rownum)+rownum newer_date
from emp )
)
14.
处理月䆾天数不定的办?
select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual
16.
扑և今年的天?
select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual
闰年的处理方?
to_char( last_day( to_date('02' || :year,'mmyyyy') ), 'dd' )
如果?8׃是闰q?
17.
yyyy与rrrr的区?
'YYYY99 TO_C
------- ----
yyyy 99 0099
rrrr 99 1999
yyyy 01 0001
rrrr 01 2001
18.不同时区的处?
select to_char( NEW_TIME( sysdate, 'GMT','EST'), 'dd/mm/yyyy hh:mi:ss') ,sysdate
from dual;
19.
5U钟一个间?
Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) * 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS')
from dual
2002-11-1 9:55:00 35786
SSSSS表示5位秒?
20.
一q的W几?
select TO_CHAR(SYSDATE,'DDD'),sysdate from dual
310 2002-11-6 10:03:51
21.计算时,?U?毫秒
select
Days,
A,
TRUNC(A*24) Hours,
TRUNC(A*24*60 - 60*TRUNC(A*24)) Minutes,
TRUNC(A*24*60*60 - 60*TRUNC(A*24*60)) Seconds,
TRUNC(A*24*60*60*100 - 100*TRUNC(A*24*60*60)) mSeconds
from
(
select
trunc(sysdate) Days,
sysdate - trunc(sysdate) A
from dual
)
select * from tabname
order by decode(mode,'FIFO',1,-1)*to_char(rq,'yyyymmddhh24miss');
//
floor((date2-date1) /365) 作ؓ(f)q?
floor((date2-date1, 365) /30) 作ؓ(f)?
mod(mod(date2-date1, 365), 30)作ؓ(f)?
23.next_day函数
next_day(sysdate,6)是从当前开始下一个星期五。后面的数字是从星期日开始算赗?
1 2 3 4 5 6 7
?一 ?????br>
last_day(d) 包含d的月份的最后一天的日期
month_between(d,e) 日期d与e之间的月份数Qe先于d
new_time(d,a,b) a时区的日期和旉d在b时区的日期和旉
next_day(d,day) 比日期d晚,由day指定的周几的日期
sysdate 当前的系l日期和旉
greatest(d1,d2,...dn) l出的日期列表中最后的日期
least(d1,k2,...dn) l出的日期列表中最早的日期
to_char(d [,fmt]) 日期d按fmt指定的格式{变成字符?br>to_date(st [,fmt]) 字符串st按fmt指定的格式{成日期|若fmt忽略Qst要用~省格式
round(d [,fmt]) 日期d按fmt指定格式舍入到最q的日期
trunc(d [,fmt]) 日期d按fmt指定格式截断到最q的日期
格式代码 说明 举例或可取值的范围
Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
DD 该月某一?nbsp; 1Q?
DY 三个大写字母表示的周?nbsp;SUNQ?..SAT
DAY 完整的周几,大写英文 SUNDAYQ?..SATURDAY
MM 月䆾 1Q?2
MON 三个大写字母表示的月?nbsp;JANQ?..DEC
MONTH 完整 JANUARY,...DECEMBER
RM 月䆾的罗马数?nbsp; I,...XII
YY或YYYY 两位Q四位数字年
HH:MI:SS Ӟ(x)分:(x)U?br>HH12或HH24 ?2时?4时昄
MI ?br>SS U?br>AM或PM 上下午指C符
SP 后缀SP要求拼写ZQ何数值字D?br>TH 后缀TH表示d的数字是序数 4th,1st
FM 前缀Ҏ(gu)或日或年|止填充
昨天在网上闲逛,发现一讲解用delphi实现华容道游戏的文章Q颇受启发.于是Q生了(jin)华定w游戏UL到手Zȝ冲动Q现在手机游戏琳琅满目,不一而Q华定w的实现版本也很多Q正巧不久前W者对J2ME下了(jin)一番功夫,正想借这个机?x)小试牛刀。选用J2ME的原因还有一个就是目前Java开发大行其刎ͼ无线增殖业务q猛发展QJ2ME的应用日渐活跃v来,也希望我的这文章能够ؓ(f)J2ME知识的普?qing)和开发团队的壮大推L助澜。由于长期受ISO规范的媄(jing)响,q次试牛刀我也打算늅软g工程的要求,q取瀑布式的开发模式来规划目Q也希望借此Z(x)向各位没有机?x)参与正式项目开发的读者介l一下Y件开发的程?/p>
q里我们先定义项目组的h员(sh)?其实只有我一个h)Q技术调研、需求分析、概要设计、详l设计、编码、测试均有笔者一人担任;工q里我找?jin)个捷径Q盗用网上现成的囄Q然后用ACDSee把它由BMP转换成PNG格式(我出于讲座的目的Q未做商业应用,应该不算侉|?Q至于发布工作,׃~少OTA服务器,此项工作不做(但是我会(x)介绍q步如何??/p>
接下来,我们规划一下项目实现的旉表,以我个hl验Q设惛_下:(x)技术调研用2?q部分解决项目的可行性和重大技术问题,旉?x)长一?Q需求分析用半天(毕竟有现成的东东可以参照Q只要理清思\p?jin),况且q有很多以前用过的设计模式和写好的代?Q概要设计再用半?有了(jin)需求,概要只不够是照方抓药)Q详l设计要??q一步要把所有的问题x(chng)楚,q要可能的准确描述出来)Q编码用2?其实1天就够了(jin)Q技术已l不是问题,多计划出一天来应付H发事g)Q测试用2?试应该臛_占全部项目的四分之一Q不q这个项目只是一个DemoQ也太简单了(jin))Q发布也要用上半?管我们不去实际发布它,但是q要q旉搞清楚应该如何做)Q最后就是项目ȝ和开?jin)功?旉待定)?/p>
二、利其器
“公Ʋ善其事Q必先利其器”,做项目之前第一步是前期调研Q我们要做的华容道这个东东随处可见,我们要调研的是两个方面:(x)
1. 游戏的内容:(x)游戏本n很简单,是有几个格子,Ҏ(gu)占据其中一个较大的格子Q然后被几个格子包围Q这些格子Ş状不一定相同,但是挡住?jin)曹操移动的方向Q游戏者需要挪动这些格子最l把Ҏ(gu)UdC个指定的位置才算是过养I更具体的分析我们攑֜后面需求分析和概要设计中讨论?/p>
2. 技术储备:(x)谈到技术,q里单介l一下J2ME.Java有三个版本,分别是J2MEQ微型版Q?J2SEQ标准版Q?J2EEQ企业版Q.J2ME是一个标准,采用Q层l构设计Q最低层是配|层QConfigurationQ也是讑֤层,其上是简表层QProfileQ?再上是应用层QApplicationQ?MIDP是Ud信息讑֤表,目前L手机支持MIDP1.0Q最新的是MIDP2.0,它比前一个版本增加了(jin)Ҏ(gu)戏的支持Q在javax.microedition.lcdui.game包中提供?jin)一些类来处理游戏中的技术,比如我们后面?x)用到的Spritec,它是用来{囄?权衡再三Q笔者决定用MIDP2.0来做开发.首先需要安装一个J2ME的模拟器Q我们就用Sun公司的WTK2.0Q我觉得Sun的东西最权威Q当然你也可以用Nokia.Siemens或是Motolora{其他模拟器Q但是他们的JDK不尽相同Q写出来的程序移植是比较ȝ(ch)的.
Sun公司的WTK2.0可以到搜索引擎寻找下载,当然要想成功下蝲的前提是你要先注册成为Sun的会(x)员(其实q样对你是有好处的)(j)Q当下来之后是按照提示一步一步的安装Q安装好?jin)之后,我们用一?Hello World"E序开始你的J2ME之旅Q我们启动WTK2.0工具集中的KToolBarQ然后点击New Project按钮Q在弹出的输入框中输入Project Name为HelloWorld,MIDlet Class Name为Hello,然后点击Create ProjectQ开始生成项目,工具?x)弹出MIDP配置表,q里接受生成的默认|以后q可以修改)(j)点击OKQ工hC我们把写好的Java源程序放到[WTK_HOME]\apps\HelloWorld\src目录之下Q我们编辑如下代码,q保存在上述目录之下Q文件名为Hello.java?/p>
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class Hello extends MIDlet
{
private Display display;
public Hello(){
display =Display.getDisplay(this);
}
public void startApp(){
TextBox t = new TextBox("Hello","Hello",256,0);
display.setCurrent(t);
}
public void pauseApp(){
}
public void destroyApp(boolean unconditional){
}
}
(tng)
(tng)
保存好了(jin)之后Q点击Build按钮Q工具会(x)Z~译E序Q如无意外再点击Run按钮Q会(x)弹出一个手机界面,剩下的就不用我教?jin)吧Q用鼠标Ҏ(gu)机按键一狂点)(j)。呵呵,你的W一个J2MEE序已经OK?什么?你还?sh)炚w没懂呢(真是厉害Q不懂都能写出J2MEE序来,果然是高手)(j)Q我q里主要是介lWTK2.0工具的用,E序q不是目的,不懂的话后面q(sh)(x)有详l的解说Q这里只是带你上路.什么?你不懂JavaQ那也没有关p,后面我再讲得l一炏V?
跌J2MEQ我们先来讲Ҏ(gu)戏的理论Q具体到华容道这个游戏,主要有三个方面,贴图Q游戏操作.逻辑判断Q这里讲讲脓(chung)图,其他两方面放在概要设计和详细设计里讲Q所谓的贴图Q其实就是画图,是在要昄囑Ş的位|上输出一副图片,Q要是牵扯到动画pȝ(ch)一些,可以使用TimerTask.Thread或Rannable之类的技?Q这副图片可以是事先准备好的也可以是临时处理的.在J2ME中有一个Imagec?专门用于理囄Q它有createImage()Ҏ(gu)Q可以直接读取图片文ӞJ2ME只支持PNG格式的图片)(j)Q也可以截取已有的图片的一部分Q这h们可以把很多囄攑֜一P然后一张一张的截下来,好处是节省存储空间和文gd旉Q对于手两者都是性能的瓶颈)(j)Q?
J2MEq有一个Graphicsc,专门用于l图Q它有drawImage()Ҏ(gu)Q可以把一副图片在指定的位|上昄出来Q它q有drawRect()Ҏ(gu)和setColor()Ҏ(gu)Q这两个Ҏ(gu)在后面我们进行游戏操作时׃(x)用到Q这里先交代一下.有了(jin)囄和绘囄Ҏ(gu)Q还需要知道把囄到谁?li)w上QJ2ME提供?jin)一个Canvasc,字面意思就是画布,它有一个paint()Ҏ(gu)用于h面Q还有一个repaint()Ҏ(gu)用于调用paint()Ҏ(gu)Q听着有些p涂是吧Q不要紧Q我来结合具体程序讲解一下.Z(jin)今后~程的方便,我们创徏两个cImages和Draw,Images用于保存?sh)些常量值和囄QDraw主要是用于画图,q两个类的源代码如下?
Imagescȝ源代码如下:(x)
package huarongroad;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
public class Images {//保存帔R
//l图位置帔R
public static final int UNIT = 32;//方块的单位长?
public static final int LEFT = 10;//d的左边界点
public static final int TOP = 9;//d的上边界点
//地图位置帔R
public static final int WIDTH = 4;//地图的宽?
public static final int HEIGHT = 5;//地图的高?
//地图标记帔R
public static final byte CAOCAO = (byte) ′a? QA href="file://?Qfile://曹</AQ操的地图标?
public static final byte MACHAO = (byte) ′b?//马超的地图标?
public static final byte HUANGZHONG = (byte) ′c?//黄忠的地图标?
public static final byte GUANYU = (byte) ′d?//关羽的地图标?
public static final byte ZHANGFEI = (byte) ′e?//张飞的地图标?
public static final byte ZHAOYUN = (byte) ′f?//赵云的地图标?
public static final byte ZU = (byte) ′g?//卒的地图标记
public static final byte BLANK = (byte) ′h?//I白的地图标?
public static final byte CURSOR = (byte) ′i?//光标的地图标?
//地图l合标记帔R
public static final byte DLEFT = (byte) ?? QA href="file://l?Qfile://l</AQ合囑Ş左边标记
public static final byte DUP = (byte) ?? QA href="file://l?Qfile://l</AQ合囑Ş上边标记
public static final byte DLEFTUP = (byte) ?? QA href="file://l?Qfile://l</AQ合囑Ş左上标记
//囄帔R
public static Image image_base;//基本囄
public static Image image_Zhaoyun;//赵云的图?
public static Image image_Caocao;//Ҏ(gu)的图?
public static Image image_Huangzhong;//黄忠的图?
public static Image image_Machao;//马超的图?
public static Image image_Guanyu;//关羽的图?
public static Image image_Zhangfei;//张飞的图?
public static Image image_Zu;//卒的囄
public static Image image_Blank;//I白的图?
public static Image image_Frame;//游戏框架的图?
public Images() {//构造函?
}
public static boolean init() {//初始化游戏中用到的图?
try {
image_base = Image.createImage("/huarongroad/BITBACK.png");
image_Frame = Image.createImage(image_base, 126, 0, 145, 177,
Sprite.TRANS_NONE);
//SpritecL用来{囄的,是MIDP2.0新新增加的支持游戏的Ҏ(gu)?
image_Zhaoyun = Image.createImage(image_base, 0, 0, UNIT, 2 * UNIT,
Sprite.TRANS_NONE);
image_Caocao = Image.createImage(image_base, UNIT, 0, 2 * UNIT,
2 * UNIT, Sprite.TRANS_NONE);
image_Huangzhong = Image.createImage(image_base, 3 * UNIT, 0, UNIT,
2 * UNIT,
Sprite.TRANS_NONE);
image_Machao = Image.createImage(image_base, 0, 2 * UNIT, UNIT,
2 * UNIT,
Sprite.TRANS_NONE);
image_Guanyu = Image.createImage(image_base, UNIT, 2 * UNIT,
2 * UNIT, UNIT,
Sprite.TRANS_NONE);
image_Zhangfei = Image.createImage(image_base, 3 * UNIT, 2 * UNIT,
UNIT, 2 * UNIT,
Sprite.TRANS_NONE);
image_Zu = Image.createImage(image_base, 0, 4 * UNIT, UNIT, UNIT,
Sprite.TRANS_NONE);
image_Blank = Image.createImage(image_base, 1 * UNIT, 4 * UNIT,UNIT,
UNIT,
Sprite.TRANS_NONE);
return true;
}catch (Exception ex) {
return false;
}
}
}
(tng)
(tng)
Drawcȝ源代码如下:(x)
package huarongroad;
import javax.microedition.lcdui.*;
public class Draw {
//l制游戏中的囄
public Draw(Canvas canvas) {//构造函?
}
public static boolean paint(Graphics g, byte img, int x, int y) {
//在地囄x,y点绘制img指定的图?
try {
paint(g, img, x, y, Images.UNIT);//把地图x,y点{化成d的绝对坐标,l图
return true;
}
catch (Exception ex) {
return false;
}
}
public static boolean paint(Graphics g, byte img, int x, int y, int unit) {
try {
switch (img) {
case Images.CAOCAO://L?
//变成l对坐标Qƈ做调?
g.drawImage(Images.image_Caocao, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.GUANYU://d?
g.drawImage(Images.image_Guanyu, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.HUANGZHONG://画黄?
g.drawImage(Images.image_Huangzhong, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.MACHAO://画马?
g.drawImage(Images.image_Machao, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.ZHANGFEI://d?
g.drawImage(Images.image_Zhangfei, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.ZHAOYUN://画n?
g.drawImage(Images.image_Zhaoyun, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.ZU://d
g.drawImage(Images.image_Zu, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.BLANK://ȝ?
g.drawImage(Images.image_Blank, Images.LEFT + x * unit,
Images.TOP + y * unit,
Graphics.TOP | Graphics.LEFT);
break;
case Images.CURSOR://d?
g.drawRect(Images.LEFT + x * unit,
Images.TOP + y * unit,Images.UNIT,Images.UNIT);
break;
}
return true;
}catch (Exception ex) {
return false;
}
}
}
(tng)
(tng)
其中Imagescd的是l图位置帔RQ也是在画图时每个格子的长度和相对坐标原点位置要进行的调整Q、地图位|常量(地图的长、宽Q,地图标记帔RQh物对应的记号Q,地图l合标记帔RQ后面会(x)l说Q,囄帔RQ存放h物的囄Q;DrawcM要负责在制定的位|画Zh物图片。下面我来说说ImagescM的地图标记常量和地图l合标记帔R。ؓ(f)?jin)能够灵zȝ安排各个关面的布局Q我们决定把游戏布局的信息存储在外部文g中,然后E序启动后把它读q来?
q样我们制定?jin)一套存储图片的代码Q这是地图标记帔RQ如上面ImagescM定义的Caocao(Ҏ(gu))用a字符来表C,当程序读到a字符时就能将它{化成Ҏ(gu)对应的图片,q在da字符的位|上q行昄。但是从实际观察中我们发现所有的囄q不是统一大小的,有的?个格子,有的?个格子,q有的占1个格子,而且即便同是占两个格子的囄q有横、竖之分。有鉴于此,我们引入?jin)地囄合标记常量,是说在遇到占有多个格子的时候,?(也就是Images.LEFT)表示它的左边是一个真正的地图标记Q?(也就是Images.UP)表示它的上边是一个真正的地图标记Q?(也就是Images.LEFTUP)表示它的左上Ҏ(gu)一个真正的地图标记。地囄合标记常量其实就是用来占位置的,与实际显C无养I当后面我们将到移动时q(sh)(x)再来分析l合标记的用?
DrawcM要是用来在画布上d囑ŞQ它有两个paintҎ(gu)Q这是很常见的函数重载。但是程序中实际上只用到?个参数的paintҎ(gu)Q它直接获得要画囄的相对坐标位|信息,然后调用5个参数的paintҎ(gu)?个参数的paintҎ(gu)相对坐标位|信息{换成l对位置Qƈ实际调用Graphics.drawImage()Ҏ(gu)Q将Images中的囄M(jin)出来。这U实现方法的好处是灵zd便于扩展Q但你需要画囄位置q不能够对应到格子中的相对坐标位|时Q你可以直接调?个参数的paintҎ(gu)Q而不必再M改这各类Q但你添加新的图片时Q只要在Images中增加对应的帔RQ然后向Draw?个参数的paintҎ(gu)d一条处理就可以?jin)。写到这里,两天的时间刚好用完?
三、需求分?
q部分叫做需求分析,听v来挺吓h的,其实是搞清楚我们要做什么,做成什么样Q那些不做。下面我引领着大家共同来完成这一步骤。首先,我们要做一个华定w的游戏,华容道的故事q里不再赘述?jin),但其中的人物在这里限定一下,如上面Imagesc里的定义,我们q个版本只提供曹?Caocao)、关?Guanyu)、张?Zhangfei)、n?Zhaoyun)、黄?Huangzhong)、马?Machao)和卒(Zu)。我们这里也限定一下游戏的操作Ҏ(gu)Q首先要通过方向键选择一个要Ud的区?是一张图?Q被选择的区域用黑色Ҏ(gu)框住Q选好后按Fire?是定?这块区域选中Q被选中的区域用l色Ҏ(gu)框住Q然后选择要移动到的区域,此时用红色方框框住被选择的区域;选好要移动到的区域之后按Fire键将要移动的区域(囄)Ud要移动到的区域,q去掉绿色和U色的方框。这里需要强调的概念有选择的区域、选中的区域、要Ud的区域和要移动到的区域,q四个概念请读者注意区分,当然也应当把q一部分记入数据字典之中?
Z(jin)使文章的重点H出(介绍如何制作一个J2ME的收集游?Q我们这里限定一些与本主题无关的内容暂不d玎ͼ(x)q关之后的动?实现时要用到TimerTask或Threadc,后箋(hu)的系列文章中我会(x)详细介绍动画斚w的知?、关面之间的切换(其实很简单,当完成Q务之后重新再做一?、暂停和保存{操?q部分的内容介绍的资料很多,我也写不Z么新的东东来Q难免抄袭,故此免掉)?
需求分析基本完成,M午还有一D|_(d)马上动手用ACDSee把从|上找来的BMP文gQ调整其大小?71*177(我的q个囄是两个部分合在一P所以比手机实际屏幕大了(jin))Q另存(sh)ؓ(f)PNG格式。半天时间刚刚好Q不但搞清楚?jin)要做的东东Q还把要用的囄准备好了(jin)?
四、概要设?
概要设计是从需求分析过渡到详细设计的桥梁和U带Q这一部分中我们确定项目的实现Ҏ(gu)和模块的划分。我们决定将整个目分成五个部分Q分别是前面介绍的Images、DrawQ还有Map和Displayable1和MIDlet1。Images和Drawcd能简单、结构固定,因此很多目我们都用这两各c,q里直接拿来Ҏ(gu)p用了(jin)Q前面已l介l过q里不再赘述。MapcL用来从外部文件读入地图,然后保存在一个数l之中,q部分的内容是我们在本阶D讨论的重点。Displayable1是一个承了(jin)CanvascȝdQ它用来处理E序的主要控刉辑和一部分控制逻辑所需的辅助函敎ͼ主要函数应该包括用来l图的paint()函数、用来控制操作的keyPressed()函数、用来控刉择区域的setRange()函数、用来控刉择要移动到区域的setMoveRange()函数、用来移动选中区域的Move()函数和判断是否完成Q务的win()函数Q更具体的分析,我们攑ֈ详细设计中去l化。MIDlet1实际上就是一个控制整个J2ME应用的控制程序,其实也没有什么可特别的,它和我们前面介绍?Hello World"E序大同异Q这里就不展开来说?jin),后面会(x)?chung)出它的全部代码?
MapcM要应该有一个Grid[][]的二l数l,用来存放华容道的地图Q还应该有一个read_map()函数用来从外部文件读取地囑ֆ容填充Grid数据l构Q再是要有一个draw_map()函数用来把Grid数据l构中的地图内容转换成图片显C出?当然要调用DrawcȝpaintҎ(gu))。说到读取外部文ӞW者知道有两种Ҏ(gu)Q一U是传统的定义一个InputStream对象Q然后用getClass().getResourceAsStream()Ҏ(gu)取得输入,然后再从输入中取得外部文g的内容,例如
InputStream is = getClass().getResourceAsStream("/filename");
if (is != null) {
byte a = (byte) is.read();
}
(tng)
(tng)
q里h意文件名中的根\径是相对于便以后的class文g攄的位|,而不是源文g(java)。第二种Ҏ(gu)是用onnector.openInputStreamҎ(gu)Q然后打开的协议是ResourceQ但是这U方法笔者反复尝试都没能调通,报告的错误是~少Resource协议Q估计第二种Ҏ(gu)用到J2ME的某些扩展类包,此处不再q。由于以前已l做q一些类似华定wq样的地图,q里直接l出Mapcȝ代码Q后面就不再详细解释MapcM(jin)Q以便于我们可以集中_֊处理Displayable1中的逻辑?
Mapcȝ代码如下Q?
package huarongroad;
import java.io.InputStream;
import javax.microedition.lcdui.*;
public class Map {
//处理游戏的地图,负责从外部文件加载地图数据,存放地图数据Qƈ按照地图数据l制地图
public byte Grid[][];//存放地图数据
public Map() {//构造函敎ͼ负责初始化地图数据的存储l构
this.Grid = new byte[Images.HEIGHT][Images.WIDTH];
//用二l数l存攑֜图数据,注意W一l是竖直坐标Q第二维是水q_?
}
public int[] read_map(int i) {
QA href="file://?Qfile://从</AQ外部文件加载地图数据,q存攑֜存储l构中,q回值是光标点的位置
//参数是加载地图文件的{
int[] a = new int[2];//光标点的位置Q?是水q位|,1是竖直位|?
try {
InputStream is = getClass().getResourceAsStream(
"/huarongroad/level".concat(String.valueOf(i)));
if (is != null) {
for (int k = 0; k Q?Images.HEIGHT; k++) {
for (int j = 0; j Q?Images.WIDTH; j++) {
this.Grid[k][j] = (byte) is.read();
if ( this.Grid[k][j] == Images.CURSOR ) {
//判断出光标所在位|?
a[0] = j;//光标水^位置
a[1] = k;//光标竖直位置
this.Grid[k][j] = Images.BLANK;//光标位|设成空白背?
}
}
is.read();//d回RQ?3Q?忽略?
is.read();//d换行Q?0Q?忽略?
}
is.close();
}else {
//d文gp|
a[0] = -1;
a[1] = -1;
}
}catch (Exception ex) {
//打开文gp|
a[0] = -1;
a[1] = -1;
}
return a;
}
public boolean draw_map(Graphics g) {
//调用Drawcȝ?rn)态方法,l制地图
try {
for (int i = 0; i Q?Images.HEIGHT; i++) {
for (int j = 0; j Q?Images.WIDTH; j++) {
Draw.paint(g, this.Grid[i][j], j, i);//l制地图
}
}
return true;
}catch (Exception ex) {
return false;
}
}
}
(tng)
(tng)
对于像华定wq样的小型地囑֏以直接用手工来绘制地囄内容Q比如:(x)
fa1c
2232
bd1e
2gg2
gihg
但是Q如果遇到像坦克大战或超U玛莉那L(fng)地图Q就必须另外开发一个地囄辑器?我会(x)在后l的文章中介l用vb来开发一个地囄辑器)?
五、详l设?
详细设计是程序开发过E中臛_重要的一个环节,好在我们在前面的各个阶段中已l搭建好?jin)项目所需的一些工P现在q个阶段中我们只需集中_֊设计好Displayable1中的逻辑?两天的时间当然不只干q点z,q要把其他几个类的设计修改一?
Displayable1q个c负责处理程序的控制逻辑。首先,它需要有表示当前关面的变量level、表C当前光标位|的变量loc、表CUd区域的变量SelectArea、表CUd到的区域的变量MoveArea、表C是否已有区域被选中而准备移动的变量Selected和Mapcȝ实例MyMap。然后,我们Ҏ(gu)用户按不同的键来处理不同的消息,我们要实现keyPressed()函数Q在函数中我们处理按键的上下左右和选中(Fire)Q这里的处理需要我展开来讲一Ԍ后面我很快会(x)把这一部分详细展开?
接下来,是实现paint()函数Q我们打在q一部分中反复的重画背景、地囑֒选择区域Q这个函数必d理好区域被选中之后的画W颜色的切换Q具体讲是在没有选中M区域时要用黑色画W,当选重要移动的区域时用绿色画W,当选择要移动到的区域时改用U色ȝ(当然附加一张流E图是必不可的)?
再下面要实现的setRange()函数和setMoveRange()函数Q这两个函数用来讄要移动的区域和要Ud到的区域Q我的思\是利用前面在ImagescM介绍q的地图l合标记帔RQ当Ud到地囄合标记常量时Q根据该点地图中的值做逆向变换扑ֈ相应的地图标记常量,然后讄相应的loc、SelectArea和MoveArea,其中setMoveRange()函数q用C(jin)一个辅助函数isInRange(),isInRange()函数是用来判断给定的Ҏ(gu)否在已选中的要Ud的区域之?如果isInRange()的返回值是假ƈ且该点处的g是空白就表明要移动到的区域R犯了(jin)其他以被占用的区域。有?jin)setRange()和setMoveRange()函数QMove()函数水到渠成了(jin),Move()函数要Ud的区域移动到要移动到的区?在移动过E中分ؓ(f)三步q行:
W一.复制要移动的区域Q?
W二.复制出的要Ud区域复制到要Ud到的区域(q两步分开q行的目的是防止在复制过E中覆盖掉要Ud的区?Q?
W三.用isInRange2()判断l定的点是否在要Ud到的区域?不在要Ud到的区域内的点设|成I白?下面我们详细的分析一下keyPressed()函数的实现方?首先,keyPressed()函数要处理按键的上下左右和选中(Fire),在处理时需要用CanvascȝgetGameAction函数来将按键的键D{换成游戏的方?q样可以提高游戏的兼Ҏ(gu)?因ؓ(f)不同的J2ME实现,其方向键的键g一定是相同??
接下?分别处理四个方向和选中.当按下向上时,先判断是否已l选定?jin)要Ud的区?即this.selected是否为真),如果没有选中要移动区域则让光标向上移动一?然后调用setRange()函数讄选择要移动的区域,再调用repaint()函数h屏幕,否则如果已经选中?jin)要Ud的区?p光标向上Ud一?然后调用setMoveRange()函数判断是否能够向上Ud已选中的区?如果能移动就调用repaint()函数h屏幕,如果不能Udp光标向下退回到原来的位|?
当按下向下时,先判断是否已l选定?jin)要Ud的区?如果没有选中要移动的区域则判断当前所处的区域是否Z个格?如果是两个格高则向下Ud两格,如果是一个格高则向下Ud一?接着再调用setRange()函数讄选择要移动的区域,而后调用repaint()函数h屏幕,否则如果已经选中?jin)要Ud的区?p光标向下Ud一?然后调用setMoveRange()函数判断是否能够向下Ud已选中的区?如果能移动就调用repaint()函数h屏幕,如果不能Udp光标向上退回到原来的位|?按下向左时情况完全类似向上的情况,按下向右时情况完全类似向下的情况,因此q里不再赘述,详细情况请参见程序的源代码?
当按下选中键时,先判断是否已l选中?jin)要Ud的区?如果已经选中?jin)要Ud的区域就调用Move()函数完成pUd的区域到要移动到的区域的Udq程,接着调用repaint()函数h屏幕,然后已选择标记|成false,l箋(hu)调用win()函数判断是否完成?jin)Q?否则如果q没有选定要移动的区域则再判断当前选中区域是否为空?如果不是I白将选中标记|成true,然后h屏幕.q里介绍一个技?在开发程序遇到复杂的逻辑的时?可以构造一格打印函数来所兛_(j)的数据结构打印出来以利调?q里我们构造一个PrintGrid()函数,q个函数Ua(b)是ؓ(f)?jin)调试之?效果q得不错.x(chng)我们完成?jin)编码前的全部工作?
六、编?
整个目共有五个c?有四个类的代码前面已l介l过?而且是在其他目中用过的相Ҏ(gu)熟的代码.现在只需全力d现Displayable1c?Displayable1cȝ代码如下:
package huarongroad;
import javax.microedition.lcdui.*;
public class Displayable1 extends Canvas implements CommandListener {
private int[] loc = new int[2]; QA href="file://?Qfile://光</AQ标的当前位|,0是水q位|,1是竖直位|?
private int[] SelectArea = new int[4];//被选定的区域,卌Ud的区?
private int[] MoveArea = new int[4];//要移动到的区?
private Map MyMap = new Map();//地图c?
private boolean selected;//是否已经选中要移动区域的标志
private int level;//但前的关?
public Displayable1() {//构造函?
try {
jbInit();//JBuilder定义的初始化函数
}catch (Exception e) {
e.printStackTrace();
}
}
private void Init_game(){
//初始化游戏,d地图Q设|选择区域Q清IUd到的区域
this.loc = MyMap.read_map(this.level);//d地图文gQƈq回光标的初始位|?
//0为水q位|,1为竖直位|?
this.SelectArea[0] = this.loc[0];//初始化选中的区?
this.SelectArea[1] = this.loc[1];
this.SelectArea[2] = 1;
this.SelectArea[3] = 1;
this.MoveArea[0] = -1;//初始化要Ud到的区域
this.MoveArea[1] = -1;
this.MoveArea[2] = 0;
this.MoveArea[3] = 0;
}
private void jbInit() throws Exception {//JBuilder定义的初始化函数
QA href="file://?Qfile://初</AQ始化实例变?
this.selected = false;//讄没有被选中的要Ud区域
this.level = 1;
Images.init();//初始化图片常?
Init_game();//初始化游戏,d地图Q设|选择区域Q清IUd到的区域
setCommandListener(this);//d命o(h)监听Q这是Displayable的实例方?
addCommand(new Command("Exit", Command.EXIT, 1));//d“退出”按?
}
public void commandAction(Command command, Displayable displayable) {
//命o(h)处理函数
if (command.getCommandType() == Command.EXIT) {//处理“退出?
MIDlet1.quitApp();
}
}
protected void paint(Graphics g) {
//d函数Q用于绘制用L(fng)面,x(chng)C图片,勄选中区域和要Ud到的区域
try {
g.drawImage(Images.image_Frame, 0, 0,
Graphics.TOP | Graphics.LEFT);//画背?
MyMap.draw_map(g);//按照地图内容d
if ( this.selected )
g.setColor(0,255,0);//如果被选中Q改用绿色画?gu)选中的区?
g.drawRect(this.SelectArea[0] * Images.UNIT + Images.LEFT,
this.SelectArea[1] * Images.UNIT + Images.TOP,
this.SelectArea[2] * Images.UNIT,
this.SelectArea[3] * Images.UNIT);//d选择区域Q?
QA href="file://?Qfile://如</AQ果被选中Q就用绿?
QA href="file://?Qfile://否</AQ则Q用黑?
g.setColor(255,255,255);//恢复ȝ颜色
if (this.selected) {//已经选中?jin)要Ud的区?
g.setColor(255, 0, 255);//改用U色
g.drawRect(this.MoveArea[0] * Images.UNIT + Images.LEFT,
this.MoveArea[1] * Images.UNIT + Images.TOP,
this.MoveArea[2] * Images.UNIT,
this.MoveArea[3] * Images.UNIT);//d要移动到的区?
g.setColor(255, 255, 255);//恢复ȝ颜色
}
}catch (Exception ex) {
}
System.out.println(Runtime.getRuntime().freeMemory());
System.out.println(Runtime.getRuntime().totalMemory());
}
private void setRange() {
//讄Ud后能够选中的区?
//调整当前光标位置到地囄M|,卌录h物信息的位置
if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFT) {
this.loc[0] -= 1;//向左?
}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DUP) {
this.loc[1] -= 1;//向上?
}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFTUP) {
this.loc[0] -= 1;//向左?
this.loc[1] -= 1;//向上?
}
this.SelectArea[0] = this.loc[0];//讄光标的水q位|?
this.SelectArea[1] = this.loc[1];//讄光标的竖直位|?
//讄光标的宽?
if (this.loc[0] + 1 Q?Images.WIDTH) {
this.SelectArea[2] = this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] != (byte) ???
1 : 2;
}else {
this.SelectArea[2] = 1;
}
//讄光标的高?
if (this.loc[1] + 1 Q?Images.HEIGHT) {
this.SelectArea[3] = this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] != (byte) ???
1 : 2;
}else {
this.SelectArea[3] = 1;
}
}
private boolean setMoveRange() {
//讄要移动到的区域,能够Udq回true,否则q回false
for (int i = 0; i Q?this.SelectArea[2]; i++) {
for (int j = 0; j Q?this.SelectArea[3]; j++) {
if (this.loc[1] + j Q? Images.HEIGHT ||
this.loc[0] + i Q? Images.WIDTH ||
(!isInRange(this.loc[0] + i, this.loc[1] + j) &&
this.MyMap.Grid[this.loc[1] + j][this.loc[0] + i] !=
Images.BLANK)) {
return false;
}
}
}
this.MoveArea[0] = this.loc[0];
this.MoveArea[1] = this.loc[1];
this.MoveArea[2] = this.SelectArea[2];
this.MoveArea[3] = this.SelectArea[3];
return true;
}
private boolean isInRange(int x, int y) {
//判断l定的(xQyQ点是否在选定区域之内Qx是水q_标,y是竖直坐?
if (x Q? this.SelectArea[0] &&
x Q?this.SelectArea[0] + this.SelectArea[2] &&
y Q? this.SelectArea[1] &&
y Q?this.SelectArea[1] + this.SelectArea[3]) {
return true;
}else {
return false;
}
}
private boolean isInRange2(int x, int y) {
//判断l定的(xQyQ点是否在要Ud到的区域之内Qx是水q_标,y是竖直坐?
if (x Q? this.MoveArea[0] &&
x Q?this.MoveArea[0] + this.MoveArea[2] &&
y Q? this.MoveArea[1] &&
y Q?this.MoveArea[1] + this.MoveArea[3]) {
return true;
}else {
return false;
}
}
protected void keyPressed(int keyCode) {
//处理按下键盘的事Ӟq是Canvas的实例方?
switch (getGameAction(keyCode)) {//按键的D{化成方向帔R
case Canvas.UP://向上
if (!this.selected) {//q没有选定要移动的区域
if (this.loc[1] - 1 Q? 0) {//向上q有UdI间
this.loc[1]--;//向上Ud一?
setRange();//讄光标Ud的区域,该函数能光标移动到地图M|?
repaint();//重新l图
}
}else {//已经选定?jin)要Ud的区?
if (this.loc[1] - 1 Q? 0) {//向上q有UdI间
this.loc[1]--;//向上Ud一?
if (setMoveRange()) {//能够UdQ该函数能够讄要移动到的区?
repaint();//重新l图
}else {//不能Ud
this.loc[1]++;//退回来
}
}
}
break;
case Canvas.DOWN://向下
if (!this.selected) {//q没有选定要移动的区域
if (this.loc[1] + 1 Q?Images.HEIGHT) {//向下q有UdI间
if (this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] ==
Images.DUP){//该图片有两个格高
this.loc[1]++;//向下Ud一?
if (this.loc[1] + 1 Q?Images.HEIGHT) {//向下q有
QA href="file://U?Qfile://U</AQ动I间
this.loc[1]++;//向下Ud一?
setRange();//讄光标Ud的区域,
QA href="file://?Qfile://该</AQ函数能光标移动到地图M|?
repaint();//重新l图
}else {//向下没有UdI间
this.loc[1]--;//退回来
}
}else {//该图片只有一个格?
this.loc[1]++;//向下Ud一?
setRange();//讄光标Ud的区域,
QA href="file://?Qfile://该</AQ函数能光标移动到地图M|?
repaint();//重新l图
}
}else {
}
}else {//已经选定?jin)要Ud的区?
if (this.loc[1] + 1 Q?Images.HEIGHT) {//向下q有UdI间
this.loc[1]++;//向下Ud一?
if (setMoveRange()) {//能够UdQ该函数能够讄要移动到的区?
repaint();//重新l图
}else {//不能Ud
this.loc[1]--;//退回来
}
}
}
break;
case Canvas.LEFT://向左
if (!this.selected) {//q没有选定要移动的区域
if (this.loc[0] - 1 Q? 0) {//向左q有UdI间
this.loc[0]--;//向左Ud一?
setRange();//讄光标Ud的区域,该函数能光标移动到地图M|?
repaint();//重新l图
}
}else {//已经选定?jin)要Ud的区?
if (this.loc[0] - 1 Q? 0) {//向左q有UdI间
this.loc[0]--;//向左Ud一?
if (setMoveRange()) {//能够UdQ该函数能够讄要移动到的区?
repaint();//重新l图
}else {//不能Ud
this.loc[0]++;//退回来
}
}
}
break;
case Canvas.RIGHT://向右
if (!this.selected) {//q没有选定要移动的区域
if (this.loc[0] + 1 Q?Images.WIDTH) {//向右q有UdI间
if (this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] ==
Images.DLEFT) {//该图片有两个格宽
this.loc[0]++;//向右Ud一?
if (this.loc[0] + 1 Q?Images.WIDTH) {//向右q有
QA href="file://U?Qfile://U</AQ动I间
this.loc[0]++;//向右Ud一?
setRange();//讄光标Ud的区域,
QA href="file://?Qfile://该</AQ函数能光标移动到地图M|?
repaint();//重新l图
}else {//向右没有UdI间
this.loc[0]--;//退回来
}
}else {//该图片只有一个格?
this.loc[0]++;//向右Ud一?
setRange();//讄光标Ud的区域,
QA href="file://?Qfile://该</AQ函数能光标移动到地图M|?
repaint();//重新l图
}
}else {
}
}else {//已经选定?jin)要Ud的区?
if (this.loc[0] + 1 Q?Images.WIDTH) {//向右q有UdI间
this.loc[0]++;//向右Ud一?
if (setMoveRange()) {//能够UdQ该函数能够讄要移动到的区?
repaint();//重新l图
}else {//不能Ud
this.loc[0]--;//退回来
}
}
}
break;
case Canvas.FIRE:
if (this.selected) {//已经选定?jin)要Ud的区?
Move();//要Ud的区域移动到刚选中的区?
repaint();//重新l图
this.selected = false;//清除已选定要移动区域的标志
if ( win()) {
System.out.println("win");
}
}else {//q没有选定要移动的区域
if (this.MyMap.Grid[this.loc[1]][this.loc[0]] ==
Images.BLANK) {//要移到的位置是一个空?
}else {//要移到的位置不是I白
this.selected = true;//讄已选定要移动区域的标志
}
repaint();//重新l图
}
break;
}
}
private boolean win(){
QA href="file://?Qfile://判</AQ断是否已经救出?jin)曹?
if ( this.MyMap.Grid[Images.HEIGHT - 2 ][Images.WIDTH - 3 ] == Images.CAOCAO )
return true;
else
return false;
}
private void PrintGrid(String a) {
QA href="file://?Qfile://打</AQ印当前地图的内容,用于调试
System.out.println(a);
for (int i = 0; i Q?Images.HEIGHT; i++) {
for (int j = 0; j Q?Images.WIDTH; j++) {
System.out.print( (char)this.MyMap.Grid[i][j]);
}
System.out.println("");
}
}
private void Move() {
QA href="file://?Qfile://</AQ要Ud的区域移动到刚选中的区?
if (this.MoveArea[0] == -1 || this.MoveArea[1] == -1 ||
this.SelectArea[0] == -1 || this.SelectArea[1] == -1) {//没有选中区域
}else {//已经选中?jin)要Ud的区域和要移动到的区?
byte[][] temp = new byte[this.SelectArea[3]][this.SelectArea[2]];
QA href="file://?Qfile://复</AQ制要移动的区域Q因块区域可能会(x)被覆盖掉
for (int i = 0; i Q?this.SelectArea[2]; i++) {
for (int j = 0; j Q?this.SelectArea[3]; j++) {
temp[j][i] =
this.MyMap.Grid[this.SelectArea[1] +j]
[this.SelectArea[0] + i];
}
}
QA href="file://PrintGrid"Q?a href="file://PrintGrid/">file://PrintGridQ?AQ?"1"); // 调试信息
QA href="file://?Qfile://</AQ要Ud的区域移动到刚选中的区域(卌Ud到的区域Q?
for (int i = 0; i Q?this.SelectArea[2]; i++) {
for (int j = 0; j Q?this.SelectArea[3]; j++) {
this.MyMap.Grid[this.MoveArea[1] + j]
[this.MoveArea[0] + i] = temp[j][i];
}
}
QA href="file://PrintGrid"Q?a href="file://PrintGrid/">file://PrintGridQ?AQ?"2");// 调试信息
QA href="file://?Qfile://</AQ要Ud的区域中无用内容|成I白
for (int i = 0; i Q?this.SelectArea[3]; i++) {
for (int j = 0; j Q?this.SelectArea[2]; j++) {
if (!isInRange2(this.SelectArea[0] + j,
this.SelectArea[1] + i)) {//该点是不在要Ud?
QA href="file://?Qfile://的</AQ区域之内,需|空
this.MyMap.Grid[this.SelectArea[1] + i]
[this.SelectArea[0] + j] = Images.BLANK;
}else {
}
}
}
QA href="file://PrintGrid"Q?a href="file://PrintGrid/">file://PrintGridQ?AQ?"3");// 调试信息
this.SelectArea[0] = this.MoveArea[0];//重置选中位置的水q_?
this.SelectArea[1] = this.MoveArea[1];//重置选中位置的竖直坐?
this.MoveArea[0] = -1;//清空要移动到的位|?
this.MoveArea[1] = -1;//清空要移动到的位|?
this.MoveArea[2] = 0;//清空要移动到的位|?
this.MoveArea[3] = 0;//清空要移动到的位|?
}
}
}
(tng)
(tng)
代码的相兛_?在详l设计阶D已l讲q?代码中有比较相近的注?误者自行研d?全部的代码写好,用wtk2.0自带的Ktoolbar工具建立一个工E?接下来把M源文件放到正位|下,然后点击build,再点run,完成了(jin)E序的编?当然如果有错误还要修改和调试?
七、测?
作ؓ(f)一个真正的产品要经q单体测试、结合测试和pȝ试。由于项目本w简?而且大部分代码已l是相对成熟?我们跌单体试Q又׃W者的实际环境所?无法搞到Java手机,无法架设OTA服务?因此我们也只能放弃系l测试。那么就让我们开始结合测试吧。测试之前要先出一个测试式样书,也就是测试的计划。我们将它简化一?只测试如下几U情?W一、对各种形状的区域的选择和移?W二、(f)q边界区域的选择和移?W三、同一区域的反复选择和反复移?W四、非法选择和非法移动。有?jin)测试的目?接下来的工作是用wtk2.0自带的Run MIDP Application工具q行试。打开q个工具,加蝲huarongRoad的jad文g,E序׃(x)自动q行,选择launch上MIDlet1q个E序,华容道游戏就?x)跃然屏q之?接下来的工作是左三?右三?拇指扭扭,来做试。测试过E中发现M的问?立刻发一个bug给自己,然后又是痛苦的调试和修正bug,如此如此?
八、发?
谈到发布,其实是个关键,再好的品不能很好的发布出去也只是个产品而已,变(sh)成商品也得不到回报.׃W者的条g所?q里只能是纸上谈?不过q是希望能够使读者对q一q程有所?jin)?|上的资料也很多)?
J2ME的程序发布一般都是通过OTA(Over The Air),你只需要一台有公网IP的主机和一个普通的web Server可以了(jin)(管要求很低,但笔者还是没?Q这里我们以apacheZ介绍一下OTA服务的配|,首先是安装好?jin)apache服务器,然后在conf目录下找到mime.types文gQ在该文件中加入如下两行
application/java-archive jar
text/vnd.sun.j2me.app-descriptor jad
然后重vapache服务器就可以?jin)。接下来的工作就是修改jad文g中MIDlet-Jar-URL:后面的参敎ͼ它改ؓ(f)URL的绝对\径,卻IA href="http://***/"Q?a href="http://***/">http://***/Q?AQhuarongroad.jar(其中***是你的域名或IP地址)。在下面是用java手机下蝲jad文gQ它?x)自动部|相应的jar文gq加载它。剩下的工作和在模拟器上操作是一L(fng)?jin)?
?ji)、项目ȝ
x(chng)Q我们已l完成了(jin)一个J2ME游戏的全部开发过E,E序中涉?qing)到了(jin)调研、分析、设计、编码、测试和发布{方面的问题Q其实在实际的工作中q有很多更ؓ(f)具体的问题,毕竟技术只在Y件开发过E中占据很有限的一部分Q这里限于篇q的限制无法一一具体展开。今后,W者计划再写一用J2ME开发手机屏保的文章Q借此Z(x)向读者展CJ2ME动画技术;然后再写一J2ME|络应用的文章,做一个类似开?j)辞兔RL(fng)知识问答游戏Q以便向读者展CJ2ME的网l技术;待这两方面的技术交待清楚之后,我将引领读者制作一个稍大一些的游戏?/p>
|
set path=c:jdk1.3in;%path% set classpath=.; |
?/td> | 颜色?/td> |
1 | 2 |
2 | 4 |
4 | 16 |
8 | 256 |
![]() |
![]() |
![]() |
![]() |
simpleMIDlet.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class simpleMIDlet extends MIDlet implements CommandListener { private Display display; // 引用MIDlet的Display 对象 private TextBox tbxMain; // Textbox 昄一条消?br />private Command cmdExit; // 讑֮按钮用于退出MIDlet // MIDlet构造程?br />public simpleMIDlet() { display = Display.getDisplay(this); cmdExit = new Command("Exit", Command.SCREEN, 1); tbxMain = new TextBox("Simple MIDlet", "Welcome ", 50, 0); tbxMain.addCommand(cmdExit); tbxMain.setCommandListener(this); } // 被应用程序管理器调用来启动MIDlet?br />public void startApp() { display.setCurrent(tbxMain); } // 一个必要的Ҏ(gu) public void pauseApp() { } file://一个必要的Ҏ(gu) public void destroyApp(boolean unconditional) { } file://(g)查一下是否选择?jin)退出命?br />public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } } |
avac -bootclasspath c:j2memidp-fcsclasses simpleMIDlet.java |
preverify -classpath c:j2memidp-fcsclasses;. -d . simpleMIDlet |
midp firstMIDlet |
?1 | |
属?/div> | 用?/div> |
MIDlet-Name | MIDletE序包的名称。例如“Game Pack?/td> |
MIDlet-Version | MIDlet的版本号 |
MIDlet-Vendor | MIDlet的创或提供?/td> |
MIDlet-Icon | 应用E序理器把q个图标?MIDlet-Name相关联,q是一个图形文Ӟ?PNG图象格式储存?/td> |
MIDlet-Description | 描述 MIDlet的文?/td> |
MIDlet-Info-URL | 可能提供更多MIDlet?或供应商信息?URL |
MIDlet- | q个属性包括三D信息:(x) ??MIDlet名称 ??用于q个 MIDlet的图?可? ??应用E序理器将调用来加载这?MIDlet的类?在我们的?Game Pack”例子中Q有两个条目Q?MIDlet-1: KOF, /images/kof.png, kof.kofMIDlet MIDlet-2: Golf, /images/golf.png, golfMIDlet |
MIDlet-Jar-URL | JAR文g?URL |
MIDlet-Jar-Size | JAR文g的大?/td> |
MIDlet-Data-Size | 持久数据存储必需的最字节数 |
MicroEdition-Profile | MIDlet需要哪一U?J2ME?/td> |
MicroEdition-Configuration | MIDlet需要哪一U?J2ME配置 |
MIDlet-Name: Show Properties MIDlet MIDlet-Version: 1.0.1 MIDlet-Vendor: ABC WorkGroup. MIDlet-1: ShowProps, , showProperties MicroEdition-Profile: MIDP-1.0 MicroEdition-Configuration: CLDC-1.0 MIDlet-Description: A simple property list example MIDlet-Data-Size: 1500 |
MIDlet-Name: Show Properties MIDlet MIDlet-Version: 1.0.1 MIDlet-Vendor: ABC WorkGroup. MIDlet-Jar-URL: file://showProperties.jar MIDlet-Jar-Size: 1132 MIDlet-1: ShowProps, , showProperties JadFile-Version: 1.5 MIDlet-Data-Size: 500 |
import javax.microedition.midlet.*; public class showProperties extends MIDlet { public void startApp() throws MIDletStateChangeException { System.out.println("Vendor: " + getAppProperty("MIDlet-Vendor")); System.out.println("Description: " + getAppProperty("MIDlet-Description")); System.out.println("JadFile Version: " + getAppProperty("JadFile-Version")); System.out.println("MIDlet-Data-Size: " + getAppProperty("MIDlet-Data-Size")); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } } |
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet1 extends MIDlet implements CommandListener { private Display display; // 引用Display对象 private TextBox tbxMain; // 昄消息的文本框 private Command cmdExit; // 退出MIDlet的命? // 构造程? public MIDlet1() { display = Display.getDisplay(this); cmdExit = new Command("Exit", Command.SCREEN, 1); tbxMain = new TextBox("MIDlet 1", "Welcome", 50, 0); tbxMain.addCommand(cmdExit); tbxMain.setCommandListener(this); } // 启动MIDlet时由应用E序理器调? public void startApp() { display.setCurrent(tbxMain); } // 一个必要的Ҏ(gu) public void pauseApp() { } // 一个必要的Ҏ(gu) public void destroyApp(boolean unconditional) { } file://(g)查一下是否选择Exit命o(h) public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } } |
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet2 extends MIDlet implements CommandListener { private Display display; file://引用Display对象 private List lstMain; private Command cmdExit; // 退?MIDlet的命? // 构造程? public MIDlet2() { display = Display.getDisplay(this); cmdExit = new Command("Exit", Command.SCREEN, 1); lstMain = new List("MIDlet 2", Choice.IMPLICIT); lstMain.append("Welcome Back", null); lstMain.addCommand(cmdExit); lstMain.setCommandListener(this); } file://启动MIDlet时由应用E序理器调? public void startApp() { display.setCurrent(lstMain); } file://一个必要的Ҏ(gu) public void pauseApp() { } file://一个必要的Ҏ(gu) public void destroyApp(boolean unconditional) { } file://(g)查一下是否选择Exit命o(h) public void commandAction(Command c, Displayable s) { if (c == cmdExit) { destroyApp(false); notifyDestroyed(); } } } |
javac -bootclasspath c:mefcs*.java preverify -classpath c:mefcs;. -d . MIDlet1 MIDlet2 jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png |
MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-1: MIDlet1, /spin.png, MIDlet1 MIDlet-2: MIDlet2, /spin.png, MIDlet2 MicroEdition-Profile: MIDP-1.0 MicroEdition-Configuration: CLDC-1.0 |
jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png |
MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-Description: Two simple examples to show how to compile and run a MIDlet MIDlet-Jar-URL: http://localhost/MIDlets.jar MIDlet-Jar-Size: 2604 MIDlet-1: MIDlet1, /spin.png, MIDlet1 MIDlet-2: MIDlet2, /spin.png, MIDlet2 |
MIDlet-1: MIDlet1, /spin.png, MIDlet1 MIDlet-2: MIDlet2, /spin.png, MIDlet2 |
midp -transient file://MIDlets.jad |
file://J2ME/MIDlets/welcome.jad |
![]() |
midp -transient http://localhost/MIDlets.jad |
midp -transient http://www.yourwebserver.com/path/MIDlets.jad |
c:j2me | MIDletPackage => Java 源代码和manifest.txt文g | jclasses => 从Java~译器编译的c? pclasses =>l过预验证的c? resources =>资源文g (囑փ文g{? |
MIDlet1.java: package simpleMIDlets; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet1 extends MIDlet implements CommandListener { ... } MIDlet2.java: package simpleMIDlets; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MIDlet2 extends MIDlet implements CommandListener { ... } |
manifest.txt: MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1 MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2 MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0 MIDlets.jad: MIDlet-Name: MIDlet Examples MIDlet-Version: 1.0 MIDlet-Vendor: My Corporation Inc. MIDlet-Description: Packaging multiple MIDlets MIDlet-Jar-URL: http://localhost/MIDlets.jar MIDlet-Jar-Size: 2884 MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1 MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2 |
javac -bootclasspath c:mefcs-d jclasses *.java |
preverify -classpath c:mefcs; -d pclasses jclasses |
jar cvfm MIDlets.jar manifest.txt -C pclasses . resources |
midp -transient file://MIDlets.jad |
midp -transient http://localhost/MIDlets.jad |
|
W二?J2ME的体pȝ?/b> J2ME领域的新的开发者常常被q些事实困惑的, 事实上, Sun的第一个配|?现在只是一U配|的引用实现 )带有UCؓ(f) KVM的虚拟机引用实现Q?KVM满配置的虚拟机的必要条件。然而, Sun?KVM也可以被另外一个虚拟机所代替Q现在, 正是因ؓ(f)配置和虚拟机l合得有点紧密,因此D?jin)这么多的乱? W三?详细谈谈J2ME配置
J2ME现在定义两个配置Q?Connected Device configuration(q接讑֤配置 CDC )和限制性更强的 Connected Limited Device Configuration (有限q接讑֤配置)?/font> 表的实现?Java应用E序接口的一个集合,用于适应被定义配|的应用E序接口提供的服务,表是一个完整的q行环境Q一个在表上执行的应用程序不需要额外的支持cR?
J2ME没有定义满q两U配|的标准化用h口,Sun也承认现在的消费讑֤多种多样Q用L(fng)面也各不一P所以定义一个可用于所有用L(fng)界面是一场失败的战(sh)?J2ME中的用户界面定义在简表中?/p>
现在个h计算机系l的数量和种cdl发展到无法控制的地步,请你想一惻I你编写的E序q行在“信息家?sh)”舞台的情景吧,q些信息家电(sh)包括呼叫器,行动?sh)话Q像Palmq样的个人数字助?PDA)Q电(sh)视机盒QPOSl端以及(qing)其他的消费电(sh)子设备。现在全世界上光是手提电(sh)话生产商有许多Q更不用说别的家?sh)设备?jin)Q而且每一U家?sh)设备又有不同的?gu)和界面。所以,你可以想刎ͼ Java应用E序的轻便性以?qing)能够解军_发这么许多不同的讑֤E序的能力,使大家对J2ME有很大的期许。当?dng)Z(jin)更好的开发这些信息家?sh),p求把Java的精髓压~进一个非常小的程序包中,q就是J2ME?
J2ME是一U通过许多部g和规范的技术, q众多的部g和规范帮?J2ME来满众多的消费品的不同的需要。和所有的爪哇E式语言技术一P在它的核?j)属于一U虚拟机?像使用所?Java技术一PJ2ME的核?j)也在一U虚拟机中?最初,用于 J2ME应用E序虚拟机的被称?Kilobyte virtual machine或简U?KVM。就像它名称的含义, KVM比较?yu),通常只有 128K或更。这比v我们通常?jin)解和用?Java 2标准?Java虚拟?( JVM )?32 MB来说小得多?jin)?
用于q接虚拟机的是一pd配置和简表,它们提供?jin)用于特?J2ME环境的类应用E序接口(见图二)(j)?每个配置和简表处理一般或具体的消费品,配置和简表规范是由多U多L(fng)讑֤生商和用户共同开发ƈ建立的。配|是用于一l通用讑֤的最的 Javaq_Q?常常归ؓ(f)一U横向的讑֤分组Q相Ҏ(gu)_(d)横向分组讑֤是那些共享相同的内存安排Q通信带宽Q能量需求以?qing)用戯力的讑֤Q一般认为配|能够提供这众多的设备的所有需求?
图二解释Q?J2ME层次 Java虚拟机是 J2ME技术的核心(j)Q但是配|和表提供特D环境的cd用程序接口。配|是用于一l通用讑֤的最的 Javaq_Q而简表则为具体的讑֤家族或特别的应用E序提供更具体的能力?/font>
另一斚wQ简表完善了(jin) 配置Qؓ(f)某个具体的设备家族或某个具体的工业片D应用程序提供更高的性能?换言之, 表ؓ(f)具体的纵向市(jng)场的讑֤比如说行动电(sh)话提供更多的性能。这里的关键是 表必d?配置Q?没有 配置和虚拟机提供核心(j)cd用程序接口和q行期环境的话,表也不会(x)工作?br />
通常Q简表ؓ(f)一U给定的垂直分组讑֤提供用户界面、输入法、持久性机制。这c?表被认ؓ(f)是发展这些设备应用程序的完整的工具包。我们见到最多的应用E序表的例子q动电(sh)话简表和个h数字助手(PDA)?其他表ؓ(f)范围宽广的设备提供非常特D的功能或应用程序可UL性,q方面的例子是提供q程Ҏ(gu)调用 ( RMI )功能的简表和提供l一银行事务的简表?br />
虚拟机?配置?表…你是不是已l被搞迷p了(jin)Q?如果q样的话Q我们就来简化一?J2ME体系l构吧?如果你想为小型信息家늼?Java应用E序的话Q你需要两个前提:(x)一?配置和至一?表?现在Q?一般是配置捆绑?jin)虚拟机和一套针对你的^台所能够用的横向分组讑֤的Javacd。其ơ,你至还需要一?表来Z的^台提供附加的 Javac,q个 表通常?x)?f)你的讑֤提供用户界面、输入和数据库类。有?jin)这两个前提Q你׃(jin)使用 JavaZ的设备编写应用程序的基本的J2ME环境?
J2ME可以在好几个不同的配|中q行配置?像先前提到的,每个配置Zl通用讑֤提供最的 Javaq_Q到目前为止Q只有两U配|规范。通过 Java规范定义的这两种配置?Connected Limited Device Configuration (有限q接讑֤配置Q?CLDC )?Connected Device Configuration (q接讑֤配置 CDC )?br />
CLDC是ؓ(f)使用较小的存储容量的讑֤设计?(参见? )?CLDC用于内存?28?512K之间的消费电(sh)子设备, q一cd中典型代表的讑֤包含呼叫器、行动电(sh)话、PDA和POSl端Q而另一斚wQ?CDC用于?PC机小但是h?512K内存多的讑֤Q这一c设备包括互联网l电(sh)视系l、机盒、POSpȝ、汽车导航以?qing)娱乐系l。一般来_(d) CDC使小型设备只要具有少量的资源Q至比台式的资源pq行Java~程Q而CLDC使小型设备所拥有的资源只要比一张智能卡多一点就可以q行Java~程?jin)?
图二解释 讑֤覆盖的范?J2ME有两个配|CLDC?CDCQCLDC是ؓ(f)使用较小的存储容量的讑֤设计的,而CDC用于?PC机小但是h?512K内存多的讑֤?/font>
除了(jin)在容量大和能力上对虚拟定了(jin)必要条gQ配|还规定?jin)类应用E序接口要包含常见的 java.io?java.net?java.util?java.lang包,配置可能q要包括其他需要的E序包?
CLDC
CLDCh可以q溯?999qJavaOne大会(x)上介l的Sun的第一个袖珍版 Java和第一?KVM以及(qing)相关的类库,虽然 CLDC和所有的配置都满x(chng)拟机的条Ӟ可它本nq(sh)是虚拟机QCLDC的引用实现只是包含在当前的分布中?KVM?br />
Ҏ(gu)规范中所_(d)q行 CLDC的设备应该有 512K或更的内存I间、一个有限的甉|供给 (通常是用电(sh)池)(j)、有限的或断断箋(hu)l的|络q接?( 9600 bps或更?)以及(qing)多样化的用户界面甚至没有用户界面?通常说来Q这个配|是Z人化的、移动的、有限连接信息设备而设计,比如呼叫器、移动电(sh)话和 PDA{?br />
?J2SE相比Q?CLDC~少下列所说的q些特征Q?br />
AWTQ抽象窗口开发包Q, Swing或其他图形库
用户定义c装载器
cd例的最l化
q引用
RMI
ReflectionQ映)(j)
CLDC有四个包Q?java.lang?java.util?java.io?javax.microedition?除了(jin) microedition包以外,其他的这几个包都是J2SE包的核心(j)子集QCLDC采用q些J2SEcdQ但是把其中一些在微型讑֤中用不到cR属性、方法去掉了(jin)。因?CLDCcd有许多细微的差别?如果(zhn)想研究J2SE?CLDCcd之间的差别,请参阅相x(chng)档,在此׃详细说明?jin)?br />
惌理解Z么CLDC去除q么多J2SE中重要的cd特征Q请回想一下与 CLDC相关的两条基本原理。首先,它只?512K的内存空_(d) 而像RMI和映需要的内存太大?jin)?其次Q配|必Lؓ(f)一l通用讑֤提供最的 Javaq_?在个人移动信息设备领域中Q许多系l都不能支持 J2SE中的众多的高U特征?例如Q许多消费电(sh)子品不能支持QҎ(gu)Q?因此 FloatQQ点类Q和 DoubleQ双_ֺc)(j)p删除?jin)?再看另外一个例子,许多pȝ没有或不提供讉K一个文件系l的功能或权限?因此与文件有关的cM被丢弃了(jin)。又如,错误处理是一个代价非帔R的过E处理,在许多消费电(sh)子设备中Q故障恢复是很难的甚x(chng)不可能的?所以在 CLDC中,许多错误处理cM被删除了(jin)?
java.microeditionE序包提供了(jin)一个一般的l构来替代许?J2SE|络输入/输出cR?CLDC一般连接器l构q定义了(jin)一?Connectorc,允许许多不同cd的连接能够用静(rn)态方法,下表列出使用同一个Connectorcd建和打开五种不同cd的连接的Ҏ(gu)Q?br />
HTTP Connector.open("http://www.xyz.com");
套接?Connector.open("socket://111.222.111.222:9000");
通讯端口 Connector.open("comm:1;baudrate=9600");
数据?Connector.open("datagram://111.222.111.222");
文g Connector.open("file:/xyz.dat");
一般连接器l构提供l应用程序开发者一个到通用低水q硬件的单的映射表。成功执?open语句返回一个实C般连接界面的对象?
CDC
CDC늛?jin)个人?sh)脑与有至?512K内存的小型设备之间的中间地带。现在,q一c设备通常是共享的、固定的 (不用Ud)|络q接信息讑֤Q像?sh)视机机盒Q网l电(sh)视系l、互联网?sh)话与汽车导?׃pȝ{等?br />
首先QCDCZ J2SE 1.3应用E序接口Q包含所有定义在CLDC规范(包括 javax.microeditionE序?中的Java语言应用E序接口。与CLDC相比Q?CLDC所有缺的Ҏ(gu)和cd CDC中都被补齐,包含映射、最l化、所有的错误处理cRQҎ(gu)、属性、输?输出 ( File?FileInputStream{等 )和弱的引用?一般说来, CDC中预期的cd括一个J2SE子集和一个完整的 CLDC集Q如?中所C:(x)
? QJ2SE、CLDC和CDC的关p?
像使用所有的配置一PCDC有基层虚拟机的具体的必要条g?Ҏ(gu) CDC规范Q基层虚拟机必须提供实现完整?Java虚拟机的支持 ?如果虚拟机实现有一个用于激z设备的本地Ҏ(gu)的界面,它必d?JNI 1.1版本?如果虚拟机实现有一个调试界面,它必d?Java虚拟试界?( JVMDI )规范?如果虚拟机有一个简表界面,它必d?Java虚拟机简表界?( JVMPI )规范?可见Qؓ(f)?jin)实现这些功能,CDC肯定?x)变得很大,׃能称其?f)K虚拟Z(jin)Q因此,我们通常U用于CDC的虚拟机?CVMQ这里的 C代表 compact、connected、consumer?br />
W四?谈谈J2ME?/b>
虽然配置Zl通用讑֤提供?jin)最的 Javaq_Q但是应用程序开发者感兴趣的是Z个个别的讑֤生应用E序Q当他们只是使用配置的话Q他们编写的应用E序׃(x)有一些欠~?配置必须满所有的讑֤的最的要求Q?用户界面、输入机制和数据持久性有高度地设备具体性,每一U设备都有自q用户界面、输入机制和数据存储Ҏ(gu)Q这些往往不在配置所满的最要求的范围之内?
表ؓ(f)相同消费?sh)子讑֤的不同的生商提供?jin)标准化的 JavacdQ?事实上,虽然配置规范的开发由 Sun领导Q但是许多简表规范仍l由Ҏ(gu)讑֤的供应商领导?比如_(d) Motorola领导?jin)行动?sh)话和呼叫器简表规范的开发,又如 Palm 领导 PDA表的开发?
现在Q五个已知简表已l有?jin)规? CQ每个简表的责Q都是Z(jin)完善配置的不I下表列出?jin)这五个表:(x)
?/td> 完善配置 Mobile information devices profile (MIDP) Ud?sh)话和呼叫?CLDC Personal digital assistant profile Palm和Handspring的PDA 讑֤ CLDC Foundation profile 用于所有不需要GUI的CDC讑֤的标准简?CDC Personal profile 替代PersonalJava的Foundation完善的简?CDC RMI profile 提供RMI的Foundation完善的简?CDC
现在我想谈一谈另一个Javacd集,它现在差不多可以被认为是另一个简表了(jin)。当Sun为Palm开发第一个KVMӞ他们需要一l类?开发Palm的演C程序。这套类库被装q?com.sun.kjavaE序包, ?CLDC早期的开发中Q这些类被广泛的使用来测试和演示 J2ME。因?kjava是唯一的允许应用程序开发者?J2ME?KVM开发应用程序的c,所以它?yu)pq泛使用?jin)。甚臛_?jin)今天,一个用?PDA或更Ҏ(gu)一点的 Palm的简表多已经在开发中Q许多开发者仍然希望?kjavacL开?PDA应用E序。尽?kjavacM被支持,q且仅仅用于设计试E序或演C程序,q且它们被一个即到来的表所替代Q但是开发者们仍然热衷于用它来开发?br />
MIDP
Mobile Information Device Profile(Ud信息讑֤?,U?MIDP )Q第一个实现的表,补充?CLDCq且提供应用E序语义和控件、用L(fng)面、持久存储器、网l和用于Ud?sh)话的计时器、双通道呼叫器和其他无线?sh)设备?因ؓ(f) MIDP?CLDC两者都有引用实玎ͼ我们可以使用一个例E来研究一下这个简表?br />
下面的例子是一个允许用戯入代表想知道的基金报L(fng)代号的例子。应用程序然后通过 HTTP接到一个金融网站,获得基金报h(hun)Q把h储存在一个数据库Q然后把hq回l用戗?
// 到如需要的J2MEc?br />import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
// 扩展MIDletcL构徏我们的自定义MIDlet
public class FundTracker extends MIDlet implements
CommandListener {
file://昄理者变?br />private Display display = null;
file://MIDlet的表单变?br />private RequestForm reqForm = null;
file://MIDlet构徏?br />public FundTracker () {
display = Display.getDisplay(this);
reqForm = new RequestForm("Fund Tracker");
reqForm.initForm();
reqForm.setCommandListener(this);
}
file://开?MIDlet 应用E序
protected void startApp() {
display.setCurrent(reqForm);
}
file://暂停 Midlet
protected void pauseApp() {
}
file://销毁Midlet
protected void destroyApp(boolean unconditional) {
}
file://通过监听者响应命?br />public void commandAction(Command c, Displayable s) {
if (c == reqForm.getExitCommand()) {
destroyApp(false);
notifyDestroyed();
return;
}
if ((c == reqForm.getGetCommand()) &&
(reqForm.getSymField().getString().length() > 0)) {
getAndDisplayQuote();
} else
{
reqForm.getMsgString().setText("Symbol required");
}
}
file://储存?分开的成对的基金字符串和报h(hun)字符?br />private void storeQuote (String fund, String newQuote) {
file://数据库变?
RecordStore quoteDB = null;
try {
quoteDB = RecordStore.openRecordStore(
"FundQuotes", true);
byte[] data = (fund + "#" + newQuote).getBytes();
int size = data.length;
quoteDB.addRecord(data, 0, size);
quoteDB.closeRecordStore();
}
catch (Exception recordException) {
System.out.println("Unable to store quote and/or
use Fund Quote database.");
}
}
file://通过QuoteServicecd回提交的代号表示的基金报?br />private void getAndDisplayQuote(){
String fundSymbol = reqForm.getSymField().getString();
if (fundSymbol.length() > 0) {
String theQuote = QuoteService.getQuote(fundSymbol);
if (theQuote != null) {
storeQuote(fundSymbol, theQuote);
reqForm.getMsgString().setText(theQuote);
}
else
reqForm.getMsgString().setText("No quote" +
'' '' + "Check Symbol");
}
}
}
MIDP应用E序UCؓ(f) MIDletQ?Z(jin)创徏一?MIDletQ你必须写一个扩展基?MIDletcȝc?(像我们在上面代码段中列出的那样Q?q有点类似常见的 applet?servlet?MIDlets独有的东西是把多?MIDletl成一?MIDlet套g的能力?q就允许 MIDlet在一个单独的 JVM环境中共享资源,比如一个数据库{等?事实上,我们上面l出的例子还包括一?MIDlet ( RetrieveQuoteQ见上段E序Q,用于取回所报h(hun)根{?当MIDlet被请求时Q?MIDlet通过构造程序实例化Q然后调用实例的 startApp()Ҏ(gu)?
?FundTracker例子中, MIDlet的用L(fng)面或昄是由 Displaycȝ一个实例管理的?对于每个 MIDletQ只有一个显C管理器实例?所有可以显C的目Q像屏幕或画布(canvasQ,通过q个理器都能够成ؓ(f)可见的。因动电(sh)话和呼叫器能力的多样?又因为用于这些设备的应用E序cd的差异, MIDP规范提供?jin)两U类型的用户界面。一个可UL性稍差、明设备、低水^的应用程序接口,允许囑Ş元素_的控制和攄?q个接口cd是用于应用程序特性比较典型的讑֤特别设计的,比如?sh)子游戏?一个可UL性稍好的、抽象的、高U的 GUI应用E序接口Q提供来用于商业应用E序?
我们的例E用的是高U的应用E序接口和典型的用户界面lg (文本框,列表{等 )Q是q类界面通用的。比如说Q实际的表单和所有的组件在一个单独的文g中都已定义?像在代码段一中列出的那样Q当 MIDlet创徏Ӟ一个表单的实例?MIDlet兌?在调?MIDlet startApp()Ҏ(gu)的时候,通过 Display对象昄表单?使用一个用于表单的c,允许我们在我们简单的报h(hun)(g)索应用程序中重新使用q个表单 ( RetrieveQuote )。ؓ(f)?jin)清晰性和风格Q我们通过一个单独的cL定义报h(hun)服务?Z(jin)演示一般连接器l构的能力,我们的报h务类通过一?Connector实例取回报h(hun)?
MIDP要求q_讑֤提供一个机制用来储存简单的数据记录Q通过正常的^CӞ比如重新启动和电(sh)池更新维护系l的完整性?MIDPUC个持久数据库?RecordStore?在我们的CZ中, MIDlet打开q添加一条记录到 " MutualFundQuotes " RecordStore?正如我们的演C程序,能添加到 RecordStore中的唯一一U类型的记录是字节数l?相同?RecordStore是一个资源,它可以通过套g׃n?Ҏ(gu) MIDP规范Q??MIDlet从^C删除后,RecordStore也会(x)被从q_中删除?
PDA?br />
Palm公司是开发PDA表规范的领头人, q个表也是完善了(jin) CLDCQ在相当长的一D|间内Q它都将?kjavacȝ序包的替代品?Java规范q个 profile臛_应当提供两个核心(j)功能片段Q?一个用L(fng)面显C工具包Q适合?"有限的尺寸和深度昄 "和一个持久数据存储器机制?昄工具包应该是抽象H口工具包的一个子集, 而持久机制将为应用程序、数据、配|?环境信息提供单的数据存储?br />
Foundation?br />
下面三种表不是非常常见, q三U简表的职责都是Z(jin)完善 CDC?Personal?RMI表实际上?Foundation表的扩展?Foundation表的d是担M个基表,便于以后开发出来的提供囑Ş用户接口?|络{功能的表附着在它之上?除了(jin)用于基础表, Foundation表还提供完整|络的支持,不管有没有用图形用h口?br />
Personal?br />
在当前的规范需求下Q?Personal表提供下一?PersonalJava环境。这个简表允诺,提供互联|连接性和 Web保真度以?qing)一个能够运?Java applets?GUI?br />
RMI?br />
回想一?CDC配置为共享的、固定网l连接信息设备提供最的 Java环境?RMI表将通过提供 Java?Java的RMI来协助提供更好的|络q接性?通过使用 J2SE ( 1.2.x或更高版本的 ) RMIQ这个简表将允许q些|络讑֤与其他系l应用程序交互操?(q个pȝ不必也运?J2ME )?br />
kjavac?br />
正如前面提到的那P kjavacL最初提供的一个供试用的c,?Palm讑֤上运行早期的 KVM和配|版本?它们被 PDA表代ѝ?kjavacL展了(jin) CLDCq且提供一个图形用h口?Palm数据库访问,单集合类和一个三角法计算器?br />
在代码段2中,我?com.sun.kjava重写?MIDP FundTrackerE序Q让它在 Palm上工作?和前面的E序一Pq个单的E序允许用户输入一个公基金代号q从WWW上的金融报h(hun)服务商那里取回报仗?br />
kjava应用E序被称?spotlet?事实上,一个应用程序可以由很多 spotletl成Q但是在M旉只有一?spotlet可以昄?Palm屏幕上?在我们的例子中,我们创徏一个基?spotlet-- RequestFormSpotlet.javaQؓ(f)我们的两?spotlets子类提供用户界面。代码段 2扩展?jin)基本?RequestFormSpotlet以便得到q储存(sh)个报仗?RetrieveSpotlet也扩展了(jin)基本 RequestFormSpotletq允许储存的报h(hun)被取回(见图Q?
代码D?
import com.sun.kjava.*;
public final class FundSpotlet extends RequestFormSpotlet {
public static void main (String args[]) {
new FundSpotlet().draw();
}
private void draw() {
initForm();
setTitle("Fund Quote Requested");
}
public void penDown(int x, int y){
if (getExitButton().pressed(x,y)){
getGraphic().playSound(Graphics.SOUND_CONFIRMATION);
System.exit(0);
}
if (getSymField().pressed(x,y))
getSymField().setFocus();
if (getGetButton().pressed(x,y)) {
quoteRequested();
}
}
private void storeQuote (String fund, String newQuote) {
int dbType = 0x46554e44;
int dbCreator = 0x43415454;
com.sun.kjava.Database quoteDB;
try {
quoteDB = new com.sun.kjava.Database(dbType,
dbCreator, com.sun.kjava.Database.READWRITE);
if (!quoteDB .isOpen()) {
com.sun.kjava.Database.create(0, "MutualFundQuotes",
dbCreator, dbType, false);
quoteDB = new com.sun.kjava.Database(dbType,
dbCreator, com.sun.kjava.Database.READWRITE);
}
byte[] data = (fund + "#" + newQuote).getBytes();
quoteDB.addRecord(data);
quoteDB.close();
}
catch (Exception recordException) {
System.out.println("Unable to store quote and/or use
Mutual Fund Quote database.");
}
}
private void getAndDisplayQuote() {
String fundSymbol = getSymField().getText();
if (fundSymbol.length() > 0) {
String theQuote = QuoteService.getQuote(fundSymbol);
if (theQuote != null) {
storeQuote(fundSymbol, theQuote);
message(theQuote);
}
else
message("No quote. Check Symbol");
}
}
private void quoteRequested() {
message("");
getGraphic().playSound(Graphics.SOUND_STARTUP);
if ((getSymField().getText().length() > 0)) {
getAndDisplayQuote();
} else
{
message("Symbol required!");
}
}
}
?RequestFormSpotletE序中,cM?MIDP中的 Display对象Q单独的 Graphics理许多 spotlet用户界面昄。它考虑C(jin)屏幕?x)被清除Q显C界会(x)被徏立?不象 MIDletQ没有屏q或d对象来让我们d用户界面组Ӟ 取而代之的是按钮、文本字D늭{,直接描画?spotlet上?paint()Ҏ(gu)利用囑Ş环境从独一无二?Graphics在屏q上昄组件?br />
我们的MIDPE序?QuoteServicecȝ大部分可以重C用?因ؓ(f) kjava没有?MIDP中HttpConnectionq样特定的连接器界面Q所以我们必d用更多标准的一般的q接器结构表单获?HTTP链接?Z(jin)做到q一点,使用代码D?3中的代码替换 getQuotePage()Ҏ(gu)。注意注意?ConnectorQ就像在 MIDP中我们?HttpConnection一栗?br />
代码D?
private static String getQuotePage(String symbolString) {
StringBuffer quotePage = new StringBuffer();
int ch;
try {
InputStream in = Connector.openInputStream (
"testhttp://someurl/some_application?page=++&mode=fund&symbol="+
symbolString);
while ((ch = in.read()) > 0) {
quotePage.append((char)ch);
}
in.close();
return quotePage.toString();
} catch (IOException ex) {
System.out.println("Exception reading quote from
HTTP Connection");
return null;
}
}
Palm讑֤q泛利用数据库, 你的 Palm中的通讯ѝ备忘录和记事本应用E序都与数据库有兟?kjavaE序包提供了(jin)一个非常小?Databasec,不仅可以创徏q保持应用程序数据,而且可以讉K现有的数据库?如果你熟(zhn)?Palm数据库,你可能会(x)?kjava DatabasecL供的功能和信息感到失望?然而,请再ơ记住, kjava只是一个演C的版本?br />
在我们的例子中,我们?spotlet讉K一?Palm数据?(如果不存在的话,则创Z个新的数据库Q来储存公基金报仗每?Palm数据库都必须有名字、创?ID (一?Palm登记的唯一的标识号 ) 和一个指定到某个单独应用E序的类型号?试图打开数据库要通过试创徏一个带?ID信息的数据库实例来实现?p MIDP RecordStoreQ记录被dq?kjava数据库,通过把一个字节数l当成记录添加到数据库中的Ş式?br />
W五?再谈谈一些J2ME规范
?J2ME内还有很多子规范Q?J2ME的重要的部分如下QPersonalJava、K虚拟?(KVM)、Java嵌入服务器以?PersonalJava的两个扩展规范:(x) JavaPhone?JavaTV应用E序接口?你可以想象, JavaPhone是一个定位于无线甉|能电(sh)话和互联|络可视?sh)话的应用程序接口,?JavaTV则满x(chng)盒?jng)场的需求?br />
下面我想详细的谈一谈以上的规范Q?br />
1、PersonalJava
PersonalJava应用E序环境目标?Webq接消费讑֤----常常执行来自|络的小应用E序。问题是 PersonalJava如何适合 J2ME的配|和表方案?{案?PersonalJava被包容q?Connected Device Configuration中,最l将被定义ؓ(f) Personal表,卛_面所谈到的Personal表?br />
另一斚wQ有一D|间将有两?Java应用E序接口为嵌入开发世界服务:(x) PersonalJava?EmbeddedJava?PersonalJava偎依?J2ME大伞之下Q?可ؓ(f)什?EmbeddedJava不呢Q?EmbeddedJava不和 PersonalJava同在 J2ME内,是因为在 PersonalJava?EmbeddedJava应用E序之间有一个基本的差别?PersonalJava应用E序期望q接到某cȝl中下蝲q执行小应用E序?按照q种观点Q?PersonalJava讑֤是一般用途的消费讑֤Q?它们的能力可以被扩展?br />
相比之下Q?EmbeddedJava讑֤则惨?jin)点?它们执行的功能都非常具体的,基本没有必要提供下蝲新的代码?EmbeddedJava讑֤的能力?HenceQ?PersonalJava讑֤使用可扩?Java应用E序接口Q?而EmbeddedJava讑֤则没有,因ؓ(f)没有必要使用?br />
PersonalJava可以以两UŞ式得刎ͼ(x) 由原码Ş式的Q提供给那些Ҏ(gu)PersonalJavaUL到其他设备感兴趣的开发者,那些已经?PersonalJavaUL到某个具体的操作pȝ和处理机的组l提供二q制形式?PersonalJava环境。有兴趣探烦(ch) PersonalJava的开发者如果没有二q制q_也可以?PersonalJava模拟环境 ( PJEE )?q个模拟器运行于 Solaris/SPARC?WindowsQƈ且在许多配置中可用?q些多种多样的配|基于?look and feel”和cd支持 (环境是否提供 PersonalJava规范中规定的最低限度的或最大的cdQ。PJEE包括cLӞ一个应用程?launcher和一?appletviewer (两者都是ؓ(f)?jin)调试功能ƈ使其最优化Q和其它的附带的文g (例如字体叙述文g)?br />
J2ME家族的另一位成?JavaCheck实用E序Q提供了(jin) PersonalJava的补充支持?你把应用E序传过 JavaCheckQ它?yu)告诉你你的应用E序在一?PersonalJava环境中能否顺利地执行?JavaCheck(g)查类之间的依赖关p,如果应用E序调用?jin)一个在 PersonalJava不可用的应用E序接口Q它?yu)׃?x)l出一个警报信受?(据我所知,目前有两UJavaCheck的版本可用,一个是用于(g)?PersonalJava 1.0版应用程序,另一个用于检?1.1.x版程序?当前?PersonalJava应用E序接口规范?1.2Q用于这一版本?JavaCheckq没有?读者请去Sun相关|站ȝ看( http : file://java.sun.com/products/personaljavaQ?br />
2、KVM
前面我也说过QKVM是用?J2MEq_最的虚拟机,q且是用于CLDC配置的虚拟机。可是J2ME应用E序q不一定非要?KVMQJ2ME技术可以用Q何虚拟机Q不q至应当有 KVMq样的功能?br />
Z(jin)满ZKVM的设备一般只有狭的内存I间和有限的处理能力的事实, KVM使用 C~写 (它不是现有的VM改进?jin)的以后的品?j)?此外Q?KVM是模块化的, 也就是说Q它是由模块构徏的,当某个模块实C(jin)预先讑֮的目标后Q就可以很容易地把这一模块卸蝲?可选的某块包括Q?大的数据cd ( long?float?double )Q多l数l、类文g验证{?br />
KVM的本地界面以M性ؓ(f)原则构徏Q所以在KVM中Q务切换不依赖g产生的记时器中断Q因此在q种意思上来说不是抢先式。Q务切换发生在虚拟机执行了(jin)一个预讄L(fng)字节码之后?q且Q?KVM的无用单元收集利用一个标记清扫(mark and sweep)法来实现无用单元释放?因此Q对象引用是直接的,像标准 Java一栗?
当然Q除?jin)虚拟机以外q有许多可用的执行环境,在小型设备中Q虚拟机必须要么被扩展,要么在附加工具协助下提供一个更加完整的q行期环境,正是q个原因Q?KVM需要附带的工具Q比如说Q?JavaCodeCompact工具提供?jin)预链接和预加蝲c, 允许Javac被直接地链接进虚拟Z?Q设备上所有的应用E序使用的类 can直接地嵌入虚拟机。)(j)
KVM一个可选的附g是 Java Application Manager ( Java应用E序理器,U?JAM )。JAM的工作就是处理下载、安装、执行和卸蝲 CLDC讑֤上的应用E序的细节问题,因ؓ(f)资源有限Q在CLDC讑֤上有可能不存在这些功能。JAM也处理更新安装应用程序的操作?如果更新q程p|Q它甚至可以重新使用旧的应用E序?)
3、Java Embedded ServerQJava嵌入服务器)(j)
Java Embedded ServerQ?Java嵌入服务器,U?JESQ,?PersonalJava基础上徏立,是一个用于嵌入式|络讑֤的运行期环境。ؓ(f)?jin)理?JESQ你必须理解两个核心(j)概念Q服务和服务I间l构。后者是前者的容器。服务程序是q行于一?JES服务器上的组件化E序Q服务空间结构是为服务程序提供生命周?支持的环境?br />
技术上_(d)服务E序是界面的实现Q事实上Q它是一个实现特定活动的Javac集合。比如说Q假如把 JES配置Z个家庭的气候控制系l的服务器,可以把从模数转换器读到的温度数据放进一个数据组件程序中。我可以称q个lg为ReadThermostats服务E序?
?JES的领域,服务的封装媒介称?bundle。简单地_(d)bundle是一个带有特D内容的JAR文g。服务程序和bundle之间有一对一关系Q一个bundle带有一个服务程序。服务程序和 bundle之间有一对一关系Q一?bundle带有一个服务程序。可q也不一定,一?bundle可以讄多个服务E序索引 (注意Q?JES提供的所有的核心(j)服务Q每?bundle中只有一?)?
正如前面提到的那P服务I间的一工作就是管理服务程序的生命周期Q这个工作的很大的部分包括解x(chng)务隶属关pRbundle内容的一个重要的部分是bundle服务的依赖信息。所以,当服务空间打开一个bundle安装它的服务Ӟ服务I间可以确定外部需要什么服务。而且Q一个服务的依赖关系q不是静(rn)止不变的Q它们可以随某些事g改变。比如说当服务程序更新时的变化就是一个很好的例子。一个服务的新的版本可以d或去除依赖关pR服务空间跟tƈ解决q样的动态依赖关pR如果服务空间处理所有服务程序的生命周期Q这暗CZ(jin)服务I间被赋予知晓一切的能力Q那是_(d)它能够推论结构、依赖、安装的l微差别{所有它负责的服务。服务空间通过?bundle内伴随服务的 Java代码模块处理一些Q务,q些模块被称?wizardQ向|(j)。JES向导是根据它们完成的d命名的:(x)
Dependencies -向导告诉调用者一个bundle依赖关系是什么?
Installer-向导处理bundle中服务的安装和删除操作?
Activator -向导知道如何启动和终止服务?
Updater -向导控g更新bundle中的服务?更新向导不仅知道更新一个服务,而且知道在何时和什么情况下更新服务?)
About -q个向导Q就像它名称意味的那Pq回关于 bundle内容的信息?
Dispatcher -q是一U元向导Qmeta-wizardQ。服务空间调用dispatcher向导定位一个bundle的其他向对{?
当一?JES服务器启动的时候,服务I间q不是完全没有启动服务。JES定义一l核?j)服?可选)(j)Q这些都是Q?JES服务器的l成部分。这些核?j)服务包含?x)
HTTP服务
日志 -记录错误和事件日?
日期 -_到秒的日?旉服务
q接理?-提供|络服务和Socketl定Q也处理q接接收?
U程理?-理服务器提供的U程。thread理器支持线E池q允许有效用线E上界的规范?
计划E序 -提供未来的事件计划安?(可用于告诉服务器某某动作必须在某某事件发?)
RMI
SNMP
控制?-提供q程理服务器功?
Z HTTP的远E应用程序接口实?
Z RMI的远E应用程序接口实?
如果你把服务I间l构当成 JavaBean中的容器的话Q?JES变得容易理解了(jin)。在q种cL关系中,服务E序q?JavaBean。那么,正象lg容器提供一个环境供 JavaBeans实例化、运行一P服务I间是以实例化的服务的聚集地。服务空间管理安装、实例化、执行、终止以?qing)卸载服务;它也提供应用E序接口供服务交互作用?
一、J2ME中需要的Java基础知识
(tng) (tng) (tng) (tng) (tng) (tng) 现在有大部分人,都是从零开始学J2ME的,学习(fn)J2ME的时候,L从Java基础开始学?fn),而且现在讲Java基础的书c中都是以J2SE来讲基础Q这q学习(fn)造成?jin)一些不必要的麻?ch),下面J2ME中用到的和不需要的Java基础知识做一个简单的说明?br /> (tng) (tng) (tng) (tng) (tng) (tng) J2ME中用到的Java基础知识Q?br /> (tng) 1、Java语法基础Q包括基本数据类型、关键字、运符{等
(tng) 2、面向对象的思想Q类和对象的概念Q承和多态等{?br /> (tng) 3、异常处?br /> (tng) 4、多U程
J2ME中没有用到的Java基础知识Q?br /> (tng) 1、JDK中javac和java命o(h)的?br /> (tng) 2、Java基础中的很多cdJ2ME中没有,或者类中的Ҏ(gu)做了(jin)大量的精。所以徏议在J2ME中熟(zhn)类库?br /> (tng) 3、Applet、AWT、Swingq些知识在J2ME中根本用不到?br /> 单说q么多,希望学J2ME的朋友们能少C些弯路,不之处希望大家U极指正和补充?/p>
二、J2ME中暂时无法完成的功能
列一些J2ME中暂时无法完成的功能Q希望大家能U极补充Q?br /> (tng) 1、在手机中不更改代码实现ULQ主要指游戏?br /> (tng) 2、动态修Ҏ(gu)钮文字?br /> (tng) 3、在Canvas上接受中文输入?br /> (tng) 4、操作本地资源、例如地址本、已收短信息{?br /> (tng) 5、制作破坏性的手机病毒?br /> (tng) 6、其他等待大家来补充?/p>
三、J2ME的跨q_?br /> J2ME技术源于JavaQ所以也hJVM的优势,可以在支持Java的^Cq行ULQ但是现在的J2ME技术在跨^C却做的很p糕Q我们来单看一下原因:(x)
1、手机的屏幕寸不一Q?br /> q个主要在界面制作上。如果你使用的是高用户界面Q比如你做的是应用开发或者用L(fng)陆、用h册这L(fng)通用功能Ӟ一般没有什么问题?br /> 如果你用的是低U用L(fng)面,比如你做的是游戏Q那么你需要考虑q个问题?sh)(jin)?br /> 2、厂商的扩展API不统一Q?br /> 例如Nokia的扩展APIcdUIpdQ在别的手机上或者没有实玎ͼ或者包名不同等{?br /> 3、手机^C实现的bugQ?br /> 例如Nokia?650在实现双~冲上有bugQ那么在q种机型上运行的软g׃能用双~冲。其他NOKIA上的一些bugQ可以参看:(x)http://blog.csdn.net/Mailbomb/archive/2005/03/24/329123.aspx
4、手机性能问题?br /> 不同手机的可用内存、最大jar文g都有要求Q例如Nokia S40的大部分手机支持的最大jar文g?4KQ最大可用内容ؓ(f)210K?br /> 所以现在的手机软gQ特别是游戏都提供支持的机型列表Q也才有?jin)手机游戏移植h员的存在?/p>
四、学?fn)J2ME可以从事的工作种c?br /> 现在J2ME技术可以说相当的火_(d)q里介绍一些学好了(jin)J2ME之后可以从事的工作的U类Q?br /> 1、J2ME游戏开发h?br /> Ҏ(gu)游戏{划或者文档要求,在某U特定的机型(以Nokia S40或S60居多)开发游戏程序?br /> q是现在大部分J2MEE序员(sh)事的工作?br /> 需要熟l掌握:(x)高用户界面、低U用L(fng)面、线E,如果是网l游戏,q需要熟l网l编E?br /> 2、J2ME应用开发h?br /> 现在的移动应用还?sh)是很多Q但是还是出C(jin)一些,特别是移动定位以?qing)移动商务相关的内容?br /> 需要熟l掌握:(x)高用户界面、线E和|络~程?br /> 3、J2ME游戏UL人员
参照源代码,可以在一个^C可以q行的游戏移植到其他q_上去。例如将Nokia S40的游戏移植到S60上,或者烦(ch)qT618{等?br /> 主要是控制屏q坐标,有些可能需要替换一些API?br /> 需要熟(zhn)各q_之间的差异以?qing)相关的技术参敎ͼ比如屏幕大小、最大jar文g寸{等?/p>
五、J2MEE序设计的几个原?br /> 1、用面向对象编E?br /> 虽然使用面向q程~程可以减小文g的尺寸,但是Z(jin)以后l护的方便和利于扩展Q还是要使用面向对象~程?br /> 2、用MVC模式
模型、界面和控制分离。现在很多的E序三者合一Q但是如果你做的E序比较大的话,q是你进行分R?br /> 3、自动存储用戯?br /> 使用RMS来存储用L(fng)信息Q例如存储用户上ơ输入的用户名、密码、用户对于系l的讑֮{,q样不仅可以减少用户的输入,而且对用户友好。很多程序甚臛_?jin)自动登陆等?br /> 4、一些系l设|允许用户关闭。如背景音乐、背景灯昄{?br /> 5、将低用户界面的绘制动作放在一个独立的U程里面厅R?br /> 6、在需要大量时间才能完成的工作Ӟl用户一个等待界面?/p>
六、从模拟器到真机试
对于J2ME开发者来_(d)模拟器给我们带来?jin)很多方便,比如可以在模拟器中调试程序以及(qing)很方便的察看程序的效果Q但是模拟器也给我们带来?jin)一些问题,比如模拟器实现的bug{等Q所以进行真机测试是必须的?br /> 1、ؓ(f)什么要q行真机试Q?br /> 因ؓ(f)模拟器程序可能存在bugQ以?qing)真机的性能有限Q所以必进行真机测试?br /> 2、如何将E序传输到机器中Q?br /> 程序传输到机器中有如下方式Q?br /> (tng) a) OTA下蝲
(tng) b) 使用数据U传?br /> (tng) c) U外传输
(tng) d) 蓝牙
你可以根据条Ӟ选择合适的方式?br /> 3?真机试主要什么?
真机试的内容很多,主要试以下几个斚wQ?br /> (tng) a) E序的功?br /> (tng) b) E序的操作性,是否易操?br /> (tng) c) E序的大?比如Nokia S40pd的手机大部分接受的最大文件尺ؓ(f)64K
(tng) d) E序q行速度Q速度是否可以忍受?/p>
七、从WTK到厂商SDK
对于J2ME爱好者来_(d)基本上大安是从SUN的WTK(J2ME Wireless Toolkit)开始的Q但是对于实际应用来_(d)仅仅使用WTK是远q不够的Q所以在学习(fn)q程中,必须完成从WTK到SDK的跨?br /> 1、厂商SDK的下载地址Q?br /> http://blog.csdn.net/Mailbomb/archive/2005/01/01/236606.aspx
2、厂商SDK和W(xu)TK有什么不同?
厂商SDK最单的理解是在WTK的基上增加了(jin)自己的模拟器和自q扩展API?br /> 也就是说Q你在用厂商的SDKӞ可以使用厂商的扩展类库,例如Nokia的UIcdQ和厂商自己的模拟器而已?br /> 每个厂商的扩展API都不多,而且不尽相同?br /> 3、如何用?
有些厂商SDK的用都和W(xu)TK相同Q例如SamSung?br /> Nokia提供?jin)独立的界面来开发,但是q个界面在实际开发中使用不多?br /> 4、厂商SDK的问?br /> 厂商SDK实现q程中,有一些bugQ而且和真机实C一致。例如NOKIA的x(chng)N题等{?/p>
八、在J2ME中获得手机IMEI的方?br /> IMEI是Internation mobile entity identification的简Uͼ在手Z输入*#06#可以昄该数字,长度?5位,全球唯一Q永q不?x)冲H,所以可以作别用L(fng)一个标志?br /> 下面是在J2ME中获得IMEI的方法:(x)
1、MOTOpd的手机可以通过dpȝ的IMEI属性获得,代码如下Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String imei = System.getProperty("IMEI");
2、SIEMENSpd的手机可以通过dpȝ的com.siemens.IMEI属性获得,代码如下Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String imei = System.getProperty("com.siemens.IMEI");
?ji)、J2ME|络q接中显C问题的解决办法
在网l编E中Q有些时候会(x)出现一些在没有接收到网l数据就昄界面的,造成界面昄不符合要求(例如公告昄Q会(x)先显C公告的背景囄再显C公告信息)(j)Q这里提一个简单的解决办法l大Ӟ(x)
解决q种情况的方法分成三个步骤:(x)
1、在需要显C的界面中,调用发送网l数据的Ҏ(gu)。每ơ显C时调用该构造方法,不调用Display的setCurrentҎ(gu)昄?br /> 2、显C等待界?例如q度条等)Q给用户提示Q在q行|络q接?br /> 3、在处理|络反馈的数据完以后Q调用Display的setCurrentҎ(gu)昄昄当前界面?/p>
十、增强J2ME的String能力——分割字W串
从JDK1.4以后QStringcM新增?jin)splitҎ(gu)来实现字W串的分Ԍ但是在J2ME中却没有该方?MIDP2.0中也没有实现)Q但是在实际使用q程中,有些时候的要用到q种操作Q这里将我以前实现的一D代码和大家׃nQ?br />/**
* 分割字符Ԍ原理Q检字W串中的分割字符Ԍ然后取子?br />* @param original 需要分割的字符?br />* @paran regex 分割字符?br />* @return 分割后生成的字符串数l?br />*/
private static String[] split(String original,String regex)
{
(tng) (tng) (tng) (tng) //取子串的起始位置
(tng) (tng) (tng) (tng) int startIndex = 0;
(tng) (tng) (tng) (tng) //结果数据先攑օVector?br /> (tng) (tng) (tng) (tng) Vector v = new Vector();
(tng) (tng) (tng) (tng) //q回的结果字W串数组
(tng) (tng) (tng) (tng) String[] str = null;
(tng) (tng) (tng) (tng) //存储取子串时起始位置
(tng) (tng) (tng) (tng) int index = 0;
(tng) (tng) (tng) (tng) //获得匚w子串的位|?br /> (tng) (tng) (tng) (tng) startIndex = original.indexOf(regex);
(tng) (tng) (tng) (tng) //System.out.println("0" + startIndex);
(tng) (tng) (tng) (tng) //如果起始字符串的位置于字符串的长度Q则证明没有取到字符串末?br /> (tng) (tng) (tng) (tng) //-1代表取到?jin)末?br /> (tng) (tng) (tng) (tng) while(startIndex < original.length() && startIndex != -1)
(tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String temp = original.substring(index,startIndex);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println(" " + startIndex);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //取子?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) v.addElement(temp);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //讄取子串的起始位置
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) index = startIndex + regex.length();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //获得匚w子串的位|?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) startIndex = original.indexOf(regex,startIndex + regex.length());
(tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) //取结束的子串
(tng) (tng) (tng) (tng) v.addElement(original.substring(index + 1 - regex.length()));
(tng) (tng) (tng) (tng) //Vector对象转换成数l?br /> (tng) (tng) (tng) (tng) str = new String[v.size()];
(tng) (tng) (tng) (tng) for(int i=0;i
(tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) str[i] = (String)v.elementAt(i);
(tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) //q回生成的数l?br /> (tng) (tng) (tng) (tng) return str;
}
十一、J2ME在低U用L(fng)面上分行昄文字
在J2ME的低U用L(fng)面开发中Q经怼(x)遇到需要在Canvas上显C大量的文字Q例如关于界面、游戏说明、游戏公告等信息。如果在设计Ӟ文字的内容和长度都固定Q既不利于修改也不利于维护。下面介l一个简单的Ҏ(gu)Q实C个简单、可l护性强的方式?br /> 实现Ҏ(gu)Q?br /> (tng) 1、将需要显C的所有信息做成一个字W串?br /> (tng) 2、编写一个将该字W串按照要求转换为字W串数组的方法?br /> (tng) 3、将转换后的数组以@环的方式昄在Canvas上?br /> 通过q样三个步骤Q则修改昄的信息时Q只需要修改包含显CZ息的字符串即可,自己书写的方法可以按照以前的标准重新分割新的字符丌Ӏ如果需要修Ҏ(gu)行显C的字符个数Q则只需要修改自׃写的Ҏ(gu)卛_?br /> 通过q样一U实现方式,可以很方便的实现昄一些比较长的文本信息,即是可变长度的字符串也没有问题?/p>
十二、J2ME中用记录存储系l?RMS)存储信息
在MIDP中,没有文g的概念,所以永久存储一般只能依靠记录存储系l实玎ͼ关于记录存储pȝ的简介,可以参看教程Q?a >http://www-900.ibm.com/developerWorks/cn/java/j-wi-rms/index.shtml
下面是一些记录存储系l的常用~码介绍Q?br /> (tng) 1、打开记录集:(x)
打开记录集用RecordStore里面的静(rn)态方法openRecordStoreQ示例代码如下:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) RecordStore rs = RecordStore.openRecordStore(“username?true);
q样打开?jin)一个名UCؓ(f)rs的记录集Q其中username录集的名Uͼ该名U可以根据需要来取,W二个参C表是否则没有时创建新的记录集Qtrue代表在该记录集不存在Ӟ创徏新的记录集,false代表不创建?br /> 如果在打开记录集时Q该记录集不存在Q则抛出RecordStoreNotFoundException异常Q所以检记录集是否已创建可以用该异常?br /> 注意Q记录集打开以后记得关闭?br /> (tng) 2、向记录集中写入数据
(tng) (tng) (tng) (tng) (tng) 2.1增加数据
向已l打开的记录集中添加数据,需要用addRecordҎ(gu)Q示例代码:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) byte[] bytes = {1,2,3};
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int id = rs. addRecord(bytes,0,bytes.length);
该代码将字节数组bytes的全部内容写入到记录集中Q该Ҏ(gu)的返回gؓ(f)该信息的idQ注意:(x)id?开始,而不是从0开始?br /> 你可以@环用该Ҏ(gu)向记录集中写入多条数据?br /> (tng) (tng) (tng) (tng) (tng) 2.2修改数据
修改已经存在的记录集中指定id的数据,需要用setRecordҎ(gu)Q示例代码:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) byte[] bytes = {1,2,3};
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) rs. setRecord(1,bytes,0,bytes.length);
以上代码的作用是字节数lbytes的全部内容写入到id?的记录集rs中?br /> 该操作会(x)覆盖已有的数据?br /> 说明Q有些时候,你需要将信息写入到记录集中的W一条记录中Q则可以l合以上两个Ҏ(gu)Q则W一ơ时向记录集增加数据Q以后来q行修改?br /> (tng) 3、从记录集中d数据
从记录集中读取已有数据,需要用getRecordҎ(gu)Q示例代码:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) byte[] bytes = rs. getRecord(1);
该代码从记录集rs中读取第一条数据,读取到的数据放在bytes数组中?br /> 在读取数据时Q可以获得记录集中id的个敎ͼ可以使用getNumRecordsҎ(gu)获得
l合代码为:(x)
(tng) (tng) (tng) (tng) (tng) (tng) int number = rs. getNumRecords();
(tng) (tng) (tng) (tng) (tng) (tng) int id = 1;
(tng) (tng) (tng) (tng) (tng) (tng) if(id >0 && id < number)
(tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) byte[] bytes = rs. getRecord(1);
(tng) (tng) (tng) (tng) (tng) (tng) }
(tng) 4、从记录集中删除记录
从记录集中删除记录的Ҏ(gu)有两U:(x)逻辑删除和物理删除?br /> 逻辑删除是指l删除的记录打标记?br /> 物理删除是指从物理上删除该记录,但是该记录的id不能被重用,也就是说该id不会(x)被l用。例如一个记录集中有5个记录,假设你删除了(jin)id?的数据,则剩余记录的id依然????。这l便历带来了(jin)一定的ȝ(ch)?br /> (tng) 5、便历记录集
便历记录集,卌问记录集中的所有数据,有两个方法,详见Q?br />http://gceclub.sun.com.cn/NASApp/sme/controller/teclist?tid=0103
(tng) 6、其他操?br /> 删除记录?br /> 删除记录集不同于删除记录Q需要用deleteRecordStoreҎ(gu)Q示例代码:(x) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) RecordStore. deleteRecordStore(“username?;
该代码删除名UCؓ(f)username的记录集?/p>
十三、J2ME加密数据的一个第三方开源免费类库介l?br /> 在J2ME~程中,l常遇到一些数据在存储或者传输时需要加密,下面介绍一个第三方的加密类库的一些资料:(x)
加密cd的官方主:(x)http://www.bouncycastle.org/
介绍的文章:(x)
中文Q?a >http://18900.motorola.com/ewa_portal/develope/jc_j2messl_5_1.jsp
英文Q?a >http://www.javaworld.com/javaworld/jw-12-2002/jw-1220-wireless.html
该文章的源代码包含用的一些方法?br /> 备注Q因cd提供的功能比较强大,所以类库的寸比较大,最后在发布旉要将cd中不需要的cd?/p>
十四、如何播攑֣?br /> 在J2ME中,处理声音需要用到Mobile Media API(MMAPI)Q该包是MIDP1.0的可选包Q在MIDP2.0中已l包含了(jin)q个包。所以如果你使用MIDP1.0的话Q请认你的q行环境是否支持?br /> 一般手机支持的声音文g格式为wav、mid和mpg{。具体请查阅你的手机说明文档?br /> 在声韛_理中Q有很多处理的方式,q里说一下最常用的情况,播放JAR文g中的wav文g?br /> 播放声音文g的流E:(x)
(tng) 1、按照一定的格式d声音文g?br /> 播放JAR文g中的声音文g一般是声x(chng)件处理成的形式。示例代码:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");
(tng) (tng) (tng) (tng) (tng) (tng) 其中Autorun.wav文g位于JAR文g的根目录下,如果位于别的目录Q需要加上目录名Uͼ?res /Autorun.wav?br /> (tng) 2、将d到的内容传递给播放器?br /> 流信息传递给播放器,播放器按照一定的格式来进行解码操作,CZ代码Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Player player = Manager.createPlayer(is,"audio/x-wav");
其中W一个参Cؓ(f)对象,W二个参Cؓ(f)声音文g的格式?br /> (tng) 3、播攑֣韟?br /> 使用Player对象的startҎ(gu)Q可以将声音播放出来Q示例代码:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) player.start()Q?br /> 在播攑֣x(chng)也可以设定声x(chng)攄ơ数Q可以用PlayercM的setLoopCountҎ(gu)来实玎ͼ具体可查阅API文档?br /> 下面是在NOKIA S60模拟器中试通过。代码如下:(x)
package sound;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import java.io.*;
public class SoundMIDlet extends MIDlet
{
private Player player = null;
/** Constructor */
public SoundMIDlet()
(tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) player = Manager.createPlayer(is,"audio/x-wav");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(IOException e)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("1:" + e);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(MediaException e)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("2:" + e);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception e)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("3:" + e);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) /** Main method */
(tng) (tng) (tng) (tng) (tng) public void startApp()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if(player != null)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) player.start();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(MediaException e)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("4:" + e);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) /** Handle pausing the MIDlet */
(tng) (tng) (tng) (tng) (tng) (tng) public void pauseApp()
(tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) /** Handle destroying the MIDlet */
(tng) (tng) (tng) (tng) (tng) (tng) public void destroyApp(boolean unconditional)
(tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) }
}
十五、J2ME 3D~程的一些资?br /> 随着J2ME技术的发展Q以?qing)硬仉度的提升,3D游戏E序慢慢的变成LQ最q想学习(fn)q一块的~程Q所以收集了(jin)一些资料,和大家一起分享:(x)
1、JSR184
JSR184是Nokia公司赯的一个关?D API的规范,下蝲地址为:(x)
http://www.forum.nokia.com/main/1,,1_0_10,00.html#jsr184
2、Nokia?D~程资料
http://www.forum.nokia.com/main/1,6566,21,00.html
3?D引擎
一个简单的开放源代码?D游戏引擎
http://www.j2me.com.cn/Soft_Show.asp?SoftID=19
国内一个合作开?D引擎的项目:(x)
http://gceclub.sun.com.cn/NASApp/sme/jive/thread.jsp?forum=11&thread=8593
4、一?D游戏产品
http://games.sina.com.cn/newgames/2004/04/040217696.shtml
5、支?D的开发工?br /> 当前一些高端的手机支持3D开发,支持3D开发的开发工具中Q通用的有SUN的J2MEWTK2.2。专用的是厂商提高的支持JSR184的SDK?/p>
十六?D~程——第一?DE序
参考WTK2.2提供的demoQ完成了(jin)W一?DE序Q虽然很单,而且有些问题q(sh)是很清楚Q还是把代码׃n出来和愿意学?fn)J2ME 3D~程的朋友一起学?fn)?br /> 关于代码的编译和q行说明如下Q?br /> 1、以下代码在J2ME WTK2.2下面~译通过?br /> 2、代码分Z个文Ӟ(x)First3DCanvas.java和First3DMIDlet.java?br /> 3、用J2ME WTK2.2建立新的工程Q主MIDletcMؓ(f)Qfirst3d. First3DMIDlet
4、将代码保存在你的工E目录下的first3d目录下?br /> 5、将J2ME WTK安装目录下的apps\Demo3D\res\com\superscape\m3g\wtksamples\retainedmode\content目录中的swerve.m3g文g复制C的工E目录下的res目录下?br /> 6、你的工E徏立后Q设|工E,通过WTK界面中的“设|”按钮打开讄H口Q在“API选择”中Q设|“目标^台”ؓ(f)Q自定义Q“简档”ؓ(f)“MIDP2.0”;“配|”ؓ(f)“CLDC1.1”;选中“Mobile 3D Graphics for J2ME(JSR184)”?br /> 7、这样你可以编译和q行以下代码?jin)?br /> 源代码如下:(x)
// First3DMIDlet.java
package first3d;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class First3DMIDlet extends MIDlet
{
(tng) (tng) (tng) (tng) (tng) private First3DCanvas displayable = new First3DCanvas();
(tng) (tng) (tng) (tng) (tng) public void startApp()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Display.getDisplay(this).setCurrent(displayable);
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) public void pauseApp() {}
(tng) (tng) (tng) (tng) (tng) public void destroyApp(boolean unconditional) {}
}
// First3Dcanvas.java
package first3d;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import java.util.*;
/**
* W一?DE序
*/
public class First3DCanvas extends Canvas implements Runnable
{
(tng) (tng) (tng) (tng) (tng) /**World对象*/
(tng) (tng) (tng) (tng) (tng) private World myWorld = null;
(tng) (tng) (tng) (tng) (tng) /**Graphics3D对象*/
(tng) (tng) (tng) (tng) (tng) private Graphics3D g3d = Graphics3D.getInstance();
(tng) (tng) (tng) (tng) (tng) /**Camera对象*/
(tng) (tng) (tng) (tng) (tng) private Camera cam = null;
(tng) (tng) (tng) (tng) (tng) private int viewport_x;
(tng) (tng) (tng) (tng) (tng) private int viewport_y;
(tng) (tng) (tng) (tng) (tng) private int viewport_width;
(tng) (tng) (tng) (tng) (tng) private int viewport_height;
(tng) (tng) (tng) (tng) (tng) private long worldStartTime = 0;
(tng) (tng) (tng) (tng) (tng) //重绘旉
(tng) (tng) (tng) (tng) (tng) private int validity = 0;
(tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) public First3DCanvas()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //启动重绘界面的线E?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Thread thread = new Thread(this);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) thread.start();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //导入3D囄
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) myWorld = (World) Loader.load("/swerve.m3g")[0];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_x = 0;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_y = 0;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_width = getWidth();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_height = getHeight();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cam = myWorld.getActiveCamera();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //讄cam对象
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) float[] params = new float[4];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int type = cam.getProjection(params);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (type != Camera.GENERIC)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //calculate window aspect ratio
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) float waspect = viewport_width / viewport_height;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (waspect < params[1])
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) float height = viewport_width / params[1];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_height = (int) height;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_y = (getHeight() - viewport_height) / 2;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) float width = viewport_height * params[1];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_width = (int) width;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) viewport_x = (getWidth() - viewport_width) / 2;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) worldStartTime = System.currentTimeMillis();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch (Exception e) {}
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) protected void paint(Graphics g)
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //清除背景
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g.setColor(0x00);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g.fillRect(0, 0, getWidth(), getHeight());
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //?D对象l定
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g3d.bindTarget(g);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g3d.setViewport(viewport_x, viewport_y, viewport_width, viewport_height);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) long startTime = System.currentTimeMillis() - worldStartTime;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) validity = myWorld.animate((int)startTime);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g3d.render(myWorld);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) finally
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g3d.releaseTarget();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) public void run()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while(true)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //重绘囑Ş
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) repaint(viewport_x, viewport_y, viewport_width, viewport_height);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception e){}
(tng) (tng) (tng) (tng) (tng) }
}
十七、在J2ME|络~程中用CMWAP代理
在中国移动提供的|络q接中,分ؓ(f)CMNET和CMWAP两种Q其中CMNET可以无限制的讉K互联|络Q资Ҏ(gu)较贵。CMWAPcM一个HTTP的代码,只能讉K支持HTTP的应用,但是资费便宜Q稳定性比较差?br /> 在实际的J2ME|络~程中,一般需要提供以CMWAP代理的方式连接网l,在J2ME中,q接的代码和直接q接有所不同Q代码如下:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) HttpConnection http = (HttpConnection)Connector.open((");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) http.setRequestProperty("X-Online-Host",ServerName);
例如你需要访问的地址为:(x)http://www.test.com/login/loginServlet则上面的代码׃ؓ(f)Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) HttpConnection http = (HttpConnection)Connector.open((" (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) http.setRequestProperty("X-Online-Host"," 在实际用过E中Q只需要用实际需要访问的地址的域名或者IP来代替ServerNameQ例如示例中的“www.test.com”,使用后箋(hu)的地址cM替代码中的urlQ例如示例中的“login/loginServlet”,可以实际的使用CMWAP代理来进行连接了(jin)?/p>
十八、J2ME中的旉处理全攻?br /> 旉处理在程序开发中相当常见Q下面对于时间处理做一个简单的说明?br /> 一、时间的表达方式
旉在J2ME中有两种表达方式Q?br /> 1、以和GMT1970q??号午?2点和现在相差的毫U数来代?br /> q种方式适合比较两个旉之间的差倹{?br /> 2、以对象的Ş式来表达
二、时间处理的相关c?br /> 旉处理在J2ME中涉?qing)三个类Q?br /> 1、Systemc?br /> long time = System. currentTimeMillis();
使用该方法可以获得当前时_(d)旉的表达方式ؓ(f)上面提到的第一U?br /> 2、Datec?br /> Date date = new Date();
获得当前旉Q用对象的形式来进行表达?br /> 3、Calendarc?br /> Calendar calendar = Calendar. getInstance();
三、时间处理的具体操作
1、以上三U表达方式的转换Q?br /> a)Systemc获得的旉转换为Date对象
Date date = new Date(System. currentTimeMillis());
b)Datecd的对象{换ؓ(f)Calendarcd的对?br /> Calendar calendar = Calendar. getInstance();
Date date = new Date();
calendar.setTime(date);
2、用Calendar完成一些日期操作:(x)
Calendar是时间处理中最常用也是功能最强大的类Q可以用它来获得某个旉的日期、星期几{信息?br /> 获得日期Q?br /> Calendar calendar = Calendar. getInstance();
…?br /> int day = calendar.get(Calendar. DATE);
获得日期、年份、星期的操作和这个类伹{?br /> 需要注意的是:(x)Calendar中表C月份的数字和实际相?Q即1月用数字0表示Q?月用数字1表示Q…?2月用数字11表示?/p>
十九(ji)、J2ME中随机数字处理全ȝ
在程序中生成随机数字Q用处比较,如h工智能领域等{,q里对于在J2ME中生成随机数的操作进行一个简单的整理Q希望对大家能有帮助?br /> J2ME和J2SE不同Q不能用Mathcȝrandom来生成随机数字,只能使用java.util包的RandomcL生成随机数字?br /> 1、创建Randomcd的对象:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Random random = new Random();
Random random = new Random(10010010);
以上两种是创建Random对象的方式,W一U用默认构造方法,和以下的代码作用完全{h(hun)Q?br /> Random random = new Random(System. currentTimeMillis());
相当与用当前时间作为种子数字来q行创徏?br /> W二U方式通过自己来指定种子数字来q行创徏?br /> 大家可以Ҏ(gu)需要用以上两U方式的MU?br /> 2、生成随机数字:(x)
创徏好了(jin)随机对象以后Q我们就可以来生成随机数字了(jin)Q?br /> 生成随机整数Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int k = random.nextInt();
(tng) (tng) (tng) (tng) (tng) (tng) 生成随机长整敎ͼ(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) long l = random.nextLong();
3、生成指定范围的数字Q?br /> 例如生成0-10之间的随机数字:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int k = random.nextInt();
int j = Math.abs(k % 10);
首先生成一个随机整数kQ然后用k?0取余Q最后用MathcȝabsҎ(gu)取绝对|获得0-10之间的随机数字?br /> 获得0-15之间的随机数Q类|(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int k = random.nextInt();
int j = Math.abs(k % 15);
获得10-20之间的随机数字:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int k = random.nextInt();
int j = Math.abs(k % 10) + 10;
二十、在J2ME手机~程中用字?br /> 在J2ME手机~程中,可以通过使用字体cZ—Font在低U用L(fng)面中Q获得更好的表现效果Q那么如何用FontcdQ?br /> 首先Q由于手备的限制Q手Z支持的字体类型很有限Q所以在J2ME中只能用手机支持的默认字体来构造Fontcd象。下面是创徏Fontcȝ对象时用的Ҏ(gu)Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) getFont(int face,int style,int size);
例如Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Font font = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD,Font. SIZE_MEDIUM);
无论哪一个参敎ͼ都只能用系l设|的数|q些数值具体的大小在不同的手机上可能不同。下面对于其中的三个参数的取值做详细的介l:(x)
face参数指字体的外观Q其的取|(x)
FACE_MONOSPACE——等宽字?br /> FACE_PROPORTIONAL——均衡字?br /> FACE_SYSTEM——系l字?br /> style参数指字体的样式Q其的取|(x)
STYLE_BOLD——粗?br /> STYLE_ITALIC——斜?br /> STYLE_PLAIN——普?br /> STYLE_UNDERLINED——下划线
STYLE_BOLD | STYLE_ITALIC——粗斜体
STYLE_UNDERLINED | STYLE_BOLD——带下划U粗?br /> STYLE_UNDERLINED | STYLE_ITALIC——带下划U斜?br /> STYLE_UNDERLINED | STYLE_ITALIC | STYLE_BOLD——带下划U的_斜?br /> size参数指字体的大小Q其的取|(x)
SIZE_SMALL——小
SIZE_MEDIUM——中
SIZE_LARGE——大
通过上面的参数的|可以l合Z需要的字体对象?br /> 下面是一些常用的字体操作Q?br /> 1. 获得pȝ的默认字体:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Font font = Font.getDefaultFont();
2. 在panitҎ(gu)内部Q假设Graphics参数的名UCؓ(f)gQ则获得当前字体的方法是Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Font font = g.getFont();
3. 在panitҎ(gu)内部Q假设Graphics参数的名UCؓ(f)gQ则讄当前字体的方法是Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g.setFont(font);
其中fontZ构造好的字体对象?br /> 4. 在MIDP2.0中,List可以讄每行的字体格式,Ҏ(gu)是:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) list.setFont(0,font);
则上面的代码是将list中的W一行设|ؓ(f)fontcd的字体?/p>
二十一、在J2ME手机E序开发中使用颜色
在J2ME手机开发过E中Q需要经常用到颜色来q行l制Q增强程序的表现效果Q下面就介绍一下如何用颜艌Ӏ?br /> ׃J2ME技术比较简单,所以没有实C门的颜色c,而只是用RGB的概忉|代表颜色。这里简单介l一下RGB的概念,颜色是由U?Red)、绿(Green)、蓝(Blue)三原色组成的Q所以可以用这三个颜色的组合来代表一U具体的颜色Q其中R、G、B的每个数值都位于0-255之间。在表达颜色的时候,卛_以用三个数字来表达Q也可以使用一个格式如0X00RRGGBBq样格式的十六进制来表达Q下面是常见颜色的表辑Ş式:(x)
U色Q?255,0,0)?x00FF0000
l色Q?0,255,0)?x0000FF00
蓝色Q?255,255,255)?x00FFFFFF
其他颜色也可以通过上面的方式组合出来?br /> 知道?jin)颜色的表达方式以后Q下面来介绍一下如何在J2MEE序中用颜Ԍ涉及(qing)的方法均在GraphicscMQ有以下几个Q?br /> 1.getColor()Q?br /> 获得当前使用的颜Ԍq回值是0x00RRGGBB格式的数字。例如:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int color = g.getColor();
其中g为Graphicscd的对象?br /> 2.setColor(int RGB)Q?br /> 讄使用的颜艌Ӏ例如:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g.setColor(0x00ff0000);
3.setColor(int red, int green, int blue)
和上面的Ҏ(gu)作用一P例如Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) g.setColor(255,0,0);
在设|了(jin)Graphics使用的颜色以后,再进行绘制的时候,可以绘制指定的颜色?jin)?/p>
二十二、在J2ME联网应用中获得客L(fng)的手机号?br /> 在J2MEE序开发过E中Qؓ(f)?jin)一定的需要,l常需要来获得用户的手机号码,但是q个功能却在标准的J2MEcd中没有提供?br /> 在用中国移动的CMWAP方式q接|络Ӟ中国Ud?x)将用户的手机号码放在一个名UCؓ(f)x-up-calling-line-id的头信息中,可以通过d该头信息Q获得用L(fng)手机L(fng)Q具体代码如下:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String usermphone = http.getHeader("x-up-calling-line-id");
其中h(hun)ttp是HttpConnctioncd的对象?/p>
二十三、用J2ME发送手机短信息
在程序中Q发送短信息的方式一般有三种Q?br /> 1?使用E序在网l上发送短信息Q例如各大网站的短信业务。这U方式是通过E序信息发送给q营商的|关服务器,然后通过q营商的|络发送给手机?br /> 2?在计机中,通过数据U连接到手机Q然后通过手机来发送短信息。这U方式是通过使用AT指o(h)来实现。爱立信手机的AT指o(h)你可以在以下地址扑ֈQ?a >http://mobilityworld.ericsson.com.cn/development/download_hit.asp
3?通过在手Zq行的程序来发送短信息。这个正是本文实现的方式?br /> 在J2ME中,如果惛_送短信息Q需要用WMA包,MIDP2.0中已l包含,MIDP1.0中可以通过厂商提供的扩展API实现Q和W(xu)MA的类库基本一栗?br /> (tng) (tng) (tng) (tng) (tng) (tng) 下面是用WMA向指定手机号码发送短信息的一个方法,很简单。当然WMA也提供了(jin)其他的方式来发送更多的内容?/p>
// SMSUtil.java
package my.util;
import javax.wireless.messaging.*;
import javax.microedition.io.*;
/**
* 发送文本短信息的方?br />*/
public class SMSUtil
{
(tng) (tng) (tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) (tng) * l指定号码发送短信息
(tng) (tng) (tng) (tng) (tng) * @param content 短信息内?br /> (tng) (tng) (tng) (tng) (tng) * @param phoneNumber 手机L(fng)
(tng) (tng) (tng) (tng) (tng) * @return 发送成功返回trueQ否则返回false
(tng) (tng) (tng) (tng) (tng) */
(tng) (tng) (tng) (tng) (tng) public static boolean send(String content,String phoneNumber)
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //q回?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) boolean result = true;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //地址
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String address = "sms://+" + phoneNumber;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //建立q接
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) MessageConnection conn = (MessageConnection)Connector.open(address);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //讄短信息类型ؓ(f)文本Q短信息有文本和二进制两U类?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) TextMessage msg = (TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //讄信息内容
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) msg.setPayloadText(content);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //发?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) conn.send(msg);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception e)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) result = false;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //未处?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return result;
(tng) (tng) (tng) (tng) (tng) }
}
二十四、用简单的J2MEE序试MIDlet的生命周?br /> 在MIDletE序学习(fn)中,生命周期是一个比较抽象的概念。其实生命周期就是一个简单的规定Q规定了(jin)MIDlet中的每个Ҏ(gu)Q什么时候被pȝ调用。下面是一个示例代码,在每个方法的内部都输Z条语句,可以Ҏ(gu)E序的输出结果来验证各方法被调用的顺序,具体代码如下Q?/p>
//文g名:(x)LifeCircleMIDlet.java
import javax.microedition.midlet.*;
/**
* 试MIDlet的生命周?br />*/
public class LifeCircleMIDlet extends MIDlet
{
(tng) (tng) (tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) (tng) * 默认构造方?br /> (tng) (tng) (tng) (tng) (tng) */
(tng) (tng) (tng) (tng) (tng) public LifeCircleMIDlet()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("默认构造方?);
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) (tng) * 启动Ҏ(gu)
(tng) (tng) (tng) (tng) (tng) */
(tng) (tng) (tng) (tng) (tng) public void startApp()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("startAppҎ(gu)");
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) (tng) * 暂停Ҏ(gu)
(tng) (tng) (tng) (tng) (tng) */
(tng) (tng) (tng) (tng) (tng) public void pauseApp()
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("pauseAppҎ(gu)");
(tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) (tng) * 销毁方?br /> (tng) (tng) (tng) (tng) (tng) * @param b
(tng) (tng) (tng) (tng) (tng) */
(tng) (tng) (tng) (tng) (tng) public void destroyApp(boolean b)
(tng) (tng) (tng) (tng) (tng) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("destroyAppҎ(gu)");
(tng) (tng) (tng) (tng) (tng) }
}
在J2WTK中运行该E序Ӟ可以使用览器中的“MIDlet”菜单中的暂停和恢复菜单Q模拟暂停事件?/p>
二十五、用OTA来发布你的程?br /> 众所周知QJ2MEE序发布的Ş式主要有QOTA、数据线传输、红外和蓝牙传输{。这里简单说说如何通过OTA来发布你的程序?br /> OTA是Over The Air的简写,也就是通过|络下蝲Q这是主要的发布形式之一。现在的癑֮都是采用这UŞ式?br /> 使用OTA来发布程序,需要如下几个步骤:(x)
1、在你的WEB服务器上d对于jad和jar文g的MIME支持?br /> 后缀?jad
MIMEcd:text/vnd.sun.j2me.app-descriptor
后缀?jar
MIMEcd:application/java-archive
2、发布WML面Q?br /> 例如你的jar文g名test.jadQ则最单的下蝲面是:(x)
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN"
" <wml>
<card id="card1" title="Download Midlet">
<a href="test.jad">test</a>
</card>
</wml>
你可以将以上代码保存在WEB服务器上Q例如保存(sh)ؓ(f)text.wml
3、修改jad文gQ?br /> 在jad文g中增加 MIDlet-Jar-URL: http://domain/directory/test.jar
其中?a href="http://domain/directory/test.jar">http://domain/directory/test.jarZ的jar文g的\径?br /> l过上面的设|,你就可以你的wml面路径作ؓ(f)你的WAP下蝲面发布?jin)。用户只需要在手机上输入这个\径就可以讉K和下载你的程序了(jin)?br />作者BlogQ?/strong>http://blog.csdn.net/Mailbomb/