Uploaded by Hoang Le

LivroProgrammingAndroid

advertisement
Download from Wow! eBook <www.wowebook.com>
Programming Android
Programming Android
=LJXUG0HGQLHNV/DLUG'RUQLQ*%ODNH0HLNH
DQG0DVXPL1DNDPXUD
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
Programming Android
E\=LJXUG0HGQLHNV/DLUG'RUQLQ*%ODNH0HLNHDQG0DVXPL1DNDPXUD
&RS\ULJKW‹=LJXUG0HGQLHNV/DLUG'RUQLQ*%ODNH0HLNHDQG0DVXPL1DNDPXUD$OOULJKWV
UHVHUYHG
3ULQWHGLQWKH8QLWHG6WDWHVRI$PHULFD
3XEOLVKHGE\2¦5HLOO\0HGLD,QF*UDYHQVWHLQ+LJKZD\1RUWK6HEDVWRSRO&$
2¦5HLOO\ERRNVPD\EHSXUFKDVHGIRUHGXFDWLRQDOEXVLQHVVRUVDOHVSURPRWLRQDOXVH2QOLQHHGLWLRQV
DUHDOVRDYDLODEOHIRUPRVWWLWOHV KWWSP\VDIDULERRNVRQOLQHFRP )RUPRUHLQIRUPDWLRQFRQWDFWRXU
FRUSRUDWHLQVWLWXWLRQDOVDOHVGHSDUWPHQW RUFRUSRUDWH#RUHLOO\FRP
Editors: $QG\2UDPDQG%ULDQ-HSVRQ
Indexer: /XFLH+DVNLQV
Production Editor: $GDP=DUHPED
Cover Designer: .DUHQ0RQWJRPHU\
Copyeditor: $XGUH\'R\OH
Interior Designer: 'DYLG)XWDWR
Technical Editors: 9LMD\6<HOODSUDJDGDDQG-RKDQ Illustrator: 5HEHFFD'HPDUHVW
YDQGHU+RHYHQ
Proofreader: 6DGD3UHLVFK
Printing History:
-XO\
)LUVW(GLWLRQ
1XWVKHOO+DQGERRNWKH1XWVKHOO+DQGERRNORJRDQGWKH2¦5HLOO\ORJRDUHUHJLVWHUHGWUDGHPDUNVRI
2¦5HLOO\0HGLD,QF3URJUDPPLQJ$QGURLGWKHLPDJHRIDSLQHJURVEHDNDQGUHODWHGWUDGHGUHVVDUH
WUDGHPDUNVRI2¦5HLOO\0HGLD,QF
0DQ\RIWKHGHVLJQDWLRQVXVHGE\PDQXIDFWXUHUVDQGVHOOHUVWRGLVWLQJXLVKWKHLUSURGXFWVDUHFODLPHGDV
WUDGHPDUNV:KHUHWKRVHGHVLJQDWLRQVDSSHDULQWKLVERRNDQG2¦5HLOO\0HGLD,QFZDVDZDUHRID
WUDGHPDUNFODLPWKHGHVLJQDWLRQVKDYHEHHQSULQWHGLQFDSVRULQLWLDOFDSV
:KLOHHYHU\SUHFDXWLRQKDVEHHQWDNHQLQWKHSUHSDUDWLRQRIWKLVERRNWKHSXEOLVKHUDQGDXWKRUVDVVXPH
QRUHVSRQVLELOLW\IRUHUURUVRURPLVVLRQVRUIRUGDPDJHVUHVXOWLQJIURPWKHXVHRIWKHLQIRUPDWLRQFRQ
WDLQHGKHUHLQ
,6%1
>/6,@
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Part I. Tools and Basics
1. Your Toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
,QVWDOOLQJWKH$QGURLG6'.DQG3UHUHTXLVLWHV
7KH-DYD'HYHORSPHQW.LW -'.
7KH(FOLSVH,QWHJUDWHG'HYHORSPHQW(QYLURQPHQW ,'(
7KH$QGURLG6'.
$GGLQJ%XLOG7DUJHWVWRWKH6'.
7KH$QGURLG'HYHORSPHQW7RRONLW $'7 3OXJLQIRU(FOLSVH
7HVW'ULYH&RQILUP7KDW<RXU,QVWDOODWLRQ:RUNV
0DNLQJDQ$QGURLG3URMHFW
0DNLQJDQ$QGURLG9LUWXDO'HYLFH $9'
5XQQLQJD3URJUDPRQDQ$9'
5XQQLQJD3URJUDPRQDQ$QGURLG'HYLFH
7URXEOHVKRRWLQJ6'.3UREOHPV1R%XLOG7DUJHWV
&RPSRQHQWVRIWKH6'.
7KH$QGURLG'HEXJ%ULGJH DGE
7KH'DOYLN'HEXJ0RQLWRU6HUYHU ''06
&RPSRQHQWVRIWKH$'7(FOLSVH3OXJLQ
$QGURLG9LUWXDO'HYLFHV
2WKHU6'.7RROV
.HHSLQJ8SWR'DWH
.HHSLQJWKH$QGURLG6'.8SWR'DWH
.HHSLQJ(FOLSVHDQGWKH$'73OXJLQ8SWR'DWH
.HHSLQJWKH-'.8SWR'DWH
([DPSOH&RGH
6'.([DPSOH&RGH
([DPSOH&RGHIURP7KLV%RRN
2Q5HDGLQJ&RGH
v
2. Java for Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
$QGURLG,V5HVKDSLQJ&OLHQW6LGH-DYD
7KH-DYD7\SH6\VWHP
3ULPLWLYH7\SHV
2EMHFWVDQG&ODVVHV
2EMHFW&UHDWLRQ
7KH2EMHFW&ODVVDQG,WV0HWKRGV
2EMHFWV,QKHULWDQFHDQG3RO\PRUSKLVP
)LQDODQG6WDWLF'HFODUDWLRQV
$EVWUDFW&ODVVHV
,QWHUIDFHV
([FHSWLRQV
7KH-DYD&ROOHFWLRQV)UDPHZRUN
*DUEDJH&ROOHFWLRQ
6FRSH
-DYD3DFNDJHV
$FFHVV0RGLILHUVDQG(QFDSVXODWLRQ
,GLRPVRI-DYD3URJUDPPLQJ
7\SH6DIHW\LQ-DYD
8VLQJ$QRQ\PRXV&ODVVHV
0RGXODU3URJUDPPLQJLQ-DYD
%DVLF0XOWLWKUHDGHG&RQFXUUHQW3URJUDPPLQJLQ-DYD
6\QFKURQL]DWLRQDQG7KUHDG6DIHW\
7KUHDG&RQWUROZLWKZDLW DQGQRWLI\ 0HWKRGV
6\QFKURQL]DWLRQDQG'DWD6WUXFWXUHV
3. The Ingredients of an Android Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7UDGLWLRQDO3URJUDPPLQJ0RGHOV&RPSDUHGWR$QGURLG
$FWLYLWLHV,QWHQWVDQG7DVNV
2WKHU$QGURLG&RPSRQHQWV
6HUYLFH
&RQWHQW3URYLGHUV
%URDGFDVW5HFHLYHU
6WDWLF$SSOLFDWLRQ5HVRXUFHVDQG&RQWH[W
$SSOLFDWLRQ0DQLIHVWV
$7\SLFDO6RXUFH7UHH
,QLWLDOL]DWLRQ3DUDPHWHUVLQ$QGURLG0DQLIHVW[PO
5HVRXUFHV
7KH$QGURLG$SSOLFDWLRQ5XQWLPH(QYLURQPHQW
7KH'DOYLN90
=\JRWH)RUNLQJD1HZ3URFHVV
6DQGER[LQJ3URFHVVHVDQG8VHUV
&RPSRQHQW/LIH&\FOHV
vi | Table of Contents
7KH$FWLYLW\/LIH&\FOH
3DFNDJLQJDQ$QGURLG$SSOLFDWLRQ7KHDSN)LOH
2Q3RUWLQJ6RIWZDUHWR$QGURLG
4. Getting Your Application into Users’ Hands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
$SSOLFDWLRQ6LJQLQJ
3XEOLF.H\(QFU\SWLRQDQG&U\SWRJUDSKLF6LJQLQJ
+RZ6LJQDWXUHV3URWHFW6RIWZDUH8VHUV3XEOLVKHUVDQG
6HFXUH&RPPXQLFDWLRQV
6LJQLQJDQ$SSOLFDWLRQ
3ODFLQJDQ$SSOLFDWLRQIRU'LVWULEXWLRQLQWKH$QGURLG0DUNHW
%HFRPLQJDQ2IILFLDO$QGURLG'HYHORSHU
8SORDGLQJ$SSOLFDWLRQVLQWKH0DUNHW
*HWWLQJ3DLG
*RRJOH0DSV$3,.H\V
6SHFLI\LQJ$3,/HYHO&RPSDWLELOLW\
&RPSDWLELOLW\ZLWK0DQ\.LQGVRI6FUHHQV
7HVWLQJIRU6FUHHQ6L]H&RPSDWLELOLW\
5HVRXUFH4XDOLILHUVDQG6FUHHQ6L]HV
5. Eclipse for Android Software Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
(FOLSVH&RQFHSWVDQG7HUPLQRORJ\
3OXJLQV
:RUNVSDFHV
-DYD(QYLURQPHQWV
3URMHFWV
%XLOGHUVDQG$UWLIDFWV
([WHQVLRQV
$VVRFLDWLRQV
(FOLSVH9LHZVDQG3HUVSHFWLYHV
7KH3DFNDJH([SORUHU9LHZ
7KH7DVN/LVW9LHZ
7KH2XWOLQH9LHZ
7KH3UREOHPV9LHZ
-DYD&RGLQJLQ(FOLSVH
(GLWLQJ-DYD&RGHDQG&RGH&RPSOHWLRQ
5HIDFWRULQJ
(FOLSVHDQG$QGURLG
3UHYHQWLQJ%XJVDQG.HHSLQJ<RXU&RGH&OHDQ
6WDWLF$QDO\]HUV
$SSO\LQJ6WDWLF$QDO\VLVWR$QGURLG&RGH
/LPLWDWLRQVRI6WDWLF$QDO\VLV
(FOLSVH,GLRV\QFUDVLHVDQG$OWHUQDWLYHV
Table of Contents | vii
6. Effective Java for Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
7KH$QGURLG)UDPHZRUN
7KH$QGURLG/LEUDULHV
([WHQGLQJ$QGURLG
2UJDQL]LQJ-DYD6RXUFH
&RQFXUUHQF\LQ$QGURLG
$V\QF7DVNDQGWKH8,7KUHDG
7KUHDGVLQDQ$QGURLG3URFHVV
6HULDOL]DWLRQ
-DYD6HULDOL]DWLRQ
3DUFHODEOH
&ODVVHV7KDW6XSSRUW6HULDOL]DWLRQ
6HULDOL]DWLRQDQGWKH$SSOLFDWLRQ/LIH&\FOH
Part II. About the Android Framework
7. Building a View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
$QGURLG*8,$UFKLWHFWXUH
7KH0RGHO
7KH9LHZ
7KH&RQWUROOHU
3XWWLQJ,W7RJHWKHU
$VVHPEOLQJD*UDSKLFDO,QWHUIDFH
:LULQJ8SWKH&RQWUROOHU
/LVWHQLQJWRWKH0RGHO
/LVWHQLQJIRU7RXFK(YHQWV
/LVWHQLQJIRU.H\(YHQWV
$OWHUQDWLYH:D\VWR+DQGOH(YHQWV
$GYDQFHG:LULQJ)RFXVDQG7KUHDGLQJ
7KH0HQX
8. Fragments and Multiplatform Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
&UHDWLQJD)UDJPHQW
)UDJPHQW/LIH&\FOH
7KH)UDJPHQW0DQDJHU
)UDJPHQW7UDQVDFWLRQV
7KH&RPSDWLELOLW\3DFNDJH
9. Drawing 2D and 3D Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
5ROOLQJ<RXU2ZQ:LGJHWV
/D\RXW
&DQYDV'UDZLQJ
viii | Table of Contents
'UDZDEOHV
%LWPDSV
%OLQJ
6KDGRZV*UDGLHQWVDQG)LOWHUV
$QLPDWLRQ
2SHQ*/*UDSKLFV
10. Handling and Persisting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
5HODWLRQDO'DWDEDVH2YHUYLHZ
64/LWH
7KH64//DQJXDJH
64/'DWD'HILQLWLRQ&RPPDQGV
64/'DWD0DQLSXODWLRQ&RPPDQGV
$GGLWLRQDO'DWDEDVH&RQFHSWV
'DWDEDVH7UDQVDFWLRQV
([DPSOH'DWDEDVH0DQLSXODWLRQ8VLQJVTOLWH
64/DQGWKH'DWDEDVH&HQWULF'DWD0RGHOIRU$QGURLG$SSOLFDWLRQV
7KH$QGURLG'DWDEDVH&ODVVHV
'DWDEDVH'HVLJQIRU$QGURLG$SSOLFDWLRQV
%DVLF6WUXFWXUHRIWKH6LPSOH9LGHR'E+HOSHU&ODVV
8VLQJWKH'DWDEDVH$3,0-$QGURLG
$QGURLGDQG6RFLDO1HWZRUNLQJ
7KH6RXUFH)ROGHU VUF
/RDGLQJDQG6WDUWLQJWKH$SSOLFDWLRQ
'DWDEDVH4XHULHVDQG5HDGLQJ'DWDIURPWKH'DWDEDVH
0RGLI\LQJWKH'DWDEDVH
Part III. A Skeleton Application for Android
11. A Framework for a Well-Behaved Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
9LVXDOL]LQJ/LIH&\FOHV
9LVXDOL]LQJWKH$FWLYLW\/LIH&\FOH
9LVXDOL]LQJWKH)UDJPHQW/LIH&\FOH
7KH$FWLYLW\&ODVVDQG:HOO%HKDYHG$SSOLFDWLRQV
7KH$FWLYLW\/LIH&\FOHDQGWKH8VHU([SHULHQFH
/LIH&\FOH0HWKRGVRIWKH$SSOLFDWLRQ&ODVV
$)ORZLQJDQG,QWXLWLYH8VHU([SHULHQFH$FURVV$FWLYLWLHV
0XOWLWDVNLQJLQD6PDOO6FUHHQ(QYLURQPHQW
7DVNVDQG$SSOLFDWLRQV
6SHFLI\LQJ/DXQFKDQG7DVN%HKDYLRU
Table of Contents | ix
12. Using Content Providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
8QGHUVWDQGLQJ&RQWHQW3URYLGHUV
,PSOHPHQWLQJD&RQWHQW3URYLGHU
%URZVLQJ9LGHRZLWK)LQFK
'HILQLQJD3URYLGHU3XEOLF$3,
'HILQLQJWKH&217(17B85,
&UHDWLQJWKH&ROXPQ1DPHV
'HFODULQJ&ROXPQ6SHFLILFDWLRQ6WULQJV
:ULWLQJDQG,QWHJUDWLQJD&RQWHQW3URYLGHU
&RPPRQ&RQWHQW3URYLGHU7DVNV
)LOH0DQDJHPHQWDQG%LQDU\'DWD
$QGURLG09&DQG&RQWHQW2EVHUYDWLRQ
$&RPSOHWH&RQWHQW3URYLGHU7KH6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU
&RGH
7KH6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU&ODVVDQG,QVWDQFH9DULDEOHV
,PSOHPHQWLQJWKHRQ&UHDWH0HWKRG
,PSOHPHQWLQJWKHJHW7\SH0HWKRG
,PSOHPHQWLQJWKH3URYLGHU$3,
'HWHUPLQLQJ+RZ2IWHQWR1RWLI\2EVHUYHUV
'HFODULQJ<RXU&RQWHQW3URYLGHU
13. Exploring Content Providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
'HYHORSLQJ5(67IXO$QGURLG$SSOLFDWLRQV
$£1HWZRUN09&¤
6XPPDU\RI%HQHILWV
&RGH([DPSOH'\QDPLFDOO\/LVWLQJDQG&DFKLQJ<RX7XEH
9LGHR&RQWHQW
6WUXFWXUHRIWKH6RXUFH&RGHIRUWKH)LQFK<RX7XEH9LGHR([DPSOH
6WHSSLQJ7KURXJKWKH6HDUFK$SSOLFDWLRQ
6WHS2XU8,&ROOHFWV8VHU,QSXW
6WHS2XU&RQWUROOHU/LVWHQVIRU(YHQWV
6WHS7KH&RQWUROOHU4XHULHVWKH&RQWHQW3URYLGHUZLWKDPDQDJHG4XHU\
RQWKH&RQWHQW3URYLGHU0RGHO
6WHS,PSOHPHQWLQJWKH5(67IXO5HTXHVW
&RQVWDQWVDQG,QLWLDOL]DWLRQ
&UHDWLQJWKH'DWDEDVH
$1HWZRUNHG4XHU\0HWKRG
LQVHUWDQG5HVSRQVH+DQGOHUV
)LOH0DQDJHPHQW6WRULQJ7KXPEQDLOV
x | Table of Contents
Part IV. Advanced Topics
14. Multimedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
$XGLRDQG9LGHR
3OD\LQJ$XGLRDQG9LGHR
$XGLR3OD\EDFN
9LGHR3OD\EDFN
5HFRUGLQJ$XGLRDQG9LGHR
$XGLR5HFRUGLQJ
9LGHR5HFRUGLQJ
6WRUHG0HGLD&RQWHQW
15. Location and Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
/RFDWLRQ%DVHG6HUYLFHV
0DSSLQJ
7KH*RRJOH0DSV$FWLYLW\
7KH0DS9LHZDQG0DS$FWLYLW\
:RUNLQJZLWK0DS9LHZV
0DS9LHZDQG0\/RFDWLRQ2YHUOD\,QLWLDOL]DWLRQ
3DXVLQJDQG5HVXPLQJD0DS$FWLYLW\
&RQWUROOLQJWKH0DSZLWK0HQX%XWWRQV
&RQWUROOLQJWKH0DSZLWKWKH.H\SDG
/RFDWLRQ:LWKRXW0DSV
7KH0DQLIHVWDQG/D\RXW)LOHV
&RQQHFWLQJWRD/RFDWLRQ3URYLGHUDQG*HWWLQJ/RFDWLRQ8SGDWHV
8SGDWLQJWKH(PXODWHG/RFDWLRQ
16. Sensors, NFC, Speech, Gestures, and Accessibility . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6HQVRUV
3RVLWLRQ
2WKHU6HQVRUV
1HDU)LHOG&RPPXQLFDWLRQ 1)&
5HDGLQJD7DJ
:ULWLQJWRD7DJ
330RGH
*HVWXUH,QSXW
$FFHVVLELOLW\
17. Communication, Identity, Sync, and Social Media . . . . . . . . . . . . . . . . . . . . . . . . . . 411
$FFRXQW&RQWDFWV
$XWKHQWLFDWLRQDQG6\QFKURQL]DWLRQ
$XWKHQWLFDWLRQ
Table of Contents | xi
6\QFKURQL]DWLRQ
%OXHWRRWK
7KH%OXHWRRWK3URWRFRO6WDFN
%OXH]7KH/LQX[%OXHWRRWK,PSOHPHQWDWLRQ
8VLQJ%OXHWRRWKLQ$QGURLG$SSOLFDWLRQV
18. The Android Native Development Kit (NDK) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
1DWLYH0HWKRGVDQG-1,&DOOV
&RQYHQWLRQVRQWKH1DWLYH0HWKRG6LGH
&RQYHQWLRQVRQWKH-DYD6LGH
7KH$QGURLG1'.
6HWWLQJ8SWKH1'.(QYLURQPHQW
&RPSLOLQJZLWKWKH1'.
-1,1'.DQG6'.$6DPSOH$SS
$QGURLG3URYLGHG1DWLYH/LEUDULHV
%XLOGLQJ<RXU2ZQ&XVWRP/LEUDU\0RGXOHV
1DWLYH$FWLYLWLHV
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
xii | Table of Contents
Download from Wow! eBook <www.wowebook.com>
Preface
7KHSXUSRVHRIWKLVERRNLVWRHQDEOH\RXWRFUHDWHZHOOHQJLQHHUHG$QGURLGDSSOLFD
WLRQVWKDWJREH\RQGWKHVFRSHRIVPDOOH[DPSOHDSSOLFDWLRQV
7KLVERRNLVIRUSHRSOHFRPLQJWR$QGURLGSURJUDPPLQJIURPDYDULHW\RIEDFNJURXQGV
,I\RXKDYHEHHQSURJUDPPLQJL3KRQHRU0DF26DSSOLFDWLRQVLQ2EMHFWLYH&\RXZLOO
ILQGFRYHUDJHRI$QGURLGWRROVDQG-DYDODQJXDJHIHDWXUHVUHOHYDQWWR$QGURLGSUR
JUDPPLQJWKDWZLOOKHOS\RXEULQJ\RXUNQRZOHGJHRIPRELOHDSSOLFDWLRQGHYHORSPHQW
WR$QGURLG,I\RXDUHDQH[SHULHQFHG-DYDFRGHU\RXZLOOILQGFRYHUDJHRI$QGURLG
DSSOLFDWLRQDUFKLWHFWXUHWKDWZLOOHQDEOH\RXWRXVH\RXU-DYDH[SHUWLVHLQWKLVQHZO\
YLEUDQWZRUOGRIFOLHQW-DYDDSSOLFDWLRQGHYHORSPHQW,QVKRUWWKLVLVDERRNIRUSHRSOH
ZLWKVRPHUHOHYDQWH[SHULHQFHLQREMHFWRULHQWHGODQJXDJHVPRELOHDSSOLFDWLRQV5(67
DSSOLFDWLRQVDQGVLPLODUGLVFLSOLQHVZKRZDQWWRJRIXUWKHUWKDQDQLQWURGXFWRU\ERRN
RURQOLQHWXWRULDOVZLOOWDNHWKHP
How This Book Is Organized
:HZDQWWRJHW\RXRIIWRDIDVWVWDUW7KHFKDSWHUVLQWKHILUVWSDUWRIWKLVERRNZLOO
VWHS\RXWKURXJKXVLQJWKH6'.WRROVVRWKDW\RXFDQDFFHVVH[DPSOHFRGHLQWKLVERRN
DQGLQWKH6'.HYHQDV\RXH[SDQG\RXUNQRZOHGJHRI6'.WRROV-DYDDQGGDWDEDVH
GHVLJQ7KHWRROVDQGEDVLFVFRYHUHGLQWKHILUVWSDUWPLJKWEHIDPLOLDUHQRXJKWR\RX
WKDW\RXZRXOGZDQWWRVNLSWR3DUW,,ZKHUHZHEXLOGIRXQGDWLRQDONQRZOHGJHIRU
GHYHORSLQJODUJHU$QGURLGDSSOLFDWLRQV
7KHFHQWUDOSDUWRIWKLVERRNLVDQH[DPSOHRIDQDSSOLFDWLRQWKDWXVHVZHEVHUYLFHVWR
GHOLYHULQIRUPDWLRQWRWKHXVHU¢VRPHWKLQJPDQ\DSSOLFDWLRQVKDYHDWWKHLUFRUH:H
SUHVHQWDQDSSOLFDWLRQDUFKLWHFWXUHDQGDQRYHODSSURDFKWRXVLQJ$QGURLG¦VIUDPH
ZRUNFODVVHVWKDWHQDEOHV\RXWRGRWKLVSDUWLFXODUO\HIILFLHQWO\<RXZLOOEHDEOHWRXVH
WKLVDSSOLFDWLRQDVDIUDPHZRUNIRUFUHDWLQJ\RXURZQDSSOLFDWLRQVDQGDVDWRROIRU
OHDUQLQJDERXW$QGURLGSURJUDPPLQJ
,QWKHILQDOSDUWRIWKLVERRNZHH[SORUH$QGURLG$3,VLQVSHFLILFDSSOLFDWLRQDUHDV
PXOWLPHGLDORFDWLRQVHQVRUVDQGFRPPXQLFDWLRQDPRQJRWKHUVLQRUGHUWRHTXLS
\RXWRSURJUDPDSSOLFDWLRQVLQ\RXUVSHFLILFDUHDRILQWHUHVW
xiii
%\WKHWLPH\RXUHDFKWKHHQGRIWKLVERRNZHZDQW\RXWRKDYHJDLQHGNQRZOHGJH
EH\RQGUHIHUHQFHPDWHULDODQGDZDONWKURXJKRIH[DPSOHV:HZDQW\RXWRKDYHD
SRLQWRIYLHZRQKRZWRPDNHJUHDW$QGURLGDSSOLFDWLRQV
Conventions Used in This Book
7KHIROORZLQJW\SRJUDSKLFDOFRQYHQWLRQVDUHXVHGLQWKLVERRN
,WDOLF
,QGLFDWHVQHZWHUPV85/VHPDLODGGUHVVHVILOHQDPHVDQGILOHH[WHQVLRQV
Constant width
8VHGIRUSURJUDPOLVWLQJVDVZHOODVZLWKLQSDUDJUDSKVWRUHIHUWRSURJUDPHOHPHQWV
VXFKDVYDULDEOHRUIXQFWLRQQDPHVGDWDEDVHVGDWDW\SHVHQYLURQPHQWYDULDEOHV
VWDWHPHQWVDQGNH\ZRUGV
Constant width bold
6KRZVFRPPDQGVRURWKHUWH[WWKDWVKRXOGEHW\SHGOLWHUDOO\E\WKHXVHU
Constant width italic
6KRZVWH[WWKDWVKRXOGEHUHSODFHGZLWKXVHUVXSSOLHGYDOXHVRUE\YDOXHVGHWHU
PLQHGE\FRQWH[W
7KLVLFRQVLJQLILHVDWLSVXJJHVWLRQRUJHQHUDOQRWH
7KLVLFRQLQGLFDWHVDZDUQLQJRUFDXWLRQ
Using Code Examples
7KLVERRNLVKHUHWRKHOS\RXJHW\RXUMREGRQH,QJHQHUDO\RXPD\XVHWKHFRGHLQ
WKLVERRNLQ\RXUSURJUDPVDQGGRFXPHQWDWLRQ<RXGRQRWQHHGWRFRQWDFWXVIRU
SHUPLVVLRQXQOHVV\RX¦UHUHSURGXFLQJDVLJQLILFDQWSRUWLRQRIWKHFRGH)RUH[DPSOH
ZULWLQJDSURJUDPWKDWXVHVVHYHUDOFKXQNVRIFRGHIURPWKLVERRNGRHVQRWUHTXLUH
SHUPLVVLRQ6HOOLQJRUGLVWULEXWLQJD&'520RIH[DPSOHVIURP2¦5HLOO\ERRNVGRHV
UHTXLUH SHUPLVVLRQ $QVZHULQJ D TXHVWLRQ E\ FLWLQJ WKLV ERRNDQGTXRWLQJH[DPSOH
FRGHGRHVQRWUHTXLUHSHUPLVVLRQ,QFRUSRUDWLQJDVLJQLILFDQWDPRXQWRIH[DPSOHFRGH
IURPWKLVERRNLQWR\RXUSURGXFW¦VGRFXPHQWDWLRQGRHVUHTXLUHSHUPLVVLRQ
:H DSSUHFLDWH EXW GR QRW UHTXLUH DWWULEXWLRQ $Q DWWULEXWLRQ XVXDOO\ LQFOXGHV WKH
WLWOH DXWKRU SXEOLVKHU DQG ,6%1 )RU H[DPSOH £3URJUDPPLQJ $QGURLG E\ =LJXUG
xiv | Preface
0HGQLHNV/DLUG'RUQLQ*%ODNH0HLNHDQG0DVXPL1DNDPXUD&RS\ULJKW
2¦5HLOO\0HGLD,QF¤
,I\RXIHHO\RXUXVHRIFRGHH[DPSOHVIDOOVRXWVLGHIDLUXVHRUWKHSHUPLVVLRQJLYHQKHUH
IHHOIUHHWRFRQWDFWXVDWSHUPLVVLRQV#RUHLOO\FRP
Safari® Books Online
6DIDUL%RRNV2QOLQHLVDQRQGHPDQGGLJLWDOOLEUDU\WKDWOHWV\RXHDVLO\
VHDUFKPRUHWKDQWHFKQRORJ\DQGFUHDWLYHUHIHUHQFHERRNVDQGYLG
HRVWRILQGWKHDQVZHUV\RXQHHGTXLFNO\
:LWKDVXEVFULSWLRQ\RXFDQUHDGDQ\SDJHDQGZDWFKDQ\YLGHRIURPRXUOLEUDU\RQOLQH
5HDGERRNVRQ\RXUFHOOSKRQHDQGPRELOHGHYLFHV$FFHVVQHZWLWOHVEHIRUHWKH\DUH
DYDLODEOHIRUSULQWDQGJHWH[FOXVLYHDFFHVVWRPDQXVFULSWVLQGHYHORSPHQWDQGSRVW
IHHGEDFNIRUWKHDXWKRUV&RS\DQGSDVWHFRGHVDPSOHVRUJDQL]H\RXUIDYRULWHVGRZQ
ORDGFKDSWHUVERRNPDUNNH\VHFWLRQVFUHDWHQRWHVSULQWRXWSDJHVDQGEHQHILWIURP
WRQVRIRWKHUWLPHVDYLQJIHDWXUHV
2¦5HLOO\0HGLDKDVXSORDGHGWKLVERRNWRWKH6DIDUL%RRNV2QOLQHVHUYLFH7RKDYHIXOO
GLJLWDODFFHVVWRWKLVERRNDQGRWKHUVRQVLPLODUWRSLFVIURP2¦5HLOO\DQGRWKHUSXE
OLVKHUVVLJQXSIRUIUHHDWKWWSP\VDIDULERRNVRQOLQHFRP
How to Contact Us
3OHDVHDGGUHVVFRPPHQWVDQGTXHVWLRQVFRQFHUQLQJWKLVERRNWRWKHSXEOLVKHU
2¦5HLOO\0HGLD,QF
*UDYHQVWHLQ+LJKZD\1RUWK
6HEDVWRSRO&$
LQWKH8QLWHG6WDWHVRU&DQDGD
LQWHUQDWLRQDORUORFDO
ID[
:HKDYHDZHESDJHIRUWKLVERRNZKHUHZHOLVWHUUDWDH[DPSOHVDQGDQ\DGGLWLRQDO
LQIRUPDWLRQ<RXFDQDFFHVVWKLVSDJHDW
KWWSRUHLOO\FRPFDWDORJ
7RFRPPHQWRUDVNWHFKQLFDOTXHVWLRQVDERXWWKLVERRNVHQGHPDLOWR
ERRNTXHVWLRQV#RUHLOO\FRP
)RUPRUHLQIRUPDWLRQDERXWRXUERRNVFRXUVHVFRQIHUHQFHVDQGQHZVVHHRXUZHEVLWH
DWKWWSZZZRUHLOO\FRP
)LQGXVRQ)DFHERRNKWWSIDFHERRNFRPRUHLOO\
)ROORZXVRQ7ZLWWHUKWWSWZLWWHUFRPRUHLOO\PHGLD
Preface | xv
:DWFKXVRQ<RX7XEHKWWSZZZ\RXWXEHFRPRUHLOO\PHGLD
Acknowledgments
7KHDXWKRUVKDYHDGDSWHGSRUWLRQVRIWKLVERRNIURPWKHLUSUHYLRXVO\UHOHDVHGWLWOH
$QGURLG$SSOLFDWLRQ'HYHORSPHQW 2¦5HLOO\ 'UDIWVRIWKLVERRNZHUHUHOHDVHGRQWKH2¦5HLOO\2SHQ)HHGEDFN3XEOLVKLQJ6\VWHP
2)36 LQRUGHUWRJHW\RXUIHHGEDFNRQZKHWKHUDQGKRZZHDUHPHHWLQJWKHJRDOVIRU
WKLVERRN:HDUHYHU\JUDWHIXOIRUWKHUHDGHUVZKRSDUWLFLSDWHGLQ2)36DQGZHRZH
WKHPPXFKLQFRUUHFWLQJRXUHUURUVDQGLPSURYLQJRXUZULWLQJ2SHQUHYLHZRIGUDIWV
ZLOOEHSDUWRIIXWXUHHGLWLRQVDQGZHZHOFRPH\RXUYLHZVRQHYHU\DVSHFWRIWKLVERRN
xvi | Preface
PART I
Tools and Basics
3DUW,VKRZV\RXKRZWRLQVWDOODQGXVH\RXUWRROVZKDW\RXQHHGWRNQRZDERXW-DYD
WRZULWHJRRG$QGURLGFRGHDQGKRZWRGHVLJQDQGXVH64/GDWDEDVHVZKLFKDUH
FHQWUDOWRWKH$QGURLGDSSOLFDWLRQPRGHOSHUVLVWHQFHV\VWHPDQGLPSOHPHQWDWLRQRI
NH\GHVLJQSDWWHUQVLQ$QGURLGSURJUDPV
CHAPTER 1
Your Toolkit
7KLVFKDSWHUVKRZV\RXKRZWRLQVWDOOWKH$QGURLGVRIWZDUHGHYHORSPHQWNLW 6'.
DQGDOOWKHUHODWHGVRIWZDUH\RX¦UHOLNHO\WRQHHG%\WKHHQG\RX¦OOEHDEOHWRUXQD
VLPSOH£+HOOR:RUOG¤SURJUDPRQDQHPXODWRU:LQGRZV0DF26;DQG/LQX[V\V
WHPVFDQDOOEHXVHGIRU$QGURLGDSSOLFDWLRQGHYHORSPHQW:HZLOOORDGWKHVRIWZDUH
LQWURGXFH\RXWRWKHWRROVLQWKH6'.DQGSRLQW\RXWRVRXUFHVRIH[DPSOHFRGH
7KURXJKRXWWKLVERRNDQGHVSHFLDOO\LQWKLVFKDSWHUZHUHIHUWRLQVWUXFWLRQVDYDLODEOH
RQYDULRXVZHEVLWHVIRULQVWDOOLQJDQGXSGDWLQJWKHWRROV\RXZLOOXVHIRUFUHDWLQJ$Q
GURLGSURJUDPV7KHPRVWLPSRUWDQWSODFHWRILQGLQIRUPDWLRQDQGOLQNVWRWRROVLVWKH
$QGURLG'HYHORSHUVVLWH
KWWSGHYHORSHUDQGURLGFRP
2XUIRFXVLVRQJXLGLQJ\RXWKURXJKLQVWDOODWLRQZLWKH[SODQDWLRQVWKDWZLOOKHOS\RX
XQGHUVWDQGKRZWKHSDUWVRI$QGURLGDQGLWVGHYHORSHUWRROVILWWRJHWKHUHYHQDVWKH
GHWDLOVRIHDFKSDUWFKDQJH
7KHOLQNVFLWHGLQWKLVERRNPD\FKDQJHRYHUWLPH'HVFULSWLRQVDQGXSGDWHGOLQNVDUH
SRVWHGRQWKLVERRN¦VZHEVLWH<RXFDQILQGDOLQNWRWKHZHEVLWHRQWKLVERRN¦VFDWDORJ
SDJH<RXPD\ILQGLWFRQYHQLHQWWRKDYHWKHERRN¦VZHEVLWHRSHQDV\RXUHDGVRWKDW
\RXFDQFOLFNWKURXJKOLQNVRQWKHVLWHUDWKHUWKDQHQWHULQJWKH85/VSULQWHGLQWKLV
ERRN
Installing the Android SDK and Prerequisites
6XFFHVVIXOO\LQVWDOOLQJWKH$QGURLG6'.UHTXLUHVWZRRWKHUVRIWZDUHV\VWHPVWKDWDUH
QRWSDUWRIWKH$QGURLG6'.WKH-DYD'HYHORSPHQW.LW -'. DQGWKH(FOLSVHLQWHJUDWHG
GHYHORSPHQWHQYLURQPHQW ,'( 7KHVHWZRV\VWHPVDUHQRWGHOLYHUHGDVSDUWRIWKH
$QGURLG6'.EHFDXVH\RXPD\EHXVLQJWKHPIRUSXUSRVHVRXWVLGHRI$QGURLGVRIWZDUH
GHYHORSPHQWRUEHFDXVHWKH\PD\DOUHDG\EHLQVWDOOHGRQ\RXUV\VWHPDQGUHGXQGDQW
LQVWDOODWLRQVRIWKHVHV\VWHPVFDQFDXVHYHUVLRQFODVKHV
3
7KH$QGURLG6'.LVFRPSDWLEOHZLWKDUDQJHRIUHFHQWUHOHDVHVRIWKH-'.DQGWKH
(FOLSVH,'(,QVWDOOLQJWKHFXUUHQWUHOHDVHRIHDFKRIWKHVHWRROVZLOOXVXDOO\EHWKHULJKW
FKRLFH7KHH[DFWUHTXLUHPHQWVDUHVSHFLILHGRQWKH6\VWHP5HTXLUHPHQWVSDJHRIWKH
$QGURLG'HYHORSHUVVLWHKWWSGHYHORSHUDQGURLGFRPVGNUHTXLUHPHQWVKWPO
2QHFDQXVH,'(VRWKHUWKDQ(FOLSVHLQ$QGURLGVRIWZDUHGHYHORSPHQWDQGLQIRUPD
WLRQRQXVLQJRWKHU,'(VLVSURYLGHGLQWKH$QGURLGGRFXPHQWDWLRQDWKWWSGHYHORSHU
DQGURLGFRPJXLGHGHYHORSLQJRWKHULGHKWPO:HFKRVH(FOLSVHDVWKH,'(FRYHUHGLQ
WKLVERRNEHFDXVH(FOLSVHVXSSRUWVWKHJUHDWHVWQXPEHURI$QGURLG6'.WRROVDQGRWKHU
SOXJLQVDQG(FOLSVHLVWKHPRVWZLGHO\XVHG-DYD,'(EXW,QWHOOL-,'($LVDQDOWHUQDWLYH
PDQ\-DYDFRGHUVSUHIHU
The Java Development Kit (JDK)
,I\RXUV\VWHPKDVDQXSWRGDWH-'.LQVWDOOHG\RXZRQ¦WQHHGWRLQVWDOOLWDJDLQ7KH
-'.SURYLGHVWRROVVXFKDVWKH-DYDFRPSLOHUXVHGE\,'(VDQG6'.VIRUGHYHORSLQJ
-DYDSURJUDPV7KH-'.DOVRFRQWDLQVD-DYD5XQWLPH(QYLURQPHQW -5( ZKLFKHQ
DEOHV-DYDSURJUDPVVXFKDV(FOLSVHWRUXQRQ\RXUV\VWHP
,I\RXDUHXVLQJD0DFLQWRVKUXQQLQJDYHUVLRQRI0DF26;VXSSRUWHGE\WKH$QGURLG
6'.WKH-'.LVDOUHDG\LQVWDOOHG
,I\RXDUHXVLQJ8EXQWX/LQX[\RXFDQLQVWDOOWKH-'.XVLQJWKHSDFNDJHPDQDJHU
WKURXJKWKHIROORZLQJFRPPDQG
sudo apt-get install sun-java6-jdk
,IWKLVFRPPDQGUHSRUWVWKDWWKH-'.SDFNDJHLVQRWDYDLODEOH\RXPD\
QHHGWRHQDEOHWKH£SDUWQHU¤UHSRVLWRULHVXVLQJWKH6\QDSWLF3DFNDJH
0DQDJHUXWLOLW\LQWKH6\VWHPൺ$GPLQLVWUDWLRQPHQX7KH£SDUWQHU¤UH
SRVLWRULHV DUH OLVWHG RQ WKH 2WKHU 6RIWZDUH WDE DIWHU \RX FKRRVH 6HW
WLQJVൺ5HSRVLWRULHV
7KLVLVRQHRIWKHYHU\IHZSODFHVLQWKLVFKDSWHUZKHUH\RXZLOOVHHDYHUVLRQQXPEHU
DQGLWDSSHDUVKHUHRQO\EHFDXVHLWFDQ¦WEHDYRLGHG7KHYHUVLRQQXPEHURIWKH-'.LV
LQWKHSDFNDJHQDPH%XWDVZLWKDOORWKHUVRIWZDUHPHQWLRQHGLQWKLVFKDSWHU\RX
VKRXOGUHIHUWRXSWRGDWHRQOLQHGRFXPHQWDWLRQWRGHWHUPLQHWKHYHUVLRQ\RXZLOOQHHG
,I\RXDUHD:LQGRZVXVHURU\RXQHHGWRLQVWDOOWKH-'.IURP2UDFOH¦VVLWHIRUVRPH
RWKHUUHDVRQ\RXFDQILQGWKH-'.DWKWWSZZZRUDFOHFRPWHFKQHWZRUNMDYDMDYDVH
GRZQORDGVLQGH[KWPO
4 | Chapter 1:ಗYour Toolkit
7KH'RZQORDGVSDJHZLOODXWRPDWLFDOO\GHWHFW\RXUV\VWHPDQGRIIHUWRGRZQORDGWKH
FRUUHFWYHUVLRQ7KHLQVWDOOHU\RXGRZQORDGLVDQH[HFXWDEOHILOH5XQWKHH[HFXWDEOH
LQVWDOOHUILOHWRLQVWDOOWKH-'.
7RFRQILUPWKDWWKH-'.LVLQVWDOOHGFRUUHFWO\LVVXHWKLVFRPPDQGIURPWKHFRPPDQG
OLQH 7HUPLQDORQ/LQX[DQG0DF&RPPDQG3URPSWRQ:LQGRZV javac -version
,I WKH javac FRPPDQG LV QRW LQ \RXU PATH \RX PD\ QHHG WR DGG WKH
ELQGLUHFWRU\LQWKH-'.WR\RXUSDWKPDQXDOO\
,W VKRXOG GLVSOD\ WKH YHUVLRQ QXPEHU FRUUHVSRQGLQJ WR WKH YHUVLRQ RI WKH -'. \RX
LQVWDOOHG,I\RXLQVWDOOHGUHYLVLRQRIWKH-DYD-'.WKHFRPPDQGZRXOGGLVSOD\
javac 1.6.0_20
'HSHQGLQJRQWKHFXUUHQWYHUVLRQRIWKH-'.DYDLODEOHZKHQ\RXUHDGWKLVYHUVLRQ
QXPEHUVPD\GLIIHUIURPZKDW\RXVHHKHUH
,ILWLVXQFOHDUZKLFK-5(\RXDUHUXQQLQJRULI\RXWKLQN\RXKDYHWKH
ZURQJ-5(UXQQLQJRQD'HELDQGHULYHG/LQX[V\VWHPVXFKDV8EXQWX
\RXFDQXVHWKHIROORZLQJFRPPDQGWRGLVSOD\WKHDYDLODEOH-5(VDQG
VHOHFWWKHULJKWRQH
sudo update-alternatives --config java
The Eclipse Integrated Development Environment (IDE)
(FOLSVHLVDJHQHUDOSXUSRVHWHFKQRORJ\SODWIRUP,WKDVEHHQDSSOLHGWRDYDULHW\RI
XVHVLQFUHDWLQJ,'(VIRUPXOWLSOHODQJXDJHVDQGLQFUHDWLQJFXVWRPL]HG,'(VIRUPDQ\
VSHFLDOL]HG6'.VDVZHOODVWRXVHVRXWVLGHRIVRIWZDUHGHYHORSPHQWWRROVVXFKDV
SURYLGLQJD5LFK&OLHQW3ODWIRUP 5&3 IRU/RWXV1RWHVDQGDIHZRWKHUDSSOLFDWLRQV
(FOLSVHLVXVXDOO\XVHGDVDQ,'(IRUZULWLQJWHVWLQJDQGGHEXJJLQJVRIWZDUHHVSHFLDOO\
-DYDVRIWZDUH7KHUHDUHDOVRVHYHUDOGHULYDWLYH,'(VDQG6'.VIRUYDULRXVNLQGVRI-DYD
VRIWZDUHGHYHORSPHQWEDVHGRQ(FOLSVH,QWKLVFDVH\RXZLOOWDNHDZLGHO\XVHG(FOLSVH
SDFNDJHDQGDGGDSOXJLQWRLWWRPDNHLWXVDEOHIRU$QGURLGVRIWZDUHGHYHORSPHQW
/HW¦VJHWWKDW(FOLSVHSDFNDJHDQGLQVWDOOLW
(FOLSVHFDQEHGRZQORDGHGIURPKWWSZZZHFOLSVHRUJGRZQORDGV
<RXZLOOVHHDVHOHFWLRQRIWKHPRVWFRPPRQO\XVHG(FOLSVHSDFNDJHVRQWKLVSDJH$Q
(FOLSVH £SDFNDJH¤ LV D UHDG\PDGH FROOHFWLRQ RI (FOLSVH PRGXOHV WKDW PDNH (FOLSVH
EHWWHUVXLWHGIRUFHUWDLQNLQGVRIVRIWZDUHGHYHORSPHQW8VXDOO\(FOLSVHXVHUVVWDUW
ZLWKRQHRIWKH(FOLSVHSDFNDJHVDYDLODEOHIRUGRZQORDGRQWKLVSDJHDQGFXVWRPL]HLW
ZLWKSOXJLQVZKLFKLVZKDW\RXZLOOGRZKHQ\RXDGGWKH$QGURLG'HYHORSPHQW7RROV
Installing the Android SDK and Prerequisites | 5
$'7 SOXJLQWR\RXU(FOLSVHLQVWDOODWLRQ7KH6\VWHP5HTXLUHPHQWVDUWLFOHRQWKH
$QGURLG'HYHORSHUVVLWHOLVWVWKUHHFKRLFHVRI(FOLSVHSDFNDJHVDVDEDVLVIRUDQ(FOLSVH
LQVWDOODWLRQIRU$QGURLGVRIWZDUHGHYHORSPHQW
‡ (FOLSVH&ODVVLF IRU(FOLSVHRUODWHU
‡ (FOLSVH,'(IRU-DYD'HYHORSHUV
‡ (FOLSVHIRU5&33OXJLQ'HYHORSHUV
$Q\RIWKHVHZLOOZRUNWKRXJKXQOHVV\RXDUHDOVRGHYHORSLQJ(FOLSVHSOXJLQVFKRRV
LQJHLWKHU&ODVVLFRUWKH-DYD'HYHORSHUVSDFNDJH ((RU6WDQGDUG PDNHVWKHPRVW
VHQVH7KHDXWKRUVRIWKLVERRNVWDUWHGZLWKWKH-DYD(('HYHORSHUVSDFNDJH £((¤
VWDQGVIRU(QWHUSULVH(GLWLRQ DQGVFUHHQVKRWVRI(FOLSVHXVHGLQWKLVERRNUHIOHFWWKDW
FKRLFH
7KH(FOLSVHGRZQORDGVLWHZLOODXWRPDWLFDOO\GHWHUPLQHWKHDYDLODEOHV\VWHPVSHFLILF
GRZQORDGVIRU\RXUV\VWHPWKRXJK\RXPD\KDYHWRFKRRVHEHWZHHQDQGELWVWR
PDWFK\RXURSHUDWLQJV\VWHP7KHILOH\RXGRZQORDGLVDQDUFKLYH7RLQVWDOO(FOLSVH
RSHQWKHDUFKLYHDQGFRS\WKHHFOLSVHIROGHUWR\RXUKRPHIROGHU7KHH[HFXWDEOHILOH
IRUODXQFKLQJ(FOLSVHRQ\RXUV\VWHPZLOOEHIRXQGLQWKHIROGHU\RXMXVWH[WUDFWHGIURP
WKHDUFKLYH
:HUHDOO\PHDQLWDERXWLQVWDOOLQJ(FOLSVHLQ\RXUKRPHIROGHU RUDQ
RWKHUIROGHU\RXRZQ HVSHFLDOO\LI\RXKDYHPXOWLSOHXVHUDFFRXQWVRQ
\RXUV\VWHP'RQRWXVH\RXUV\VWHP¦VSDFNDJHPDQDJHU<RXU(FOLSVH
LQVWDOODWLRQLVRQHRIDZLGHUDQJHRISRVVLEOHJURXSLQJVRI(FOLSVHSOXJ
LQV,QDGGLWLRQ\RXZLOOSUREDEO\IXUWKHUFXVWRPL]H\RXULQVWDOODWLRQ
RI(FOLSVH$QG(FOLSVHSOXJLQVDQGXSGDWHVDUHPDQDJHGVHSDUDWHO\
IURPRWKHUVRIWZDUHLQ\RXUV\VWHP
)RUWKHVHUHDVRQVLWLVYHU\GLIILFXOWWRVXFFHVVIXOO\LQVWDOODQGXVH(FOLSVH
DVDFRPPDQGDYDLODEOHWRDOOXVHUVRQ\RXUV\VWHPHYHQLI\RXUV\VWHP
FDQGRWKLVIURPLWVSDFNDJHPDQDJHU7RVXFFHVVIXOO\FRPSOHWHDQLQ
VWDOODWLRQ DV LW LV GHVFULEHG KHUH \RX PXVW LQVWDOO (FOLSVH LQ D IROGHU
PDQDJHGE\RQHXVHUDQGODXQFKLWIURPWKLVORFDWLRQ
,I\RXDUHXVLQJ8EXQWXRUDQRWKHU/LQX[GLVWULEXWLRQ\RXVKRXOGQRWLQVWDOO(FOLSVH
IURP\RXUGLVWULEXWLRQ¦VUHSRVLWRULHVDQGLILWLVFXUUHQWO\LQVWDOOHGWKLVZD\\RXPXVW
UHPRYHLWDQGLQVWDOO(FOLSVHDVGHVFULEHGKHUH7KHSUHVHQFHRIDQ£HFOLSVH¤SDFNDJH
LQWKH8EXQWXUHSRVLWRULHVLVDQLQKHULWDQFHIURPWKH'HELDQUHSRVLWRULHVRQZKLFK
8EXQWXLVEDVHG,WLVQRWDZLGHO\XVHGDSSURDFKWRLQVWDOOLQJDQGXVLQJ(FOLSVHEH
FDXVH PRVW RI WKH WLPH \RXU GLVWULEXWLRQ¦V UHSRVLWRULHV ZLOO KDYH ROGHU YHUVLRQV RI
(FOLSVH
6 | Chapter 1:ಗYour Toolkit
7RFRQILUPWKDW(FOLSVHLVFRUUHFWO\LQVWDOOHGDQGWKDW\RXKDYHD-5(WKDWVXSSRUWV
(FOLSVHODXQFKWKHH[HFXWDEOHILOHLQWKH(FOLSVHIROGHU<RXPD\ZDQWWRPDNHDVKRUW
FXW WR WKLV H[HFXWDEOH ILOH WR ODXQFK (FOLSVH PRUH FRQYHQLHQWO\ <RX VKRXOG VHH WKH
:HOFRPHVFUHHQVKRZQLQ)LJXUH
(FOLSVHLVLPSOHPHQWHGLQ-DYDDQGUHTXLUHVD-5(7KH-'.\RXSUHYLRXVO\LQVWDOOHG
SURYLGHVD-5(,I(FOLSVHGRHVQRWUXQ\RXVKRXOGFKHFNWKDWWKH-'.LVFRUUHFWO\
LQVWDOOHG
)LJXUH:HOFRPHVFUHHQWKDW\RXVHHWKHILUVWWLPH\RXUXQ(FOLSVH
The Android SDK
:LWKWKH-'.DQG(FOLSVHLQVWDOOHG\RXKDYHWKHSUHUHTXLVLWHVIRUWKH$QGURLG6'.
DQGDUHUHDG\WRLQVWDOOWKH6'.7KH$QGURLG6'.LVDFROOHFWLRQRIILOHVOLEUDULHV
H[HFXWDEOHVVFULSWVGRFXPHQWDWLRQDQGVRIRUWK,QVWDOOLQJWKH6'.PHDQVGRZQ
ORDGLQJWKHYHUVLRQRIWKH6'.IRU\RXUSODWIRUPDQGSXWWLQJWKH6'.ILOHVLQWRDIROGHU
LQ\RXUKRPHGLUHFWRU\
7RLQVWDOOWKH6'.GRZQORDGWKH6'.SDFNDJHWKDWFRUUHVSRQGVWR\RXUV\VWHPIURP
KWWSGHYHORSHUDQGURLGFRPVGNLQGH[KWPO
7KHGRZQORDGLVDQDUFKLYH2SHQWKHDUFKLYHDQGH[WUDFWWKHIROGHULQWKHDUFKLYHWR
\RXUKRPHIROGHU
Installing the Android SDK and Prerequisites | 7
,I\RXDUHXVLQJDELWYHUVLRQRI/LQX[\RXPD\QHHGWRLQVWDOOWKH
ia32-libsSDFNDJH
7RFKHFNZKHWKHU\RXQHHGWKLVSDFNDJHWU\UXQQLQJWKHadbFRPPDQG
~/android-sdk-linux_*/platform-tools/adb ,I \RXU V\VWHP UHSRUWV
WKDW DGE FDQQRW EH IRXQG GHVSLWH EHLQJ ULJKW WKHUH LQ WKH SODWIRUP
WRROVGLUHFWRU\ LWOLNHO\PHDQVWKDWWKHFXUUHQWYHUVLRQRIDGEDQGSRV
VLEO\RWKHUWRROVZLOOQRWUXQZLWKRXWWKHia32-libsSDFNDJHLQVWDOOHG
7KHFRPPDQGWRLQVWDOOWKHia32-libsSDFNDJHLV
sudo apt-get install ia32-libs
7KH6'.FRQWDLQVRQHRUWZRIROGHUVIRUWRROVRQHQDPHGWRROVDQGVWDUWLQJLQYHUVLRQ
RIWKH6'.DQRWKHUFDOOHGSODWIRUPWRROV7KHVHIROGHUVQHHGWREHRQ\RXUSDWK
ZKLFKLVDOLVWRIIROGHUV\RXUV\VWHPVHDUFKHVIRUH[HFXWDEOHILOHVZKHQ\RXLQYRNHDQ
H[HFXWDEOH IURP WKH FRPPDQG OLQH 2Q 0DFLQWRVK DQG /LQX[ V\VWHPV VHWWLQJ WKH
PATHHQYLURQPHQWYDULDEOHLVGRQHLQWKHSURILOH 8EXQWX RUEDVKBSURILOH 0DF26;
ILOHLQ\RXUKRPHGLUHFWRU\$GGDOLQHWRWKDWILOHWKDWVHWVWKHPATHHQYLURQPHQWYDULDEOH
WRLQFOXGHWKHWRROVGLUHFWRU\LQWKH6'. LQGLYLGXDOHQWULHVLQWKHOLVWDUHVHSDUDWHGE\
FRORQV )RUH[DPSOH\RXFRXOGXVHWKHIROORZLQJOLQH EXWUHSODFHERWKLQVWDQFHVRI
~/android-sdk-ARCHZLWKWKHIXOOSDWKWR\RXU$QGURLG6'.LQVWDOO export PATH=$PATH:~/android-sdk-ARCH/tools:~/android-sdk-ARCH/platform-tools
2Q:LQGRZVV\VWHPVFOLFN6WDUWൺULJKWFOLFN&RPSXWHUDQGFKRRVH3URSHUWLHV7KHQ
FOLFN$GYDQFHG6\VWHP6HWWLQJVDQGFOLFNWKH(QYLURQPHQW9DULDEOHVEXWWRQ'RXEOH
FOLFNWKHSDWKV\VWHPYDULDEOHDQGDGGWKHSDWKWRWKHIROGHUVE\JRLQJWRWKHHQGRI
WKLVYDULDEOH¦VYDOXH GRQRWFKDQJHDQ\WKLQJWKDW¦VDOUHDG\WKHUH DQGDGGLQJWKHWZR
SDWKVWRWKHHQGVHSDUDWHGE\VHPLFRORQVZLWKQRVSDFHEHIRUHWKHP)RUH[DPSOH
;C:\android-sdk-windows\tools;C:\android-sdk-windows\platform-tools
$IWHU\RX¦YHHGLWHG\RXUSDWKRQ:LQGRZV0DFRU/LQX[FORVHDQGUHRSHQDQ\&RP
PDQG3URPSWVRU7HUPLQDOVWRSLFNXSWKHQHZPATHVHWWLQJ RQ8EXQWX\RXPD\QHHG
WRORJRXWDQGORJLQXQOHVV\RXU7HUPLQDOSURJUDPLVFRQILJXUHGDVDORJLQVKHOO Adding Build Targets to the SDK
%HIRUH\RXFDQEXLOGDQ$QGURLGDSSOLFDWLRQRUHYHQFUHDWHDSURMHFWWKDWZRXOGWU\WR
EXLOGDQ$QGURLGDSSOLFDWLRQ\RXPXVWLQVWDOORQHRUPRUHEXLOGWDUJHWV7RGRWKLV
\RXZLOOXVHWKH6'.DQG$9'0DQDJHU7KLVWRROHQDEOHV\RXWRLQVWDOOSDFNDJHVLQ
WKH6'.WKDWZLOOVXSSRUWPXOWLSOHYHUVLRQVRIWKH$QGURLG26DQGPXOWLSOH$3,OHYHOV
2QFHWKH$'7SOXJLQLVLQVWDOOHGLQ(FOLSVHZKLFKZHGHVFULEHLQWKHQH[WVHFWLRQWKH
6'.DQG$9'0DQDJHUFDQEHLQYRNHGIURPZLWKLQ(FOLSVH,WFDQDOVREHLQYRNHG
IURPWKHFRPPDQGOLQHZKLFKLVKRZZHZLOOGRLWKHUH7RLQYRNHWKH6'.DQG$9'
0DQDJHUIURPWKHFRPPDQGOLQHLVVXHWKLVFRPPDQG
android
8 | Chapter 1:ಗYour Toolkit
7KHVFUHHQVKRWLQ)LJXUHVKRZVWKH6'.DQG$9'0DQDJHUZLWKDOOWKHDYDLODEOH
6'.YHUVLRQVVHOHFWHGIRULQVWDOODWLRQ
)LJXUH7KH6'.DQG$9'0DQDJHUZKLFKHQDEOHVLQVWDOODWLRQRI$QGURLG$3,OHYHOV
7KHSDFNDJHVODEHOHG£6'.SODWIRUP¤VXSSRUWEXLOGLQJDSSOLFDWLRQVFRPSDWLEOHZLWK
GLIIHUHQW$QGURLG$3,OHYHOV<RXVKRXOGLQVWDOODWDPLQLPXPWKHPRVWUHFHQW KLJKHVW
QXPEHUHG YHUVLRQEXWLQVWDOOLQJDOOWKHDYDLODEOH$3,OHYHOVDQGDOOWKH*RRJOH$3,
DGGRQSDFNDJHVLVDJRRGFKRLFHLI\RXPLJKWVRPHGD\ZDQWWREXLOGDSSOLFDWLRQV
WKDWUXQRQROGHU$QGURLGYHUVLRQV<RXVKRXOGDOVRLQVWDOODWDPLQLPXPWKHPRVW
UHFHQWYHUVLRQVRIWKHH[DPSOHDSSOLFDWLRQVSDFNDJH<RXPXVWDOVRLQVWDOOWKH$QGURLG
6'.3ODWIRUP7RROVSDFNDJH
The Android Development Toolkit (ADT) Plug-in for Eclipse
1RZWKDW\RXKDYHWKH6'.ILOHVLQVWDOOHGDORQJZLWK(FOLSVHDQGWKH-'.WKHUHLVRQH
PRUHFULWLFDOSDUWWRLQVWDOOWKH$QGURLG'HYHORSHU7RRONLW $'7 SOXJLQ7KH$'7
SOXJLQDGGV$QGURLGVSHFLILFIXQFWLRQDOLW\WR(FOLSVH
6RIWZDUHLQWKHSOXJLQHQDEOHV(FOLSVHWREXLOG$QGURLGDSSOLFDWLRQVODXQFKWKH$Q
GURLGHPXODWRUFRQQHFWWRGHEXJJLQJVHUYLFHVRQWKHHPXODWRUHGLW$QGURLG;0/ILOHV
HGLWDQGFRPSLOH$QGURLG,QWHUIDFH'HILQLWLRQ/DQJXDJH $,'/ ILOHVFUHDWH$QGURLG
DSSOLFDWLRQSDFNDJHV DSNILOHV DQGSHUIRUPRWKHU$QGURLGVSHFLILFWDVNV
Installing the Android SDK and Prerequisites | 9
Using the Install New Software Wizard to download and install the ADT plug-in
<RXVWDUWWKH,QVWDOO1HZ6RIWZDUH:L]DUGE\VHOHFWLQJ+HOSൺ,QVWDOO1HZ6RIWZDUH
)LJXUH 7RLQVWDOOWKH$'7SOXJLQW\SHWKLV85/LQWRWKH:RUN:LWKILHOGDQG
SUHVV5HWXUQRU(QWHUhttps://dl-ssl.google.com/android/eclipse/ VHH)LJXUH )LJXUH7KH(FOLSVH$GG6LWHGLDORJ
0RUHLQIRUPDWLRQRQLQVWDOOLQJWKH$'7SOXJLQXVLQJWKH,QVWDOO1HZ
6RIWZDUH:L]DUGFDQEHIRXQGRQWKH$QGURLG'HYHORSHUVVLWHDWKWWS
GHYHORSHUDQGURLGFRPVGNHFOLSVHDGWKWPOGRZQORDGLQJ
(FOLSVHGRFXPHQWDWLRQRQWKLVZL]DUGFDQEHIRXQGRQWKH(FOLSVHGRF
XPHQWDWLRQ VLWH DW KWWSKHOSHFOLSVHRUJJDOLOHRLQGH[MVS"WRSLF RUJ
HFOLSVHSODWIRUPGRFXVHUWDVNVWDVNVKWP
2QFH\RXKDYHDGGHGWKH85/WRWKHOLVWRIVLWHVIRUDFTXLULQJQHZSOXJLQV\RXZLOO
VHHDQHQWU\FDOOHG'HYHORSHU7RROVOLVWHGLQWKH$YDLODEOH6RIWZDUHOLVW
6HOHFWWKH'HYHORSHU7RROVLWHPE\FOLFNLQJRQWKHFKHFNER[QH[WWRLWDQGFOLFNRQ
WKH1H[WEXWWRQ7KHQH[WVFUHHQZLOODVN\RXWRDFFHSWWKHOLFHQVHIRUWKLVVRIWZDUH
$IWHU\RXDFFHSWDQGFOLFN)LQLVKWKH$'7ZLOOEHLQVWDOOHG<RXZLOOKDYHWRUHVWDUW
(FOLSVHWRFRPSOHWHWKHLQVWDOODWLRQ
10 | Chapter 1:ಗYour Toolkit
)LJXUH7KH(FOLSVH,QVWDOO1HZ6RIWZDUHGLDORJZLWKWKH$QGURLG+LHUDUFK9LHZHUSOXJLQVKRZQ
DVDYDLODEOH
Configuring the ADT plug-in
2QHPRUHVWHSDQG\RXDUHGRQHLQVWDOOLQJ2QFH\RXKDYHLQVWDOOHGWKH$'7SOXJLQ
\RXZLOOQHHGWRFRQILJXUHLW,QVWDOOLQJWKHSOXJLQPHDQVWKDWYDULRXVSDUWVRI(FOLSVH
QRZFRQWDLQ$QGURLGVRIWZDUHGHYHORSPHQWVSHFLILFGLDORJVPHQXFRPPDQGVDQG
RWKHUWRROVLQFOXGLQJWKHGLDORJ\RXZLOOQRZXVHWRFRQILJXUHWKH$'7SOXJLQ6WDUW
WKH 3UHIHUHQFHV GLDORJ XVLQJ WKH :LQGRZൺ3UHIHUHQFHV /LQX[ DQG :LQGRZV RU
(FOLSVHൺ3UHIHUHQFHV 0DF PHQXRSWLRQ&OLFNWKHLWHPODEHOHG$QGURLGLQWKHOHIWSDQH
RIWKH3UHIHUHQFHVGLDORJ
7KHILUVWWLPH\RXYLVLWWKLVVHFWLRQRIWKHSUHIHUHQFHV\RX¦OOVHHDGLDORJ
DVNLQJLI\RXZDQWWRVHQGVRPHXVDJHVWDWLVWLFVWR*RRJOH0DNH\RXU
FKRLFHDQGFOLFN3URFHHG
$GLDORJZLWKWKH$QGURLGVHWWLQJVLVGLVSOD\HGQH[W,QWKLVGLDORJDWH[WHQWU\ILHOG
ODEHOHG£6'.ORFDWLRQ¤DSSHDUVQHDUWKHWRS<RXPXVWHQWHUWKHSDWKWRZKHUH\RX
SXWWKH6'.RU\RXFDQXVHWKHILOHEURZVHUWRVHOHFWWKHGLUHFWRU\DVVKRZQLQ)LJ
XUH&OLFN$SSO\1RWHWKDWWKHEXLOGWDUJHWV\RXLQVWDOOHGDVGHVFULEHGLQ£$GGLQJ
%XLOG7DUJHWVWRWKH6'.¤RQSDJHDUHOLVWHGKHUHDVZHOO
Installing the Android SDK and Prerequisites | 11
)LJXUH&RQILJXULQJWKH6'.ORFDWLRQLQWRWKH(FOLSVH$'7SOXJLQXVLQJWKH$QGURLG3UHIHUHQFHV
GLDORJ
<RXU$QGURLG6'.LQVWDOODWLRQLVQRZFRPSOHWH
Test Drive: Confirm That Your Installation Works
,I\RXKDYHIROORZHGWKHVWHSVLQWKLVFKDSWHUDQGWKHRQOLQHLQVWUXFWLRQVUHIHUUHGWR
KHUH\RXULQVWDOODWLRQRIWKH$QGURLG6'.LVQRZFRPSOHWH7RFRQILUPWKDWHYHU\WKLQJ
\RXLQVWDOOHGVRIDUZRUNVOHW¦VFUHDWHDVLPSOH$QGURLGDSSOLFDWLRQ
Making an Android Project
7KHILUVWVWHSLQFUHDWLQJDVLPSOH$QGURLGDSSOLFDWLRQLVWRFUHDWHDQ$QGURLGSURMHFW
(FOLSVH RUJDQL]HV \RXU ZRUN LQWR £SURMHFWV¤ DQG E\ GHVLJQDWLQJ \RXU SURMHFW DV DQ
12 | Chapter 1:ಗYour Toolkit
$QGURLGSURMHFW\RXWHOO(FOLSVHWKDWWKH$'7SOXJLQDQGRWKHU$QGURLGWRROVDUH
JRLQJWREHXVHGLQFRQMXQFWLRQZLWKWKLVSURMHFW
5HIHUHQFHLQIRUPDWLRQDQGGHWDLOHGRQOLQHLQVWUXFWLRQVIRUFUHDWLQJDQ
$QGURLGSURMHFWFDQEHIRXQGDWKWWSGHYHORSHUDQGURLGFRPJXLGHGH
YHORSLQJHFOLSVHDGWKWPO
6WDUW\RXUQHZSURMHFWZLWKWKH)LOHൺ1HZൺ$QGURLG3URMHFWPHQXFRPPDQG/RFDWH
WKH$QGURLG3URMHFWRSWLRQLQWKH1HZ3URMHFWGLDORJ LWVKRXOGEHXQGHUDVHFWLRQ
QDPHG$QGURLG &OLFN1H[WDQGWKH1HZ3URMHFWGLDORJDSSHDUVDVVKRZQLQ)LJ
XUH
7RFUHDWH\RXU$QGURLGSURMHFW\RXZLOOSURYLGHWKHIROORZLQJLQIRUPDWLRQ
3URMHFWQDPH
7KLVLVWKHQDPHRIWKHSURMHFW QRWWKHDSSOLFDWLRQ WKDWDSSHDUVLQ(FOLSVH7\SH
TestProjectDVVKRZQLQ)LJXUH
:RUNVSDFH
$ ZRUNVSDFH LV D IROGHU FRQWDLQLQJ D VHW RI (FOLSVH SURMHFWV ,Q FUHDWLQJ D QHZ
SURMHFW\RXKDYHWKHFKRLFHRIFUHDWLQJWKHSURMHFWLQ\RXUFXUUHQWZRUNVSDFHRU
VSHFLI\LQJDGLIIHUHQWORFDWLRQLQWKHILOHV\VWHPIRU\RXUSURMHFW8QOHVV\RXQHHG
WRSXWWKLVSURMHFWLQDVSHFLILFORFDWLRQXVHWKHGHIDXOWV £&UHDWHQHZSURMHFWLQ
ZRUNVSDFH¤DQG£8VHGHIDXOWORFDWLRQ¤ 7DUJHWQDPH
7KH$QGURLGV\VWHPLPDJHV\RXLQVWDOOHGLQWKH6'.DUHVKRZQLQWKHEXLOGWDUJHW
OLVW<RXFDQSLFNRQHRIWKHVHV\VWHPLPDJHVDQGWKHFRUUHVSRQGLQJYHQGRUSODW
IRUP $QGURLG26YHUVLRQQXPEHU DQG$3,OHYHODVWKHWDUJHWIRUZKLFK\RXU
DSSOLFDWLRQLVEXLOW7KHSODWIRUPDQG$3,OHYHODUHWKHPRVWLPSRUWDQWSDUDPHWHUV
KHUHWKH\JRYHUQWKH$QGURLGSODWIRUPOLEUDU\WKDW\RXUDSSOLFDWLRQZLOOEHFRP
SLOHGZLWKDQGWKH$3,OHYHOVXSSRUWHG¢$3,VZLWKDKLJKHU$3,OHYHOWKDQWKHRQH
\RXVHOHFWZLOOQRWEHDYDLODEOHWR\RXUSURJUDP)RUQRZSLFNWKHPRVWUHFHQW
$QGURLG26YHUVLRQDQG$3,OHYHO\RXKDYHLQVWDOOHG
$SSOLFDWLRQQDPH
7KLVLVWKHDSSOLFDWLRQQDPHWKHXVHUZLOOVHH7\SHTest Application
3DFNDJHQDPH
7KHSDFNDJHQDPHFUHDWHVD-DYDSDFNDJHQDPHVSDFHWKDWXQLTXHO\LGHQWLILHVSDFN
DJHVLQ\RXUDSSOLFDWLRQDQGPXVWDOVRXQLTXHO\LGHQWLI\\RXUZKROH$QGURLGDS
SOLFDWLRQDPRQJDOORWKHULQVWDOOHGDSSOLFDWLRQV,WFRQVLVWVRIDXQLTXHGRPDLQ
QDPH¢WKHDSSOLFDWLRQSXEOLVKHU¦VGRPDLQQDPH¢SOXVDQDPHVSHFLILFWRWKHDS
SOLFDWLRQ1RWDOOSDFNDJHQDPHVSDFHVDUHXQLTXHLQ-DYDEXWWKHFRQYHQWLRQVXVHG
IRU$QGURLGDSSOLFDWLRQVPDNHQDPHVSDFHFRQIOLFWVOHVVOLNHO\,QRXUH[DPSOHZH
XVHGFRPRUHLOO\WHVWDSSEXW\RXFDQSXWVRPHWKLQJDSSURSULDWHIRU\RXUGRPDLQ
Test Drive: Confirm That Your Installation Works | 13
)LJXUH7KH1HZ$QGURLG3URMHFWGLDORJ
14 | Chapter 1:ಗYour Toolkit
KHUH \RXFDQDOVRXVHFRPH[DPSOHWHVWDSSVLQFHH[DPSOHFRPLVDGRPDLQQDPH
UHVHUYHGIRUH[DPSOHVVXFKDVWKLVRQH $FWLYLW\
$QDFWLYLW\LVDXQLWRILQWHUDFWLYHXVHULQWHUIDFHLQDQ$QGURLGDSSOLFDWLRQXVXDOO\
FRUUHVSRQGLQJ WR D JURXS RI XVHU LQWHUIDFH REMHFWV RFFXS\LQJ WKH HQWLUH VFUHHQ
2SWLRQDOO\ZKHQ\RXFUHDWHDSURMHFW\RXFDQKDYHDVNHOHWRQDFWLYLW\FUHDWHGIRU
\RX,I\RXDUHFUHDWLQJDYLVXDODSSOLFDWLRQ LQFRQWUDVWZLWKDVHUYLFHZKLFKFDQ
EH£KHDGOHVV¤¢ZLWKRXWDYLVXDO8, WKLVLVDFRQYHQLHQWZD\WRFUHDWHWKHDFWLYLW\
WKHDSSOLFDWLRQZLOOVWDUWZLWK,QWKLVH[DPSOH\RXVKRXOGFUHDWHDQDFWLYLW\FDOOHG
7HVW$FWLYLW\
0LQLPXP6'.YHUVLRQ
7KHILHOGODEHOHG0LQ6'.9HUVLRQVKRXOGFRQWDLQDQLQWHJHUFRUUHVSRQGLQJWRWKH
PLQLPXP6'.YHUVLRQUHTXLUHGE\\RXUDSSOLFDWLRQDQGLVXVHGWRLQLWLDOL]HWKH
uses-sdkDWWULEXWHLQWKHDSSOLFDWLRQ¦VPDQLIHVWZKLFKLVDILOHWKDWVWRUHVDSSOLFD
WLRQ DWWULEXWHV 6HH £7KH $QGURLG 0DQLIHVW (GLWRU¤ RQ SDJH ,Q PRVW FDVHV
WKLVVKRXOGEHWKHVDPHDVWKH$3,OHYHORIWKHEXLOGWDUJHW\RXVHOHFWHGZKLFKLV
GLVSOD\HGLQWKHULJKWPRVWFROXPQRIWKHOLVWRIEXLOGWDUJHWVDVVKRZQLQ)LJXUH
&OLFN)LQLVK QRW1H[W WRFUHDWH\RXU$QGURLGSURMHFWDQG\RXZLOOVHHLWOLVWHGLQWKH
OHIWSDQHRIWKH(FOLSVH,'(DVVKRZQLQ)LJXUH
)LJXUH7KH3DFNDJH([SORUHUYLHZVKRZLQJWKHILOHVDQGWKHLUFRPSRQHQWVWKDWDUHSDUWRIWKH
SURMHFW
Test Drive: Confirm That Your Installation Works | 15
Download from Wow! eBook <www.wowebook.com>
,I\RXH[SDQGWKHYLHZRIWKHSURMHFWKLHUDUFK\E\FOLFNLQJWKH£¤ :LQGRZV RUWUL
DQJOH 0DFDQG/LQX[ QH[WWRWKHSURMHFWQDPH\RXZLOOVHHWKHYDULRXVSDUWVRIDQ
$QGURLGSURMHFW([SDQGWKHVUFIROGHUDQG\RXZLOOVHHD-DYDSDFNDJHZLWKWKHQDPH
\RXHQWHUHGLQWKHZL]DUG([SDQGWKDWSDFNDJHDQG\RXZLOOVHHWKH ActivityFODVV
FUHDWHGIRU\RXE\WKHZL]DUG'RXEOHFOLFNWKDWDQG\RXZLOOVHHWKH-DYDFRGHRI\RXU
ILUVW$QGURLGSURJUDP
package com.oreilly.demo.pa.ch01.testapp;
import android.app.Activity;
import android.os.Bundle;
import com.oreilly.demo.pa.ch01.R;
public class TestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
,I\RX¦YHEHHQIROORZLQJDORQJDQGVHHWKHVDPHWKLQJRQ\RXUFRPSXWHU\RXU6'.
LQVWDOODWLRQLVSUREDEO\ZRUNLQJFRUUHFWO\%XWOHW¦VPDNHVXUHDQGH[SORUHWKH6'.
MXVWDELWIXUWKHUE\UXQQLQJ\RXUILUVWSURJUDPLQDQHPXODWRUDQGRQDQ$QGURLG
GHYLFHLI\RXKDYHRQHKDQG\
Making an Android Virtual Device (AVD)
7KH$QGURLG6'.SURYLGHVDQHPXODWRUZKLFKHPXODWHVDGHYLFHZLWKDQ$50&38
UXQQLQJDQ$QGURLGRSHUDWLQJV\VWHP 26 IRUUXQQLQJ$QGURLGSURJUDPVRQ\RXU3&
$Q$QGURLG9LUWXDO'HYLFH $9' LVDVHWRISDUDPHWHUVIRUWKLVHPXODWRUWKDWFRQILJXUHV
LWWRXVHDSDUWLFXODUV\VWHPLPDJH¢WKDWLVDSDUWLFXODUYHUVLRQRIWKH$QGURLGRSHUDWLQJ
V\VWHP¢DQGWRVHWRWKHUSDUDPHWHUVWKDWJRYHUQVFUHHQVL]HPHPRU\VL]HDQGRWKHU
HPXODWHGKDUGZDUHFKDUDFWHULVWLFV'HWDLOHGGRFXPHQWDWLRQRQ$9'VLVDYDLODEOHDW
KWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJWRROVDYGKWPO DQG GHWDLOHG GRFXPHQ
WDWLRQ RQ WKH HPXODWRU LV IRXQG KHUH KWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJ
WRROVHPXODWRUKWPO
%HFDXVHZHDUHMXVWYDOLGDWLQJWKDW\RXU6'.LQVWDOODWLRQZRUNVZHZRQ¦WJRLQWRGHSWK
RQ$9'VPXFKOHVVGHWDLOVRIWKHHPXODWRUMXVW\HW+HUHZHZLOOXVHWKH$QGURLG
6'.DQG$9'0DQDJHU VHH)LJXUH WRVHWXSDQ$9'IRUWKHSXUSRVHRIUXQQLQJ
WKHSURJUDPZHMXVWFUHDWHGZLWKWKH1HZ$QGURLG3URMHFW:L]DUG
16 | Chapter 1:ಗYour Toolkit
)LJXUH7KH6'.DQG$9'0DQDJHU
<RXZLOOQHHGWRFUHDWHDQ$9'ZLWKDV\VWHPLPDJHWKDWLVQROHVVUHFHQWWKDQWKH
WDUJHWVSHFLILHGIRUWKHSURMHFW\RXFUHDWHG&OLFNWKH1HZEXWWRQ<RXZLOOQRZVHH
WKH&UHDWH1HZ$QGURLG9LUWXDO'HYLFH $9' GLDORJVKRZQLQ)LJXUHZKHUH\RX
VSHFLI\WKHSDUDPHWHUVRI\RXUQHZ$9'
7KLVVFUHHQHQDEOHV\RXWRVHWWKHSDUDPHWHUVRI\RXUQHZ$9'
1DPH
7KLVLVWKHQDPHRIWKH$9'<RXFDQXVHDQ\QDPHIRUDQ$9'EXWDQDPHWKDW
LQGLFDWHVZKLFKV\VWHPLPDJHLWXVHVLVKHOSIXO
7DUJHW
7KH7DUJHWSDUDPHWHUVHWVZKLFKV\VWHPLPDJHZLOOEHXVHGLQWKLV$9',WVKRXOG
EHWKHVDPHDVRUPRUHUHFHQWWKDQWKHWDUJHW\RXVHOHFWHGDVWKHEXLOGWDUJHWIRU
\RXUILUVW$QGURLGSURMHFW
6'&DUG
6RPHDSSOLFDWLRQVUHTXLUHDQ6'FDUGWKDWH[WHQGVVWRUDJHEH\RQGWKHIODVKPHP
RU\EXLOWLQWRDQ$QGURLGGHYLFH8QOHVV\RXSODQWRSXWDORWRIGDWDLQ6'FDUG
VWRUDJH PHGLD ILOHV IRU H[DPSOH IRU DSSOLFDWLRQV \RX DUH GHYHORSLQJ \RX FDQ
FUHDWHDVPDOOYLUWXDO6'FDUGRIVD\0%LQVL]HHYHQWKRXJKPRVWSKRQHV
DUHHTXLSSHGZLWK6'FDUGVKROGLQJVHYHUDOJLJDE\WHV
Test Drive: Confirm That Your Installation Works | 17
)LJXUH&UHDWLQJDQHZ$9'
6NLQ
7KH£VNLQ¤RIDQ$9'PDLQO\VHWVWKHVFUHHQVL]H<RXZRQ¦WQHHGWRFKDQJHWKH
GHIDXOWIRUWKHSXUSRVHRIYHULI\LQJWKDW\RXU6'.LQVWDOODWLRQZRUNVEXWDYDULHW\
RIHPXODWRUVZLWKGLIIHUHQWVFUHHQVL]HVLVXVHIXOWRFKHFNWKDW\RXUOD\RXWVZRUN
DFURVVGLIIHUHQWGHYLFHV
+DUGZDUH
7KH+DUGZDUHILHOGRIDQ$9'FRQILJXUDWLRQHQDEOHV\RXWRVHWSDUDPHWHUVLQGL
FDWLQJZKLFKRSWLRQDOKDUGZDUHLVSUHVHQW<RXZRQ¦WQHHGWRFKDQJHWKHGHIDXOWV
IRUWKLVSURMHFW
)LOOLQWKH1DPH7DUJHWDQG6'&DUGILHOGVDQGFUHDWHDQHZ$9'E\FOLFNLQJWKH
&UHDWH$9'EXWWRQ,I\RXKDYHQRWFUHDWHGDQ$9'ZLWKDV\VWHPLPDJHWKDWPDWFKHV
RULVPRUHUHFHQWWKDQWKHWDUJHW\RXVSHFLILHGIRUDQ$QGURLGSURMHFW\RXZRQ¦WEH
DEOHWRUXQ\RXUSURJUDP
18 | Chapter 1:ಗYour Toolkit
Running a Program on an AVD
1RZWKDW\RXKDYHDSURMHFWWKDWEXLOGVDQDSSOLFDWLRQDQGDQ$9'ZLWKDV\VWHP
LPDJHFRPSDWLEOHZLWKWKHDSSOLFDWLRQ¦VEXLOGWDUJHWDQG$3,OHYHOUHTXLUHPHQWV\RX
FDQUXQ\RXUDSSOLFDWLRQDQGFRQILUPWKDWWKH6'.SURGXFHGDQGLVDEOHWRUXQDQ
$QGURLGDSSOLFDWLRQ
7RUXQ\RXUDSSOLFDWLRQULJKWFOLFNRQWKHSURMHFW\RXFUHDWHGDQGLQWKHFRQWH[WPHQX
WKDWSRSVXSVHOHFW5XQ$Vൺ$QGURLG$SSOLFDWLRQ
,IWKH$9'\RXFUHDWHGLVFRPSDWLEOHZLWKWKHDSSOLFDWLRQ\RXFUHDWHGWKH$9'ZLOO
VWDUWWKH$QGURLG26ZLOOERRWRQWKH$9'DQG\RXUDSSOLFDWLRQZLOOVWDUW<RXVKRXOG
VHH\RXUDSSOLFDWLRQUXQQLQJLQWKH$9'VLPLODUO\WRZKDWLVVKRZQLQ)LJXUH
)LJXUH7KHDSSOLFDWLRQ\RXMXVWFUHDWHGUXQQLQJLQDQ$9'
,I\RXKDYHPRUHWKDQRQHFRPSDWLEOH$9'FRQILJXUHGWKH$QGURLG'HYLFH&KRRVHU
GLDORJZLOODSSHDUDQGDVN\RXWRVHOHFWDPRQJWKH$9'VWKDWDUHDOUHDG\UXQQLQJRU
DPRQJWKH$QGURLGGHYLFHVDWWDFKHGWR\RXUV\VWHPLIDQ\RUWRSLFNDQ$9'WRVWDUW
)LJXUHVKRZVWKH$QGURLG'HYLFH&KRRVHUGLVSOD\LQJRQH$9'WKDWLVUXQQLQJ
DQGRQHWKDWFDQEHODXQFKHG
Test Drive: Confirm That Your Installation Works | 19
)LJXUH7KH$QGURLG'HYLFH&KRRVHU
Running a Program on an Android Device
<RXFDQDOVRUXQWKHSURJUDP\RXMXVWFUHDWHGRQPRVW$QGURLGGHYLFHV
<RXZLOOQHHGWRFRQQHFW\RXUGHYLFHWR\RXU3&ZLWKD86%FDEOHDQGLIQHHGHG
LQVWDOODGULYHURUVHWSHUPLVVLRQVWRDFFHVVWKHGHYLFHZKHQFRQQHFWHGYLD86%
6\VWHPVSHFLILFLQVWUXFWLRQVIRU:LQGRZVDORQJZLWKWKHQHHGHGGULYHUDUHDYDLODEOH
DWKWWSGHYHORSHUDQGURLGFRPVGNZLQXVEKWPO
,I\RXDUHUXQQLQJ/LQX[\RXZLOOQHHGWRFUHDWHD£UXOHV¤ILOHIRU\RXU$QGURLGGHYLFH
,I\RXDUHUXQQLQJ0DF26;QRFRQILJXUDWLRQLVUHTXLUHG
'HWDLOHGUHIHUHQFHLQIRUPDWLRQRQ86%GHEXJJLQJLVKHUHKWWSGHYHORSHUDQGURLGFRP
JXLGHGHYHORSLQJGHYLFHKWPO
<RXZLOODOVRQHHGWRWXUQRQ86%GHEXJJLQJLQ\RXU$QGURLGGHYLFH,QPRVWFDVHV
\RXZLOOVWDUWWKH6HWWLQJVDSSOLFDWLRQVHOHFW$SSOLFDWLRQVDQGWKHQ'HYHORSPHQWDQG
WKHQ\RXZLOOVHHDQRSWLRQWRWXUQ86%GHEXJJLQJRQRURII
,IDQ$9'LVFRQILJXUHGRULVUXQQLQJWKH$QGURLG'HYLFH&KRRVHUZLOODSSHDUGLV
SOD\LQJERWKWKH$QGURLGGHYLFH\RXKDYHFRQQHFWHGDQGWKH$9'
6HOHFWWKHGHYLFHDQGWKH$QGURLGDSSOLFDWLRQZLOOEHORDGHGDQGUXQRQWKHGHYLFH
20 | Chapter 1:ಗYour Toolkit
Troubleshooting SDK Problems: No Build Targets
,I\RXDUHXQDEOHWRPDNHDQHZSURMHFWRULPSRUWDQH[DPSOHSURMHFWIURPWKH6'.
\RXPD\KDYHPLVVHGLQVWDOOLQJEXLOGWDUJHWVLQWR\RXU6'.5HUHDGWKHLQVWUXFWLRQVLQ
£$GGLQJ%XLOG7DUJHWVWRWKH6'.¤RQSDJHDQGPDNHVXUHWKH$QGURLGSDQHLQWKH
3UHIHUHQFHVGLDORJOLVWVEXLOGWDUJHWVDVLQVWDOOHGLQ\RXU6'.DVVKRZQLQ)LJXUH
Components of the SDK
7KH$QGURLG6'.LVPDGHRIPRVWO\RIIWKHVKHOIFRPSRQHQWVSOXVVRPHSXUSRVHEXLOW
FRPSRQHQWV,QPDQ\FDVHVFRQILJXUDWLRQVSOXJLQVDQGH[WHQVLRQVDGDSWWKHVHFRP
SRQHQWV WR $QGURLG 7KH $QGURLG 6'. LV D VWXG\ LQ WKH HIILFLHQW GHYHORSPHQW RI D
PRGHUQDQGFRPSOHWH6'.*RRJOHWRRNWKLVDSSURDFKLQRUGHUWREULQJ$QGURLGWR
PDUNHWTXLFNO\<RXZLOOVHHWKLVIRU\RXUVHOIDV\RXH[SORUHWKHFRPSRQHQWVRIWKH
$QGURLG 6'. (FOLSVH WKH -DYD ODQJXDJH 4(08 DQG RWKHU SUHH[LVWLQJ SODWIRUPV
WRROVDQGWHFKQRORJLHVFRPSULVHVRPHRIWKHPRVWLPSRUWDQWSDUWVRIWKH$QGURLG6'.
,QFUHDWLQJWKHVLPSOHSURJUDPWKDWFRQILUPVWKDW\RXU6'.LQVWDOODWLRQLVFRUUHFW\RX
KDYH DOUHDG\ XVHG PDQ\ RI WKH FRPSRQHQWV RI WKH 6'. +HUH ZH ZLOO LGHQWLI\ DQG
GHVFULEHWKHFRPSRQHQWVRIWKH6'.LQYROYHGLQFUHDWLQJ\RXUSURJUDPDQGRWKHUSDUWV
\RXKDYH\HWWRXVH
The Android Debug Bridge (adb)
DGELVDSURJUDPWKDWHQDEOHV\RXWRFRQWUROERWKHPXODWRUVDQGGHYLFHVDQGWRUXQD
VKHOOLQRUGHUWRH[HFXWHFRPPDQGVLQWKHHQYLURQPHQWRIDQHPXODWRURUGHYLFHDGE
LVHVSHFLDOO\KDQG\IRULQVWDOOLQJDQGUHPRYLQJSURJUDPVIURPDQHPXODWRURUGHYLFH
'RFXPHQWDWLRQRQDGEFDQEHIRXQGDWKWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJ
WRROVDGEKWPO
The Dalvik Debug Monitor Server (DDMS)
7KH'DOYLN'HEXJ0RQLWRU6HUYHU ''06 LVDWUDIILFGLUHFWRUEHWZHHQWKHVLQJOHSRUW
WKDW(FOLSVH DQGRWKHU-DYDGHEXJJHUV ORRNVIRUWRFRQQHFWWRD-DYD9LUWXDO0DFKLQH
-90 DQGWKHVHYHUDOSRUWVWKDWH[LVWIRUHDFK$QGURLGGHYLFHRUYLUWXDOGHYLFHDQG
IRUHDFKLQVWDQFHRIWKH'DOYLNYLUWXDOPDFKLQH 90 RQHDFKGHYLFH7KH''06DOVR
SURYLGHVDFROOHFWLRQRIIXQFWLRQDOLW\WKDWLVDFFHVVLEOHWKURXJKDVWDQGDORQHXVHULQ
WHUIDFHRUWKURXJKDQLQWHUIDFHHPEHGGHGLQ(FOLSVHYLDWKH$'7SOXJLQ
:KHQ\RXLQYRNHWKH''06IURPWKHFRPPDQGOLQH\RXZLOOVHHVRPHWKLQJVLPLODU
WRWKHZLQGRZVKRZQLQ)LJXUH
Components of the SDK | 21
)LJXUH7KH'DOYLN'HEXJ0RQLWRUUXQQLQJVWDQGDORQH
7KH''06¦VXVHULQWHUIDFHSURYLGHVDFFHVVWRWKHIROORZLQJ
$OLVWRIGHYLFHVDQGYLUWXDOGHYLFHVDQGWKH90VUXQQLQJRQWKRVHGHYLFHV
,QWKHXSSHUOHIWSDQHRIWKH''06ZLQGRZ\RXZLOOVHHOLVWHGWKH$QGURLGGHYLFHV
\RXKDYHFRQQHFWHGWR\RXU3&SOXVDQ\$9'V\RXKDYHUXQQLQJ/LVWHGXQGHU
HDFKGHYLFHRUYLUWXDOGHYLFHDUHWKHWDVNVUXQQLQJLQ'DOYLN90V
90LQIRUPDWLRQ
6HOHFWLQJRQHRIWKH'DOYLN90VUXQQLQJRQDGHYLFHRUYLUWXDOGHYLFHFDXVHVLQ
IRUPDWLRQDERXWWKDW90WREHGLVSOD\HGLQWKHXSSHUULJKWSDQH
7KUHDGLQIRUPDWLRQ
,QIRUPDWLRQIRUWKUHDGVZLWKLQHDFKSURFHVVLVDFFHVVHGWKURXJKWKH£7KUHDGV¤WDE
LQWKHXSSHUULJKWSDQHRIWKH''06ZLQGRZ
)LOHV\VWHPH[SORUHU
<RXFDQH[SORUHWKHILOHV\VWHPRQDGHYLFHRUYLUWXDOGHYLFHXVLQJWKH''06ILOH
V\VWHPH[SORUHUDFFHVVLEOHWKURXJKWKH£)LOHH[SORUHU¤PHQXLWHPLQWKH'HYLFHV
PHQX,WGLVSOD\VWKHILOHKLHUDUFK\LQDZLQGRZVLPLODUWRWKHRQHVKRZQLQ)LJ
XUH
22 | Chapter 1:ಗYour Toolkit
)LJXUH7KH''06ILOHV\VWHPH[SORUHU
6LPXODWLQJSKRQHFDOOV
7KH(PXODWRU&RQWUROWDELQWKHXSSHUULJKWSDQHRIWKH''06ZLQGRZHQDEOHV
\RXWR£IDNH¤DSKRQHFDOORUWH[WPHVVDJHLQDQHPXODWRU
6FUHHQFDSWXUH
7KH£6FUHHQFDSWXUH¤FRPPDQGLQWKH'HYLFHPHQXIHWFKHVDQLPDJHRIWKHFXUUHQW
VFUHHQIURPWKHVHOHFWHG$QGURLGGHYLFHRUYLUWXDOGHYLFH
/RJJLQJ
7KHERWWRPSDQHRIWKH''06ZLQGRZGLVSOD\VORJRXWSXWIURPSURFHVVHVRQWKH
VHOHFWHGGHYLFHRUYLUWXDOGHYLFH<RXFDQILOWHUWKHORJRXWSXWE\VHOHFWLQJDILOWHU
IURPDPRQJWKHEXWWRQVRQWKHWRROEDUDERYHWKHORJJLQJSDQH
'XPSLQJVWDWHIRUGHYLFHVDSSVDQGWKHPRELOHUDGLR
$VHWRIFRPPDQGVLQWKH'HYLFHPHQXHQDEOHV\RXWRFRPPDQGWKHGHYLFHRU
YLUWXDOGHYLFHWRGXPSVWDWHIRUWKHZKROHGHYLFHDQDSSRUWKHPRELOHUDGLR
'HWDLOHG GRFXPHQWDWLRQ RQ WKH ''06 LV DYDLODEOH DW KWWSGHYHORSHUDQGURLGFRP
JXLGHGHYHORSLQJWRROVGGPVKWPO
Components of the ADT Eclipse Plug-in
(FOLSVH HQDEOHV \RX WR FUHDWH VSHFLILF SURMHFW W\SHV LQFOXGLQJ VHYHUDO NLQGV RI -DYD
SURMHFWV7KH$'7SOXJLQDGGVWKHDELOLW\WRPDNHDQGXVH$QGURLGSURMHFWV:KHQ
\RXPDNHDQHZ$QGURLGSURMHFWWKH$'7SOXJLQFUHDWHVWKHSURMHFWILOHKLHUDUFK\DQG
DOOWKHUHTXLUHGILOHVIRUWKHPLQLPDO$QGURLGSURMHFWWREHFRUUHFWO\EXLOW)RU$QGURLG
SURMHFWVWKH$'7SOXJLQHQDEOHV(FOLSVHWRDSSO\FRPSRQHQWVRIWKH$'7SOXJLQWR
HGLWLQJEXLOGLQJUXQQLQJDQGGHEXJJLQJWKDWSURMHFW
Components of the SDK | 23
,QVRPHFDVHVFRPSRQHQWVRIWKH6'.FDQEHXVHGZLWK(FOLSVHRULQDVWDQGDORQH
PRGH%XWLQPRVWRIWKH$QGURLGDSSOLFDWLRQGHYHORSPHQWFDVHVFRYHUHGLQWKLVERRN
WKHZD\WKHVHFRPSRQHQWVDUHXVHGLQRUZLWK(FOLSVHZLOOEHWKHPRVWUHOHYDQW
7KH$'7SOXJLQKDVQXPHURXVVHSDUDWHFRPSRQHQWVDQGGHVSLWHWKHFRQQRWDWLRQV
RID£SOXJLQ¤DVDPRGHVWHQKDQFHPHQWLW¦VDVXEVWDQWLDODPRXQWRIVRIWZDUH+HUH
ZHZLOOGHVFULEHHDFKVLJQLILFDQWSDUWRIWKH$'7SOXJLQWKDW\RXZLOOHQFRXQWHULQ
XVLQJ(FOLSVHIRUGHYHORSLQJ$QGURLGVRIWZDUH
The Android Layout Editor
/D\RXWVIRUXVHULQWHUIDFHVLQ$QGURLGDSSOLFDWLRQVFDQEHVSHFLILHGLQ;0/7KH$'7
SOXJLQDGGVDYLVXDOHGLWRUWKDWKHOSV\RXWRFRPSRVHDQGSUHYLHZ$QGURLGOD\RXWV
:KHQ\RXRSHQDOD\RXWILOHWKH$'7SOXJLQDXWRPDWLFDOO\VWDUWVWKLVHGLWRUWRYLHZ
DQGHGLWWKHILOH7DEVDORQJWKHERWWRPRIWKHHGLWLQJSDQHHQDEOH\RXWRVZLWFKEHWZHHQ
WKHYLVXDOHGLWRUDQGDQ;0/HGLWRU
,QHDUOLHUYHUVLRQVRIWKH$QGURLG6'.WKH$QGURLG/D\RXW(GLWRUZDVWRROLPLWHGWR
EHRIPXFKXVH1RZWKRXJK\RXVKRXOGFRQVLGHUXVLQJYLVXDOHGLWLQJRI$QGURLG
OD\RXWVDVDSUHIHUUHGZD\RIFUHDWLQJOD\RXWV$XWRPDWLQJWKHVSHFLILFDWLRQRIOD\RXWV
PDNHVLWPRUHOLNHO\WKDW\RXUOD\RXWVZLOOZRUNRQWKHZLGHVWUDQJHRI$QGURLGGHYLFHV
The Android Manifest Editor
,Q$QGURLGSURMHFWVDPDQLIHVWILOHLVLQFOXGHGZLWKWKHSURMHFW¦VVRIWZDUHDQGUHVRXUFHV
ZKHQWKHSURMHFWLVEXLOW7KLVILOHWHOOVWKH$QGURLGV\VWHPKRZWRLQVWDOODQGXVHWKH
VRIWZDUHLQWKHDUFKLYHWKDWFRQWDLQVWKHEXLOWSURMHFW7KHPDQLIHVWILOHLVLQ;0/DQG
WKH$'7SOXJLQSURYLGHVDVSHFLDOL]HG;0/HGLWRUWRHGLWWKHPDQLIHVW
2WKHUFRPSRQHQWVRIWKH$'7(FOLSVHSOXJLQVXFKDVWKHDSSOLFDWLRQEXLOGHUVFDQ
DOVRPRGLI\WKHPDQLIHVW
XML editors for other Android XML files
2WKHU$QGURLG;0/ILOHVWKDWKROGLQIRUPDWLRQVXFKDVVSHFLILFDWLRQVIRUPHQXVRU
UHVRXUFHVVXFKDVVWULQJVRUWKDWRUJDQL]HJUDSKLFDODVVHWVRIDQDSSOLFDWLRQKDYHVSH
FLDOL]HGHGLWRUVWKDWDUHRSHQHGZKHQ\RXRSHQWKHVHILOHV
Building Android apps
(FOLSVHSURMHFWVDUHXVXDOO\EXLOWDXWRPDWLFDOO\7KDWPHDQV\RXZLOOQRUPDOO\QRWHQ
FRXQWHUDVHSDUDWHVWHSIRUWXUQLQJWKHVRXUFHFRGHDQGUHVRXUFHVIRUDSURMHFWLQWRD
GHSOR\DEOHUHVXOW$QGURLGUHTXLUHV$QGURLGVSHFLILFVWHSVWREXLOGDILOH\RXFDQGHSOR\
WR DQ $QGURLG HPXODWRU RU GHYLFH DQG WKH $'7 SOXJLQ SURYLGHV WKH VRIWZDUH WKDW
H[HFXWHV WKHVH VWHSV )RU $QGURLG SURMHFWV WKH UHVXOW RI EXLOGLQJ WKH SURMHFW LV
DQDSNILOH<RXFDQILQGWKLVILOHIRUWKHWHVWSURMHFWFUHDWHGHDUOLHULQWKLVFKDSWHULQ
WKHELQVXEIROGHURIWKHSURMHFW¦VILOHKLHUDUFK\LQ\RXU(FOLSVHZRUNVSDFH
24 | Chapter 1:ಗYour Toolkit
7KH$QGURLGVSHFLILFEXLOGHUVSURYLGHGLQWKH$'7SOXJLQHQDEOH\RXWRXVH-DYDDV
WKHODQJXDJHIRUFUHDWLQJ$QGURLGVRIWZDUHZKLOHUXQQLQJWKDWVRIWZDUHRQD'DOYLN
90WKDWSURFHVVHVLWVRZQE\WHFRGHV
Running and debugging Android apps
:KHQ\RXUXQRUGHEXJDQ$QGURLGSURMHFWIURPZLWKLQ(FOLSVHWKHDSNILOHIRUWKDW
SURMHFWLVGHSOR\HGDQGVWDUWHGRQDQ$9'RU$QGURLGGHYLFHXVLQJWKH$'%DQG''06
WRFRPPXQLFDWHZLWKWKH$9'RUGHYLFHDQGWKH'DOYLNUXQWLPHHQYLURQPHQWWKDWUXQV
WKHSURMHFW¦VFRGH7KH$'7SOXJLQDGGVWKHFRPSRQHQWVWKDWHQDEOH(FOLSVHWRGRWKLV
The DDMS
,Q£7KH'DOYLN'HEXJ0RQLWRU6HUYHU ''06 ¤RQSDJHZHGHVFULEHGWKH'DOYLN
'HEXJ0RQLWRUDQGKRZWRLQYRNHWKH''06XVHULQWHUIDFHIURPWKHFRPPDQGOLQH
7KH''06XVHULQWHUIDFHLVDOVRDYDLODEOHIURPZLWKLQ(FOLSVH<RXFDQDFFHVVLWE\
XVLQJWKH:LQGRZൺ2SHQ3HUVSHFWLYHൺ''06FRPPDQGLQWKH(FOLSVHPHQX<RXFDQ
DOVRDFFHVVHDFKYLHZWKDWPDNHVXSWKH''06SHUVSHFWLYHVHSDUDWHO\E\XVLQJWKH
:LQGRZൺ6KRZ9LHZPHQXDQGVHOHFWLQJIRUH[DPSOHWKH/RJ&DWYLHZ
Android Virtual Devices
$9'VDUHPDGHXSRI4(08EDVHGHPXODWRUVWKDWHPXODWHWKHKDUGZDUHRIDQ$QGURLG
GHYLFHSOXV$QGURLGV\VWHPLPDJHVZKLFKFRQVLVWRI$QGURLGVRIWZDUHEXLOWWRUXQRQ
WKHHPXODWHGKDUGZDUH$9'VDUHFRQILJXUHGE\WKH6'.DQG$9'0DQDJHUZKLFK
VHWVSDUDPHWHUVVXFKDVWKHVL]HRIHPXODWHGVWRUDJHGHYLFHVDQGVFUHHQGLPHQVLRQV
DQGZKLFKHQDEOHV\RXWRVSHFLI\ZKLFK$QGURLGV\VWHPLPDJHZLOOEHXVHGZLWKZKLFK
HPXODWHGGHYLFH
$9'VHQDEOH\RXWRWHVW\RXUVRIWZDUHRQDEURDGHUUDQJHRIV\VWHPFKDUDFWHULVWLFV
WKDQ\RXDUHOLNHO\WREHDEOHWRDFTXLUHDQGWHVWRQSK\VLFDOGHYLFHV%HFDXVH4(08
EDVHGKDUGZDUHHPXODWRUVV\VWHPLPDJHVDQGWKHSDUDPHWHUVRI$9'VDUHDOOLQWHU
FKDQJHDEOH SDUWV \RX FDQ HYHQ WHVW GHYLFHV DQG V\VWHP LPDJHV EHIRUH KDUGZDUH LV
DYDLODEOHWRUXQWKHP
QEMU
4(08LVWKHEDVLVRI$9'V%XW4(08LVDYHU\JHQHUDOWRROWKDWLVXVHGLQDZLGH
UDQJHRIHPXODWLRQV\VWHPVRXWVLGHWKH$QGURLG6'.:KLOH\RXZLOOFRQILJXUH4(08
LQGLUHFWO\WKURXJKWKH6'.DQG$9'0DQDJHU\RXPD\VRPHGD\QHHGWRWZHDNHP
XODWLRQLQZD\VXQVXSSRUWHGE\WKH6'.WRROVRU\RXPD\EHFXULRXVDERXWWKHFDSD
ELOLWLHVDQGOLPLWDWLRQVRI4(08/XFNLO\4(08KDVDODUJHDQGYLEUDQWGHYHORSHU
DQGXVHUFRPPXQLW\ZKLFK\RXFDQILQGDWKWWSZZZTHPXRUJ
Components of the SDK | 25
The SDK and AVD Manager
4(08LVDJHQHUDOSXUSRVHHPXODWRUV\VWHP7KH$QGURLG6'.SURYLGHVFRQWUROVRYHU
WKHFRQILJXUDWLRQRI4(08WKDWPDNHVHQVHIRUFUHDWLQJHPXODWRUVWKDWUXQ$QGURLG
V\VWHPLPDJHV7KH6'.DQG$9'0DQDJHUSURYLGHVDXVHULQWHUIDFHIRU\RXWRFRQWURO
4(08EDVHG$QGURLGYLUWXDOGHYLFHV
Other SDK Tools
,QDGGLWLRQWRWKHPDMRUWRROV\RXDUHOLNHO\WRXVHLQWKHQRUPDOFRXUVHRIPRVWGHYHO
RSPHQWSURMHFWVWKHUHDUHVHYHUDORWKHUWRROVLQWKH6'.DQGWKRVHWKDWDUHXVHGRU
LQYRNHGGLUHFWO\E\GHYHORSHUVDUHGHVFULEHGKHUH6WLOOPRUHFRPSRQHQWVRIWKH6'.
DUHOLVWHGLQWKH7RROV2YHUYLHZDUWLFOHLQWKH$QGURLGGRFXPHQWDWLRQIRXQGDWKWWS
GHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJWRROVLQGH[KWPO
Hierarchy Viewer
7KH+LHUDUFK\9LHZHUGLVSOD\VDQGHQDEOHVDQDO\VLVRIWKHYLHZKLHUDUFK\RIWKHFXUUHQW
DFWLYLW\RIDVHOHFWHG$QGURLGGHYLFH7KLVHQDEOHV\RXWRVHHDQGGLDJQRVHSUREOHPV
ZLWK\RXUYLHZKLHUDUFKLHVDV\RXUDSSOLFDWLRQLVUXQQLQJRUWRH[DPLQHWKHYLHZKL
HUDUFKLHVRIRWKHUDSSOLFDWLRQVWRVHHKRZWKH\DUHGHVLJQHG,WDOVROHWV\RXH[DPLQHD
PDJQLILHGYLHZRIWKHVFUHHQZLWKDOLJQPHQWJXLGHVWKDWKHOSLGHQWLI\SUREOHPVZLWK
OD\RXWV'HWDLOHGLQIRUPDWLRQRQWKH+LHUDUFK\9LHZHULVDYDLODEOHDWKWWSGHYHORSHU
DQGURLGFRPJXLGHGHYHORSLQJWRROVKLHUDUFK\YLHZHUKWPO
Layoutopt
/D\RXWRSWLVDVWDWLFDQDO\]HUWKDWRSHUDWHVRQ;0/OD\RXWILOHVDQGFDQGLDJQRVHVRPH
SUREOHPVZLWK$QGURLGOD\RXWV'HWDLOHGLQIRUPDWLRQRQ/D\RXWRSWLVDYDLODEOHDWKWWS
GHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJWRROVOD\RXWRSWKWPO
Monkey
0RQNH\LVDWHVWDXWRPDWLRQWRROWKDWUXQVLQ\RXUHPXODWRURUGHYLFH<RXLQYRNHWKLV
WRROXVLQJDQRWKHUWRROLQWKH6'.DGE$GEHQDEOHV\RXWRVWDUWDVKHOORQDQHPXODWRU
RUGHYLFHDQG0RQNH\LVLQYRNHGIURPDVKHOOOLNHWKLV
adb shell monkey --wait-dbg -p your.package.name 500
7KLV LQYRFDWLRQ RI 0RQNH\ VHQGV UDQGRP HYHQWV WR WKH VSHFLILHG DSSOLFDWLRQ
VSHFLILHGE\WKHSDFNDJHQDPH DIWHUZDLWLQJIRUDGHEXJJHUWREHDWWDFKHG'HWDLOHG
LQIRUPDWLRQRQ0RQNH\FDQEHIRXQGDWKWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJ
WRROVPRQNH\KWPO
26 | Chapter 1:ಗYour Toolkit
sqlite3
$QGURLGXVHV64/LWHDVWKHGDWDEDVHV\VWHPIRUPDQ\V\VWHPGDWDEDVHVDQGSURYLGHV
$3,VIRUDSSOLFDWLRQVWRPDNHXVHRI64/LWHZKLFKLVFRQYHQLHQWIRUGDWDVWRUDJHDQG
SUHVHQWDWLRQ64/LWHDOVRKDVDFRPPDQGOLQHLQWHUIDFHDQGWKH sqlite3FRPPDQG
HQDEOHVGHYHORSHUVWRGXPSGDWDEDVHVFKHPDVDQGSHUIRUPRWKHURSHUDWLRQVRQ$Q
GURLGGDWDEDVHV
7KHVHGDWDEDVHVDUHRIFRXUVHLQDQ$QGURLGGHYLFHRUWKH\DUHFRQWDLQHGLQDQ$9'
DQGWKHUHIRUHWKH sqlite3FRPPDQGLVDYDLODEOHLQWKHDGEVKHOO'HWDLOHGGLUHFWLRQV
IRUKRZWRDFFHVVWKHsqlite3FRPPDQGOLQHIURPLQVLGHWKHDGEVKHOODUHDYDLODEOHDW
KWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJWRROVDGEKWPOVKHOOFRPPDQGV :H LQ
WURGXFHsqlite3LQ£([DPSOH'DWDEDVH0DQLSXODWLRQ8VLQJVTOLWH¤RQSDJH
keytool
keytoolJHQHUDWHVHQFU\SWLRQNH\VDQGLVXVHGE\WKH$'7SOXJLQWRFUHDWHWHPSRUDU\
GHEXJNH\VZLWKZKLFKLWVLJQVFRGHIRUWKHSXUSRVHRIGHEXJJLQJ,QPRVWFDVHV\RX
ZLOOXVHWKLVWRROWRFUHDWHDVLJQLQJFHUWLILFDWHIRUUHOHDVLQJ\RXUDSSOLFDWLRQVDVGH
VFULEHGLQ£&UHDWLQJDVHOIVLJQHGFHUWLILFDWH¤RQSDJH
Zipalign
=LSDOLJQHQDEOHVRSWLPL]HGDFFHVVWRGDWDIRUSURGXFWLRQUHOHDVHVRI$QGURLGDSSOLFD
WLRQV7KLVRSWLPL]DWLRQPXVWEHSHUIRUPHGDIWHUDQDSSOLFDWLRQLVVLJQHGIRUUHOHDVH
EHFDXVHWKHVLJQDWXUHDIIHFWVE\WHDOLJQPHQW'HWDLOHGLQIRUPDWLRQRQ=LSDOLJQLVDYDLO
DEOHDWKWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJWRROV]LSDOLJQKWPO
Draw9patch
$SDWFKLVDVSHFLDONLQGRI$QGURLGUHVRXUFHFRPSRVHGRIQLQHLPDJHVDQGXVHIXO
ZKHQ\RXZDQWIRUH[DPSOHEXWWRQVWKDWFDQJURZODUJHUZLWKRXWFKDQJLQJWKHUDGLXV
RIWKHLUFRUQHUV'UDZSDWFKLVDVSHFLDOL]HGGUDZLQJSURJUDPIRUFUHDWLQJDQGSUH
YLHZLQJWKHVHW\SHVRIUHVRXUFHV'HWDLOVRQGUDZSDWFKDUHDYDLODEOHDWKWWSGHYHORSHU
DQGURLGFRPJXLGHGHYHORSLQJWRROVGUDZSDWFKKWPO
android
7KHFRPPDQGQDPHGandroidFDQEHXVHGWRLQYRNHWKH6'.DQG$9'0DQDJHUIURP
WKHFRPPDQGOLQHDVZHGHVFULEHGLQWKH6'.LQVWDOODWLRQLQVWUXFWLRQVLQ£7KH$QGURLG
6'.¤RQSDJH,WFDQDOVREHXVHGWRFUHDWHDQ$QGURLGSURMHFWIURPWKHFRPPDQG
OLQH8VHGLQWKLVZD\LWFDXVHVDOOWKHSURMHFWIROGHUVWKHPDQLIHVWWKHEXLOGSURSHUWLHV
DQGWKHDQWVFULSWIRUEXLOGLQJWKHSURMHFWWREHJHQHUDWHG'HWDLOVRQWKLVXVHRIWKH
androidFRPPDQGFDQEHIRXQGDWKWWSGHYHORSHUDQGURLGFRPJXLGHGHYHORSLQJRWKHU
LGHKWPO&UHDWLQJ$3URMHFW
Components of the SDK | 27
Keeping Up-to-Date
7KH-'.(FOLSVHDQGWKH$QGURLG6'.HDFKFRPHIURPVHSDUDWHVXSSOLHUV7KHWRROV
\RXXVHWRGHYHORS$QGURLGVRIWZDUHFDQFKDQJHDWDUDSLGSDFH7KDWLVZK\LQWKLV
ERRNDQGHVSHFLDOO\LQWKLVFKDSWHUZHUHIHU\RXWRWKH$QGURLG'HYHORSHUVVLWHIRU
LQIRUPDWLRQRQWKHODWHVWFRPSDWLEOHYHUVLRQVRI\RXUWRROV.HHSLQJ\RXUWRROVXSWR
GDWHDQGFRPSDWLEOHLVDWDVN\RXDUHOLNHO\WRKDYHWRSHUIRUPHYHQDV\RXOHDUQKRZ
WRGHYHORS$QGURLGVRIWZDUH
:LQGRZV0DF26;DQG/LQX[DOOKDYHV\VWHPXSGDWHPHFKDQLVPVWKDWNHHS\RXU
VRIWZDUHXSWRGDWH%XWRQHFRQVHTXHQFHRIWKHZD\WKH$QGURLG6'.LVSXWWRJHWKHU
LVWKDW\RXZLOOQHHGWRNHHSVHSDUDWHVRIWZDUHV\VWHPVXSWRGDWHWKURXJKVHSDUDWH
PHFKDQLVPV
Keeping the Android SDK Up-to-Date
7KH$QGURLG6'.LVQ¦WSDUWRI\RXUGHVNWRS26QRULVLWSDUWRIWKH(FOLSVHSOXJLQ
DQGWKHUHIRUHWKHFRQWHQWVRIWKH6'.IROGHUDUHQRWXSGDWHGE\WKH26RU(FOLSVH7KH
6'.KDVLWVRZQXSGDWHPHFKDQLVPZKLFKKDVDXVHULQWHUIDFHLQWKH6'.DQG$9'
0DQDJHU$VVKRZQLQ)LJXUHVHOHFW,QVWDOOHG3DFNDJHVLQWKHOHIWSDQHWRVKRZD
OLVWRI6'.FRPSRQHQWVLQVWDOOHGRQ\RXUV\VWHP&OLFNRQWKH8SGDWH$OOEXWWRQWR
VWDUWWKHXSGDWHSURFHVVZKLFKZLOOVKRZ\RXDOLVWRIDYDLODEOHXSGDWHV
)LJXUH8SGDWLQJWKH6'.ZLWKWKH6'.DQG$9'0DQDJHU
8VXDOO\\RXZLOOZDQWWRLQVWDOODOODYDLODEOHXSGDWHV
28 | Chapter 1:ಗYour Toolkit
Keeping Eclipse and the ADT Plug-in Up-to-Date
:KLOHWKH6'.KDVWREHXSGDWHGRXWVLGHRIERWK\RXURSHUDWLQJV\VWHPDQG(FOLSVH
WKH$'7SOXJLQDQGDOORWKHUFRPSRQHQWVRI(FOLSVHDUHXSGDWHGXVLQJ(FOLSVH¦VRZQ
XSGDWHPDQDJHPHQWV\VWHP7RXSGDWHDOOWKHFRPSRQHQWV\RXKDYHLQ\RXU(FOLSVH
HQYLURQPHQWLQFOXGLQJWKH$'7SOXJLQXVHWKH£&KHFNIRU8SGDWHV¤FRPPDQGLQ
WKH +HOS PHQX 7KLV ZLOO FDXVH WKH DYDLODEOH XSGDWHV WR EH GLVSOD\HG DV VKRZQ LQ
)LJXUH
)LJXUH8SGDWLQJ(FOLSVHFRPSRQHQWVDQGWKH$'7SOXJLQ
1RUPDOO\\RXZLOOZDQWWRXVHWKH6HOHFW$OOEXWWRQWRLQVWDOODOODYDLODEOHXSGDWHV7KH
XSGDWHV\RXVHHOLVWHGRQ\RXUV\VWHPGHSHQGRQZKDW(FOLSVHPRGXOHV\RXKDYHLQ
VWDOOHGDQGZKHWKHU\RXU(FOLSVHKDVEHHQXSGDWHGUHFHQWO\
Keeping the JDK Up-to-Date
<RXZRQ¦WEHXSGDWLQJ-DYDDVPXFKDVWKH6'.$'7SOXJLQDQGRWKHU(FOLSVHSOXJ
LQV(YHQLI-DYDKDVQRWEHHQUHOHDVHGE\WKHWLPH\RXUHDGWKLVLWLVOLNHO\WRKDSSHQ
VRRQHQRXJKWRPDWWHUWR$QGURLGGHYHORSHUV%HIRUHFKRRVLQJWRXSGDWHWKH-'.ILUVW
FKHFNWKH6\VWHP5HTXLUHPHQWVSDJHRIWKH$QGURLG'HYHORSHUVVLWHDWKWWSGHYHORSHU
DQGURLGFRPVGNUHTXLUHPHQWVKWPO
Keeping Up-to-Date | 29
,IDQXSGDWHLVQHHGHGDQG\RXDUHXVLQJD0DFRU/LQX[V\VWHPFKHFNWKHDYDLODEOH
XSGDWHVIRU\RXUV\VWHPWRVHHLIDQHZYHUVLRQRIWKH-'.LVLQFOXGHG,IWKH-'.ZDV
LQVWDOOHGRQ\RXUV\VWHPE\WKHYHQGRURULI\RXLQVWDOOHGLWIURP\RXU/LQX[GLVWULEX
WLRQ¦VUHSRVLWRULHVXSGDWHVZLOOEHDYDLODEOHWKURXJKWKHXSGDWHVPHFKDQLVPRQ\RXU
V\VWHP
Example Code
+DYLQJLQVWDOOHGWKH$QGURLG6'.DQGWHVWHGWKDWLWZRUNV\RXDUHUHDG\WRH[SORUH
(YHQLI\RXDUHXQIDPLOLDUZLWKWKH$QGURLG)UDPHZRUNFODVVHVDQGDUHQHZWR-DYD
H[SORULQJVRPHH[DPSOHFRGHQRZZLOOJLYH\RXIXUWKHUFRQILGHQFHLQ\RXU6'.LQ
VWDOODWLRQEHIRUH\RXPRYHRQWRRWKHUSDUWVRIWKLVERRN
SDK Example Code
7KHPRVWFRQYHQLHQWVDPSOHFRGHFRPHVZLWKWKH6'.<RXFDQFUHDWHDQHZSURMHFW
EDVHGRQWKH6'.VDPSOHVDVVKRZQLQ)LJXUH7KHVDPSOH\RXVHOHFWDSSHDUVLQ
WKHOHIWSDQHRIWKH(FOLSVHZLQGRZZKHUH\RXFDQEURZVHWKHILOHVFRPSULVLQJWKH
VDPSOHDQGUXQLWWRVHHZKDWLWGRHV,I\RXDUHIDPLOLDUZLWKXVLQJ,'(VWRGHEXJFRGH
\RXPD\ZDQWWRVHWVRPHEUHDNSRLQWVLQWKHVDPSOHFRGHWRVHHZKHQPHWKRGVJHW
H[HFXWHG
,QWKHGLDORJSLFWXUHGLQ)LJXUH\RXPXVWSLFNDEXLOGWDUJHWEHIRUH
\RXSLFNDVDPSOH6DPSOHVDUHRUJDQL]HGE\$3,OHYHODQGLI\RXKDYH
QRWSLFNHGDEXLOGWDUJHWWKHGURSGRZQOLVWZLOOEHHPSW\
(DFKVDPSOHDSSOLFDWLRQWKDWFRPHVZLWKWKH6'.FRUUHVSRQGVWRDQDUWLFOHRQWKH
$QGURLG'HYHORSHUVVLWH0RUHLQIRUPDWLRQDERXWHDFKVDPSOHFDQEHIRXQGWKHUH$OO
RIWKHVDPSOHVDUHOLVWHGRQWKHGRFXPHQWDWLRQSDJHDWKWWSGHYHORSHUDQGURLGFRP
UHVRXUFHVVDPSOHVLQGH[KWPO
7KHUHDUHPRUHWKDQDGR]HQDSSOLFDWLRQVRQHRIZKLFK¢WKH$3,GHPRVDSSOLFDWLRQ¢
LVDVSUDZOLQJH[SORUDWLRQRIPRVWRIWKH$QGURLG$3,V&UHDWLQJDIHZSURMHFWVEDVHG
RQWKHVHFRGHVDPSOHVZLOOJLYH\RXIDPLOLDULW\ZLWKKRZWKHVHSURJUDPVZRUNDQGZLOO
KHOS\RXXQGHUVWDQGZKDW\RXZLOOUHDGLQWKHXSFRPLQJFKDSWHUVRIWKLVERRNHYHQ
LI\RXGRQ¦WIXOO\XQGHUVWDQGZKDW\RXDUHORRNLQJDW\HW
Example Code from This Book
([DPSOHFRGHIURPWKLVERRNFDQEHGRZQORDGHGIURPWKHERRN¦VZHEVLWHDWKWWS
RUHLOO\FRPFDWDORJ
30 | Chapter 1:ಗYour Toolkit
)LJXUH&UHDWLQJDQHZSURMHFWXVLQJH[DPSOHFRGHIURPWKH6'.
Example Code | 31
Download from Wow! eBook <www.wowebook.com>
On Reading Code
*RRGFRGHUVUHDGDORWRIFRGH7KHH[DPSOHFRGHSURYLGHGE\WKHDXWKRUVRIWKLVERRN
LVLQWHQGHGWREHERWKDQH[DPSOHRIJRRG-DYDFRGLQJDQGDQH[DPSOHRIKRZWRXVH
FDSDELOLWLHVRIWKH$QGURLGSODWIRUP
6RPH H[DPSOHV \RX ZLOO UHDG IDOO VKRUW RI ZKDW \RX ZLOO QHHG IRU FUHDWLQJ WKH EHVW
SRVVLEOHH[WHQVLEOHDQGPDLQWDLQDEOHFRPPHUFLDOVRIWZDUH0DQ\H[DPSOHDSSOLFDWLRQV
PDNHFKRLFHVWKDWPDNHVHQVHLIWKHFRGHU¦VJRDOLVWRFUHDWHDQH[DPSOHLQDVLQJOH-DYD
FODVV,QPDQ\FDVHV$QGURLGDSSOLFDWLRQVDUHRYHUJURZQYHUVLRQVRIH[DPSOHFRGH
DQGWKH\HQGXSXQUHDGDEOHDQGXQPDLQWDLQDEOH%XWWKDWGRHVQRWPHDQ\RXVKRXOG
DYRLGUHDGLQJH[DPSOHVWKDWDUHPRUHH[SHGLHQWWKDQDODUJHDSSOLFDWLRQVKRXOGEH
7KHQH[WFKDSWHUZLOOH[SORUHWKH-DYDODQJXDJHZLWKWKHJRDORIJLYLQJ\RXWKHDELOLW\
WRHYDOXDWHH[DPSOHFRGHZLWKJRRGHQJLQHHULQJDQGGHVLJQSUDFWLFHVLQPLQG:HZDQW
\RXWREHDEOHWRWDNHH[DPSOHVDQGPDNHWKHPEHWWHUDQGWRDSSO\WKHLGHDVLQH[
DPSOHVWRFRGH\RXHQJLQHHUWRFUHDWHKLJKTXDOLW\SURGXFWV
32 | Chapter 1:ಗYour Toolkit
CHAPTER 2
Java for Android
:HGRQ¦WWHDFK\RX-DYDLQWKLVERRNEXWLQWKLVFKDSWHUZH¦OOKHOS\RXXQGHUVWDQG
WKHVSHFLDOXVHRI-DYDZLWKLQ$QGURLG0DQ\SHRSOHFDQEHQHILWIURPWKLVFKDSWHU
VWXGHQWVZKRKDYHOHDUQHGVRPH-DYDEXWKDYHQ¦W\HWVWXPEOHGRYHUWKHUHDOOLIHSUR
JUDPPLQJGLOHPPDVLWSUHVHQWVSURJUDPPHUVIURPRWKHUPRELOHHQYLURQPHQWVZKR
KDYHXVHGRWKHUYHUVLRQVRI-DYDEXWQHHGWRUHOHDUQVRPHDVSHFWVRIWKHODQJXDJHLQ
WKHFRQWH[WRI$QGURLGSURJUDPPLQJDQG-DYDSURJUDPPHUVLQJHQHUDOZKRDUHQHZ
WR$QGURLG¦VSDUWLFXODUFRQYHQWLRQVDQGUHTXLUHPHQWV
,I\RXILQGWKLVFKDSWHUWRRIDVWSDFHGSLFNXSDQLQWURGXFWRU\ERRNRQ-DYD,I\RX
IROORZDORQJDOOULJKWEXWDSDUWLFXODUFRQFHSWGHVFULEHGLQWKLVFKDSWHUUHPDLQVXQFOHDU
WR \RX \RX PLJKW UHIHU WR WKH -DYD WXWRULDO DW KWWSGRZQORDGRUDFOHFRPGRFVFG
(BMDYDVHWXWRULDOLQGH[KWPO
Android Is Reshaping Client-Side Java
$QGURLGLVDOUHDG\WKHPRVWZLGHO\XVHGZD\RIFUHDWLQJLQWHUDFWLYHFOLHQWVXVLQJWKH
-DYDODQJXDJH$OWKRXJKWKHUHKDYHEHHQVHYHUDORWKHUXVHULQWHUIDFHFODVVOLEUDULHVIRU
-DYD $:76:76ZLQJ-0(&DQYDVHWF QRQHRIWKHPKDYHEHHQDVZLGHO\DF
FHSWHGDV$QGURLG)RUDQ\-DYDSURJUDPPHUWKH$QGURLG8,LVZRUWKOHDUQLQJMXVWWR
XQGHUVWDQGZKDWWKHIXWXUHRI-DYD8,VPLJKWORRNOLNH
7KH$QGURLGWRRONLWGRHVQ¦WJUDWXLWRXVO\EHQG-DYDLQXQIDPLOLDUGLUHFWLRQV7KHPRELOH
HQYLURQPHQW LV VLPSO\ GLIIHUHQW 7KHUH LV D PXFK ZLGHU YDULHW\ RI GLVSOD\ VL]HV DQG
VKDSHVWKHUHLVQRPRXVH WKRXJKWKHUHPLJKWEHDWRXFKVFUHHQ WH[WLQSXWPLJKWEH
WULSOHWDSDQGVRRQ7KHUHDUHDOVROLNHO\WREHPDQ\PRUHSHULSKHUDOGHYLFHVPRWLRQ
VHQVRUV *36 XQLWV FDPHUDV PXOWLSOH UDGLRV DQG PRUH )LQDOO\ WKHUH LV WKH HYHU
SUHVHQWFRQFHUQDERXWSRZHU:KLOH0RRUH¦VODZDIIHFWVSURFHVVRUVDQGPHPRU\ GRX
EOLQJWKHLUSRZHUDSSUR[LPDWHO\HYHU\WZR\HDUV QRVXFKODZDIIHFWVEDWWHU\OLIH:KHQ
SURFHVVRUVZHUHVORZGHYHORSHUVXVHGWREHFRQFHUQHGDERXW&38VSHHGDQGHIILFLHQF\
0RELOHGHYHORSHUVRQWKHRWKHUKDQGQHHGWREHFRQFHUQHGDERXWHQHUJ\HIILFLHQF\
33
7KLVFKDSWHUSURYLGHVDUHIUHVKHUIRUJHQHULF-DYD$QGURLGVSHFLILFOLEUDULHVDUHGLV
FXVVHGLQGHWDLOLQ&KDSWHU
The Java Type System
7KHUHDUHWZRGLVWLQFWIXQGDPHQWDOW\SHVLQWKH-DYDODQJXDJHREMHFWVDQGSULPLWLYHV
-DYDSURYLGHVW\SHVDIHW\E\HQIRUFLQJVWDWLFW\SLQJZKLFKUHTXLUHVWKDWHYHU\YDULDEOH
PXVWEHGHFODUHGZLWKLWVW\SHEHIRUHLWLVXVHG)RUH[DPSOHDYDULDEOHQDPHGiGHFODUHG
DVW\SHint DSULPLWLYHELWLQWHJHU ORRNVOLNHWKLV
int i;
7KLVPHFKDQLVPVWDQGVLQFRQWUDVWWRQRQVWDWLFDOO\W\SHGODQJXDJHVZKHUHYDULDEOHV
DUHRQO\RSWLRQDOO\GHFODUHG7KRXJKH[SOLFLWW\SHGHFODUDWLRQVDUHPRUHYHUERVHWKH\
HQDEOHWKHFRPSLOHUWRSUHYHQWDZLGHUDQJHRISURJUDPPLQJHUURUV¢DFFLGHQWDOYDUL
DEOHFUHDWLRQUHVXOWLQJIURPPLVVSHOOHGYDULDEOHQDPHVFDOOVWRQRQH[LVWHQWPHWKRGV
DQGVRRQ¢IURPHYHUPDNLQJLWLQWRUXQQLQJFRGH'HWDLOVRIWKH-DYD7\SH6\VWHPFDQ
EHIRXQGLQWKH-DYD/DQJXDJH6SHFLILFDWLRQ
Primitive Types
-DYDSULPLWLYHW\SHVDUHQRWREMHFWVDQGGRQRWVXSSRUWWKHRSHUDWLRQVDVVRFLDWHGZLWK
REMHFWVGHVFULEHGODWHULQWKLVFKDSWHU<RXFDQPRGLI\DSULPLWLYHW\SHRQO\ZLWKD
OLPLWHGQXPEHURISUHGHILQHGRSHUDWRUV£¤£¤£ ¤£_¤£ ¤DQGVRRQ7KH-DYD
SULPLWLYHW\SHVDUH
boolean
7KHYDOXHVtrueRUfalse
byte
$QELW¦VFRPSOHPHQWLQWHJHU
short
$ELW¦VFRPSOHPHQWLQWHJHU
int
$ELW¦VFRPSOHPHQWLQWHJHU
long
$ELW¦VFRPSOHPHQWLQWHJHU
char
$ELWXQVLJQHGLQWHJHUUHSUHVHQWLQJD87)FRGHXQLW
float
$ELW,(((IORDWLQJSRLQWQXPEHU
double
$ELW,(((IORDWLQJSRLQWQXPEHU
34 | Chapter 2:ಗJava for Android
Objects and Classes
-DYDLVDQREMHFWRULHQWHGODQJXDJHDQGIRFXVHVQRWRQLWVSULPLWLYHVEXWRQREMHFWV¢
FRPELQDWLRQVRIGDWDDQGSURFHGXUHVIRURSHUDWLQJRQWKDWGDWD$FODVVGHILQHVWKH
ILHOGV GDWD DQGPHWKRGV SURFHGXUHV WKDWFRPSULVHDQREMHFW,Q-DYDWKLVGHILQLWLRQ
¢WKHWHPSODWHIURPZKLFKREMHFWVDUHFRQVWUXFWHG¢LVLWVHOIDSDUWLFXODUNLQGRIRE
MHFWDClass,Q-DYDFODVVHVIRUPWKHEDVLVRIDW\SHV\VWHPWKDWDOORZVGHYHORSHUVWR
GHVFULEHDUELWUDULO\FRPSOH[REMHFWVZLWKFRPSOH[VSHFLDOL]HGVWDWHDQGEHKDYLRU
,Q-DYDDVLQPRVWREMHFWRULHQWHGODQJXDJHVW\SHVPD\LQKHULWIURPRWKHUW\SHV$
FODVVWKDWLQKHULWVIURPDQRWKHULVVDLGWRVXEW\SHRUWREHDVXEFODVVRILWVSDUHQW7KH
SDUHQWFODVVLQWXUQPD\EHFDOOHGWKHVXSHUW\SHRUVXSHUFODVV$FODVVWKDWKDVVHYHUDO
GLIIHUHQWVXEFODVVHVPD\EHFDOOHGWKHEDVHW\SHIRUWKRVHVXEFODVVHV
%RWKPHWKRGVDQGILHOGVKDYHJOREDOVFRSHZLWKLQWKHFODVVDQGPD\EHYLVLEOHIURP
RXWVLGHWKHREMHFWWKURXJKDUHIHUHQFHWRDQLQVWDQFHRIWKHFODVV
+HUHLVWKHGHILQLWLRQRIDYHU\YHU\VLPSOHFODVVZLWKRQHILHOGctrDQGRQHPHWKRG
incr
public class Trivial {
/** a field: its scope is the entire class */
private long ctr;
/** Modify the field. */
public void incr() { ctr++; }
}
Object Creation
$QHZREMHFWDQLQVWDQFHRIVRPHFODVVLVFUHDWHGE\XVLQJWKHnewNH\ZRUG
Trivial trivial = new Trivial();
2QWKHOHIWVLGHRIWKHDVVLJQPHQWRSHUDWRU£ ¤WKLVVWDWHPHQWGHILQHVDYDULDEOHQDPHG
trivial7KHYDULDEOHKDVDW\SHTrivialVRRQO\REMHFWVRIW\SHTrivialFDQEHDVVLJQHG
WR LW 7KH ULJKW VLGH RI WKH DVVLJQPHQW DOORFDWHV PHPRU\ IRU D QHZ LQVWDQFH RI WKH
TrivialFODVVDQGLQLWLDOL]HVWKHLQVWDQFH7KHDVVLJQPHQWRSHUDWRUDVVLJQVDUHIHUHQFH
WRWKHQHZO\FUHDWHGREMHFWWRWKHYDULDEOH
,WPD\VXUSULVH\RXWRNQRZWKDWWKHGHILQLWLRQRIctrLQTrivialLVSHUIHFWO\VDIHGHVSLWH
WKHIDFWWKDWLWLVQRWH[SOLFLWO\LQLWLDOL]HG-DYDJXDUDQWHHVWKDWLWZLOOEHLQLWLDOL]HGWR
KDYHWKHYDOXH-DYDJXDUDQWHHVWKDWDOOILHOGVDUHDXWRPDWLFDOO\LQLWLDOL]HGDWREMHFW
FUHDWLRQbooleanLVLQLWLDOL]HGWRfalseQXPHULFSULPLWLYHW\SHVWR0DQGDOOREMHFWW\SHV
LQFOXGLQJStrings WRnull
7KLV DSSOLHV RQO\ WR REMHFW ILHOGV /RFDO YDULDEOHV PXVW EH LQLWLDOL]HG
EHIRUHWKH\DUHUHIHUHQFHG
The Java Type System | 35
<RXFDQWDNHJUHDWHUFRQWURORYHUWKHLQLWLDOL]DWLRQRIDQREMHFWE\DGGLQJDFRQVWUXF
WRUWRLWVFODVVGHILQLWLRQ$FRQVWUXFWRUGHILQLWLRQORRNVOLNHDPHWKRGH[FHSWWKDWLW
GRHVQ¦WVSHFLI\DUHWXUQW\SH,WVQDPHPXVWEHH[DFWO\WKHQDPHRIWKHFODVVWKDWLW
FRQVWUXFWV
public class LessTrivial {
/** a field: its scope is the entire class */
private long ctr;
/** Constructor: initialize the fields */
public LessTrivial(long initCtr) { ctr = initCtr; }
}
/** Modify the field. */
public void incr() { ctr++; }
,QIDFWHYHU\FODVVLQ-DYDKDVDFRQVWUXFWRU7KH-DYDFRPSLOHUDXWRPDWLFDOO\FUHDWHV
DFRQVWUXFWRUZLWKQRDUJXPHQWVLIQRRWKHUFRQVWUXFWRULVVSHFLILHG)XUWKHULIDFRQ
VWUXFWRUGRHVQRWH[SOLFLWO\FDOOVRPHVXSHUFODVVFRQVWUXFWRUWKH-DYDFRPSLOHUZLOO
DXWRPDWLFDOO\DGGDQLPSOLFLWFDOOWRWKHVXSHUFODVVQRDUJFRQVWUXFWRUDVWKHYHU\ILUVW
VWDWHPHQW7KHGHILQLWLRQRITrivialJLYHQHDUOLHU ZKLFKVSHFLILHVQRH[SOLFLWFRQVWUXF
WRU DFWXDOO\KDVDFRQVWUXFWRUWKDWORRNVOLNHWKLV
public Trivial() { super(); }
6LQFHWKHLessTrivialFODVVH[SOLFLWO\GHILQHVDFRQVWUXFWRU-DYDGRHVQRWLPSOLFLWO\DGG
DGHIDXOW7KDWPHDQVWKDWWU\LQJWRFUHDWHD LessTrivialREMHFWZLWKQRDUJXPHQWV
ZLOOFDXVHDQHUURU
LessTrivial fail = new LessTrivial(); // ERROR!!
LessTrivial ok = new LessTrivial(18); // ... works
7KHUHDUHWZRFRQFHSWVWKDWLWLVLPSRUWDQWWRNHHSVHSDUDWHQRDUJFRQVWUXFWRUDQG
GHIDXOWFRQVWUXFWRU$GHIDXOWFRQVWUXFWRULVWKHFRQVWUXFWRUWKDW-DYDDGGVWR\RXUFODVV
LPSOLFLWO\LI\RXGRQ¦WGHILQHDQ\RWKHUFRQVWUXFWRUV,WKDSSHQVWREHDQRDUJFRQ
VWUXFWRU $ QRDUJ FRQVWUXFWRU RQ WKH RWKHU KDQG LV VLPSO\ D FRQVWUXFWRU ZLWK QR
SDUDPHWHUV7KHUHLVQRUHTXLUHPHQWWKDWDFODVVKDYHDQRDUJFRQVWUXFWRU7KHUHLVQR
REOLJDWLRQWRGHILQHRQHXQOHVV\RXKDYHDVSHFLILFQHHGIRULW
2QHSDUWLFXODUFDVHLQZKLFKQRDUJFRQVWUXFWRUVDUHQHFHVVDU\GHVHUYHV
VSHFLDODWWHQWLRQ6RPHOLEUDULHVQHHGWKHDELOLW\WRFUHDWHQHZREMHFWV
JHQHULFDOO\RQ\RXUEHKDOI7KH-8QLWIUDPHZRUNIRULQVWDQFHQHHGV
WREHDEOHWRFUHDWHQHZWHVWFDVHVUHJDUGOHVVRIZKDWWKH\WHVW/LEUDULHV
WKDW PDUVKDO DQG XQPDUVKDO FRGH WR D SHUVLVWHQW VWRUH RU D QHWZRUN
FRQQHFWLRQDOVRQHHGWKLVFDSDELOLW\6LQFHLWZRXOGEHSUHWW\KDUGIRU
WKHVHOLEUDULHVWRILJXUHRXWDWUXQWLPHWKHH[DFWFDOOLQJSURWRFROIRU
\RXUSDUWLFXODUREMHFWWKH\W\SLFDOO\UHTXLUHDQRDUJFRQVWUXFWRU
,IDFODVVKDVPRUHWKDQRQHFRQVWUXFWRULWLVZLVHWRFDVFDGHWKHPWRPDNHVXUHRQO\
DVLQJOHFRS\RIWKHFRGHDFWXDOO\LQLWLDOL]HVWKHLQVWDQFHDQGWKDWDOORWKHUFRQVWUXFWRUV
36 | Chapter 2:ಗJava for Android
FDOO LW )RU LQVWDQFH DV D FRQYHQLHQFH ZH PLJKW DGG D QRDUJ FRQVWUXFWRU WR WKH
LessTrivialFODVVWRDFFRPPRGDWHDFRPPRQFDVH
public class LessTrivial {
/** a field: its scope is the entire class */
private long ctr;
/** Constructor: init counter to 0 */
public LessTrivial() { this(0); }
/** Constructor: initialize the fields */
public LessTrivial(long initCtr) { ctr = initCtr; }
/** Modify the field. */
public void incr() { ctr++; }
}
&DVFDGLQJPHWKRGVLVWKHVWDQGDUG-DYDLGLRPIRUGHIDXOWLQJWKHYDOXHVRIVRPHDUJX
PHQWV$OOWKHFRGHWKDWDFWXDOO\LQLWLDOL]HVDQREMHFWLVLQDVLQJOHFRPSOHWHPHWKRG
RUFRQVWUXFWRUDQGDOORWKHUPHWKRGVRUFRQVWUXFWRUVVLPSO\FDOOLW,WLVDSDUWLFXODUO\
JRRG LGHD WR XVH WKLV LGLRP ZLWK FRQVWUXFWRUV WKDW PXVW PDNH H[SOLFLW FDOOV WR D
VXSHUFRQVWUXFWRU
&RQVWUXFWRUVVKRXOGEHVLPSOHDQGVKRXOGGRQRPRUHZRUNWKDQLVQHFHVVDU\WRSXW
DQREMHFWLQWRDFRQVLVWHQWLQLWLDOVWDWH2QHFDQLPDJLQHIRULQVWDQFHDGHVLJQIRUDQ
REMHFWWKDWUHSUHVHQWVDGDWDEDVHRUQHWZRUNFRQQHFWLRQ,WPLJKWFUHDWHWKHFRQQHFWLRQ
LQLWLDOL]HLWDQGYHULI\FRQQHFWLYLW\DOOLQWKHFRQVWUXFWRU:KLOHWKLVPLJKWVHHPHQ
WLUHO\UHDVRQDEOHLQSUDFWLFHLWFUHDWHVFRGHWKDWLVLQVXIILFLHQWO\PRGXODUDQGGLIILFXOW
WRGHEXJDQGPRGLI\,QDEHWWHUGHVLJQWKHFRQVWUXFWRUVLPSO\LQLWLDOL]HVWKHFRQQHF
WLRQVWDWHDVFORVHGDQGOHDYHVLWWRDQH[SOLFLWopenPHWKRGWRVHWXSWKHQHWZRUN
The Object Class and Its Methods
7KH-DYDFODVV Object¢java.lang.Object¢LVWKHURRWDQFHVWRURIHYHU\FODVV(YHU\
-DYDREMHFWLVDQObject,IWKHGHILQLWLRQRIDFODVVGRHVQRWH[SOLFLWO\VSHFLI\DVXSHU
FODVVLWLVDGLUHFWVXEFODVVRI Object7KH ObjectFODVVGHILQHVWKHGHIDXOWLPSOHPHQ
WDWLRQV IRU VHYHUDO NH\ EHKDYLRUV WKDW DUH FRPPRQ WR HYHU\ REMHFW 8QOHVV WKH\ DUH
RYHUULGGHQE\WKHVXEFODVVWKHEHKDYLRUVDUHLQKHULWHGGLUHFWO\IURPObject
7KHPHWKRGVwaitnotifyDQGnotifyAllLQWKHObjectFODVVDUHSDUWRI-DYD¦VFRQFXU
UHQF\VXSSRUW7KH\DUHGLVFXVVHGLQ£7KUHDG&RQWUROZLWKZDLW DQGQRWLI\ 0HWK
RGV¤RQSDJH
7KHtoStringPHWKRGLVWKHZD\DQREMHFWFUHDWHVDVWULQJUHSUHVHQWDWLRQRILWVHOI2QH
LQWHUHVWLQJXVHRItoStringLVVWULQJFRQFDWHQDWLRQDQ\REMHFWFDQEHFRQFDWHQDWHGWR
DVWULQJ7KLVH[DPSOHGHPRQVWUDWHVWZRZD\VWRSULQWWKHVDPHPHVVDJHWKH\ERWK
H[HFXWH LGHQWLFDOO\ ,Q ERWK D QHZ LQVWDQFH RI WKH Foo FODVV LV FUHDWHG LWV toString
PHWKRGLVLQYRNHGDQGWKHUHVXOWLVFRQFDWHQDWHGZLWKDOLWHUDOVWULQJ7KHUHVXOWLVWKHQ
SULQWHG
The Java Type System | 37
System.out.println(
"This is a new foo: " + new Foo());
System.out.println(
"This is a new foo: ".concat((new Foo()).toString()));
7KH ObjectLPSOHPHQWDWLRQRI toStringUHWXUQVDQRWYHU\XVHIXOVWULQJWKDWLVEDVHG
RQWKHORFDWLRQRIWKHREMHFWLQWKHKHDS2YHUULGLQJ toStringLQ\RXUFRGHLVDJRRG
ILUVWVWHSWRZDUGPDNLQJLWHDVLHUWRGHEXJ
7KHcloneDQGfinalizePHWKRGVDUHKLVWRULFDOOHIWRYHUV7KH-DYDUXQWLPHZLOOFDOOWKH
finalize PHWKRG RQO\ LI LW LV RYHUULGGHQ LQ D VXEFODVV ,I D FODVV H[SOLFLWO\ GHILQHV
finalizeWKRXJKLWLVFDOOHGIRUDQREMHFWRIWKHFODVVMXVWEHIRUHWKDWREMHFWLVJDUEDJH
FROOHFWHG1RWRQO\GRHV-DYDQRWJXDUDQWHHZKHQWKLVPLJKWKDSSHQLWDFWXDOO\FDQ¦W
JXDUDQWHHWKDWLWZLOOKDSSHQDWDOO,QDGGLWLRQDFDOOWRfinalizeFDQUHVXUUHFWDQREMHFW
7KLVLVWULFN\REMHFWVDUHJDUEDJHFROOHFWHGZKHQWKHUHDUHQROLYHUHIHUHQFHVWRWKHP
$QLPSOHPHQWDWLRQRIfinalizeKRZHYHUFRXOGHDVLO\FUHDWHDQHZOLYHUHIHUHQFHIRU
LQVWDQFHE\DGGLQJWKHREMHFWEHLQJILQDOL]HGWRVRPHNLQGRIOLVW%HFDXVHRIWKLVWKH
H[LVWHQFHRIDfinalizePHWKRGSUHFOXGHVWKHGHILQLQJFODVVIURPPDQ\NLQGVRIRSWL
PL]DWLRQ7KHUHLVOLWWOHWRJDLQDQGORWVWRORVHLQDWWHPSWLQJWRXVHfinalize
7KH clone PHWKRG FUHDWHV REMHFWV E\SDVVLQJ WKHLU FRQVWUXFWRUV $OWKRXJK clone LV
GHILQHG RQ Object FDOOLQJ LW RQ DQ REMHFW ZLOO FDXVH DQ H[FHSWLRQ XQOHVV WKH REMHFW
LPSOHPHQWVWKHCloneableLQWHUIDFH7KHclonePHWKRGLVDQRSWLPL]DWLRQWKDWFDQEH
XVHIXOZKHQREMHFWFUHDWLRQKDVDVLJQLILFDQWFRVW:KLOHFOHYHUXVHVRI clonePD\EH
QHFHVVDU\LQVSHFLILFFDVHVDFRS\FRQVWUXFWRU¢RQHZKLFKWDNHVDQH[LVWLQJLQVWDQFH
DVLWVRQO\DUJXPHQW¢LVPXFKPRUHVWUDLJKWIRUZDUGDQGLQPRVWFDVHVKDVQHJOLJLEOH
FRVW
7KHODVWWZRObjectPHWKRGVhashCodeDQGequalsDUHWKHPHWKRGVE\ZKLFKDFDOOHU
FDQWHOOZKHWKHURQHREMHFWLV£WKHVDPHDV¤DQRWKHU
7KHGHILQLWLRQRIWKH equalsPHWKRGLQWKH$3,GRFXPHQWDWLRQIRUWKH ObjectFODVV
VWLSXODWHVWKHFRQWUDFWWRZKLFKHYHU\LPSOHPHQWDWLRQRIequalsPXVWDGKHUH$FRUUHFW
LPSOHPHQWDWLRQRIWKHequalsPHWKRGKDVWKHIROORZLQJDWWULEXWHVDQGWKHDVVRFLDWHG
VWDWHPHQWVPXVWDOZD\VEHWUXH
reflexive
x.equals(x)
symmetric
x.equals(y) == y.equals(x)
transitive
(x.equals(y) && y.equals(z)) == x.equals(z)
consistent
,Ix.equals(y)LVWUXHDWDQ\SRLQWLQWKHOLIHRIDSURJUDPLWLVDOZD\VWUXHSURYLGHG
xDQGyGRQRWFKDQJH
38 | Chapter 2:ಗJava for Android
*HWWLQJWKLVULJKWLVVXEWOHDQGFDQEHVXUSULVLQJO\GLIILFXOW$FRPPRQHUURU¢RQHWKDW
YLRODWHVUHIOH[LYLW\¢LVGHILQLQJDQHZFODVVWKDWLVVRPHWLPHVHTXDOWRDQH[LVWLQJFODVV
6XSSRVH\RXUSURJUDPXVHVDQH[LVWLQJOLEUDU\WKDWGHILQHVWKHFODVVEnglishWeekdays
6XSSRVHQRZWKDW\RXGHILQHDFODVVFrenchWeekdays7KHUHLVDQREYLRXVWHPSWDWLRQ
WRGHILQHDQequalsPHWKRGIRUFrenchWeekdaysWKDWUHWXUQVtrueZKHQLWFRPSDUHVRQH
RIWKHEnglishWeekdaysWRLWV)UHQFKHTXLYDOHQW'RQ¦WGRLW7KHH[LVWLQJ(QJOLVKFODVV
KDVQRDZDUHQHVVRI\RXUQHZFODVVDQGVRZLOOQHYHUUHFRJQL]HLQVWDQFHVRI\RXUFODVV
DVEHLQJHTXDO<RX¦YHEURNHQUHIOH[LYLW\
hashCodeDQG equalsVKRXOGEHFRQVLGHUHGDSDLULI\RXRYHUULGHHLWKHU\RXVKRXOG
RYHUULGHERWK0DQ\OLEUDU\URXWLQHVWUHDWhashCodeDVDQRSWLPL]HGURXJKJXHVVDVWR
ZKHWKHUWZRREMHFWVDUH equalRUQRW7KHVHOLEUDULHVILUVWFRPSDUHWKHKDVKFRGHVRI
WKHWZRREMHFWV,IWKHWZRFRGHVDUHGLIIHUHQWWKH\DVVXPHWKHUHLVQRQHHGWRGRDQ\
PRUHH[SHQVLYHFRPSDULVRQVEHFDXVHWKHREMHFWVDUHGHILQLWHO\GLIIHUHQW7KHSRLQWRI
KDVK FRGH FRPSXWDWLRQ WKHQ LV WR FRPSXWH VRPHWKLQJ YHU\ TXLFNO\ WKDW LV D JRRG
SUR[\IRUWKHequalsPHWKRG9LVLWLQJHYHU\FHOOLQDODUJHDUUD\LQRUGHUWRFRPSXWHD
KDVKFRGHLVSUREDEO\QRIDVWHUWKDQGRLQJWKHDFWXDOFRPSDULVRQ$WWKHRWKHUH[WUHPH
LWZRXOGEHYHU\IDVWWRUHWXUQ0DOZD\VIURPDKDVKFRGHFRPSXWDWLRQ,WMXVWZRXOGQ¦W
EHYHU\KHOSIXO
Objects, Inheritance, and Polymorphism
-DYDVXSSRUWVSRO\PRUSKLVPRQHRIWKHNH\FRQFHSWVLQREMHFWRULHQWHGSURJUDPPLQJ
$ODQJXDJHLVVDLGWREHSRO\PRUSKLFLIREMHFWVRIDVLQJOHW\SHFDQKDYHGLIIHUHQWEH
KDYLRU7KLVKDSSHQVZKHQVXEW\SHVRIDJLYHQFODVVFDQEHDVVLJQHGWRDYDULDEOHRI
WKHEDVHFODVVW\SH$QH[DPSOHZLOOPDNHWKLVPXFKFOHDUHU
6XEW\SHVLQ-DYDDUHGHFODUHGWKURXJKXVHRIWKHextendsNH\ZRUG+HUHLVDQH[DPSOH
RILQKHULWDQFHLQ-DYD
public class Car {
public void drive() {
System.out.println("Going down the road!");
}
}
public class Ragtop extends Car {
// override the parent's definition.
public void drive() {
System.out.println("Top down!");
// optionally use a superclass method
super.drive();
System.out.println("Got the radio on!");
}
}
The Java Type System | 39
RagtopLVDVXEW\SHRICar:HQRWHGSUHYLRXVO\WKDWCarLVLQWXUQDVXEFODVVRIObject
RagtopFKDQJHVWKHGHILQLWLRQRI Car¦V drivePHWKRG,WLVVDLGWRRYHUULGH drive Car
DQGRagtopDUHERWKRIW\SHCar WKH\DUHQRWERWKRIW\SHRagtop DQGKDYHGLIIHUHQW
EHKDYLRUVIRUWKHPHWKRGdrive
:HFDQQRZGHPRQVWUDWHSRO\PRUSKLFEHKDYLRU
Car auto = new Car();
auto.drive();
auto = new Ragtop();
auto.drive();
7KLVFRGHIUDJPHQWZLOOFRPSLOHZLWKRXWHUURU GHVSLWHWKHDVVLJQPHQWRID RagtopWR
DYDULDEOHZKRVHW\SHLV Car ,WZLOODOVRUXQZLWKRXWHUURUDQGZRXOGSURGXFHWKH
IROORZLQJRXWSXW
Going down the road!
Top down!
Going down the road!
Got the radio on!
7KHYDULDEOHautoKROGVDWGLIIHUHQWWLPHVLQLWVOLIHUHIHUHQFHVWRWZRGLIIHUHQWREMHFWV
RIW\SH Car2QHRIWKRVHREMHFWVLQDGGLWLRQWREHLQJRIW\SH CarLVDOVRRIVXEW\SH
Ragtop 7KH H[DFW EHKDYLRU RI WKH VWDWHPHQW auto.drive() GHSHQGV RQ ZKHWKHU WKH
YDULDEOHFXUUHQWO\FRQWDLQVDUHIHUHQFHWRWKHIRUPHURUWKHODWWHU7KLVLVSRO\PRUSKLF
EHKDYLRU
/LNHPDQ\RWKHUREMHFWRULHQWHGODQJXDJHV-DYDVXSSRUWVW\SHFDVWLQJWRDOORZFRHUFLRQ
RI WKH GHFODUHG W\SH RI D YDULDEOH WR EH DQ\ RI WKH W\SHV ZLWK ZKLFK WKH YDULDEOH LV
SRO\PRUSKLF
Ragtop funCar;
Car auto = new Car();
funCar = (Ragtop) auto; //ERROR! auto is a Car, not a Ragtop!
auto.drive();
auto = new Ragtop();
Ragtop funCar = (Ragtop) auto; //Works! auto is a Ragtop
auto.drive();
:KLOHRFFDVLRQDOO\QHFHVVDU\H[FHVVLYHXVHRIFDVWLQJLVDQLQGLFDWLRQWKDWWKHFRGHLV
PLVVLQJ WKH SRLQW 2EYLRXVO\ E\ WKH UXOHV RI SRO\PRUSKLVP DOO YDULDEOHV FRXOG EH
GHFODUHGWREHRIW\SH ObjectDQGWKHQFDVWDVQHFHVVDU\7RGRWKDWKRZHYHULVWR
DEDQGRQWKHYDOXHRIVWDWLFW\SLQJ
-DYDOLPLWVDPHWKRG¦VDUJXPHQWV LWVDFWXDOSDUDPHWHUV WRREMHFWVRIW\SHVWKDWDUH
SRO\PRUSKLF ZLWK LWV IRUPDO SDUDPHWHUV 6LPLODUO\ PHWKRGV UHWXUQ YDOXHV WKDW DUH
SRO\PRUSKLFZLWKWKHGHFODUHGUHWXUQW\SH)RULQVWDQFHFRQWLQXLQJRXUDXWRPRWLYH
H[DPSOHWKHIROORZLQJFRGHIUDJPHQWZLOOFRPSLOHDQGUXQZLWKRXWHUURU
40 | Chapter 2:ಗJava for Android
public class JoyRide {
private Car myCar;
public void park(Car auto) {
myCar = auto;
}
public Car whatsInTheGarage() {
return myCar;
}
public void letsGo() {
park(new Ragtop());
whatsInTheGarage().drive();
}
}
7KHPHWKRGparkLVGHFODUHGWRWDNHDQREMHFWRIW\SHCarDVLWVRQO\SDUDPHWHU,QWKH
PHWKRG letsGoKRZHYHULWLVFDOOHGZLWKDQREMHFWRIW\SH RagtopDVXEW\SHRIW\SH
Car6LPLODUO\WKHYDULDEOH myCarLVDVVLJQHGDYDOXHRIW\SH RagtopDQGWKHPHWKRG
whatsInTheGarageUHWXUQVLW7KHREMHFWLVDRagtopLI\RXFDOOLWVdrivePHWKRGLWZLOO
WHOO\RXDERXWLWVWRSDQGLWVUDGLR2QWKHRWKHUKDQGVLQFHLWLVDOVRD CarLWFDQEH
XVHGDQ\ZKHUHWKDWRQHZRXOGXVHDCar7KLVVXEW\SHUHSODFHPHQWFDSDELOLW\LVDNH\
H[DPSOHRIWKHSRZHURISRO\PRUSKLVPDQGKRZLWZRUNVZLWKW\SHVDIHW\(YHQDW
FRPSLOHWLPHLWLVFOHDUZKHWKHUDQREMHFWLVFRPSDWLEOHZLWKLWVXVHRUQRW7\SHVDIHW\
HQDEOHVWKHFRPSLOHUWRILQGHUURUVHDUO\WKDWPLJKWEHPXFKPRUHGLIILFXOWWRILQG
ZHUHWKH\SHUPLWWHGWRRFFXUDWUXQWLPH
Final and Static Declarations
7KHUHDUHPRGLILHUNH\ZRUGVWKDWFDQEHDSSOLHGWRDGHFODUDWLRQLQ-DYD7KHVH
PRGLILHUVFKDQJHWKHEHKDYLRURIWKHGHFODUHGREMHFWVRPHWLPHVLQLPSRUWDQWZD\V
7KHHDUOLHUH[DPSOHVXVHGDFRXSOHRIWKHPpublicDQGprivateZLWKRXWH[SODQDWLRQ
WKH\DUHDPRQJWKHVHYHUDOPRGLILHUVWKDWFRQWUROVFRSHDQGYLVLELOLW\:H¦OOUHYLVLWWKHP
LQDPLQXWH,QWKLVVHFWLRQZHFRQVLGHUWZRRWKHUPRGLILHUVWKDWDUHHVVHQWLDOWRD
FRPSOHWHXQGHUVWDQGLQJRIWKH-DYDW\SHV\VWHPfinalDQGstatic
$finalGHFODUDWLRQLVRQHWKDWFDQQRWEHFKDQJHG&ODVVHVPHWKRGVILHOGVSDUDPHWHUV
DQGORFDOYDULDEOHVFDQDOOEHILQDO
:KHQDSSOLHGWRDFODVVfinalPHDQVWKDWDQ\DWWHPSWWRGHILQHDVXEFODVVZLOOFDXVH
DQHUURU7KHFODVV StringIRULQVWDQFHLV finalEHFDXVHVWULQJVPXVWEHLPPXWDEOH
LH\RXFDQ¦WFKDQJHWKHFRQWHQWRIRQHDIWHU\RXFUHDWHLW ,I\RXWKLQNDERXWLWIRU
DZKLOH\RXZLOOVHHWKDWWKLVFDQEHJXDUDQWHHGRQO\LIStringFDQQRWEHVXEW\SHG,I
LWZHUHSRVVLEOHWRVXEW\SHWKHStringFODVVDGHYLRXVOLEUDU\FRXOGFUHDWHDVXEFODVVRI
StringDeadlyStringSDVVDQLQVWDQFHWR\RXUFRGHDQGFKDQJHLWVYDOXHIURP£IUHG¤
WR£¥'5237$%/(FRQWDFWV¤ DQDWWHPSWWRLQMHFWURJXH64/LQWR\RXUV\VWHPWKDW
The Java Type System | 41
PLJKWZLSHRXWSDUWVRI\RXUGDWDEDVH LPPHGLDWHO\DIWHU\RXUFRGHKDGYDOLGDWHGLWV
FRQWHQWV
:KHQDSSOLHGWRDPHWKRG finalPHDQVWKDWWKHPHWKRGFDQQRWEHRYHUULGGHQLQD
VXEFODVV'HYHORSHUVXVHfinalPHWKRGVWRGHVLJQIRULQKHULWDQFHZKHQWKHVXSHUW\SH
QHHGVWRPDNHDKLJKO\LPSOHPHQWDWLRQGHSHQGHQWEHKDYLRUDYDLODEOHWRDVXEFODVVDQG
FDQQRWDOORZWKDWEHKDYLRUWREHFKDQJHG$IUDPHZRUNWKDWLPSOHPHQWHGDJHQHULF
FDFKHPLJKWGHILQHDEDVHFODVVCacheableObjectIRULQVWDQFHZKLFKWKHSURJUDPPHU
XVLQJWKHIUDPHZRUNVXEW\SHVIRUHDFKQHZFDFKHDEOHREMHFWW\SH,QRUGHUWRPDLQWDLQ
WKHLQWHJULW\RIWKHIUDPHZRUNKRZHYHU CacheableObjectPLJKWQHHGWRFRPSXWHD
FDFKHNH\WKDWZDVFRQVLVWHQWDFURVVDOOREMHFWW\SHV,QWKLVFDVHLWPLJKWGHFODUHLWV
computeCacheKeyPHWKRGfinal
:KHQDSSOLHGWRDYDULDEOH¢DILHOGDSDUDPHWHURUDORFDOYDULDEOH¢finalPHDQVWKDW
WKHYDOXHRIWKHYDULDEOHRQFHDVVLJQHGPD\QRWFKDQJH7KLVUHVWULFWLRQLVHQIRUFHG
E\WKHFRPSLOHULWLVQRWHQRXJKWKDWWKHYDOXHGRHVQRWFKDQJHWKHFRPSLOHUPXVWEH
DEOH WR SURYH WKDW LW FDQQRW FKDQJH )RU D ILHOG WKLV PHDQV WKDW WKH YDOXH PXVW EH
DVVLJQHGHLWKHUDVSDUWRIWKHGHFODUDWLRQRULQHYHU\FRQVWUXFWRU)DLOXUHWRLQLWLDOL]HD
finalILHOGDWLWVGHFODUDWLRQRULQWKHFRQVWUXFWRU¢RUDQDWWHPSWWRDVVLJQWRLWDQ\
ZKHUHHOVH¢ZLOOFDXVHDQHUURU
)RUSDUDPHWHUVfinalPHDQVWKDWZLWKLQWKHPHWKRGWKHSDUDPHWHUYDOXHDOZD\VKDV
WKHYDOXHSDVVHGLQWKHFDOO$QDWWHPSWWRDVVLJQWRD finalSDUDPHWHUZLOOFDXVHDQ
HUURU2IFRXUVHVLQFHWKHSDUDPHWHUYDOXHLVPRVWOLNHO\WREHDUHIHUHQFHWRVRPHNLQG
RIREMHFWLWLVSRVVLEOHWKDWWKHREMHFWPLJKWFKDQJH7KHDSSOLFDWLRQRIWKHNH\ZRUG
finalWRDSDUDPHWHUVLPSO\PHDQVWKDWWKHSDUDPHWHUFDQQRWEHDVVLJQHG
,Q-DYDSDUDPHWHUVDUHSDVVHGE\YDOXHWKHPHWKRGDUJXPHQWVDUHQHZ
FRSLHVRIWKHYDOXHVWKDWZHUHSDVVHGDWWKHFDOO2QWKHRWKHUKDQGPRVW
WKLQJVLQ-DYDDUHUHIHUHQFHVWRREMHFWVDQG-DYDRQO\FRSLHVWKHUHIHU
HQFHQRWWKHZKROHREMHFW5HIHUHQFHVDUHSDVVHGE\YDOXH
$ finalYDULDEOHPD\EHDVVLJQHGQRPRUHWKDQRQFH6LQFHXVLQJDYDULDEOHZLWKRXW
LQLWLDOL]LQJLWLVDOVRDQHUURULQ-DYDD finalYDULDEOHPXVWEHDVVLJQHGH[DFWO\RQFH
7KHDVVLJQPHQWPD\WDNHSODFHDQ\ZKHUHLQWKHHQFORVLQJEORFNSULRUWRXVH
$staticGHFODUDWLRQEHORQJVWRWKHFODVVLQZKLFKLWLVGHVFULEHGQRWWRDQLQVWDQFHRI
WKDWFODVV7KHRSSRVLWHRI staticLVG\QDPLF$Q\HQWLW\WKDWLVQRWGHFODUHGVWDWLFLV
LPSOLFLWO\G\QDPLF7KLVH[DPSOHLOOXVWUDWHV
public class QuietStatic {
public static int classMember;
public int instanceMember;
}
public class StaticClient {
public void test() {
QuietStatic.classMember++;
42 | Chapter 2:ಗJava for Android
QuietStatic.instanceMember++; // ERROR!!
}
}
QuietStatic ex = new QuietStatic();
ex.classMember++; // WARNING!
ex.instanceMember++;
,QWKLVH[DPSOHQuietStaticLVWKHQDPHRIDFODVVDQGexLVDUHIHUHQFHWRDQLQVWDQFH
RIWKDWFODVV7KHVWDWLFPHPEHUclassMemberLVDQDWWULEXWHRIWKHFODVV\RXFDQUHIHU
WRLWVLPSO\E\TXDOLI\LQJLWZLWKWKHFODVVQDPH2QWKHRWKHUKDQGinstanceMemberLV
DPHPEHURIDQLQVWDQFHRIWKHFODVV$QDWWHPSWWRUHIHUWRLWWKURXJKWKHFODVVUHIHUHQFH
FDXVHVDQHUURU7KDWPDNHVVHQVH7KHUHDUHPDQ\GLIIHUHQWYDULDEOHVFDOOHGinstance
MemberRQHEHORQJLQJWRHDFKLQVWDQFHRI QuietStatic,I\RXGRQ¦WH[SOLFLWO\VSHFLI\
ZKLFKRQH\RXDUHWDONLQJDERXWWKHUH¦VQRZD\IRU-DYDWRILJXUHLWRXW
$VWKHVHFRQGSDLURIVWDWHPHQWVGHPRQVWUDWHV-DYDGRHVDFWXDOO\DOORZUHIHUHQFHVWR
FODVV VWDWLF YDULDEOHVWKURXJKLQVWDQFHUHIHUHQFHV,WLVPLVOHDGLQJWKRXJKDQGFRQ
VLGHUHGDEDGSUDFWLFH0RVWFRPSLOHUVDQG,'(VZLOOJHQHUDWHZDUQLQJVLI\RXGRLW
7KHLPSOLFDWLRQVRIVWDWLFYHUVXVG\QDPLFGHFODUDWLRQVFDQEHVXEWOH,WLVHDVLHVWWR
XQGHUVWDQGWKHGLVWLQFWLRQIRUILHOGV$JDLQZKLOHWKHUHLVH[DFWO\RQHFRS\RIDVWDWLF
GHILQLWLRQWKHUHLVRQHFRS\SHULQVWDQFHRIDG\QDPLFGHILQLWLRQ6WDWLFFODVVPHPEHUV
DOORZ\RXWRPDLQWDLQLQIRUPDWLRQWKDWLVKHOGLQFRPPRQE\DOOPHPEHUVRIDFODVV
+HUH¦VVRPHH[DPSOHFRGH
public class LoudStatic {
private static int classMember;
private int instanceMember;
public void incr() {
classMember++;
instanceMember++;
}
@Override public String toString() {
return "classMember: " + classMember
+ ", instanceMember: " + instanceMember;
}
public static void main(String[] args) {
LoudStatic ex1 = new LoudStatic();
LoudStatic ex2 = new LoudStatic();
ex1.incr();
ex2.incr();
System.out.println(ex1);
System.out.println(ex2);
}
}
DQGLWVRXWSXW
classMember: 2, instanceMember: 1
classMember: 2, instanceMember: 1
The Java Type System | 43
7KHLQLWLDOYDOXHRIWKHYDULDEOHclassMemberLQWKHSUHFHGLQJH[DPSOHLV,WLVLQFUH
PHQWHGE\HDFKRIWKHWZRGLIIHUHQWLQVWDQFHV%RWKLQVWDQFHVQRZVHHDQHZYDOXH
7KHYDOXHRIWKHYDULDEOHinstanceMemberDOVRVWDUWVDWLQHDFKLQVWDQFH2QWKHRWKHU
KDQGWKRXJKHDFKLQVWDQFHLQFUHPHQWVLWVRZQFRS\DQGVHHVWKHYDOXHRILWVRZQ
YDULDEOH
6WDWLFFODVVDQGPHWKRGGHILQLWLRQVDUHVLPLODULQWKDWLQERWKFDVHVDVWDWLFREMHFWLV
YLVLEOHXVLQJLWVTXDOLILHGQDPHZKLOHDG\QDPLFREMHFWLVYLVLEOHRQO\WKURXJKDQLQ
VWDQFHUHIHUHQFH%H\RQGWKDWKRZHYHUWKHGLIIHUHQFHVDUHWULFNLHU
2QH VLJQLILFDQW GLIIHUHQFH LQ EHKDYLRU EHWZHHQ VWDWLFDOO\ DQG G\QDPLFDOO\ GHFODUHG
PHWKRGVLVWKDWVWDWLFDOO\GHFODUHGPHWKRGVFDQQRWEHRYHUULGGHQLQDVXEFODVV7KH
IROORZLQJIRULQVWDQFHIDLOVWRFRPSLOH
public class Star {
public static void twinkle() { }
}
public class Arcturus extends Star {
public void twinkle() { } // ERROR!!
}
public class Rigel {
// this one works
public void twinkle() { Star.twinkle(); }
}
7KHUHLVYHU\OLWWOHUHDVRQWRXVHVWDWLFPHWKRGVLQ-DYD,QHDUO\LPSOHPHQWDWLRQVRI
-DYDG\QDPLFPHWKRGGLVSDWFKZDVVLJQLILFDQWO\VORZHUWKDQVWDWLFGLVSDWFK'HYHO
RSHUVXVHGWRSUHIHUVWDWLFPHWKRGVLQRUGHUWR£RSWLPL]H¤WKHLUFRGH,Q$QGURLG¦VMXVW
LQWLPHFRPSLOHG'DOYLNHQYLURQPHQWWKHUHLVQRQHHGIRUWKLVNLQGRIRSWLPL]DWLRQ
DQ\PRUH([FHVVLYHXVHRIVWDWLFPHWKRGVLVXVXDOO\DQLQGLFDWRURIEDGDUFKLWHFWXUH
7KHGLIIHUHQFHEHWZHHQVWDWLFDOO\DQGG\QDPLFDOO\GHFODUHGFODVVHVLVWKHVXEWOHVW0RVW
RIWKHFODVVHVWKDWFRPSULVHDQDSSOLFDWLRQDUHVWDWLF$W\SLFDOFODVVLVGHFODUHGDQG
GHILQHGDWWKHWRSOHYHO¢RXWVLGHDQ\HQFORVLQJEORFN,PSOLFLWO\DOOVXFKGHFODUDWLRQV
DUHVWDWLF0RVWRWKHUGHFODUDWLRQVRQWKHRWKHUKDQGWDNHSODFHZLWKLQWKHHQFORVLQJ
EORFNRIVRPHFODVVDQGDUHE\GHIDXOWG\QDPLF:KHUHDVPRVWILHOGVDUHG\QDPLFE\
GHIDXOWDQGUHTXLUHDPRGLILHUWREHVWDWLFPRVWFODVVHVDUHVWDWLF
$EORFNLVWKHFRGHEHWZHHQWZRFXUO\EUDFHV^DQG`$Q\WKLQJ¢YDU
LDEOHVW\SHVPHWKRGVDQGVRRQ¢GHILQHGZLWKLQWKHEORFNLVYLVLEOH
ZLWKLQWKHEORFNDQGZLWKLQOH[LFDOO\QHVWHGEORFNV([FHSWZLWKLQWKH
VSHFLDOEORFNGHILQLQJDFODVVWKLQJVGHILQHGZLWKLQDEORFNDUHQRWYLVL
EOHRXWVLGHWKHEORFN
7KLVLVDFWXDOO\HQWLUHO\FRQVLVWHQW$FFRUGLQJWRRXUGHVFULSWLRQRIVWDWLF¢VRPHWKLQJ
WKDWEHORQJVWRWKHFODVVQRWWRDQLQVWDQFHRIWKDWFODVV¢WRSOHYHOGHFODUDWLRQVVKRXOG
44 | Chapter 2:ಗJava for Android
EHVWDWLF WKH\EHORQJWRQRFODVV :KHQGHFODUHGZLWKLQDQHQFORVLQJEORFNKRZHYHU¢
IRUH[DPSOHLQVLGHWKHGHILQLWLRQRIDWRSOHYHOFODVV¢DFODVVGHILQLWLRQLVDOVRG\QDPLF
E\GHIDXOW,QRUGHUWRFUHDWHDG\QDPLFDOO\GHFODUHGFODVVMXVWGHILQHLWLQVLGHDQRWKHU
FODVV
7KLVEULQJVXVWRWKHGLIIHUHQFHEHWZHHQDVWDWLFDQGDG\QDPLFFODVV$G\QDPLFFODVV
KDVDFFHVVWRLQVWDQFHPHPEHUVRIWKHHQFORVLQJFODVV VLQFHLWEHORQJVWRWKHLQVWDQFH $VWDWLFFODVVGRHVQRW+HUH¦VVRPHFRGHWRGHPRQVWUDWH
public class Outer {
public int x;
public class InnerOne {
public int fn() { return x; }
}
public static class InnerTube {
public int fn() {
return x; // ERROR!!!
}
}
}
public class OuterTest {
public void test() {
new Outer.InnerOne(); // ERROR!!!
new Outer.InnerTube();
}
}
$PRPHQW¦VUHIOHFWLRQZLOOFODULI\ZKDWLVKDSSHQLQJKHUH7KHILHOG xLVDPHPEHURI
DQLQVWDQFHRIWKHFODVVOuter,QRWKHUZRUGVWKHUHDUHORWVRIYDULDEOHVQDPHG[RQH
IRUHDFKUXQWLPHLQVWDQFHRIOuter7KHFODVVInnerTubeLVDSDUWRIWKHFODVVOuterEXW
QRWRIDQ\LQVWDQFHVRIOuter,WKDVQRZD\RILGHQWLI\LQJDQ[7KHFODVVInnerOneRQ
WKHRWKHUKDQGEHFDXVHLWLVG\QDPLFEHORQJVWRDQLQVWDQFHRIOuter<RXPLJKWWKLQN
RIDVHSDUDWHFODVVInnerOneIRUHDFKLQVWDQFHRIOuter WKRXJKWKLVLVQRWDFWXDOO\KRZ
LWLVLPSOHPHQWHG &RQVHTXHQWO\InnerOneKDVDFFHVVWRWKHPHPEHUVRIWKHLQVWDQFH
RIOuterWRZKLFKLWEHORQJV
OuterTestGHPRQVWUDWHVWKDWDVZLWKILHOGVZHFDQXVHWKHVWDWLFLQQHUGHILQLWLRQ LQ
WKLVFDVHFUHDWHDQLQVWDQFHRIWKHFODVV VLPSO\E\XVLQJLWVTXDOLILHGQDPH7KHG\
QDPLFGHILQLWLRQLVXVHIXOKRZHYHURQO\LQWKHFRQWH[WRIDQLQVWDQFH
Abstract Classes
-DYDSHUPLWVDFODVVGHFODUDWLRQWRHQWLUHO\RPLWWKHLPSOHPHQWDWLRQRIRQHRUPRUH
PHWKRGVE\GHFODULQJWKHFODVVDQGXQLPSOHPHQWHGPHWKRGVWREHabstract
public abstract class TemplatedService {
public final void service() {
The Java Type System | 45
}
// subclasses prepare in their own ways
prepareService();
// ... but they all run the same service
runService()
public abstract void prepareService();
private final void runService() {
// implementation of the service ...
}
}
public class ConcreteService extends TemplatedService {
void prepareService() {
// set up for the service
}
}
$QDEVWUDFWFODVVFDQQRWEHLQVWDQWLDWHG6XEW\SHVRIDQDEVWUDFWFODVVPXVWHLWKHUSUR
YLGHGHILQLWLRQVIRUDOOWKHDEVWUDFWPHWKRGVLQWKHVXSHUFODVVRUPXVWWKHPVHOYHVEH
GHFODUHGDEVWUDFW
$V KLQWHG LQ WKH H[DPSOH DEVWUDFW FODVVHV DUH XVHIXO LQ LPSOHPHQWLQJ WKH FRPPRQ
WHPSODWHSDWWHUQZKLFKSURYLGHVDUHXVDEOHSLHFHRIFRGHWKDWDOORZVFXVWRPL]DWLRQDW
VSHFLILFSRLQWVGXULQJLWVH[HFXWLRQ7KHUHXVDEOHSLHFHVDUHLPSOHPHQWHGDVDQDEVWUDFW
FODVV6XEW\SHVFXVWRPL]HWKHWHPSODWHE\LPSOHPHQWLQJWKHDEVWUDFWPHWKRGV
)RUPRUHLQIRUPDWLRQRQDEVWUDFWFODVVHVVHHWKH-DYDWXWRULDODWKWWSGRZQORDGRUDFOH
FRPMDYDVHWXWRULDOMDYD,DQG,DEVWUDFWKWPO
Interfaces
2WKHUODQJXDJHV HJ&3\WKRQDQG3HUO SHUPLWDFDSDELOLW\NQRZQDVPXOWLSOH
LPSOHPHQWDWLRQLQKHULWDQFHZKHUHE\DQREMHFWFDQLQKHULWLPSOHPHQWDWLRQVRIPHWK
RGVIURPPRUHWKDQRQHSDUHQWFODVV6XFKLQKHULWDQFHKLHUDUFKLHVFDQJHWSUHWW\FRP
SOLFDWHGDQGEHKDYHLQXQH[SHFWHGZD\V VXFKDVLQKHULWLQJWZRILHOGYDULDEOHVZLWKWKH
VDPHQDPHIURPWZRGLIIHUHQWVXSHUFODVVHV -DYD¦VGHYHORSHUVFKRVHWRWUDGHWKHSRZHU
RIPXOWLSOHLQKHULWDQFHIRUVLPSOLFLW\8QOLNHWKHPHQWLRQHGODQJXDJHVLQ-DYDDFODVV
PD\H[WHQGRQO\DVLQJOHVXSHUFODVV
,QVWHDGRIPXOWLSOHLPSOHPHQWDWLRQLQKHULWDQFHKRZHYHU-DYDSURYLGHVWKHDELOLW\IRU
DFODVVWRLQKHULWIURPVHYHUDOW\SHVXVLQJWKHFRQFHSWRIDQLQWHUIDFH,QWHUIDFHVSURYLGH
DZD\WRGHILQHDW\SHZLWKRXWGHILQLQJLWVLPSOHPHQWDWLRQ<RXFDQWKLQNRILQWHUIDFHV
DVDEVWUDFWFODVVHVZLWKDOODEVWUDFWPHWKRGV7KHUHLVQROLPLWRQWKHQXPEHURILQWHU
IDFHVWKDWDFODVVPD\LPSOHPHQW
+HUH¦VDQH[DPSOHRID-DYDLQWHUIDFHDQGDFODVVWKDWLPSOHPHQWVLW
public interface Growable {
// declare the signature but not the implementation
46 | Chapter 2:ಗJava for Android
}
void grow(Fertilizer food, Water water);
public interface Eatable {
// another signature with no implementation
void munch();
}
/**
* An implementing class must implement all interface methods
*/
public class Beans implements Growable, Eatable {
@Override
public void grow(Fertilizer food, Water water) {
// ...
}
}
@Override
public void munch() {
// ...
}
$JDLQLQWHUIDFHVSURYLGHDZD\WRGHILQHDW\SHGLVWLQFWIURPWKHLPSOHPHQWDWLRQRI
WKDWW\SH7KLVNLQGRIVHSDUDWLRQLVFRPPRQHYHQLQHYHU\GD\OLIH,I\RXDQGDFROOHDJXH
DUHWU\LQJWRPL[PRMLWRV\RXPLJKWZHOOGLYLGHWDVNVVRWKDWVKHJRHVWRJHWWKHPLQW
:KHQ\RXVWDUWPXGGOLQJWKLQJVLQWKHERWWRPRIWKHJODVVLWLVLUUHOHYDQWZKHWKHUVKH
GURYHWRWKHVWRUHWREX\WKHPLQWRUZHQWRXWWRWKHEDFN\DUGDQGSLFNHGLWIURPD
VKUXE:KDW¦VLPSRUWDQWLVWKDW\RXKDYHPLQW
$VDQRWKHUH[DPSOHRIWKHSRZHURILQWHUIDFHVFRQVLGHUDSURJUDPWKDWQHHGVWRGLVSOD\
DOLVWRIFRQWDFWVVRUWHGE\HPDLODGGUHVV$V\RXZRXOGFHUWDLQO\H[SHFWWKH$QGURLG
UXQWLPH OLEUDULHV FRQWDLQ JHQHULF URXWLQHV WR VRUW REMHFWV %HFDXVH WKH\ DUH JHQHULF
KRZHYHUWKHVHURXWLQHVKDYHQRLQWULQVLFLGHDRIZKDWRUGHULQJPHDQVIRUWKHLQVWDQFHV
RIDQ\SDUWLFXODUFODVV,QRUGHUWRXVHWKHOLEUDU\VRUWLQJURXWLQHVDFODVVQHHGVDZD\
WRGHILQHLWVRZQRUGHULQJ&ODVVHVGRWKLVLQ-DYDXVLQJWKHLQWHUIDFHComparable
2EMHFWVRIW\SHComparableLPSOHPHQWWKHPHWKRGcompareTo2QHREMHFWDFFHSWVDQ
RWKHUVLPLODUREMHFWDVDQDUJXPHQWDQGUHWXUQVDQLQWHJHUWKDWLQGLFDWHVZKHWKHUWKH
DUJXPHQWREMHFWLVJUHDWHUWKDQHTXDOWRRUOHVVWKDQWKHWDUJHW7KHOLEUDU\URXWLQHV
FDQVRUWDQ\WKLQJWKDWLV Comparable$SURJUDP¦V ContactW\SHQHHGRQO\EH Compara
bleDQGLPSOHPHQWcompareToWRDOORZFRQWDFWVWREHVRUWHG
public class Contact implements Comparable<Contact> {
// ... other fields
private String email;
public Contact(
// other params...
String emailAddress)
{
The Java Type System | 47
}
// ... init other fields from corresponding params
email = emailAddress;
public int compareTo(Contact c) {
return email.compareTo(c.email);
}
}
public class ContactView {
// ...
private List<Contact> getContactsSortedByEmail(
List<Contact> contacts)
{
// getting the sorted list of contacts
// is completely trivial
return Collections.sort(contacts);
}
// ...
}
,QWHUQDOO\WKHCollections.sortURXWLQHNQRZVRQO\WKDWcontactsLVDOLVWRIWKLQJVRI
W\SHComparable,WLQYRNHVWKHFODVV¦VcompareToPHWKRGWRGHFLGHKRZWRRUGHUWKHP
$VWKLVH[DPSOHGHPRQVWUDWHVLQWHUIDFHVHQDEOHWKHGHYHORSHUWRUHXVHJHQHULFURXWLQHV
WKDWFDQVRUWDQ\OLVWRIREMHFWVWKDWLPSOHPHQWComparable%H\RQGWKLVVLPSOHH[DPSOH
-DYDLQWHUIDFHVHQDEOHDGLYHUVHVHWRISURJUDPPLQJSDWWHUQVWKDWDUHZHOOGHVFULEHGLQ
RWKHUVRXUFHV:HIUHTXHQWO\DQGKLJKO\UHFRPPHQGWKHH[FHOOHQW(IIHFWLYH-DYDE\
-RVKXD%ORFK 3UHQWLFH+DOO Exceptions
7KH-DYDODQJXDJHXVHVH[FHSWLRQVDVDFRQYHQLHQWZD\WRKDQGOHXQXVXDOFRQGLWLRQV
)UHTXHQWO\WKHVHFRQGLWLRQVDUHHUURUV
&RGHWU\LQJWRSDUVHDZHESDJHIRULQVWDQFHFDQQRWFRQWLQXHLILWFDQQRWUHDGWKH
SDJHIURPWKHQHWZRUN&HUWDLQO\LWLVSRVVLEOHWRFKHFNWKHUHVXOWVRIWKHDWWHPSWWR
UHDGDQGSURFHHGRQO\LIWKDWDWWHPSWVXFFHHGVDVVKRZQLQWKLVH[DPSOH
public void getPage(URL url) {
String smallPage = readPageFromNet(url);
if (null != smallPage) {
Document dom = parsePage(smallPage);
if (null != dom) {
NodeList actions = getActions(dom);
if (null != action) {
// process the action here...
}
}
}
}
48 | Chapter 2:ಗJava for Android
([FHSWLRQVPDNHWKLVPRUHHOHJDQWDQGUREXVW
public void getPage(URL url)
throws NetworkException, ParseException, ActionNotFoundException
{
String smallPage = readPageFromNet(url);
Document dom = parsePage(smallPage);
NodeList actions = getActions(dom);
// process the action here...
}
public String readPageFromNet(URL url) throws NetworkException {
// ...
public Document parsePage(String xml) throws ParseException {
// ...
public NodeList getActions(Document doc) throws ActionNotFoundException {
// ...
,QWKLVYHUVLRQRIWKHFRGHHDFKPHWKRGFDOOHGIURPgetPageXVHVDQH[FHSWLRQWRLP
PHGLDWHO\VKRUWFLUFXLWDOOIXUWKHUSURFHVVLQJLIVRPHWKLQJJRHVZURQJ7KHPHWKRGV
DUHVDLGWRWKURZH[FHSWLRQV)RULQVWDQFHWKH getActionsPHWKRGPLJKWORRNVRPH
WKLQJOLNHWKLV
public NodeList getActions(Document dom)
throws ActionNotFoundException
{
Object actions = xPathFactory.newXPath().compile("//node/@action")
.evaluate(dom, XPathConstants.NODESET);
if (null == actions) {
throw new ActionNotFoundException("Action not found");
}
return (NodeList) actions;
}
:KHQWKHthrowVWDWHPHQWLVH[HFXWHGSURFHVVLQJLVLPPHGLDWHO\LQWHUUXSWHGDQGUH
VXPHVDWWKHQHDUHVWFDWFKEORFN+HUH¦VDQH[DPSOHRIDWU\FDWFKEORFN
for (int i = 0; i < MAX_RETRIES; i++) {
try {
getPage(theUrl);
break;
}
catch (NetworkException e) {
Log.d("ActionDecoder", "network error: " + e);
}
}
7KLV FRGH UHWULHV QHWZRUN IDLOXUHV 1RWH WKDW LW LV QRW HYHQ LQ WKH VDPH PHWKRG
readPageFromNetWKDWWKUHZWKH NetworkException:KHQZHVD\WKDWSURFHVVLQJUH
VXPHVDWWKH£QHDUHVW¤WU\FDWFKEORFNZH¦UHWDONLQJDERXWDQLQWHUHVWLQJZD\WKDW-DYD
GHOHJDWHVUHVSRQVLELOLW\IRUH[FHSWLRQV
The Java Type System | 49
,IWKHUHLVQRWU\FDWFKEORFNVXUURXQGLQJWKH throwVWDWHPHQWZLWKLQWKHPHWKRGD
WKURZQH[FHSWLRQPDNHVLWVHHPDVWKRXJKWKHPHWKRGUHWXUQVLPPHGLDWHO\1RIXUWKHU
VWDWHPHQWVDUHH[HFXWHGDQGQRYDOXHLVUHWXUQHG,QWKHSUHYLRXVH[DPSOHIRULQVWDQFH
QRQH RI WKH FRGH IROORZLQJ WKH DWWHPSW WR JHW WKH SDJH IURP WKH QHWZRUN QHHGV WR
FRQFHUQ LWVHOI ZLWK WKH SRVVLELOLW\ WKDW WKH SUHFRQGLWLRQ¢D SDJH ZDV UHDG¢ZDV
QRWPHW7KHPHWKRGLVVDLGWRKDYHEHHQWHUPLQDWHGDEUXSWO\DQGLQWKHH[DPSOH
FRQWUROUHWXUQVWRgetActions6LQFHgetActionsGRHVQRWFRQWDLQDWU\FDWFKEORFNHL
WKHULWLVWHUPLQDWHGDEUXSWO\WRR&RQWUROLVSDVVHGEDFN XSWKHVWDFN WRWKHFDOOHU
,QWKHH[DPSOHZKHQDNetworkExceptionLVWKURZQFRQWUROUHWXUQVWRWKHILUVWVWDWH
PHQWLQVLGHWKHH[DPSOHcatchEORFNWKHFDOOWRORJWKHQHWZRUNHUURU7KHH[FHSWLRQ
LVVDLGWRKDYHEHHQFDXJKWDWWKHILUVWcatchVWDWHPHQWZKRVHDUJXPHQWW\SHLVWKHVDPH
W\SHRUDVXSHUW\SHRIWKHWKURZQH[FHSWLRQ3URFHVVLQJUHVXPHVDWWKHILUVWVWDWHPHQW
LQWKHcatchEORFNDQGFRQWLQXHVQRUPDOO\DIWHUZDUG
,QWKHH[DPSOHDQHWZRUNHUURUZKLOHDWWHPSWLQJWRUHDGDSDJHIURPWKHQHWZRUNZLOO
FDXVHERWK ReadPageFromNetDQG getPageWRWHUPLQDWHDEUXSWO\$IWHUWKH catchEORFN
ORJVWKHIDLOXUHWKHforORRSZLOOUHWU\JHWWLQJWKHSDJHXSWRMAX_RETRIESWLPHV
,WLVXVHIXOWRKDYHDFOHDUXQGHUVWDQGLQJRIWKHURRWRIWKH-DYDH[FHSWLRQFODVVWUHH
VKRZQLQ)LJXUH
)LJXUH([FHSWLRQEDVHFODVVHV
$OOH[FHSWLRQVDUHVXEFODVVHVRI Throwable7KHUHLVDOPRVWQHYHUDQ\UHDVRQWRPDNH
UHIHUHQFHWRThrowableLQ\RXUFRGH7KLQNRILWDVMXVWDQDEVWUDFWEDVHFODVVZLWKWZR
50 | Chapter 2:ಗJava for Android
VXEFODVVHVErrorDQGExceptionErrorDQGLWVVXEFODVVHVDUHUHVHUYHGIRUSUREOHPVZLWK
WKH'DOYLNUXQWLPHHQYLURQPHQWLWVHOI:KLOH\RXFDQZULWHFRGHWKDWDSSHDUVWRFDWFK
DQError RUDThrowable \RXFDQQRWLQIDFWFDWFKWKHP$QREYLRXVH[DPSOHRIWKLV
IRULQVWDQFHLVWKHGUHDGHG220(WKHOutOfMemoryExceptionHUURU:KHQWKH'DOYLN
V\VWHPLVRXWRIPHPRU\LWPD\QRWEHDEOHWRFRPSOHWHH[HFXWLRQRIHYHQDVLQJOH
RSFRGH:ULWLQJWULFN\FRGHWKDWDWWHPSWVWRFDWFKDQ220(DQGWKHQWRUHOHDVHVRPH
EORFNRISUHDOORFDWHGPHPRU\PLJKWZRUN¢RULWPLJKWQRW&RGHWKDWWULHVWRFDWFK
ThrowableRUErrorLVDEVROXWHO\ZKLVWOLQJLQWKHZLQG
-DYDUHTXLUHVWKHVLJQDWXUHRIDPHWKRGWRLQFOXGHWKHH[FHSWLRQVWKDWLWWKURZV,QWKH
SUHYLRXVH[DPSOHgetPageGHFODUHVWKDWLWWKURZVWKUHHH[FHSWLRQVEHFDXVHLWXVHVWKUHH
PHWKRGVHDFKRIZKLFKWKURZVRQH0HWKRGVWKDWFDOOgetPagePXVWLQWXUQGHFODUH
DOOWKUHHRIWKHH[FHSWLRQVWKDW getPageWKURZVDORQJZLWKDQ\RWKHUVWKURZQE\DQ\
RWKHUPHWKRGVWKDWLWFDOOV
$V\RXFDQLPDJLQHWKLVFDQEHFRPHRQHURXVIRUPHWKRGVIDUXSWKHFDOOWUHH$WRS
OHYHOPHWKRGPLJKWKDYHWRGHFODUHWHQVRIGLIIHUHQWNLQGVRIH[FHSWLRQVMXVWEHFDXVH
LWFDOOVPHWKRGVWKDWWKURZWKHP7KLVSUREOHPFDQEHPLWLJDWHGE\FUHDWLQJDQH[
FHSWLRQWUHHWKDWLVFRQJUXHQWWRWKHDSSOLFDWLRQWUHH5HPHPEHUWKDWDPHWKRGQHHGV
RQO\WRGHFODUHVXSHUW\SHVIRUDOOWKHH[FHSWLRQVLWWKURZV,I\RXFUHDWHDEDVHFODVV
QDPHGMyApplicationExceptionDQGWKHQVXEFODVVLWWRFUHDWHMyNetworkExceptionDQG
MyUIExceptionIRUWKHQHWZRUNLQJDQG8,VXEV\VWHPVUHVSHFWLYHO\\RXUWRSOD\HUFRGH
QHHGRQO\KDQGOHMyApplicationException
5HDOO\WKRXJKWKLVLVRQO\DSDUWLDOVROXWLRQ6XSSRVHQHWZRUNLQJFRGHVRPHZKHUH
ZD\GRZQLQWKHERZHOVRI\RXUDSSOLFDWLRQIDLOVIRULQVWDQFHWRRSHQDQHWZRUNFRQ
QHFWLRQ$VWKHH[FHSWLRQEXEEOHVXSWKURXJKUHWULHVDQGDOWHUQDWLYHVDWVRPHSRLQWLW
ORVHVDQ\VLJQLILFDQFHH[FHSWWRLQGLFDWHWKDW£VRPHWKLQJZHQWZURQJ¤$VSHFLILFGD
WDEDVHH[FHSWLRQIRULQVWDQFHPHDQVQRWKLQJWRFRGHWKDWLVWU\LQJWRSUHSRSXODWHD
SKRQHQXPEHU$GGLQJWKHH[FHSWLRQWRDPHWKRGVLJQDWXUHDWWKDWSRLQWLVUHDOO\MXVW
DQXLVDQFH\RXPLJKWDVZHOOVLPSO\GHFODUHWKDWDOO\RXUPHWKRGVWKURZException
RuntimeExceptionLVDVSHFLDOVXEFODVVRIException6XEFODVVHVRIRuntimeExceptionDUH
FDOOHGXQFKHFNHGH[FHSWLRQVDQGGRQRWKDYHWREHGHFODUHG7KLVFRGHIRULQVWDQFH
ZLOOFRPSLOHZLWKRXWHUURU
public void ThrowsRuntimeException() {
throw new RuntimeException();
}
7KHUHLVFRQVLGHUDEOHGHEDWHLQWKH-DYDFRPPXQLW\DERXWZKHQWRXVHDQGZKHQQRW
WRXVHXQFKHFNHGH[FHSWLRQV2EYLRXVO\\RXFRXOGXVHRQO\XQFKHFNHGH[FHSWLRQVLQ
\RXUDSSOLFDWLRQDQGQHYHUGHFODUHDQ\H[FHSWLRQLQDQ\RI\RXUPHWKRGVLJQDWXUHV
6RPHVFKRROVRI-DYDSURJUDPPLQJHYHQUHFRPPHQGWKLV8VLQJFKHFNHGH[FHSWLRQV
KRZHYHUJLYHV\RXWKHFKDQFHWRXVHWKHFRPSLOHUWRYHULI\\RXUFRGHDQGLVYHU\PXFK
LQWKHVSLULWRIVWDWLFW\SLQJ([SHULHQFHDQGWDVWHZLOOEH\RXUJXLGH
The Java Type System | 51
The Java Collections Framework
7KH-DYD&ROOHFWLRQV)UDPHZRUNLVRQHRI-DYD¦VPRVWSRZHUIXODQGFRQYHQLHQWWRROV
,WSURYLGHVREMHFWVWKDWUHSUHVHQWFROOHFWLRQVRIREMHFWVOLVWVVHWVDQGPDSV7KHLQ
WHUIDFHV DQG LPSOHPHQWDWLRQV WKDW FRPSULVH WKH OLEUDU\ DUH DOO WR EH IRXQG LQ WKH
java.utilSDFNDJH
7KHUHDUHDIHZOHJDF\FODVVHVLQjava.utilWKDWDUHKLVWRULFUHOLFVDQGDUHQRWWUXO\SDUW
RIWKHIUDPHZRUN,W¦VEHVWWRUHPHPEHUDQGDYRLGWKHP7KH\DUHVectorHashtable
EnumerationDQGDictionary
Collection interface types
(DFKRIWKHILYHPDLQW\SHVRIREMHFWLQWKH&ROOHFWLRQV/LEUDU\LVUHSUHVHQWHGE\DQ
LQWHUIDFH
Collection
7KLVLVWKHURRWW\SHIRUDOORIWKHREMHFWVLQWKH&ROOHFWLRQ/LEUDU\$ Collection
LVDJURXSRIREMHFWVQRWQHFHVVDULO\RUGHUHGQRWQHFHVVDULO\DGGUHVVDEOHSRVVLEO\
FRQWDLQLQJGXSOLFDWHV<RXFDQDGGDQGUHPRYHWKLQJVIURPLWJHWLWVVL]HDQG
LWHUDWHRYHULW PRUHRQLWHUDWLRQLQDPRPHQW List
$ ListLVDQRUGHUHGFROOHFWLRQ7KHUHLVDPDSSLQJEHWZHHQWKHLQWHJHUVDQG
OHQJWK¡DQGWKHREMHFWVLQWKHOLVW$ ListPD\FRQWDLQGXSOLFDWHV<RXFDQGR
DQ\WKLQJWRDListWKDW\RXFDQGRWRD Collection,QDGGLWLRQWKRXJK\RXFDQ
PDSDQHOHPHQWWRLWVLQGH[DQGDQLQGH[WRDQHOHPHQWZLWKWKHgetDQGindexOf
PHWKRGV<RXFDQDOVRFKDQJHWKHHOHPHQWDWDVSHFLILFLQGH[ZLWKWKHadd(index,
e)PHWKRG7KHLWHUDWRUIRUDListUHWXUQVWKHHOHPHQWVLQRUGHU
Set
$ Set LV DQ XQRUGHUHG FROOHFWLRQ WKDW GRHV QRW FRQWDLQ GXSOLFDWHV <RX FDQ GR
DQ\WKLQJWRDSetWKDW\RXFDQGRWRDCollection$WWHPSWLQJWRDGGDQHOHPHQW
WRDSetWKDWDOUHDG\FRQWDLQVLWWKRXJKGRHVQRWFKDQJHWKHVL]HRIWKHSet
Map
$MapLVOLNHDOLVWH[FHSWWKDWLQVWHDGRIPDSSLQJLQWHJHUVWRREMHFWVLWPDSVDVHW
RINH\REMHFWVWRDFROOHFWLRQRIYDOXHREMHFWV<RXFDQDGGDQGUHPRYHNH\YDOXH
SDLUVIURPWKH MapJHWLWVVL]HDQGLWHUDWHRYHULWMXVWOLNHDQ\RWKHUFROOHFWLRQ
([DPSOHV RI PDSV PLJKW LQFOXGH PDSSLQJ ZRUGV WR WKHLU GHILQLWLRQV GDWHV WR
HYHQWVRU85/VWRFDFKHGFRQWHQW
Iterator
$Q IteratorUHWXUQVWKHHOHPHQWVRIWKHFROOHFWLRQIURPZKLFKLWLVGHULYHGHDFK
H[DFWO\RQFHLQUHVSRQVHWRFDOOVWRLWVnextPHWKRG,WLVWKHSUHIHUUHGPHDQVIRU
SURFHVVLQJDOOWKHHOHPHQWVRIDFROOHFWLRQ,QVWHDGRI
52 | Chapter 2:ಗJava for Android
Download from Wow! eBook <www.wowebook.com>
for (int i = 0; i < list.size(); i++) {
String s = list.get(i)
// ...
}
WKHIROORZLQJLVSUHIHUUHG
for (Iterator<String> i = list.iterator(); i.hasNext();) {
String s = i.next();
// ...
}
,QIDFWWKHODWWHUPD\EHDEEUHYLDWHGVLPSO\DV
for (String s: list) {
// ...
}
Collection implementation types
7KHVHLQWHUIDFHW\SHVKDYHPXOWLSOHLPSOHPHQWDWLRQVHDFKDSSURSULDWHWRLWVRZQXVH
FDVH$PRQJWKHPRVWFRPPRQRIWKHVHDUHWKHIROORZLQJ
ArrayList
$Q ArrayListLVDOLVWWKDWLVEDFNHGE\DQDUUD\,WLVTXLFNWRLQGH[EXWVORZWR
FKDQJHVL]H
LinkedList
$LinkedListLVDOLVWWKDWFDQFKDQJHVL]HTXLFNO\EXWLVVORZHUWRLQGH[
HashSet
$HashSetLVDVHWWKDWLVLPSOHPHQWHGDVDKDVKaddremovecontainsDQGsizeDOO
H[HFXWHLQFRQVWDQWWLPHDVVXPLQJDZHOOEHKDYHGKDVK$ HashSetPD\FRQWDLQ
QRPRUHWKDQRQH null
HashMap
$ HashMapLVDQLPSOHPHQWDWLRQRIWKH MapLQWHUIDFHWKDWXVHVDKDVKWDEOHDVLWV
LQGH[addremovecontainsDQGsizeDOOH[HFXWHLQFRQVWDQWWLPHDVVXPLQJDZHOO
EHKDYHGKDVK,WPD\FRQWDLQD VLQJOH nullNH\EXWDQ\QXPEHURIYDOXHVPD\
EHnull
TreeMap
$TreeMapLVDQRUGHUHGMapREMHFWVLQWKHPDSDUHVRUWHGDFFRUGLQJWRWKHLUQDWXUDO
RUGHU LI WKH\ LPSOHPHQW WKH Comparable LQWHUIDFH RU DFFRUGLQJ WR D Comparator
SDVVHGWRWKHTreeMapFRQVWUXFWRULIWKH\GRQRW
,GLRPDWLFXVHUVRI-DYDSUHIHUWRXVHGHFODUDWLRQVRILQWHUIDFHW\SHVLQVWHDGRIGHFODUD
WLRQVRILPSOHPHQWDWLRQW\SHVZKHQHYHUSRVVLEOH7KLVLVDJHQHUDOUXOHEXWLWLVHDVLHVW
WRXQGHUVWDQGKHUHLQWKHFRQWH[WRIWKHFROOHFWLRQIUDPHZRUN
The Java Type System | 53
&RQVLGHUDPHWKRGWKDWUHWXUQVDQHZOLVWRIVWULQJVWKDWLVMXVWOLNHWKHOLVWRIVWULQJV
SDVVHGDVLWVVHFRQGSDUDPHWHUEXWLQZKLFKHDFKHOHPHQWLVSUHIL[HGZLWKWKHVWULQJ
SDVVHGDVWKHILUVWSDUDPHWHU,WPLJKWORRNOLNHWKLV
public ArrayList<String> prefixList(
String prefix,
ArrayList<String> strs)
{
ArrayList<String> ret
= new ArrayList<String>(strs.size());
for (String s: strs) { ret.add(prefix + s); }
return ret;
}
7KHUH¦VDSUREOHPZLWKWKLVLPSOHPHQWDWLRQWKRXJKLWZRQ¦WZRUNRQMXVWDQ\OLVW,W
ZLOORQO\ZRUNRQDQArrayList,IDWVRPHSRLQWWKHFRGHWKDWFDOOVWKLVPHWKRGQHHGV
WREHFKDQJHGIURPXVLQJDQArrayListWRDLinkedListLWFDQQRORQJHUXVHWKHPHWKRG
7KHUH¦VQRJRRGUHDVRQIRUWKDWDWDOO
$EHWWHULPSOHPHQWDWLRQPLJKWORRNOLNHWKLV
public List<String> prefix(
String prefix,
List<String> strs)
{
List<String> ret = new ArrayList<String>(strs.size());
for (String s: strs) { ret.add(prefix + s); }
return ret;
}
7KLV YHUVLRQ LV PRUH DGDSWDEOH EHFDXVH LW GRHVQ¦W ELQG WKH PHWKRG WR D SDUWLFXODU
LPSOHPHQWDWLRQRIWKHOLVW7KHPHWKRGGHSHQGVRQO\RQWKHIDFWWKDWWKHSDUDPHWHU
LPSOHPHQWVDFHUWDLQLQWHUIDFH,WGRHVQ¦WFDUHKRZ%\XVLQJWKHLQWHUIDFHW\SHDVD
SDUDPHWHULWUHTXLUHVH[DFWO\ZKDWLWQHHGVWRGRLWVMRE¢QRPRUHQROHVV
,QIDFWWKLVFRXOGSUREDEO\EHIXUWKHULPSURYHGLILWVSDUDPHWHUDQGUHWXUQW\SHZHUH
Collection
Java generics
*HQHULFVLQ-DYDDUHDODUJHDQGIDLUO\FRPSOH[WRSLF(QWLUHERRNVKDYHEHHQZULWWHQ
RQWKHVXEMHFW7KLVVHFWLRQLQWURGXFHVWKHPLQWKHLUPRVWFRPPRQVHWWLQJWKH&RO
OHFWLRQV/LEUDU\EXWZLOOQRWDWWHPSWWRGLVFXVVWKHPLQGHWDLO
%HIRUH WKH LQWURGXFWLRQ RI JHQHULFV LQ -DYD LW ZDVQ¦W SRVVLEOH WR VWDWLFDOO\ W\SH WKH
FRQWHQWVRIDFRQWDLQHU2QHIUHTXHQWO\VDZFRGHWKDWORRNHGOLNHWKLV
public List makeList() {
// ...
}
public void useList(List l) {
Thing t = (Thing) l.get(0);
// ...
54 | Chapter 2:ಗJava for Android
}
// ...
useList(makeList());
7KH SUREOHP LV REYLRXV useList KDV QR JXDUDQWHH WKDW makeList FUHDWHG D OLVW RI
Thing7KHFRPSLOHUFDQQRWYHULI\WKDWWKHFDVWLQuseListZLOOZRUNDQGWKHFRGHPLJKW
H[SORGHDWUXQWLPH
*HQHULFVVROYHWKLVSUREOHP¢DWWKHFRVWRIVRPHVLJQLILFDQWFRPSOH[LW\7KHV\QWD[
IRUDJHQHULFGHFODUDWLRQZDVLQWURGXFHGZLWKRXWFRPPHQWSUHYLRXVO\+HUH¦VDYHU
VLRQRIWKHH[DPSOHZLWKWKHJHQHULFVDGGHG
public List<Thing> makeList() {
// ...
}
public void useList(List<Thing> l) {
Thing t = l.get(0);
// ...
}
// ...
useList(makeList());
7KHW\SHRIWKHREMHFWVLQDFRQWDLQHULVVSHFLILHGLQWKHDQJOHEUDFNHWV ! WKDWDUH
SDUWRIWKHFRQWDLQHUW\SH1RWLFHWKDWWKHFDVWLVQRORQJHUQHFHVVDU\LQuseListEHFDXVH
WKHFRPSLOHUFDQQRZWHOOWKDWWKHSDUDPHWHUlLVDOLVWRIThing
*HQHULF W\SH GHVFULSWLRQV FDQ JHW SUHWW\ YHUERVH 'HFODUDWLRQV OLNH WKLV DUH QRW
XQFRPPRQ
Map<UUID, Map<String, Thing>> cache
= new HashMap<UUID, Map<String, Thing>>();
Garbage Collection
-DYDLVDJDUEDJHFROOHFWHGODQJXDJH7KDWPHDQV\RXUFRGHGRHVQRWPDQDJHPHPRU\
,QVWHDG\RXUFRGHFUHDWHVQHZREMHFWVDOORFDWLQJPHPRU\DQGWKHQVLPSO\VWRSVXVLQJ
WKRVHREMHFWVZKHQLWQRORQJHUQHHGVWKHP7KH'DOYLNUXQWLPHZLOOGHOHWHWKHPDQG
FRPSUHVVPHPRU\DVDSSURSULDWH
,QWKHQRWVRGLVWDQWSDVWGHYHORSHUVKDGWRZRUU\DERXWORQJDQGXQSUHGLFWDEOHSH
ULRGVRIXQUHVSRQVLYHQHVVLQWKHLUDSSOLFDWLRQVZKHQWKHJDUEDJHFROOHFWRUVXVSHQGHG
DOODSSOLFDWLRQSURFHVVLQJWRUHFRYHUPHPRU\0DQ\GHYHORSHUVERWKWKRVHWKDWXVHG
-DYDLQLWVHDUO\GD\VDQGWKRVHWKDWXVHG-0(PRUHUHFHQWO\ZLOOUHPHPEHUWKHWULFNV
KDFNVDQGXQZULWWHQUXOHVQHFHVVDU\WRDYRLGWKHORQJSDXVHVDQGPHPRU\IUDJPHQ
WDWLRQFDXVHGE\HDUO\JDUEDJHFROOHFWRUV*DUEDJHFROOHFWLRQWHFKQRORJ\KDVFRPHD
ORQJZD\VLQFHWKRVHGD\V'DOYLNHPSKDWLFDOO\GRHVQRWKDYHWKHVHSUREOHPV&UHDWLQJ
QHZREMHFWV KDVHVVHQWLDOO\QR RYHUKHDG 2QO\ WKH PRVW GHPDQGLQJO\UHVSRQVLYHRI
8,V¢SHUKDSVVRPHJDPHV¢ZLOOHYHUQHHGWRZRUU\DERXWJDUEDJHFROOHFWLRQSDXVHV
The Java Type System | 55
Scope
6FRSHGHWHUPLQHVZKHUHYDULDEOHVPHWKRGVDQGRWKHUV\PEROVDUHYLVLEOHLQDSURJUDP
2XWVLGHRIDV\PERO¦VVFRSHWKHV\PEROLVQRWYLVLEOHDWDOODQGFDQQRWEHXVHG:H¦OO
JRRYHUWKHPDMRUDVSHFWVRIVFRSHLQWKLVVHFWLRQVWDUWLQJZLWKWKHKLJKHVWOHYHO
Java Packages
-DYDSDFNDJHVSURYLGHDPHFKDQLVPIRUJURXSLQJUHODWHGW\SHVWRJHWKHULQDXQLYHUVDOO\
XQLTXHQDPHVSDFH6XFKJURXSLQJSUHYHQWVLGHQWLILHUVZLWKLQWKHSDFNDJHQDPHVSDFH
IURPFROOLGLQJZLWKWKRVHFUHDWHGDQGXVHGE\RWKHUGHYHORSHUVLQRWKHUQDPHVSDFHV
$W\SLFDO-DYDSURJUDPLVPDGHXSRIFRGHIURPDIRUHVWRISDFNDJHV7KHVWDQGDUG-DYD
5XQWLPH(QYLURQPHQWVXSSOLHVSDFNDJHVOLNHjava.langDQGjava.util,QDGGLWLRQWKH
SURJUDPPD\GHSHQGRQRWKHUFRPPRQOLEUDULHVOLNHWKRVHLQWKHorg.apacheWUHH%\
FRQYHQWLRQDSSOLFDWLRQFRGH¢FRGH\RXFUHDWH¢JRHVLQWRDSDFNDJHZKRVHQDPHLV
FUHDWHGE\UHYHUVLQJ\RXUGRPDLQQDPHDQGDSSHQGLQJWKHQDPHRIWKHSURJUDP7KXV
LI \RXU GRPDLQ QDPH LV androidhero.com WKH URRW RI \RXU SDFNDJH WUHH ZLOO EH
com.androidhero DQG \RX ZLOO SXW \RXU FRGH LQWR SDFNDJHV OLNH
com.androidhero.awesomeprogramDQGcom.androidhero.geohottness.service$W\SLFDO
SDFNDJH OD\RXW IRU DQ $QGURLG DSSOLFDWLRQ PLJKW KDYH D SDFNDJH IRU SHUVLVWHQFH D
SDFNDJHIRUWKH8,DQGDSDFNDJHIRUDSSOLFDWLRQORJLFRUFRQWUROOHUFRGH
,QDGGLWLRQWRSURYLGLQJDXQLTXHQDPHVSDFHSDFNDJHVKDYHLPSOLFDWLRQVRQPHPEHU
ILHOGDQGPHWKRG YLVLELOLW\IRUREMHFWVLQWKHVDPHSDFNDJH&ODVVHVLQWKHVDPHSDFN
DJHPD\EHDEOHWRVHHHDFKRWKHU¦VLQWHUQDOVLQZD\VWKDWDUHQRWDYDLODEOHWRFODVVHV
RXWVLGHWKHSDFNDJH:H¦OOUHWXUQWRWKLVWRSLFLQDPRPHQW
7RGHFODUHDFODVVDVSDUWRIDSDFNDJHXVHWKH packageNH\ZRUGDWWKHWRSRIWKHILOH
FRQWDLQLQJ\RXUFODVVGHILQLWLRQ
package your.qualifieddomainname.functionalgrouping
'RQ¦W EH WHPSWHG WR VKRUWFXW \RXU SDFNDJH QDPH $V VXUHO\ DV D TXLFN WHPSRUDU\
LPSOHPHQWDWLRQODVWVIRU\HDUVVRWKHFKRLFHRIDSDFNDJHQDPHWKDWLVQRWJXDUDQWHHG
XQLTXHZLOOFRPHEDFNWRKDXQW\RX
6RPHODUJHUSURMHFWVXVHFRPSOHWHO\GLIIHUHQWWRSOHYHOGRPDLQVWRVHSDUDWHSXEOLF$3,
SDFNDJHVIURPWKHSDFNDJHVWKDWLPSOHPHQWWKRVH$3,V)RUH[DPSOHWKH$QGURLG$3,
XVHVWKHWRSOHYHOSDFNDJHandroidDQGLPSOHPHQWDWLRQFODVVHVJHQHUDOO\UHVLGHLQWKH
SDFNDJH com.android6XQ¦V-DYDVRXUFHFRGHIROORZVDVLPLODUVFKHPH3XEOLF$3,V
UHVLGHLQWKHjavaSDFNDJHEXWWKHLPSOHPHQWDWLRQFRGHUHVLGHVLQWKHSDFNDJHsun,Q
HLWKHUFDVHDQDSSOLFDWLRQWKDWLPSRUWVDQLPSOHPHQWDWLRQSDFNDJHLVFOHDUO\GRLQJ
VRPHWKLQJIDVWDQGORRVHGHSHQGLQJRQVRPHWKLQJWKDWLVQRWSDUWRIWKHSXEOLF$3,
:KLOHLWLVSRVVLEOHWRDGGFRGHWRH[LVWLQJSDFNDJHVLWLVXVXDOO\FRQVLGHUHGEDGIRUP
WRGRVR,QJHQHUDOLQDGGLWLRQWREHLQJDQDPHVSDFHDSDFNDJHLVXVXDOO\DVLQJOH
VRXUFHWUHHDWOHDVWXSDVIDUDVWKHUHYHUVHGGRPDLQQDPH,WLVRQO\FRQYHQWLRQEXW
56 | Chapter 2:ಗJava for Android
-DYD GHYHORSHUV XVXDOO\ H[SHFW WKDW ZKHQ WKH\ ORRN DW WKH VRXUFH IRU WKH SDFNDJH
com.brashandroid.coolapp.uiWKH\ZLOOVHHDOOWKHVRXUFHIRUWKH8,IRU&RRO$SS0RVW
ZLOOEHVXUSULVHGLIWKH\KDYHWRILQGDQRWKHUVRXUFHWUHHVRPHZKHUHZLWKIRULQVWDQFH
SDJHWZRRIWKH8,
7KH$QGURLGDSSOLFDWLRQIUDPHZRUNDOVRKDVWKHFRQFHSWRIDPackage
,WLVGLIIHUHQWDQGZH¦OOFRQVLGHULWLQ&KDSWHU'RQ¦WFRQIXVHLWZLWK
-DYDSDFNDJHQDPHV
)RUPRUHLQIRUPDWLRQRQ-DYDSDFNDJHVVHHWKH-DYDWXWRULDODWKWWSGRZQORDGRUDFOH
FRPMDYDVHWXWRULDOMDYDSDFNDJHSDFNDJHVKWPO
Access Modifiers and Encapsulation
:HKLQWHGHDUOLHUWKDWPHPEHUVRIDFODVVKDYHVSHFLDOYLVLELOLW\UXOHV'HILQLWLRQVLQ
PRVW-DYDEORFNVDUHOH[LFDOO\VFRSHGWKH\DUHYLVLEOHRQO\ZLWKLQWKHEORFNDQGLWV
QHVWHGEORFNV7KHGHILQLWLRQVLQDFODVVKRZHYHUPD\EHYLVLEOHRXWVLGHWKHEORFN
-DYDVXSSRUWVSXEOLVKLQJWRSOHYHOPHPEHUVRIDFODVV¢LWVPHWKRGVDQGILHOGV¢WRFRGH
LQRWKHUFODVVHVWKURXJKWKHXVHRIDFFHVVPRGLILHUV$FFHVVPRGLILHUVDUHNH\ZRUGVWKDW
PRGLI\WKHYLVLELOLW\RIWKHGHFODUDWLRQVWRZKLFKWKH\DUHDSSOLHG
7KHUHDUHWKUHHDFFHVVPRGLI\LQJNH\ZRUGVLQWKH-DYDODQJXDJH public protected
DQGprivate7RJHWKHUWKH\VXSSRUWIRXUOHYHOVRIDFFHVV:KLOHDFFHVVPRGLILHUVDIIHFW
WKH YLVLELOLW\ RI D GHFODUDWLRQ IURP RXWVLGH WKH FODVV FRQWDLQLQJ LW ZLWKLQ WKH FODVV
QRUPDOEORFNVFRSLQJUXOHVDSSO\UHJDUGOHVVRIDFFHVVPRGLILFDWLRQ
7KHprivateDFFHVVPRGLILHULVWKHPRVWUHVWULFWLYH$GHFODUDWLRQZLWKprivateDFFHVV
LVQRWYLVLEOHRXWVLGHWKHEORFNWKDWFRQWDLQVLW7KLVLVWKHVDIHVWNLQGRIGHFODUDWLRQ
EHFDXVHLWJXDUDQWHHVWKDWWKHUHDUHQRUHIHUHQFHVWRWKHGHFODUDWLRQH[FHSWZLWKLQWKH
FRQWDLQLQJFODVV7KHPRUHprivateGHFODUDWLRQVWKHUHDUHLQDFODVVWKHVDIHUWKHFODVV
LV
7KHQH[WPRVWUHVWULFWLYHOHYHORIDFFHVVLVGHIDXOWRUSDFNDJHDFFHVV'HFODUDWLRQVWKDW
DUHQRWPRGLILHGE\DQ\RIWKHWKUHHDFFHVVPRGLILHUVKDYHGHIDXOWDFFHVVDQGDUHYLVLEOH
RQO\IURPRWKHUFODVVHVLQWKHVDPHSDFNDJH'HIDXOWDFFHVVFDQEHDYHU\KDQG\ZD\
WRFUHDWHVWDWHVKDUHGEHWZHHQREMHFWVVLPLODUWRWKHXVHRIWKH friendGHFODUDWLRQLQ
&
7KHprotectedDFFHVVPRGLILHUSHUPLWVDOOWKHDFFHVVULJKWVWKDWZHUHSHUPLWWHGE\GH
IDXOWDFFHVVEXWLQDGGLWLRQDOORZVDFFHVVIURPZLWKLQDQ\VXEW\SH$Q\FODVVWKDW
H[WHQGVDFODVVZLWKprotectedGHFODUDWLRQVKDVDFFHVVWRWKRVHGHFODUDWLRQV
)LQDOO\publicDFFHVVWKHZHDNHVWRIWKHPRGLILHUVDOORZVDFFHVVIURPDQ\ZKHUH
Scope | 57
+HUH¦V DQ H[DPSOH WKDW ZLOO PDNH WKLV PRUH FRQFUHWH 7KHUH DUH IRXU FODVVHV LQ
WZRGLIIHUHQWSDFNDJHVKHUHDOORIZKLFKUHIHUWRILHOGVGHFODUHGLQRQHRIWKHFODVVHV
Accessible
package over.here;
public class Accessible {
private String localAccess;
String packageAccess;
protected String subtypeAccess;
public String allAccess;
public void test() {
// all of the assignments below work:
// the fields are declared in an enclosing
// block and are therefore visible.
localAccess = "success!!";
packageAccess = "success!!";
subtypeAccess = "success!!";
allAccess = "success!!";
}
}
package over.here;
import over.here.Accessible;
// this class is in the same package as Accessible
public class AccessibleFriend {
public void test() {
Accessible target = new Accessible();
// private members are not visible
// outside the declaring class
target.localAccess = "fail!!"; // ERROR!!
// default access visible within package
target.packageAccess = "success!!";
// protected access is superset of default
target.subtypeAccess = "success!!";
// visible everywhere
target.allAccess = "success!!";
}
}
package over.there;
import over.here.Accessible;
// a subtype of Accessible
// in a different package
public class AccessibleChild extends Accessible {
58 | Chapter 2:ಗJava for Android
// the visible fields from Accessible appear
// as if declared in a surrounding block
public void test() {
localAccess = "fail!!"; // ERROR!!
packageAccess = "fail!!"; // ERROR!!
// protected declarations are
// visible from subtypes
subtypeAccess = "success!!";
// visible everywhere
allAccess = "success!!";
}
}
package over.there;
import over.here.Accessible;
// a class completely unrelated to Accessible
public class AccessibleStranger {
public void test() {
Accessible target = new Accessible();
target.localAccess = "fail!!"; // ERROR!!
target.packageAccess = "fail!!"; // ERROR!!
target.subtypeAccess = "success!!"; // ERROR!!
// visible everywhere
target.allAccess = "success!!";
}
}
Idioms of Java Programming
6RPHZKHUHEHWZHHQJHWWLQJWKHVSHFLILFVRIDSURJUDPPLQJODQJXDJHV\QWD[ULJKWDQG
JRRGSDWWHUQRULHQWHGGHVLJQ ZKLFKLVODQJXDJHDJQRVWLF LVLGLRPDWLFXVHRIDODQ
JXDJH$QLGLRPDWLFSURJUDPPHUXVHVFRQVLVWHQWFRGHWRH[SUHVVVLPLODULGHDVDQGE\
GRLQJ VR SURGXFHV SURJUDPV WKDW DUH HDV\ WR XQGHUVWDQG PDNH RSWLPDO XVH RI WKH
UXQWLPHHQYLURQPHQWDQGDYRLGWKH£JRWFKDV¤WKDWH[LVWLQDQ\ODQJXDJHV\QWD[
Type Safety in Java
$ SULPDU\ GHVLJQ JRDO IRU WKH -DYD ODQJXDJH ZDV SURJUDPPLQJ VDIHW\ 0XFK RI WKH
IUHTXHQWO\PDOLJQHGYHUERVLW\DQGLQIOH[LELOLW\RI-DYDZKLFKLVQRWSUHVHQWLQODQJXDJHV
VXFKDV5XE\3\WKRQDQG2EMHFWLYH&LVWKHUHWRPDNHVXUHDFRPSLOHUFDQJXDUDQWHH
WKDWHQWLUHFODVVHVRIHUURUVZLOOQHYHURFFXUDWUXQWLPH
Idioms of Java Programming | 59
-DYD¦VVWDWLFW\SLQJKDVSURYHQWREHYDOXDEOHZHOOEH\RQGLWVRZQFRPSLOHU7KHDELOLW\
IRUDPDFKLQHWRSDUVHDQGUHFRJQL]HWKHVHPDQWLFVRI-DYDFRGHZDVDPDMRUIRUFHLQ
WKHGHYHORSPHQWRISRZHUIXOWRROVOLNH)LQG%XJVDQG,'(UHIDFWRULQJWRROV
0DQ\GHYHORSHUVDUJXHWKDWHVSHFLDOO\ZLWKPRGHUQFRGLQJWRROVWKHVHFRQVWUDLQWVDUH
DVPDOOSULFHWRSD\IRUEHLQJDEOHWRILQGSUREOHPVLPPHGLDWHO\WKDWPLJKWRWKHUZLVH
PDQLIHVWWKHPVHOYHVRQO\ZKHQWKHFRGHLVDFWXDOO\GHSOR\HG2IFRXUVHWKHUHLVDOVR
DKXJHFRPPXQLW\RIGHYHORSHUVZKRDUJXHWKDWWKH\VDYHVRPXFKWLPHFRGLQJLQD
G\QDPLFODQJXDJHWKDWWKH\FDQZULWHH[WHQVLYHXQLWDQGLQWHJUDWLRQWHVWVDQGVWLOOFRPH
RXWDKHDG
:KDWHYHU\RXUSRVLWLRQLQWKLVGLVFXVVLRQLWPDNHVDORWRIVHQVHWRPDNHWKHEHVW
SRVVLEOHXVHRI\RXUWRROV-DYD¦VVWDWLFELQGLQJDEVROXWHO\LVDFRQVWUDLQW2QWKHRWKHU
KDQG-DYDLVDSUHWW\JRRGVWDWLFDOO\ERXQGODQJXDJH,WLVDORXV\G\QDPLFODQJXDJH
,WLVDFWXDOO\SRVVLEOHWRGRIDLUO\G\QDPLFWKLQJVZLWK-DYDE\XVLQJLWVUHIOHFWLRQDQG
LQWURVSHFWLRQ$3,VDQGGRLQJDORWRIW\SHFDVWLQJ'RLQJVRH[FHSWLQYHU\OLPLWHG
FLUFXPVWDQFHVLVXVLQJWKHODQJXDJHDQGLWVUXQWLPHHQYLURQPHQWWRFURVVSXUSRVHV
<RXUSURJUDPLVOLNHO\WRUXQYHU\VORZO\DQGWKH$QGURLGWRROFKDLQZRQ¦WEHDEOHWR
PDNHKHDGVRUWDLOVRILW3HUKDSVPRVWLPSRUWDQWLIWKHUHDUHEXJVLQWKLVVHOGRPXVHG
SDUWRIWKHSODWIRUP\RX¦OOEHWKHILUVWWRILQGWKHP:HVXJJHVWHPEUDFLQJ-DYD¦VVWDWLF
QDWXUH¢DWOHDVWXQWLOWKHUHLVDJRRGG\QDPLFDOWHUQDWLYH¢DQGWDNLQJHYHU\SRVVLEOH
DGYDQWDJHRILW
Encapsulation
'HYHORSHUVOLPLWWKHYLVLELOLW\RIREMHFWPHPEHUVLQRUGHUWRFUHDWHHQFDSVXODWLRQ(Q
FDSVXODWLRQLVWKHLGHDWKDWDQREMHFWVKRXOGQHYHUUHYHDOGHWDLOVDERXWLWVHOIWKDWLWGRHV
QRWLQWHQGWRVXSSRUW7RUHWXUQWRWKHPRMLWRPDNLQJH[DPSOHUHFDOOWKDWZKHQLW
FRPHV WLPH WR PDNH WKH FRFNWDLO \RX GRQ¦W FDUH DW DOO KRZ \RXU FROOHDJXH JRW WKH
QHFHVVDU\PLQW6XSSRVHWKRXJKWKDW\RXKDGVDLGWRKHU£&DQ\RXJHWWKHPLQW"$QG
RKE\WKHZD\ZKLOH\RXDUHRXWWKHUHFRXOG\RXZDWHUWKHURVHEXVK"¤,WLVQRORQJHU
WUXHWKDW\RXGRQ¦WFDUHKRZ\RXUFROOHDJXHSURGXFHVPLQW<RXQRZGHSHQGRQWKH
H[DFWZD\WKDWVKHGRHVLW
,QWKHVDPHZD\WKHLQWHUIDFH VRPHWLPHVDEEUHYLDWHGDV$3, RIDQREMHFWFRQVLVWVRI
WKHPHWKRGVDQGW\SHVWKDWDUHDFFHVVLEOHIURPFDOOLQJFRGH%\FDUHIXOHQFDSVXODWLRQ
DGHYHORSHUNHHSVLPSOHPHQWDWLRQGHWDLOVRIDQREMHFWKLGGHQIURPFRGHWKDWXVHVLW
6XFKFRQWURODQGSURWHFWLRQSURGXFHSURJUDPVWKDWDUHPRUHIOH[LEOHDQGDOORZWKH
GHYHORSHU RI DQ REMHFW WR FKDQJH REMHFW LPSOHPHQWDWLRQ RYHU WLPH ZLWKRXW FDXVLQJ
ULSSOHHIIHFWFKDQJHVLQFDOOLQJFRGH
Getters and setters
$VLPSOHEXWFRPPRQIRUPRIHQFDSVXODWLRQLQ-DYDLQYROYHVWKHXVHRIJHWWHUDQG
VHWWHUPHWKRGV&RQVLGHUDQDLYHGHILQLWLRQRIDContactFODVV
60 | Chapter 2:ಗJava for Android
public class Contact {
public String name;
public int age;
public String email;
}
7KLVGHILQLWLRQPDNHVLWQHFHVVDU\IRUH[WHUQDOREMHFWVWRDFFHVVWKHILHOGVRIWKHFODVV
GLUHFWO\)RUH[DPSOH
Contact c = new Contact();
c.name = "Alice";
c.age = 13;
c.email = "alice@mymail.com";
,WZLOOWDNHRQO\DWLQ\DPRXQWRIXVHLQWKHUHDOZRUOGWRGLVFRYHUWKDWFRQWDFWVDFWXDOO\
KDYHVHYHUDOHPDLODGGUHVVHV8QIRUWXQDWHO\DGGLQJDPXOWLSOHDGGUHVVIHDWXUHWRWKH
QDLYHLPSOHPHQWDWLRQUHTXLUHVXSGDWLQJHYHU\VLQJOHUHIHUHQFHWRContact.emailLQWKH
HQWLUHSURJUDP
,QFRQWUDVWFRQVLGHUWKHIROORZLQJFODVV
class Contact {
private int age;
private String name;
private String email;
Contact(int age, String name, String email) {
this.age = age;
this.name = name;
this.email = email;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public String getEmail() {
return address;
}
}
8VHRIWKHprivateDFFHVVPRGLILHUSUHYHQWVGLUHFWDFFHVVWRWKHILHOGVRIWKLVYHUVLRQRI
WKH ContactFODVV8VHRI publicJHWWHUPHWKRGVSURYLGHVWKHGHYHORSHUZLWKWKHRS
SRUWXQLW\WRFKDQJHKRZWKHContactREMHFWUHWXUQVWKHQDPHDJHRUHPDLODGGUHVVRI
WKHContact)RUH[DPSOHWKHHPDLODGGUHVVFRXOGEHVWRUHGE\LWVHOIDVLQWKHSUHFHGLQJ
FRGHRUFRQFDWHQDWHGIURPDXVHUQDPHDQGDKRVWQDPHLIWKDWKDSSHQHGWREHPRUH
FRQYHQLHQWIRUDJLYHQDSSOLFDWLRQ,QWHUQDOO\WKHDJHFRXOGEHKHOGDVDQintRUDVDQ
Integer7KHFODVVFDQEHH[WHQGHGWRVXSSRUWPXOWLSOHHPDLODGGUHVVHVZLWKRXWDQ\
FKDQJHWRDQ\FOLHQW
Idioms of Java Programming | 61
-DYDGRHVDOORZGLUHFWUHIHUHQFHWRILHOGVDQGGRHVQRWOLNHVRPHODQJXDJHVDXWRPDW
LFDOO\ZUDSUHIHUHQFHVWRWKHILHOGVLQJHWWHUVDQGVHWWHUV,QRUGHUWRSUHVHUYHHQFDSVX
ODWLRQ\RXPXVWGHILQHHDFKDQGHYHU\DFFHVVPHWKRG\RXUVHOI0RVW,'(VSURYLGHFRGH
JHQHUDWLRQIHDWXUHVWKDWZLOOGRWKLVTXLFNO\DQGDFFXUDWHO\
:UDSSHUJHWWHUDQGVHWWHUPHWKRGVSURYLGHIXWXUHIOH[LELOLW\ZKHUHDVGLUHFWILHOGDFFHVV
PHDQVWKDWDOOFRGHWKDWXVHVDILHOGZLOOKDYHWRFKDQJHLIWKHW\SHRIWKDWILHOGFKDQJHV
RULILWJRHVDZD\*HWWHUDQGVHWWHUPHWKRGVUHSUHVHQWDVLPSOHIRUPRIREMHFWHQFDS
VXODWLRQ$QH[FHOOHQWUXOHRIWKXPEUHFRPPHQGVWKDWDOOILHOGVEHHLWKHU privateRU
final :HOOZULWWHQ -DYD SURJUDPV XVH WKLV DQG RWKHU PRUH VRSKLVWLFDWHG IRUPV RI
HQFDSVXODWLRQLQRUGHUWRSUHVHUYHDGDSWDELOLW\LQPRUHFRPSOH[SURJUDPV
Using Anonymous Classes
'HYHORSHUVZKRKDYHH[SHULHQFHZRUNLQJZLWK8,GHYHORSPHQWZLOOEHIDPLOLDUZLWK
WKHFRQFHSWRIDFDOOEDFN\RXUFRGHQHHGVWREHQRWLILHGZKHQVRPHWKLQJLQWKH8,
FKDQJHV3HUKDSVDEXWWRQLVSXVKHGDQG\RXUPRGHOQHHGVWRPDNHDFRUUHVSRQGLQJ
FKDQJHLQVWDWH3HUKDSVQHZGDWDKDVDUULYHGIURPWKHQHWZRUNDQGLWQHHGVWREH
GLVSOD\HG<RXQHHGDZD\WRDGGDEORFNRIFRGHWRDIUDPHZRUNIRUODWHUH[HFXWLRQ
RQ\RXUEHKDOI
$OWKRXJK WKH -DYD ODQJXDJH GRHV SURYLGH DQ LGLRP IRU SDVVLQJ EORFNV RI FRGH LW LV
VOLJKWO\DZNZDUGEHFDXVHQHLWKHUFRGHEORFNVQRUPHWKRGVDUHILUVWFODVVREMHFWVLQWKH
ODQJXDJH7KHUHLVQRZD\LQWKHODQJXDJHWRREWDLQDUHIHUHQFHWRHLWKHU
<RXFDQKDYHDUHIHUHQFHWRDQLQVWDQFHRIDFODVV,Q-DYDLQVWHDGRISDVVLQJEORFNVRU
IXQFWLRQV\RXSDVVDQHQWLUHFODVVWKDWGHILQHVWKHFRGH\RXQHHGDVRQHRILWVPHWKRGV
$VHUYLFHWKDWSURYLGHVDFDOOEDFN$3,ZLOOGHILQHLWVSURWRFROXVLQJDQLQWHUIDFH7KH
VHUYLFHFOLHQWGHILQHVDQLPSOHPHQWDWLRQRIWKLVLQWHUIDFHDQGSDVVHVLWWRWKHIUDPHZRUN
&RQVLGHUIRULQVWDQFHWKH$QGURLGPHFKDQLVPIRULPSOHPHQWLQJWKHUHVSRQVHWRD
XVHUNH\SUHVV7KH$QGURLG ViewFODVVGHILQHVDQLQWHUIDFH OnKeyListenerZKLFKLQ
WXUQ GHILQHV DQ onKey PHWKRG ,I \RXU FRGH SDVVHV DQ LPSOHPHQWDWLRQ RI
OnKeyListenerWRDViewLWVonKeyPHWKRGZLOOEHFDOOHGHDFKWLPHWKHViewSURFHVVHVD
QHZNH\HYHQW
7KHFRGHPLJKWORRNVRPHWKLQJOLNHWKLV
public class MyDataModel {
// Callback class
private class KeyHandler implements View.OnKeyListener {
public boolean onKey(View v, int keyCode, KeyEvent event) {
handleKey(v, keyCode, event)
}
}
/** @param view the view we model */
public MyDataModel(View view) { view.setOnKeyListener(new KeyHandler()) }
62 | Chapter 2:ಗJava for Android
}
/** Handle a key event */
void handleKey(View v, int keyCode, KeyEvent event) {
// key handling code goes here...
}
:KHQDQHZMyDataModelLVFUHDWHGLWLVLQIRUPHGDERXWWKHYLHZWRZKLFKLWLVDWWDFKHG
E\DQDUJXPHQWWRWKHFRQVWUXFWRU7KHFRQVWUXFWRUFUHDWHVDQHZLQVWDQFHRIWKHWULYLDO
FDOOEDFNFODVV KeyHandlerDQGLQVWDOOVLWLQWKHYLHZ$Q\VXEVHTXHQWNH\HYHQWVZLOO
EHUHOD\HGWRWKHPRGHOLQVWDQFH¦VhandleKeyPHWKRG
:KLOHWKLVFHUWDLQO\JHWVWKHMREGRQHLWFDQJHWSUHWW\XJO\HVSHFLDOO\LI\RXUPRGHO
FODVVQHHGVWRKDQGOHPXOWLSOHNLQGVRIHYHQWVIURPPXOWLSOHYLHZV$IWHUDZKLOHDOO
WKRVHW\SHGHILQLWLRQVFOXWWHUXSWKHWRSRI\RXUSURJUDP7KHGHILQLWLRQVFDQEHDORQJ
ZD\IURPWKHLUXVHDQGLI\RXWKLQNDERXWLWWKH\UHDOO\VHUYHQRSXUSRVHDWDOO
-DYDSURYLGHVDZD\WRVLPSOLI\WKLVVRPHZKDWXVLQJDQDQRQ\PRXVFODVV+HUHLVD
FRGHIUDJPHQWVLPLODUWRWKHRQHVKRZQHDUOLHUH[FHSWWKDWLWLVLPSOHPHQWHGXVLQJDQ
DQRQ\PRXVFODVV
public class MyDataModel {
/** @param view the view we model */
public MyDataModel(View view) {
view.setOnKeyListener(
// this is an anonymous class!!
new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
handleKey(v, keyCode, event)
} } );
}
/** Handle a key event */
void handleKey(View v, int keyCode, KeyEvent event) {
// key handling code goes here...
}
}
:KLOHLWPLJKWWDNHDPLQXWHWRSDUVHWKLVFRGHLVDOPRVWLGHQWLFDOWRWKHSUHYLRXV
H[DPSOH,WSDVVHVDQHZO\FUHDWHGLQVWDQFHRIDVXEW\SHRI View.OnKeyListenerDVDQ
DUJXPHQWLQWKHFDOOWRview.setOnKeyListener,QWKLVH[DPSOHWKRXJKWKHDUJXPHQW
WRWKHFDOOWRview.setOnKeyListenerLVVSHFLDOV\QWD[WKDWGHILQHVDQHZVXEFODVVRIWKH
LQWHUIDFHView.OnKeyListenerDQGLQVWDQWLDWHVLWLQDVLQJOHVWDWHPHQW7KHQHZLQVWDQFH
LVDQLQVWDQFHRIDFODVVWKDWKDVQRQDPHLWLVDQRQ\PRXV,WVGHILQLWLRQH[LVWVRQO\LQ
WKHVWDWHPHQWWKDWLQVWDQWLDWHVLW
$QRQ\PRXVFODVVHVDUHDYHU\KDQG\WRRODQGDUHWKH-DYDLGLRPIRUH[SUHVVLQJPDQ\
NLQGVRIFRGHEORFNV2EMHFWVFUHDWHGXVLQJDQDQRQ\PRXVFODVVDUHILUVWFODVVREMHFWV
RIWKHODQJXDJHDQGFDQEHXVHGDQ\ZKHUHDQ\RWKHUREMHFWRIWKHVDPHW\SHZRXOGEH
OHJDO)RULQVWDQFHWKH\FDQEHDVVLJQHG
public class MyDataModel {
/** @param view the view we model */
Idioms of Java Programming | 63
public MyDataModel(View view1, View view2) {
// get a reference to the anonymous class
View.OnKeyListener keyHdlr = new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
handleKey(v, keyCode, event)
} };
}
}
// use the class to relay for two views
view1.setOnKeyListener(keyHdlr);
view2.setOnKeyListener(keyHdlr);
/** Handle a key event */
void handleKey(View v, int keyCode, KeyEvent event) {
// key handling code goes here...
}
<RXPLJKWZRQGHUZK\WKHDQRQ\PRXVFODVVLQWKLVH[DPSOHGHOHJDWHVLWVDFWXDOLP
SOHPHQWDWLRQ WKHhandleKeyPHWKRG WRWKHFRQWDLQLQJFODVV7KHUH¦VFHUWDLQO\QRUXOH
WKDWFRQVWUDLQVWKHFRQWHQWRIWKHDQRQ\PRXVFODVVLWDEVROXWHO\FRXOGFRQWDLQWKH
FRPSOHWHLPSOHPHQWDWLRQ2QWKHRWKHUKDQGJRRGLGLRPDWLFWDVWHVXJJHVWVSXWWLQJ
WKHFRGHWKDWFKDQJHVDQREMHFW¦VVWDWHLQWRWKHREMHFWFODVV,IWKHLPSOHPHQWDWLRQLVLQ
WKHFRQWDLQLQJFODVVLWFDQEHXVHGIURPRWKHUPHWKRGVDQGFDOOEDFNV7KHDQRQ\PRXV
FODVVLVVLPSO\DUHOD\DQGWKDWLVDOOLWVKRXOGGR
-DYDGRHVKDYHVRPHIDLUO\VWURQJFRQVWUDLQWVFRQFHUQLQJWKHXVHRIWKHYDULDEOHVWKDW
DUHLQVFRSH¢DQ\WKLQJGHILQHGLQDQ\VXUURXQGLQJEORFN¢ZLWKLQDQDQRQ\PRXVFODVV
,QSDUWLFXODUDQDQRQ\PRXVFODVVFDQRQO\UHIHUWRDYDULDEOHLQKHULWHGIURPWKHVXU
URXQGLQJVFRSHLIWKDWYDULDEOHLVGHFODUHGILQDO)RUH[DPSOHWKHIROORZLQJFRGHIUDJ
PHQWZLOOQRWFRPSLOH
/** Create a key handler that matches the passed key */
public View.OnKeyListener curry(int keyToMatch) {
return new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyToMatch == keyCode) { foundMatch(); } // ERROR!!
} };
}
7KHUHPHG\LVWRPDNHWKHDUJXPHQWWRcurryILQDO0DNLQJLWILQDORIFRXUVHPHDQV
WKDWLWFDQQRWEHFKDQJHGLQWKHDQRQ\PRXVFODVV%XWWKHUHLVDQHDV\LGLRPDWLFZD\
DURXQGWKDW
/** Create a key handler that increments and matches the passed key */
public View.OnKeyListener curry(final int keyToMatch) {
return new View.OnKeyListener() {
private int matchTarget = keyToMatch;
public boolean onKey(View v, int keyCode, KeyEvent event) {
matchTarget++;
if (matchTarget == keyCode) { foundMatch(); }
} };
}
64 | Chapter 2:ಗJava for Android
Modular Programming in Java
:KLOHFODVVH[WHQVLRQLQ-DYDRIIHUVGHYHORSHUVVLJQLILFDQWIOH[LELOLW\LQEHLQJDEOHWR
UHGHILQH DVSHFWV RI REMHFWV DV WKH\ DUH XVHG LQ GLIIHUHQW FRQWH[WV LW DFWXDOO\ WDNHV D
UHDVRQDEOHDPRXQWRIH[SHULHQFHWRPDNHMXGLFLRXVXVHRIFODVVHVDQGLQWHUIDFHV,GH
DOO\GHYHORSHUVDLPWRFUHDWHVHFWLRQVRIFRGHWKDWDUHWROHUDQWRIFKDQJHRYHUWLPHDQG
WKDWFDQEHUHXVHGLQDVPDQ\GLIIHUHQWFRQWH[WVDVSRVVLEOHLQPXOWLSOHDSSOLFDWLRQV
RUSHUKDSVHYHQDVOLEUDULHV3URJUDPPLQJLQWKLVZD\FDQUHGXFHEXJVDQGWKHDSSOL
FDWLRQ¦V WLPH WR PDUNHW 0RGXODU SURJUDPPLQJ HQFDSVXODWLRQ DQG VHSDUDWLRQ RI
FRQFHUQVDUHDOONH\VWUDWHJLHVIRUPD[LPL]LQJFRGHUHXVHDQGVWDELOLW\
$IXQGDPHQWDOGHVLJQFRQVLGHUDWLRQLQREMHFWRULHQWHGGHYHORSPHQWFRQFHUQVWKHGH
FLVLRQWRGHOHJDWHRULQKHULWDVDPHDQVRIUHXVLQJSUHH[LVWLQJFRGH7KHIROORZLQJVHULHV
RIH[DPSOHVFRQWDLQVGLIIHUHQWREMHFWKLHUDUFKLHVIRUUHSUHVHQWLQJDXWRPRWLYHYHKLFOHV
WKDWPLJKWEHXVHGLQDFDUJDPLQJDSSOLFDWLRQ(DFKH[DPSOHSUHVHQWVDGLIIHUHQWDS
SURDFKWRPRGXODULW\
$GHYHORSHUVWDUWVE\FUHDWLQJDYHKLFOHFODVVWKDWFRQWDLQVDOOYHKLFOHORJLFDQGDOOORJLF
IRUHDFKGLIIHUHQWW\SHRIHQJLQHDVIROORZV
// Naive code!
public class MonolithicVehicle {
private int vehicleType;
// fields for an electric engine
// fields for a gas engine
// fields for a hybrid engine
// fields for a steam engine
public MonolithicVehicle(int vehicleType) {
vehicleType = vehicleType;
}
// other methods for implementing vehicles and engine types.
void start() {
// code for an electric engine
// code for a gas engine
// code for a hybrid engine
// code for a steam engine
}
}
7KLVLVQDLYHFRGH:KLOHLWPD\EHIXQFWLRQDOLWPL[HVWRJHWKHUXQUHODWHGELWVRILP
SOHPHQWDWLRQ HJDOOW\SHVRIYHKLFOHHQJLQHV DQGZLOOEHKDUGWRH[WHQG)RULQVWDQFH
FRQVLGHUPRGLI\LQJWKHLPSOHPHQWDWLRQWRDFFRPPRGDWHDQHZHQJLQHW\SH QXFOHDU 7KHFRGHIRUHDFKNLQGRIFDUHQJLQHKDVXQUHVWULFWHGDFFHVVWRWKHFRGHIRUHYHU\RWKHU
HQJLQH$EXJLQRQHHQJLQHLPSOHPHQWDWLRQPLJKWHQGXSFDXVLQJDEXJLQDQRWKHU
XQUHODWHGHQJLQH$FKDQJHLQRQHPLJKWUHVXOWLQDQXQH[SHFWHGFKDQJHWRDQRWKHU
$QGRIFRXUVHDFDUWKDWKDVDQHOHFWULFHQJLQHPXVWGUDJDORQJUHSUHVHQWDWLRQVRIDOO
H[LVWLQJ HQJLQH W\SHV )XWXUH GHYHORSHUV ZRUNLQJ RQ WKH PRQROLWKLF YHKLFOH PXVW
Idioms of Java Programming | 65
XQGHUVWDQGDOOWKHFRPSOH[LQWHUDFWLRQVLQRUGHUWRPRGLI\WKHFRGH7KLVMXVWGRHVQ¦W
VFDOH
+RZPLJKWZHLPSURYHRQWKLVLPSOHPHQWDWLRQ"$QREYLRXVLGHDLVWRXVHVXEFODVVLQJ
:HPLJKWXVHWKHFODVVKLHUDUFK\VKRZQLQWKHIROORZLQJFRGHWRLPSOHPHQWGLIIHUHQW
W\SHVRIDXWRPRWLYHYHKLFOHVHDFKWLJKWO\ERXQGWRLWVHQJLQHW\SH
public abstract class TightlyBoundVehicle {
// has no engine field
// each subclass must override this method to
// implement its own way of starting the vehicle
protected abstract void startEngine();
public final void start() { startEngine(); }
}
public class ElectricVehicle extends TightlyBoundVehicle {
protected void startEngine() {
// implementation for engine start electric
}
public class GasVehicle extends TightlyBoundVehicle {
protected void startEngine() {
// implementation for engine start gas
}
}
public void anInstantiatingMethod() {
TightlyBoundVehicle vehicle = new ElectricVehicle();
TightlyBoundVehicle vehicle = new GasVehicle();
TightlyBoundVehicle vehicle = new HybridVehicle();
TightlyBoundVehicle vehicle = new SteamVehicle();
}
7KLVLVFOHDUO\DQLPSURYHPHQW7KHFRGHIRUHDFKHQJLQHW\SHLVQRZHQFDSVXODWHG
ZLWKLQLWVRZQFODVVDQGFDQQRWLQWHUIHUHZLWKDQ\RWKHUV<RXFDQH[WHQGLQGLYLGXDO
W\SHVRIYHKLFOHVZLWKRXWDIIHFWLQJDQ\RWKHUW\SH,QPDQ\FLUFXPVWDQFHVWKLVLVDQ
LGHDOLPSOHPHQWDWLRQ
2QWKHRWKHUKDQGZKDWKDSSHQVZKHQ\RXZDQWWRFRQYHUW\RXUWLJKWO\ERXQGJDV
YHKLFOHWRELRGLHVHO",QWKLVLPSOHPHQWDWLRQFDUVDQGHQJLQHVDUHWKHVDPHREMHFW7KH\
FDQQRWEHVHSDUDWHG,IWKHUHDOZRUOGVLWXDWLRQWKDW\RXDUHPRGHOLQJUHTXLUHV\RXWR
FRQVLGHUWKHREMHFWVVHSDUDWHO\\RXUDUFKLWHFWXUHZLOOKDYHWREHPRUHORRVHO\FRXSOHG
interface Engine {
void start();
}
class GasEngine implements Engine {
void start() {
// spark plugs ignite gas
}
}
66 | Chapter 2:ಗJava for Android
class ElectricEngine implements Engine {
void start() {
// run power to battery
}
}
class DelegatingVehicle {
// has an engine field
private Engine mEngine;
public DelegatingVehicle(Engine engine) {
mEngine = engine;
}
}
public void start() {
// delegating vehicle can use a gas or electric engine
mEngine.start();
}
void anInstantiatingMethod() {
// new vehicle types are easily created by just
// plugging in different kinds of engines.
DelegatingVehicle electricVehicle =
new DelegatingVehicle(new ElectricEngine());
DelegatingVehicle gasVehicle = new DelegatingVehicle(new GasEngine());
//DelegatingVehicle hybridVehicle = new DelegatingVehicle(new HybridEngine());
//DelegatingVehicle steamVehicle = new DelegatingVehicle(new SteamEngine());
}
,QWKLVDUFKLWHFWXUHWKHYHKLFOHFODVVGHOHJDWHVDOOHQJLQHUHODWHGEHKDYLRUVWRDQHQJLQH
REMHFWWKDWLWRZQV7KLVLVVRPHWLPHVFDOOHGKDVDDVRSSRVHGWRWKHSUHYLRXVVXE
FODVVHG H[DPSOH FDOOHG LVD ,W FDQ EH HYHQ PRUH IOH[LEOH EHFDXVH LW VHSDUDWHV WKH
NQRZOHGJHRIKRZDQHQJLQHDFWXDOO\ZRUNVIURPWKHFDUWKDWFRQWDLQVLW(DFKYHKLFOH
GHOHJDWHVWRDORRVHO\FRXSOHGHQJLQHW\SHDQGKDVQRLGHDKRZWKDWHQJLQHLPSOHPHQWV
LWVEHKDYLRU7KHHDUOLHUH[DPSOHPDNHVXVHRIDUHXVDEOHDelegatingVehicleFODVVWKDW
GRHVQRWFKDQJHDWDOOZKHQLWLVJLYHQDQHZNLQGRIHQJLQH$YHKLFOHFDQXVHDQ\
LPSOHPHQWDWLRQRIWKHEngineLQWHUIDFH,QDGGLWLRQLW¦VSRVVLEOHWRFUHDWHGLIIHUHQWW\SHV
RIYHKLFOH¢689FRPSDFWRUOX[XU\IRULQVWDQFH¢WKDWHDFKPDNHXVHRIDQ\RIWKH
GLIIHUHQWW\SHVRIEngine
8VLQJGHOHJDWLRQPLQLPL]HVWKHLQWHUGHSHQGHQFHEHWZHHQWKHWZRREMHFWVDQGPD[L
PL]HVWKHIOH[LELOLW\WRFKDQJHWKHPODWHU%\SUHIHUULQJGHOHJDWLRQRYHULQKHULWDQFHD
GHYHORSHUPDNHVLWHDVLHUWRH[WHQGDQGLPSURYHWKHFRGH%\XVLQJLQWHUIDFHVWRGHILQH
WKHFRQWUDFWEHWZHHQDQREMHFWDQGLWVGHOHJDWHVDGHYHORSHUJXDUDQWHHVWKDWWKHGHO
HJDWHVZLOOKDYHWKHH[SHFWHGEHKDYLRU
Idioms of Java Programming | 67
Basic Multithreaded Concurrent Programming in Java
7KH-DYDODQJXDJHVXSSRUWVFRQFXUUHQWWKUHDGVRIH[HFXWLRQ6WDWHPHQWVLQGLIIHUHQW
WKUHDGVDUHH[HFXWHGLQSURJUDPRUGHUEXWWKHUHLVQRRUGHULQJUHODWLRQVKLSEHWZHHQ
WKHVWDWHPHQWVLQGLIIHUHQWWKUHDGV7KHEDVLFXQLWRIFRQFXUUHQWH[HFXWLRQLQ-DYDLV
HQFDSVXODWHGLQWKHFODVVjava.lang.Thread7KHUHFRPPHQGHGPHWKRGRIVSDZQLQJD
WKUHDGXVHVDQLPSOHPHQWDWLRQRIWKHLQWHUIDFH java.lang.RunnableDVGHPRQVWUDWHG
LQWKHIROORZLQJH[DPSOH
// program that interleaves messages from two threads
public class ConcurrentTask implements Runnable {
public void run() {
while (true) {
System.out.println("Message from spawned thread");
}
}
}
public void spawnThread() {
(new Thread(new ConcurrentTask())).start();
while (true) {
System.out.println("Message from main thread");
}
}
,QWKHSUHFHGLQJH[DPSOHWKHPHWKRGspawnThreadFUHDWHVDQHZWKUHDGSDVVLQJDQHZ
LQVWDQFHRIConcurrentTaskWRWKHWKUHDG¦VFRQVWUXFWRU7KHPHWKRGWKHQFDOOVstartRQ
WKHQHZWKUHDG:KHQWKHstartPHWKRGRIWKHWKUHDGLVFDOOHGWKHXQGHUO\LQJYLUWXDO
PDFKLQH 90 ZLOOFUHDWHDQHZFRQFXUUHQWWKUHDGRIH[HFXWLRQZKLFKZLOOLQWXUQ
FDOOWKHrunPHWKRGRIWKHSDVVHGRunnableH[HFXWLQJLWLQSDUDOOHOZLWKWKHVSDZQLQJ
WKUHDG$WWKLVSRLQWWKH90LVUXQQLQJWZRLQGHSHQGHQWSURFHVVHVRUGHURIH[HFXWLRQ
DQGWLPLQJLQRQHWKUHDGDUHXQUHODWHGWRRUGHUDQGWLPLQJLQWKHRWKHU
7KHFODVV ThreadLVQRWILQDO,WLVSRVVLEOHWRGHILQHDQHZFRQFXUUHQWWDVNE\VXE
FODVVLQJThreadDQGRYHUULGLQJLWVrunPHWKRG7KHUHLVQRDGYDQWDJHWRWKDWDSSURDFK
KRZHYHU,QIDFWXVLQJDRunnableLVPRUHDGDSWDEOH%HFDXVHRunnableLVDQLQWHUIDFH
WKHRunnableWKDW\RXSDVVLQWRWKHThreadFRQVWUXFWRUPD\H[WHQGVRPHRWKHUXVHIXO
FODVV
Synchronization and Thread Safety
:KHQWZRRUPRUHUXQQLQJWKUHDGVKDYHDFFHVVWRWKHVDPHVHWRIYDULDEOHVLW¦VSRVVLEOH
IRUWKHWKUHDGVWRPRGLI\WKRVHYDULDEOHVLQDZD\WKDWFDQSURGXFHGDWDFRUUXSWLRQDQG
EUHDNWKHORJLFLQRQHRUPRUHRIWKRVHWKUHDGV7KHVHNLQGVRIXQLQWHQGHGFRQFXUUHQW
DFFHVVEXJVDUHFDOOHGWKUHDGVDIHW\YLRODWLRQV7KH\DUHGLIILFXOWWRUHSURGXFHGLIILFXOW
WRILQGDQGGLIILFXOWWRWHVW
68 | Chapter 2:ಗJava for Android
-DYDGRHVQRWH[SOLFLWO\HQIRUFHUHVWULFWLRQVRQDFFHVVWRYDULDEOHVE\PXOWLSOHWKUHDGV
,QVWHDG WKH SULPDU\ PHFKDQLVP -DYD SURYLGHV WR VXSSRUW WKUHDG VDIHW\ LV WKH
synchronizedNH\ZRUG7KLVNH\ZRUGVHULDOL]HVDFFHVVWRWKHEORFNLWFRQWUROVDQGPRUH
LPSRUWDQW V\QFKURQL]HV YLVLEOH VWDWH EHWZHHQ WZR WKUHDGV ,W LV YHU\ HDV\ WR IRUJHW
ZKHQWU\LQJWRUHDVRQDERXWFRQFXUUHQF\LQ-DYDWKDWV\QFKURQL]DWLRQFRQWUROVERWK
DFFHVVDQGYLVLELOLW\&RQVLGHUWKHIROORZLQJSURJUDP
// This code is seriously broken!!!
public class BrokenVisibility {
public static boolean shouldStop;
public static void main(String[] args) {
new Thread(
new Runnable() {
@Override public void run() {
// this code runs in the spawned thread
final long stopTime
= System.currentTimeMillis() + 1000;
for (;;) {
shouldStop
= System.currentTimeMillis() > stopTime;
}
}
}
).start();
// this runs in the main thread
for (;;) {
if (shouldStop) { System.exit(0); }
}
}
}
2QHPLJKWWKLQN£:HOOWKHUH¦VQRQHHGWRV\QFKURQL]HWKHYDULDEOHshouldStop6XUH
WKHPDLQWKUHDGDQGWKHVSDZQHGWKUHDGPLJKWFROOLGHZKHQDFFHVVLQJLW6RZKDW"7KH
VSDZQHGWKUHDGZLOODIWHURQHVHFRQGDOZD\VVHWLWWRWUXH%RROHDQZULWHVDUHDWRPLF
,IWKHPDLQWKUHDGGRHVQ¦WVHHLWDVWUXHWKLVWLPHVXUHO\LWZLOOVHHLWDVWUXHWKHQH[W
WLPH¤7KLVUHDVRQLQJLVGDQJHURXVO\IODZHG,WGRHVQRWWDNHLQWRDFFRXQWRSWLPL]LQJ
FRPSLOHUVDQGFDFKLQJSURFHVVRUV,QIDFWWKLVSURJUDPPD\ZHOOQHYHUWHUPLQDWH7KH
WZRWKUHDGVPLJKWYHU\HDVLO\HDFKXVHWKHLURZQFRS\RIshouldStopH[LVWLQJRQO\LQ
VRPHORFDOSURFHVVRUKDUGZDUHFDFKH6LQFHWKHUHLVQRV\QFKURQL]DWLRQEHWZHHQWKH
WZRWKUHDGVWKHFDFKHFRS\PLJKWQHYHUEHSXEOLVKHGVRWKDWWKHVSDZQHGWKUHDG¦V
YDOXHLVYLVLEOHIURPWKHPDLQWKUHDG
7KHUHLVDVLPSOHUXOHIRUDYRLGLQJWKUHDGVDIHW\YLRODWLRQVLQ-DYDZKHQWZRGLIIHUHQW
WKUHDGVDFFHVVWKHVDPHPXWDEOHVWDWH YDULDEOH DOODFFHVVWRWKDWVWDWHPXVWEHSHU
IRUPHGKROGLQJDVLQJOHORFN
6RPHGHYHORSHUVPD\YLRODWHWKLVUXOHDIWHUUHDVRQLQJDERXWWKHEHKDYLRURIVKDUHG
VWDWHLQWKHLUSURJUDPLQDQDWWHPSWWRRSWLPL]HFRGH6LQFHPDQ\RIWKHGHYLFHVRQ
ZKLFK WKH $QGURLG SODWIRUP LV FXUUHQWO\ LPSOHPHQWHG FDQQRW DFWXDOO\ SURYLGH
Idioms of Java Programming | 69
FRQFXUUHQWH[HFXWLRQ LQVWHDGDVLQJOHSURFHVVRULVVKDUHGVHULDOO\DFURVVWKHWKUHDGV LWLVSRVVLEOHWKDWWKHVHSURJUDPVZLOODSSHDUWRUXQFRUUHFWO\+RZHYHUZKHQLQHYL
WDEO\ PRELOH GHYLFHV KDYH SURFHVVRUV ZLWK PXOWLSOH FRUHV DQG ODUJH PXOWLOD\HUHG
SURFHVVRUFDFKHVLQFRUUHFWSURJUDPVDUHOLNHO\WRIDLOZLWKEXJVWKDWDUHVHULRXVLQWHU
PLWWHQWDQGH[WUHPHO\KDUGWRILQG
:KHQLPSOHPHQWLQJFRQFXUUHQWSURFHVVHVLQ-DYDWKHEHVWDSSURDFKLVWRWXUQWRWKH
SRZHUIXO java.util.concurrent OLEUDULHV +HUH \RX ZLOO ILQG QHDUO\ DQ\ FRQFXUUHQW
VWUXFWXUH\RXPLJKWUHTXLUHRSWLPDOO\LPSOHPHQWHGDQGZHOOWHVWHG,Q-DYDWKHUHLV
VHOGRPPRUHUHDVRQIRUDGHYHORSHUWRXVHWKHORZOHYHOFRQFXUUHQF\FRQVWUXFWVWKDQ
WKHUHLVIRUKLPWRLPSOHPHQWKLVRZQYHUVLRQRIDGRXEO\OLQNHGOLVW
7KH synchronizedNH\ZRUGFDQEHXVHGLQWKUHHFRQWH[WVWRFUHDWHDEORFNRQDG\
QDPLFPHWKRGRURQDVWDWLFPHWKRG:KHQXVHGWRGHILQHDEORFNWKHNH\ZRUGWDNHV
DVDQDUJXPHQWDUHIHUHQFHWRDQREMHFWWREHXVHGDVDVHPDSKRUH3ULPLWLYHW\SHV
FDQQRWEHXVHGDVVHPDSKRUHVEXWDQ\REMHFWFDQ
:KHQXVHGDVDPRGLILHURQDG\QDPLFPHWKRGWKHNH\ZRUGEHKDYHVDVWKRXJKWKH
FRQWHQWVRIWKHPHWKRGZHUHZUDSSHGLQDV\QFKURQL]HGEORFNWKDWXVHGWKHLQVWDQFH
LWVHOIDVWKHORFN7KHIROORZLQJH[DPSOHGHPRQVWUDWHVWKLV
class SynchronizationExample {
public synchronized void aSynchronizedMethod() {
// a thread executing this method holds
// the lock on "this". Any other thread attempting
// to use this or any other method synchronized on
// "this" will be queued until this thread
// releases the lock
}
public void equivalentSynchronization() {
synchronized (this) {
// this is exactly equivalent to using the
// synchronized keyword in the method def.
}
}
private Object lock = new Object();
public void containsSynchronizedBlock() {
synchronized (lock) {
// A thread executing this method holds
// the lock on "lock", not "this".
// Threads attempting to seize "this"
// may succeed. Only those attempting to
// seize "lock" will be blocked
}
}
7KLVLVYHU\FRQYHQLHQWEXWPXVWEHXVHGZLWKFDXWLRQ$FRPSOH[FODVVWKDWKDVPXO
WLSOHKLJKXVHPHWKRGVDQGV\QFKURQL]HVWKHPLQWKLVZD\PD\EHVHWWLQJLWVHOIXSIRU
70 | Chapter 2:ಗJava for Android
ORFNFRQWHQWLRQ,IVHYHUDOH[WHUQDOWKUHDGVDUHDWWHPSWLQJWRDFFHVVXQUHODWHGSLHFHVRI
GDWDVLPXOWDQHRXVO\LWLVEHVWWRSURWHFWWKRVHSLHFHVRIGDWDZLWKVHSDUDWHORFNV
,IWKHsynchronizedNH\ZRUGLVXVHGRQDVWDWLFPHWKRGLWLVDVWKRXJKWKHFRQWHQWVRI
WKH PHWKRG ZHUH ZUDSSHG LQ D EORFN V\QFKURQL]HG RQ WKH REMHFW¦V FODVV $OO VWDWLF
V\QFKURQL]HGPHWKRGVIRUDOOLQVWDQFHVRIDJLYHQFODVVZLOOFRQWHQGIRUWKHVLQJOHORFN
RQWKHFODVVREMHFWLWVHOI
)LQDOO\LWLVZRUWKQRWLQJWKDWREMHFWORFNVLQ-DYDDUHUHHQWUDQW7KHIROORZLQJFRGHLV
SHUIHFWO\VDIHDQGGRHVQRWFDXVHDGHDGORFN
class SafeSeizure {
private Object lock = new Object();
public void method1() {
synchronized (lock) {
// do stuff
method2();
}
}
public void method2() {
synchronized (lock) {
// do stuff
}
}
}
Thread Control with wait() and notify() Methods
7KHFODVVjava.lang.ObjectGHILQHVWKHPHWKRGVwait()DQGnotify()DVSDUWRIWKHORFN
SURWRFROWKDWLVSDUWRIHYHU\REMHFW6LQFHDOOFODVVHVLQ-DYDH[WHQG ObjectDOOREMHFW
LQVWDQFHVVXSSRUWWKHVHPHWKRGVIRUFRQWUROOLQJWKHORFNDVVRFLDWHGZLWKWKHLQVWDQFH
$FRPSOHWHGLVFXVVLRQRI-DYD¦VORZOHYHOFRQFXUUHQF\WRROVLVZHOOEH\RQGWKHVFRSH
RIWKLVERRN,QWHUHVWHGGHYHORSHUVVKRXOGWXUQWR%ULDQ*RHW]¦VH[FHOOHQW-DYD&RQ
FXUUHQF\LQ3UDFWLFH $GGLVRQ:HVOH\3URIHVVLRQDO 7KLVH[DPSOHKRZHYHULOOXVWUDWHV
WKHHVVHQWLDOHOHPHQWQHFHVVDU\WRDOORZWZRWKUHDGVWRFRRSHUDWH2QHWKUHDGSDXVHV
ZKLOHWKHRWKHUFRPSOHWHVDWDVNWKDWLWUHTXLUHV
/**
* Task that slowly fills a list and notifies the
* lock on "this" when finished. Filling the
* list is thread safe.
*/
public class FillListTask implements Runnable {
private final int size;
private List<String> strings;
public FillListTask(int size) {
this.size = size;
}
Idioms of Java Programming | 71
public synchronized boolean isFinished() {
return null != strings;
}
public synchronized List<String> getList() {
return strings;
}
@Override
public void run() {
List<String> strs = new ArrayList<String>(size);
try {
for (int i = 0; i < size; i++ ) {
Thread.sleep(2000);
strs.add("element " + String.valueOf(i));
}
synchronized (this) {
strings = strs;
this.notifyAll();
}
}
}
catch (InterruptedException e) {
// catch interrupted exception outside loop,
// since interrupted exception is a sign that
// the thread should quit.
}
/**
* Waits for the fill list task to complete
*/
public static void main(String[] args)
throws InterruptedException
{
FillListTask task = new FillListTask(7);
new Thread(task).start();
// The call to wait() releases the lock
// on task and suspends the thread until
// it receives a notification
synchronized (task) {
while (!task.isFinished()) {
task.wait();
}
}
}
System.out.println("Array full: " + task.getList());
}
,QIDFWPRVWGHYHORSHUVZLOOQHYHUXVHORZOHYHOWRROVOLNH waitDQG notifyWXUQLQJ
LQVWHDGWRWKHjava.util.concurrentSDFNDJHIRUKLJKHUOHYHOWRROV
72 | Chapter 2:ಗJava for Android
Synchronization and Data Structures
$QGURLGVXSSRUWVWKHIHDWXUHULFK-DYD&ROOHFWLRQV/LEUDU\IURP6WDQGDUG(GLWLRQ-DYD
,I\RXSHUXVHWKHOLEUDU\\RX¦OOILQGWKDWWKHUHDUHWZRYHUVLRQVRIPRVWNLQGVRIFRO
OHFWLRQVListDQGVectorHashMapDQGHashtableDQGVRRQ-DYDLQWURGXFHGDQHQWLUHO\
QHZFROOHFWLRQVIUDPHZRUNLQYHUVLRQ7KHQHZIUDPHZRUNFRPSOHWHO\UHSODFHVWKH
ROGFROOHFWLRQV7RPDLQWDLQEDFNZDUGFRPSDWLELOLW\KRZHYHUWKHROGYHUVLRQVZHUH
QRWGHSUHFDWHG
7KHQHZFROOHFWLRQVVKRXOGEHSUHIHUUHGRYHUWKHLUOHJDF\FRXQWHUSDUWV7KH\KDYHD
PRUHXQLIRUP$3,WKHUHDUHEHWWHUWRROVWRVXSSRUWWKHPDQGVRRQ3HUKDSVPRVW
LPSRUWDQWKRZHYHUWKHOHJDF\FROOHFWLRQVDUHDOOV\QFKURQL]HG7KDWPLJKWVRXQGOLNH
DJUHDWLGHDEXWDVWKHIROORZLQJH[DPSOHVKRZVLWLVQRWQHFHVVDULO\VXIILFLHQW
Download from Wow! eBook <www.wowebook.com>
public class SharedListTask implements Runnable {
private final Vector<String> list;
public SharedListTask(Vector<String> l) {
this.list = l;
}
@Override
public void run() {
// the size of the list is obtained early
int s = list.size();
}
while (true) {
for (int i = 0; i < s; i++ ) {
// throws IndexOutOfBoundsException!!
// when the list is size 3, and s is 4.
System.out.println(list.get(i));
}
}
public static void main(String[] args) {
Vector<String> list = new Vector<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
new Thread(new SharedListTask(list)).start();
try { Thread.sleep(2000); }
catch (InterruptedException e) { /* ignore */ }
}
}
// the data structure is fully synchronized,
// but that only protects the individual methods!
list.remove("three");
Idioms of Java Programming | 73
(YHQWKRXJKHYHU\XVHRIWKH VectorLVIXOO\V\QFKURQL]HGDQGHDFKFDOOWRRQHRILWV
PHWKRGVLVJXDUDQWHHGWREHDWRPLFWKLVSURJUDPEUHDNV7KHFRPSOHWHV\QFKURQL]D
WLRQRIWKHVectorLVQRWVXIILFLHQWRIFRXUVHEHFDXVHWKHFRGHPDNHVDFRS\RILWVVL]H
DQGXVHVLWHYHQZKLOHDQRWKHUWKUHDGFKDQJHVWKDWVL]H
%HFDXVHVLPSO\V\QFKURQL]LQJWKHPHWKRGVRIDFROOHFWLRQREMHFWLWVHOILVVRRIWHQLQ
VXIILFLHQWWKHFROOHFWLRQVLQWKHQHZIUDPHZRUNDUHQRWV\QFKURQL]HGDWDOO,IWKHFRGH
KDQGOLQJWKHFROOHFWLRQLVJRLQJWRKDYHWRV\QFKURQL]HDQ\ZD\V\QFKURQL]LQJWKHFRO
OHFWLRQLWVHOILVUHGXQGDQWDQGZDVWHIXO
74 | Chapter 2:ಗJava for Android
CHAPTER 3
The Ingredients of an Android
Application
%DVHGRQWKHIRXQGDWLRQODLGLQWKHODVWFKDSWHUIRUZULWLQJUREXVW-DYDFRGHWKLVFKDSWHU
LQWURGXFHV WKH PDMRU KLJKOHYHO FRQFHSWV LQYROYHG LQ SURJUDPPLQJ IRU WKH $QGURLG
SODWIRUP
Traditional Programming Models Compared to Android
:KHQVWDUWLQJDSSOLFDWLRQVRSHUDWLQJV\VWHPVWUDGLWLRQDOO\XVHDVLQJOHHQWU\SRLQW
RIWHQFDOOHGmainZKLFKPLJKWSDUVHVRPHFRPPDQGOLQHDUJXPHQWVDQGWKHQSURFHHG
WRH[HFXWHDORRSWKDWZRXOGUHDGXVHULQSXWDQGSURGXFHRXWSXW7KH26ZRXOGORDG
WKHSURJUDPFRGHLQWRDSURFHVVDQGWKHQVWDUWH[HFXWLQJLW&RQFHSWXDOO\WKLVNLQGRI
SURFHVVZRXOGORRNVRPHWKLQJOLNH)LJXUH
)LJXUH$VLPSOHDSSOLFDWLRQLQDSURFHVV
75
:LWKSURJUDPVZULWWHQLQ-DYDLWJHWVDOLWWOHPRUHFRPSOH[D-DYDYLUWXDOPDFKLQH
90 LQDSURFHVVORDGVE\WHFRGHWRLQVWDQWLDWH-DYDFODVVHVDVWKHSURJUDPXVHVWKHP
7KLVSURFHVVORRNVVRPHWKLQJOLNH)LJXUH,I\RXXVHDULFKJUDSKLFDOXVHULQWHUIDFH
V\VWHPOLNH6ZLQJ\RXPLJKWVWDUWD8,V\VWHPDQGWKHQZULWHFDOOEDFNVWR\RXUFRGH
WKDWSURFHVVHYHQWV
)LJXUH$-DYDDSSOLFDWLRQUXQQLQJLQD-DYDYLUWXDOPDFKLQHLQDSURFHVV
$QGURLGLQWURGXFHVDULFKHUDQGPRUHFRPSOH[DSSURDFKE\VXSSRUWLQJPXOWLSOHDS
SOLFDWLRQHQWU\SRLQWV$QGURLGSURJUDPVVKRXOGH[SHFWWKHV\VWHPWRVWDUWWKHPLQ
GLIIHUHQWSODFHVGHSHQGLQJRQZKHUHWKHXVHULVFRPLQJIURPDQGZKDWVKHZDQWVWR
GRQH[W,QVWHDGRIDKLHUDUFK\RISODFHV\RXUSURJUDPLVDFRRSHUDWLQJJURXSRIFRP
SRQHQWVWKDWPD\EHVWDUWHGIURPRXWVLGHWKHQRUPDOIORZRI\RXUDSSOLFDWLRQ)RU
H[DPSOHDFRPSRQHQWWRVFDQDEDUFRGHSURYLGHVDGLVFUHWHIXQFWLRQWKDWPDQ\DS
SOLFDWLRQVFDQLQWHJUDWHLQWRWKHLU8,IORZ,QVWHDGRIUHO\LQJRQWKHXVHUWRGLUHFWO\VWDUW
HDFKDSSOLFDWLRQWKHFRPSRQHQWVWKHPVHOYHVLQYRNHRQHDQRWKHUWRSHUIRUPLQWHUDF
WLRQVRQEHKDOIRIWKHXVHU
76 | Chapter 3:ಗThe Ingredients of an Android Application
Activities, Intents, and Tasks
$Q $QGURLG DFWLYLW\ LV ERWK D XQLW RI XVHU LQWHUDFWLRQ¢W\SLFDOO\ ILOOLQJ WKH ZKROH
VFUHHQ RI DQ $QGURLG PRELOH GHYLFH¢DQG D XQLW RI H[HFXWLRQ :KHQ \RX PDNH DQ
LQWHUDFWLYH $QGURLG SURJUDP \RX VWDUW E\ VXEFODVVLQJ WKH Activity FODVV $FWLYLWLHV
SURYLGHWKHUHXVDEOHLQWHUFKDQJHDEOHSDUWVRIWKHIORZRI8,FRPSRQHQWVDFURVV$Q
GURLGDSSOLFDWLRQV
+RZWKHQGRHVRQHDFWLYLW\LQYRNHDQRWKHUDQGSDVVLQIRUPDWLRQDERXWZKDWWKHXVHU
ZDQWVWRGR"7KHXQLWRIFRPPXQLFDWLRQLVWKH IntentFODVV$QIntentUHSUHVHQWVDQ
DEVWUDFWGHVFULSWLRQRIDIXQFWLRQWKDWRQHDFWLYLW\UHTXLUHVDQRWKHUDFWLYLW\WRSHUIRUP
VXFKDVWDNLQJDSLFWXUH,QWHQWVIRUPWKHEDVLVRIDV\VWHPRIORRVHFRXSOLQJWKDWDOORZV
DFWLYLWLHVWRODXQFKRQHDQRWKHU:KHQDQDSSOLFDWLRQGLVSDWFKHVDQLQWHQWLW¦VSRVVLEOH
WKDWVHYHUDOGLIIHUHQWDFWLYLWLHVPLJKWEHUHJLVWHUHGWRSURYLGHWKHGHVLUHGRSHUDWLRQ
<RXKDYHDOUHDG\ZULWWHQWKHFRGHIRUDQDFWLYLW\LQWKHWHVWDSSOLFDWLRQ\RXFUHDWHG
WRYHULI\WKDW\RXU$QGURLG6'.LVFRUUHFWO\LQVWDOOHG/HW¦VWDNHDORRNDWWKDWFRGH
DJDLQ
public class TestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
:KHQWKHV\VWHPVWDUWVWKLVDFWLYLW\LWFDOOVWKHFRQVWUXFWRUIRUTestActivityDVXEFODVV
RIActivityDQGWKHQFDOOVLWVonCreatePHWKRG7KLVFDXVHVWKHYLHZKLHUDUFK\GHVFUL
EHGLQWKHPDLQ[POILOHWRORDGDQGGLVSOD\7KH onCreatePHWKRGNLFNVRIIWKHOLIH
F\FOHRIWKHActivityZKLFK&KDSWHUFRYHUVLQGHWDLO
7KH ActivityFODVVLVRQHRIWKHPRVWLPSRUWDQWFODVVHVLQWKH$QGURLGV\VWHPSUR
PRWLQJDSSV PRGXODULW\DQGDOORZLQJIXQFWLRQDOLW\WREHVKDUHG$QActivityLQWHUDFWV
ZLWKWKH$QGURLGUXQWLPHWRLPSOHPHQWNH\DVSHFWVRIWKHDSSOLFDWLRQOLIHF\FOH(DFK
DFWLYLW\FDQDOVREHLQGHSHQGHQWO\FRQILJXUHGWKURXJKDContextFODVV
(DFKDFWLYLW\LQDQ$QGURLGDSSOLFDWLRQLVODUJHO\VHSDUDWHIURPRWKHUDFWLYLWLHV7KH
FRGHWKDWLPSOHPHQWVRQHDFWLYLW\GRHVQRWGLUHFWO\FDOOPHWKRGVLQWKHFRGHWKDWLP
SOHPHQWV DQRWKHU DFWLYLW\ 2WKHU HOHPHQWV LQ WKH $QGURLG IUDPHZRUN¢VXFK WKH
IntentDOUHDG\PHQWLRQHG¢DUHXVHGWRPDQDJHFRPPXQLFDWLRQLQVWHDG7KXV\RXDUH
GLVFRXUDJHGIURPNHHSLQJUHIHUHQFHVWRActivityREMHFWV7KH$QGURLG5XQWLPH(QYL
URQPHQWZKLFKFUHDWHVDQGPDQDJHVDFWLYLWLHVDQGRWKHUDSSOLFDWLRQFRPSRQHQWVRI
WHQUHFODLPVWKHPHPRU\WKH\XVHLQRUGHUWRUHVWULFWLQGLYLGXDOWDVNVWRUHODWLYHO\VPDOO
DPRXQWVRIPHPRU\<RXZLOOILQGDGKRFDWWHPSWVWRPDQDJHDFWLYLW\PHPRU\WREH
ODUJHO\FRXQWHUSURGXFWLYH
Activities, Intents, and Tasks | 77
:HXVHWKHZRUGDFWLYLW\WRUHIHUWRLQVWDQFHVRIWKHActivityFODVVPXFK
WKHZD\WKDWREMHFWLVXVHGWRUHIHUWRLQVWDQFHVRIFODVVHV
,QVWHDGRIDXVHULQWHUIDFHIORZFRQWUROEDVHGRQPHWKRGFDOOVDSSOLFDWLRQVGHVFULEHDQ
IntentWKDWWKH\ZDQWWRH[HFXWHDQGDVNWKHV\VWHPWRILQGRQHWKDWPDWFKHV7KH
$QGURLG+RPHVFUHHQDSSOLFDWLRQVWDUWV\RXUSURJUDPXVLQJWKHVHGHVFULSWLRQVDQG
HDFKDSSFDQWKHQGRWKHVDPHXVLQJLWVRZQFKRLFHRILQWHQWV$QGURLG'HYHORSHUVFDOO
WKHUHVXOWDQWIORZD£WDVN¤DFKDLQRIDFWLYLWLHVWKDWRIWHQVSDQPRUHWKDQRQHDSSOL
FDWLRQDQGLQGHHGPRUHWKDQRQHSURFHVV)LJXUHVKRZVDWDVNVSDQQLQJWKUHH
DSSOLFDWLRQVDQGPXOWLSOHDFWLYLWLHV 7DEOHJLYHVDQH[DPSOH 7KHFKDLQRIDFWLYLWLHV
FRPSULVLQJ WKLV WDVN VSDQV WKUHH VHSDUDWH SURFHVVHV DQG KHDSV DQG FDQ H[LVW LQGH
SHQGHQWO\RIRWKHUWDVNVWKDWPD\KDYHVWDUWHGRWKHULQVWDQFHVRIWKHVDPH Activity
VXEFODVVHV
7DEOH([DPSOHVRIDVLQJOHWDVNPDGHXSRIDFWLYLWLHVDFURVVDSSOLFDWLRQV
App
Activity
User’s next action
Messaging
View list of messages
User taps on a message in the list
Messaging
View a message
User taps Menu→View Contact
Contacts
View a contact
User taps Call Mobile
Phone
Call the contact's mobile number
)LJXUH$FWLYLWLHVLQDVLQJOHWDVNVSDQQLQJPXOWLSOHDSSOLFDWLRQV
Other Android Components
7KUHHRWKHUFRPSRQHQWVLQ$QGURLGFRQWULEXWHWRDSSOLFDWLRQVVHUYLFHVFRQWHQWSUR
YLGHUVDQGEURDGFDVWUHFHLYHUV7KHServiceFODVVVXSSRUWVEDFNJURXQGIXQFWLRQV7KH
ContentProviderFODVVSURYLGHVDFFHVVWRDGDWDVWRUHIRUPXOWLSOHDSSOLFDWLRQVDQGWKH
Broadcast Receiver DOORZV PXOWLSOH SDUWLHV WR OLVWHQ IRU LQWHQWV EURDGFDVW E\
DSSOLFDWLRQV
<RX ZLOO ILQG WKDW FRPSDUHG WR LWV FRPSRQHQWV WKH DSSOLFDWLRQ LWVHOI LV D
UHODWLYHO\XQLPSRUWDQWXQLW:HOOGHVLJQHGDSSOLFDWLRQV£GLVVROYH¤LQWRWKH$QGURLG
78 | Chapter 3:ಗThe Ingredients of an Android Application
HQYLURQPHQWZKHUHWKH\FDQVWDUWDFWLYLWLHVLQRWKHUDSSOLFDWLRQVWRERUURZWKHLUIXQF
WLRQVDQGSURYLGHRUDXJPHQWWKHLURZQIXQFWLRQDOLW\WKURXJKWKHXVHRIVXSSRUWLQJ
$QGURLGFRPSRQHQWV<RXFDQWKLQNRI$QGURLG VFRQWHQWSURYLGHUVDQGLQWHQWVDVD
VHFRQGDU\$3,WKDW\RXVKRXOGOHDUQWRXVHLQRUGHUWRWDNHDGYDQWDJHRI$QGURLG V
VWURQJHVWIHDWXUHVDQGLQWHJUDWHVHDPOHVVO\ZLWKWKH$QGURLGSODWIRUP
Service
7KH$QGURLG ServiceFODVVLVIRUEDFNJURXQGWDVNVWKDWPD\EHDFWLYHEXWQRWYLVLEOH
RQWKHVFUHHQ$PXVLFSOD\LQJDSSOLFDWLRQZRXOGOLNHO\EHLPSOHPHQWHGDVDVHUYLFHLQ
RUGHUWRFRQWLQXHWRSOD\PXVLFZKLOHDXVHUPLJKWEHYLHZLQJZHESDJHV6HUYLFHVDOVR
DOORZDSSOLFDWLRQVWRVKDUHIXQFWLRQVWKURXJKORQJWHUPFRQQHFWLRQV7KLVSUDFWLFHLV
UHPLQLVFHQWRI,QWHUQHWVHUYLFHVVXFKDV)73DQG+773ZKLFKZDLWXQWLODUHTXHVWIURP
DFOLHQWWULJJHUVWKHP7KH$QGURLGSODWIRUPDYRLGVUHFODLPLQJVHUYLFHUHVRXUFHVVR
RQFH D VHUYLFH VWDUWV LW LV OLNHO\ WR EH DYDLODEOH XQOHVV PHPRU\ JHWV H[WUHPHO\
FRQVWUDLQHG
/LNHActivityWKHServiceFODVVRIIHUVPHWKRGVWKDWFRQWUROLWVOLIHF\FOHVXFKDVVWRS
SLQJDQGUHVWDUWLQJWKHVHUYLFH
Content Providers
&RQWHQWSURYLGHUFRPSRQHQWVDUHURXJKO\DQDORJRXVWRD5(67IXOZHEVHUYLFH\RX
ILQG WKHP XVLQJ D 85, DQG WKH RSHUDWLRQV RI D ContentProvider VXEFODVV SDUDOOHO
5(67IXOZHERSHUDWLRQVVXFKDVSXWWLQJDQGJHWWLQJGDWD$VSHFLDO85,VWDUWLQJZLWK
WKH content:// ZKLFK LV UHFRJQL]HG DFURVV WKH ORFDO GHYLFH JLYHV \RX DFFHVV WR WKH
FRQWHQWSURYLGHUGDWD7RXVHDContentProvider\RXVSHFLI\D85,DQGKRZWRDFWRQ
UHIHUHQFHGGDWD+HUHLVDOLVWRIFRQWHQWSURYLGHURSHUDWLRQVZKLFKSURYLGHWKHZHOO
NQRZQTXDUWHWRIEDVLFGDWDKDQGOLQJDFWLYLWLHVFUHDWH LQVHUW UHDG TXHU\ XSGDWH
DQGGHOHWH
,QVHUW
7KH insertPHWKRGRIWKH ContentProviderFODVVLVDQDORJRXVWRWKH5(67 POST
RSHUDWLRQ,WLQVHUWVQHZUHFRUGVLQWRWKHGDWDEDVH
4XHU\
7KHqueryPHWKRGRIWKHContentProviderFODVVLVDQDORJRXVWRWKH5(67GETRS
HUDWLRQ,WUHWXUQVDVHWRIUHFRUGVLQDVSHFLDOL]HGFROOHFWLRQFODVVFDOOHGCursor
8SGDWH
7KHupdatePHWKRGRIWKHContentProviderFODVVLVDQDORJRXVWRWKH5(67UPDATE
RSHUDWLRQ,WUHSODFHVUHFRUGVLQWKHGDWDEDVHZLWKXSGDWHGUHFRUGV
'HOHWH
7KHdeletePHWKRGRIWKHContentProviderFODVVLVDQDORJRXVWRWKH5(67DELETE
RSHUDWLRQ,WUHPRYHVPDWFKLQJUHFRUGVIURPWKHGDWDEDVH
Other Android Components | 79
5(67 VWDQGV IRU £5HSUHVHQWDWLRQDO 6WDWH 7UDQVIHU¤ ,W LVQ¦W D IRUPDO
SURWRFROWKHZD\WKDW+773LV,WLVPRUHRIDFRQFHSWXDOIUDPHZRUN
IRUXVLQJ+773DVDEDVLVIRUHDV\DFFHVVWRGDWD:KLOH5(67LPSOH
PHQWDWLRQVPD\GLIIHUWKH\DOOVWULYHIRUVLPSOLFLW\$QGURLG¦VFRQWHQW
SURYLGHU $3, IRUPDOL]HV 5(67OLNH RSHUDWLRQV LQWR DQ $3, DQG LV GH
VLJQHGLQWKHVSLULWRI5(67¦VVLPSOLFLW\<RXFDQILQGPRUHLQIRUPDWLRQ
RQ5(67RQ:LNLSHGLDKWWSHQZLNLSHGLDRUJZLNL5(67
&RQWHQWSURYLGHUFRPSRQHQWVDUHWKHKHDUWRIWKH$QGURLGFRQWHQWPRGHOE\SURYLGLQJ
DContentProvider\RXUDSSOLFDWLRQFDQVKDUHGDWDZLWKRWKHUDSSOLFDWLRQVDQGPDQDJH
WKHGDWDPRGHORIDQDSSOLFDWLRQ$FRPSDQLRQFODVVContentResolverHQDEOHVRWKHU
FRPSRQHQWV LQ DQ $QGURLG V\VWHP WR ILQG FRQWHQW SURYLGHUV <RX ZLOO ILQG FRQWHQW
SURYLGHUVWKURXJKRXWWKHSODWIRUPXVHGERWKLQWKHRSHUDWLQJV\VWHPDQGLQDSSOLFD
WLRQVIURPRWKHUGHYHORSHUV1RWDEO\WKHFRUH$QGURLGDSSOLFDWLRQVPDNHXVHRIFRQ
WHQW SURYLGHUV WKDW FDQ SURYLGH TXLFN DQG VRSKLVWLFDWHG IXQFWLRQV IRU QHZ $QGURLG
DSSOLFDWLRQVLQFOXGLQJSURYLGHUVIRU%URZVHU&DOHQGDU&RQWDFWV&DOO/RJ0HGLD
DQG6HWWLQJV
&RQWHQWSURYLGHUVDUHXQLTXHDPRQJWKH,3&V\VWHPVIRXQGRQRWKHUSODWIRUPVVXFK
DV&25%$50,DQG'&20ZKLFKIRFXVRQUHPRWHSURFHGXUHFDOOV&RQWHQWSUR
YLGHUVRSHUDWHERWKDVDSHUVLVWHQFHPHFKDQLVPDQGDVDIRUPRILQWHUSURFHVVFRPPX
QLFDWLRQ,QVWHDGRIMXVWHQDEOLQJLQWHUSURFHVVPHWKRGFDOOVFRQWHQWSURYLGHUVDOORZ
GHYHORSHUVWRHIILFLHQWO\VKDUHHQWLUH64/GDWDEDVHVDFURVVSURFHVVHVLQVWHDGRIVKDULQJ
MXVWREMHFWVFRQWHQWSURYLGHUVPDQDJHHQWLUH64/WDEOHV
Using a content provider
'XHWRLWVLPSRUWDQFHLQ$QGURLGZHSURYLGHDEULHILQWURGXFWLRQKHUHWRZULWLQJD
FOLHQWWKDWXVHVDFRQWHQWSURYLGHU7KLVH[DPSOHZKLFKXVHVRQHRIWKHPRVWLPSRUWDQW
FRQWHQWSURYLGHUV¢WKH&RQWDFWVGDWDEDVH¢VKRXOGJLYH\RXDVRPHZKDWPRUHJURXQ
GHG XQGHUVWDQGLQJ RI KRZ D FRQWHQW SURYLGHU FDQ ILW LQWR \RXU DSSOLFDWLRQ 7KH
ContentProviderFODVVSURYLGHVWKHFHQWUDOFRQWHQWSURYLGHU$3,ZKLFK\RXFDQVXEW\SH
WRPDQLSXODWHVSHFLILFW\SHVRIGDWD$FWLYLWLHVDFFHVVVSHFLILFFRQWHQWSURYLGHULQVWDQFHV
XVLQJWKHContentResolverFODVVDQGDVVRFLDWHG85/VDVIROORZV
// code from an activity method
ContentProviderClient client = getContentResolver().
acquireContentProviderClient("content://contacts/people");
ContentProvider provider = client.getLocalContentProvider();
8VLQJ D FRQWHQW SURYLGHU LQYROYHV FDOOLQJ LWV GDWD RSHUDWLRQV ZLWK 5(67VW\OH 85,V
GHILQHGE\WKH UriMatcherFODVV UriMatcherSURYLGHVDVLPSOHVWULQJPDWFKLQJXWLOLW\
IRU5(67EDVHG85/VZLWKVXSSRUWIRUZLOGFDUGLQJVWULQJV&RQWHQWSURYLGHU85/V
DOZD\VWDNHWKHIROORZLQJIRUP
content://authority/path/id
80 | Chapter 3:ಗThe Ingredients of an Android Application
ZKHUHauthorityLVWKH-DYDSDFNDJHRIWKHFRQWHQWSURYLGHUQDPHVSDFH RIWHQWKH-DYD
QDPHVSDFHRIWKHFRQWHQWSURYLGHULPSOHPHQWDWLRQ +HUHDUHVRPHH[DPSOHFRQWHQW
SURYLGHU85,V
// references a person
content://contacts/people/25
// this URI designates the phone numbers of the person whose ID is "25"
content://contacts/people/25/phones
:KHQDGHYHORSHUFDOOVWKHqueryPHWKRGRQDFRQWHQWSURYLGHUWKHFDOOZLOOUHWXUQD
CursorREMHFWWKDWLPSOHPHQWVWKH android.database.CursorLQWHUIDFH7KLVLQWHUIDFH
OHWV\RXUHWULHYHRQHUHVXOW OLNHDURZIURPDGDWDEDVH DWDWLPHXVLQJDQLQGH[WKDWLV
DXWRPDWLFDOO\XSGDWHGDV\RXUHWULHYHHDFKUHVXOW'HYHORSHUVIDPLOLDUZLWK-'%&FDQ
FRPSDUHWKLVWRjava.sql.ResultSet,QPRVWFDVHVCursorREMHFWVUHSUHVHQWWKHUHVXOWV
RITXHULHVRQ64/LWHWDEOHV'HYHORSHUVFDQDFFHVVFXUVRUILHOGVXVLQJWKHLQGH[HVRI
WKHXQGHUO\LQJ64/LWHWDEOH+HUHLVDQH[DPSOHRILWHUDWLQJDQ$QGURLGFXUVRUDQG
DFFHVVLQJLWVILHOGV
// code from an activity method
Cursor contactsCursor =
managedQuery(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (contactsCursor.moveToFirst()) {
int idx = contactsCursor.getColumnIndex(Contacts.People.DISPLAY_NAME);
do { name = contactsCursor.getString(idx); }
while (contactsCursor.moveToNext());
}
1RWHKHUHWKDWZKHQHYHUDFOLHQWXVHVDFXUVRUIURPDSURYLGHULW¦VFULWLFDOWRFORVHWKH
FXUVRUZKHQWKHFOLHQWLV¦VGRQHZLWKLW)DLOXUHWRGRVRZLOOUHVXOWLQDVHULRXVPHPRU\
OHDNWKDWFDQFUDVK\RXUDSSOLFDWLRQ$QGURLGSURYLGHVWZRZD\VWRHQVXUHWKDWSURYLGHU
FXUVRUVJHWFORVHGZKHQQRWLQXVH
‡ 7KHDFWLYLW\FDOOVCursor.closeGLUHFWO\
‡ 7KHDFWLYLW\FDOOVmanagedQueryWRTXHU\FRQWHQWSURYLGHUVRUFDOOVstartManaging
Cursor(Cursor c)%RWKRIWKHVHFDOOVUHO\RQWKHV\VWHPWRZDWFKFXUVRUUHIHUHQFHV
WRNQRZZKHQDJLYHQUHIHUHQFHKDVQRPRUHDFWLYHFOLHQWV:KHQUHIHUHQFHFRXQWV
LQGLFDWHWKDWDOOFOLHQWVKDYHILQLVKHGWKHV\VWHPZLOOLWVHOIFDOOCursor.close
:H¦OOVSHQGPRUHWLPHFRYHULQJGDWDDQGFRQWHQWSURYLGHUVLQGHWDLOLQ&KDSWHUV
DQG
Content providers and the Internet
7RJHWKHUZLWKWKHActivityFRPSRQHQWRIDQ$QGURLGDSSOLFDWLRQFRQWHQWSURYLGHUV
SURYLGHWKHQHFHVVDU\SDUWVRID0RGHO9LHZ&RQWUROOHU 09& DUFKLWHFWXUH,QDGGL
WLRQ WR VXSSRUWLQJ 5(67OLNH RSHUDWLRQV WKH\ VXSSRUW WKH REVHUYHU SDWWHUQ WKDW
Other Android Components | 81
VXSSRUWV09&7KHContentResolverFODVVSURYLGHVDnotifyChangePHWKRGWKDWEURDG
FDVWVDFKDQJHLQWKHGDWDEDVHWRCursorREMHFWVWKDWKDYHUHJLVWHUHGFRQWHQWREVHUYHUV
XVLQJWKHregisterContentObserverPHWKRG
<RXPD\EHWKLQNLQJ£7KDW¦VQLFHEXWWKHGDWD,¦PLQWHUHVWHGLQLVRXWWKHUHRQWKH
,QWHUQHW¤$VLWKDSSHQV$QGURLGSURYLGHVSOHQW\RIWRROVWRPDNHDFFHVVLQJWKDWGDWD
VLPSOH<RXKDYHSUREDEO\XVHGVRPHDSSOLFDWLRQVWKDWDFFHVV,QWHUQHWEDVHGGDWDXV
LQJ$QGURLG¦VQHWZRUNFODVVHV8QIRUWXQDWHO\\RXFDQRIWHQUHFRJQL]HWKHVHDSSOLFD
WLRQVEHFDXVHWKH\WDNHDQRWLFHDEOHDPRXQWRIWLPHWRDFFHVVDQGUHWULHYHGDWDIURP
VRPHVHUYHURQWKH,QWHUQHW7KH\PLJKWHYHQVKRZDSURJUHVVLQGLFDWRUZKLOH\RXZDLW
:RXOGQ¦WLWEHQLFHULI\RXFRXOGKDUQHVVWKHSRZHURIFRQWHQWSURYLGHUVWRFDFKHGDWD
ORFDOO\ DQG WKH SRZHU RI $QGURLG¦V GDWDEDVHFHQWULF 09& DUFKLWHFWXUH VXSSRUW WR
PDNHIUHVKGDWDDSSHDURQWKHXVHU¦VVFUHHQDVLWDUULYHV"7KDW¦VZKDW&KDSWHULV
DERXW 7KHUH \RX ZLOO OHDUQ KRZ WR FRPELQH XVHU LQWHUIDFHV FRQWHQW SURYLGHUV DQG
UHODWHGFODVVHV$QGURLG¦VQHWZRUN$3,VDQG09&VXSSRUWLQ$QGURLGWRFUHDWHD5(67
FOLHQWWKDWWDNHVDGYDQWDJHRIWKHVLPLODULW\RIWKHFRQWHQWSURYLGHUDUFKLWHFWXUHWR5(67
WRIUHHWKHXVHUIURPVWDULQJDWDSURJUHVVLQGLFDWRUZKLOH\RXUDSSOLFDWLRQIHWFKHVGDWD
BroadcastReceiver
7KHBroadcastReceiverFODVVLPSOHPHQWVDQRWKHUYDULDQWRI$QGURLG¦VKLJKOHYHOLQWHU
SURFHVV FRPPXQLFDWLRQ PHFKDQLVP XVLQJ Intent REMHFWV BroadcastReceiver KDV D
VLPSOHUOLIHF\FOHWKDQWKHRWKHUFRPSRQHQWVZH YHFRYHUHG$EURDGFDVWUHFHLYHUUH
FHLYHVWKHDFWLRQRIIntentREMHFWVVLPLODUO\WRDQActivityEXWGRHVQRWKDYHLWVRZQ
XVHULQWHUIDFH$W\SLFDOXVHIRUDEURDGFDVWUHFHLYHUPLJKWEHWRUHFHLYHDQDODUPWKDW
FDXVHVDQDSSWREHFRPHDFWLYHDWDSDUWLFXODUWLPH7KHV\VWHPFDQEURDGFDVWDQLQWHQW
WRPXOWLSOHUHFHLYHUV
Static Application Resources and Context
$SSOLFDWLRQVPD\QHHGWRVWRUHVLJQLILFDQWDPRXQWVRIGDWDWRFRQWUROWKHLUUXQWLPH
EHKDYLRU6RPHRIWKLVGDWDGHVFULEHVWKHDSSOLFDWLRQHQYLURQPHQWWKHDSSQDPHWKH
LQWHQWVLWUHJLVWHUVWKHSHUPLVVLRQVLWQHHGVDQGVRRQ7KLVGDWDLVVWRUHGLQDILOHFDOOHG
WKHPDQLIHVW2WKHUGDWDPLJKWEHLPDJHVWRGLVSOD\RUVLPSOHWH[WVWULQJVLQGLFDWLQJ
ZKDWEDFNJURXQGFRORURUIRQWWRXVH7KHVHGDWDDUHFDOOHGUHVRXUFHV7RJHWKHUDOO
WKLVLQIRUPDWLRQIRUPVWKHFRQWH[WRIWKHDSSOLFDWLRQDQG$QGURLGSURYLGHVDFFHVVWR
LWWKURXJKWKHContextFODVV%RWKActivityDQGServiceH[WHQGWKHContextFODVVZKLFK
PHDQV WKDW DOO DFWLYLWLHV DQG VHUYLFHV KDYH DFFHVV WR Context GDWD WKURXJK WKH this
SRLQWHU,QVXEVHTXHQWVHFWLRQVZHZLOOGHVFULEHKRZWRXVHDContextREMHFWWRDFFHVV
DSSOLFDWLRQUHVRXUFHVDWUXQWLPH
82 | Chapter 3:ಗThe Ingredients of an Android Application
Application Manifests
$QGURLGUHTXLUHVDSSOLFDWLRQVWRH[SOLFLWO\GHVFULEHWKHLUFRQWHQWVLQDQ;0/ILOHFDOOHG
$QGURLG0DQLIHVW[PO +HUH DSSOLFDWLRQV GHFODUH WKH SUHVHQFH RI FRQWHQW SURYLGHUV
VHUYLFHVUHTXLUHGSHUPLVVLRQVDQGRWKHUHOHPHQWV7KHDSSOLFDWLRQFRQWH[WPDNHVWKLV
GDWDDYDLODEOHWRWKH$QGURLGUXQWLPH7KHPDQLIHVWILOHRUJDQL]HVDQ$QGURLGDSSOL
FDWLRQLQWRDZHOOGHILQHGVWUXFWXUHWKDWLVVKDUHGE\DOODSSOLFDWLRQVDQGHQDEOHVWKH
$QGURLGRSHUDWLQJV\VWHPWRORDGDQGH[HFXWHWKHPLQDPDQDJHGHQYLURQPHQW7KH
VWUXFWXUH HQFRPSDVVHV D FRPPRQ GLUHFWRU\ OD\RXW DQG FRPPRQ ILOH W\SHV LQ WKRVH
GLUHFWRULHV
$V ZH¦YH VHHQ WKH IRXU FRPSRQHQWV RI $QGURLG DSSOLFDWLRQV¢Activity Service
ContentProviderDQG BroadcastReceiver¢SURYLGHWKHIRXQGDWLRQRI$QGURLGDSSOL
FDWLRQGHYHORSPHQW VHH)LJXUH 7RPDNHXVHRIDQ\RIWKHPDQDSSOLFDWLRQPXVW
LQFOXGHFRUUHVSRQGLQJGHFODUDWLRQVLQLWV$QGURLG0DQLIHVW[POILOH
)LJXUH7KHIRXUNLQGVRI$QGURLGFRPSRQHQWV
The Application Class
7KHUH LV D £ILIWK %HDWOH¤ RI $QGURLG FRPSRQHQWV WKH Application FODVV %XW PDQ\
$QGURLGDSSOLFDWLRQVGRQRWVXEFODVVApplication%HFDXVHLQPRVWFDVHVVXEFODVVLQJ
Application LV XQQHFHVVDU\ WKH $QGURLG SURMHFW ZL]DUG GRHVQ¦W FUHDWH RQH
DXWRPDWLFDOO\
Static Application Resources and Context | 83
A Typical Source Tree
7KHVRXUFHFRGHIRU$QGURLGDSSOLFDWLRQVDOPRVWDOZD\VPDNHVXVHRIWKHIROORZLQJ
GLUHFWRU\KLHUDUFK\
AndroidManifest.xml
res/
layout/
... contains application layout files ...
drawable/
...contains images, patches, drawable xml ...
raw/
... contains data files that can be loaded as streams ...
values/
... contains xml files that contain string, number values used in code ...
src/
java/package/directories/
:H¦OOVHHLQDPLQXWHKRZWKHUHVGLUHFWRU\LVSDUWLFXODUO\LPSRUWDQWIRUPDNLQJDSSOL
FDWLRQGDWDDFFHVVLEOHXVLQJDContextREMHFW
Initialization Parameters in AndroidManifest.xml
7KH IROORZLQJ FRGH VKRZV WKH $QGURLG PDQLIHVW IURP RXU WHVW DSSOLFDWLRQ WKDW ZH
LQWURGXFHGLQ&KDSWHU7KHWHVWDSSOLFDWLRQGRHVQRWGRDQ\WKLQJEH\RQGGHPRQ
VWUDWLQJWKHEDVLFOD\RXWRIDQ$QGURLGDSSOLFDWLRQ7KLVPDQLIHVWILOHFRQWDLQVEDVLF
HOHPHQWVWKDWZHKDYHGLVFXVVHG
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oreilly.demo.pa.ch01.testapp"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:icon="@drawable/icon"
android:label="@string/app_name"
android:debuggable="true">
<activity android:name=".TestActivity"
android:label="Test Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider android:name=".TestProvider"
android:authorities= "com.oreilly.demo.pa.ch11.video.FinchVideo"
84 | Chapter 3:ಗThe Ingredients of an Android Application
/>
<service android:name=".TestService"
android:label="Test Service"/>
<receiver
android:name=".TestBroadcastReceiver"
android:label="Test Broadcast Receiver"/>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>
/LNHDOOJRRG;0/ILOHVOLQHKDVWKHVWDQGDUGGHFODUDWLRQRIWKHYHUVLRQRI;0/DQG
WKH FKDUDFWHU HQFRGLQJ XVHG :H WKHQ GHILQH D IHZ SDUDPHWHUV DQG GHFODUH QHHGHG
SHUPLVVLRQVIRUWKHZKROHDSSOLFDWLRQ7KHIROORZLQJOLVWGHVFULEHVWKHWDJVZHKDYH
XVHG
manifest
package="com.oreilly.demo.pa.ch01.testapp"
7KHGHIDXOWSDFNDJHZKHUHPRGXOHVLQWKHDSSOLFDWLRQFDQEHIRXQG
android:versionCode
$QDUELWUDU\LQWHJHUGHQRWLQJYHUVLRQVRIWKHDSSOLFDWLRQ(YHU\DSSOLFDWLRQ
VKRXOGLQFOXGHDYHUVLRQFRGHDQGLWVKRXOGDOZD\VLQFUHDVHIRUHDFKYHUVLRQ
UHOHDVHGWRFXVWRPHUV7KLVOHWVRWKHUSURJUDPV OLNHWKH$QGURLG0DUNHWLQ
VWDOOHUVDQGODXQFKHUV HDVLO\ILJXUHRXWZKLFKYHUVLRQRIDQDSSOLFDWLRQLVODWHU
WKDQDQRWKHU7KHILOHQDPHRI\RXUDSNILOHVKRXOGLQFOXGHWKLVVDPHYHUVLRQ
QXPEHUVRWKDWLWLVREYLRXVZKLFKYHUVLRQLVFRQWDLQHGLQLW
android:versionName
$ VWULQJ LQWHQGHG WR EH PRUH OLNH WKH YHUVLRQ QXPEHUV \RX XVXDOO\ VHH IRU
DSSOLFDWLRQVVXFKDV7KLVLVWKHYHUVLRQLGHQWLILHUWKDWZLOOEHGLVSOD\HG
WRDXVHU HLWKHUE\\RXUDSSOLFDWLRQRUE\DQRWKHUDSSOLFDWLRQ 7KHQDPLQJ
FRQYHQWLRQLVXSWR\RXEXWLQJHQHUDOWKHLGHDLVWRXVHDVFKHPHOLNHPQR
IRU DV PDQ\ QXPEHUV DV \RX ZDQW WR XVH WR LGHQWLI\ VXFFHVVLYH OHYHOV RI
FKDQJHWRWKHDSSOLFDWLRQ
uses-permission android:name=...
)RXUGHFODUDWLRQVLQWKHTestAppPDQLIHVWGHFODUHWKDWWKHDSSOLFDWLRQLQWHQGV
WRXVHIHDWXUHVRI$QGURLGWKDWUHTXLUHH[SOLFLWSHUPLVVLRQIURPWKHXVHURIWKH
GHYLFHUXQQLQJWKHDSSOLFDWLRQ7KHSHUPLVVLRQLVUHTXHVWHGZKHQWKHDSSOL
FDWLRQLVLQVWDOOHG)URPWKHQRQ$QGURLGUHPHPEHUVWKDWWKHXVHUVDLGLWZDV
2. RUQRW WRUXQWKLVDSSOLFDWLRQDQGDOORZDFFHVVWRWKHVHFXUHIHDWXUHV
0DQ\SHUPLVVLRQVDUHDOUHDG\GHILQHGLQ$QGURLGDQGDOODUHGHVFULEHGLQWKH
$QGURLG GRFXPHQWDWLRQ VHDUFK IRU android.Manifest.permission :KDW¦V
PRUH\RXFDQGHILQH\RXURZQSHUPLVVLRQVDQGXVHWKHPWRUHVWULFWRWKHU
DSSOLFDWLRQV¦DFFHVVWRIXQFWLRQVLQ\RXUDSSOLFDWLRQXQOHVVWKHXVHUJUDQWVWKH
RWKHUDSSOLFDWLRQWKDWSHUPLVVLRQ:HKDYHUHTXHVWHGWKHIROORZLQJFRPPRQO\
XVHGSHUPLVVLRQVDVDQH[DPSOH
Static Application Resources and Context | 85
ACCESS_FINE_LOCATION
5HTXLUHGWRREWDLQORFDWLRQLQIRUPDWLRQIURPD*36VHQVRU
CALL_PHONE
$OORZVDSKRQHFDOORQEHKDOIRIWKHXVHU
ACCESS_MOCK_LOCATION
$OORZVXVWRJHWIDNHORFDWLRQLQIRUPDWLRQZKHQZH¦UHUXQQLQJXQGHUWKH
HPXODWRU
INTERNET
$OORZVXVWRRSHQ,QWHUQHWFRQQHFWLRQVWRUHWULHYHGDWD
application
label
3URYLGHVDKXPDQUHDGDEOHDSSOLFDWLRQODEHO
icon="@drawable/icon"
7KHILOHQDPHIRUD31*ILOHWKDWFRQWDLQVWKHLFRQ\RX¦GOLNHWRXVHIRU\RXU
DSSOLFDWLRQ,QWKLVFDVHZH¦UHWHOOLQJWKH$QGURLG6'.WRORRNIRUWKHLFRQILOH
LQWKHGUDZDEOHVXEGLUHFWRU\RIWKHUHV UHVRXUFHV GLUHFWRU\XQGHU7HVW$SS
$QGURLGZLOOXVHWKLVLFRQIRU\RXUDSSOLFDWLRQLQWKH$QGURLG'HVNWRS
activity
7XUQLQJ RXU DWWHQWLRQ WR WKH GHILQLWLRQ RI TestActivity ZH ILUVW GHILQH D IHZ
DWWULEXWHV7KHPRVWLPSRUWDQWDUH
android:name
7KHQDPHRIWKHFODVVIRUWKHActivity7KHIXOOQDPHRIWKHDFWLYLW\LQFOXGHV
WKH SDFNDJH QDPH ZKLFK LQ WKLV DSSOLFDWLRQ LV com.oreilly.demo.pa.ch01
.testapp EXW VLQFH WKLV ILOH LV DOZD\V XVHG LQ WKH FRQWH[W RI WKH SDFNDJH¦V
QDPHVSDFHZHGRQ¦WQHHGWRLQFOXGHWKHOHDGLQJSDFNDJHQDPHVZHVWULSWKH
QDPHGRZQWRMXVW.TestActivity$FWXDOO\HYHQWKHOHDGLQJSHULRGLVRSWLRQDO
android:label
7KHODEHOWKDWZHZDQWWRDSSHDUDWWKHWRSRIWKH$QGURLGVFUHHQZKHQWKH
DFWLYLW\ LV RQ WKH VFUHHQ :H¦YH GHILQHG WKLV LQ VWULQJV[PO WR PDWFK RXU
DSSOLFDWLRQ
intent-filter
+HUHZHGHFODUHDQLQWHQWILOWHUWKDWWHOOV$QGURLGZKHQWKLVActivityVKRXOG
EH UXQ :KHQ DQ DSS DVNV $QGURLG WR IXOILOO DQ Intent WKH UXQWLPH ORRNV
DPRQJWKHDYDLODEOHDFWLYLWLHVDQGVHUYLFHVWRILQGVRPHWKLQJWKDWFDQVHUYLFH
LW:HVHWWZRDWWULEXWHV
action
7KLVWHOOV$QGURLGKRZWRODXQFKWKLVDSSOLFDWLRQRQFHWKHUXQWLPHKDV
GHFLGHGWKLVLVWKHDSSOLFDWLRQWRUXQ$QGURLGORRNVIRUDQDFWLYLW\WKDW
GHFODUHVLWVHOIUHDG\WRUHVROYHWKHMAINDFWLRQ$Q\DSSOLFDWLRQWKDWLVJRLQJ
WREHODXQFKHGE\WKH/DXQFKHUQHHGVWRKDYHH[DFWO\RQHDFWLYLW\RUVHUY
LFHWKDWPDNHVWKLVDVVHUWLRQ
86 | Chapter 3:ಗThe Ingredients of an Android Application
category
7KH IntentUHVROYHULQ$QGURLGXVHVWKLVDWWULEXWHWRIXUWKHUTXDOLI\WKH
IntentWKDWLW¦VORRNLQJIRU,QWKLVFDVHWKHTXDOLILFDWLRQLVWKDWZH¦GOLNH
WKLVActivityWREHGLVSOD\HGLQWKH8VHUPHQXVRWKDWWKHXVHUFDQVHOHFW
LWWRVWDUWWKLVDSSOLFDWLRQ6SHFLI\LQJWKHLAUNCHERFDWHJRU\DFFRPSOLVKHV
WKLV<RXFDQKDYHDSHUIHFWO\YDOLGDSSOLFDWLRQZLWKRXWWKLVDWWULEXWH¢
\RXMXVWZRQ¦WEHDEOHWRODXQFKLWIURPWKH$QGURLGGHVNWRS1RUPDOO\
DJDLQ\RX¦OOKDYHH[DFWO\RQHLAUNCHERSHUDSSOLFDWLRQDQGLWZLOODSSHDU
LQWKHVDPHLQWHQWILOWHUDVWKHRSHQLQJActivityRI\RXUDSSOLFDWLRQ
provider
(QDEOHVWKHGHFODUDWLRQRIDFRQWHQWSURYLGHUnameVSHFLILHVWKHQDPHRIWKHSUR
YLGHUFODVVDQGauthoritiesVSHFLILHVWKH85,DXWKRULWLHVWKDWWKHFRQWHQWSURYLGHU
VKRXOGKDQGOH$85,DXWKRULW\SURYLGHVWKHGRPDLQVHFWLRQRIDFRQWHQWSURYLGHU
85,DQGHQDEOHVWKH$QGURLGFRQWHQWUHVROXWLRQV\VWHPWRORFDWHDSURYLGHUWKDW
VKRXOGKDQGOHDSDUWLFXODUW\SHRI85,:H¦OOSURYLGHPRUHGHWDLORQKRZFOLHQWV
XVHFRQWHQWSURYLGHUVDELWODWHULQWKHFKDSWHU:H¦YHGHFODUHGDSURYLGHUZLWKWKH
QDPHTestProvider
service
(QDEOHVWKHDSSWRGHFODUHWKDWLWVXSSRUWVDJLYHQVHUYLFHZKHUHnameVSHFLILHVWKH
VHUYLFH FODVV DQG label SURYLGHV D KXPDQUHDGDEOH ODEHO IRU WKH VHUYLFH :H¦YH
GHFODUHGDVHUYLFHZLWKWKHQDPH.TestService
receiver
3URYLGHVDZD\WRGHFODUHDQDSS¦VVXSSRUWIRUDEURDGFDVWUHFHLYHU nameDJDLQ
VSHFLILHV WKH UHFHLYLQJ FODVV DQG label SURYLGHV D KXPDQUHDGDEOH ODEHO IRU WKH
UHFHLYHU:H¦YHGHFODUHGDUHFHLYHUZLWKWKHQDPHTestBroadcastReceiver
Resources
$QGURLGDSSOLFDWLRQVSODFHLPDJHVLFRQVDQGXVHULQWHUIDFHOD\RXWILOHVLQWRDGLUHFWRU\
QDPHGUHV7KHUHVGLUHFWRU\XVXDOO\ZLOOFRQWDLQDWOHDVWIRXUVXEGLUHFWRULHVDVIROORZV
OD\RXW
&RQWDLQV$QGURLGXVHULQWHUIDFH;0/ILOHVGHVFULEHGLQ&KDSWHU
GUDZDEOH
&RQWDLQV GUDZLQJ DUWLIDFWV VXFK DV WKH DSSOLFDWLRQ LFRQ QRWHG LQ WKH SUHYLRXV
VHFWLRQ
UDZ
+ROGVILOHVWKDWPD\EHUHDGDVVWUHDPVGXULQJWKHH[HFXWLRQRIDQDSSOLFDWLRQ5DZ
ILOHVDUHDJUHDWZD\WRSURYLGHGHEXJLQIRUPDWLRQWRDUXQQLQJDSSOLFDWLRQZLWKRXW
KDYLQJWRDFFHVVWKHQHWZRUNWRUHWULHYHGDWD
Resources | 87
YDOXHV
&RQWDLQVYDOXHVWKDWWKHDSSOLFDWLRQZLOOUHDGGXULQJLWVH[HFXWLRQRUVWDWLFGDWD
DQDSSOLFDWLRQZLOOXVHIRUVXFKSXUSRVHVDVLQWHUQDWLRQDOL]DWLRQRI8,VWULQJV
$SSOLFDWLRQVDFFHVVUHVRXUFHVLQWKHVHGLUHFWRULHVXVLQJWKHPHWKRGContext.getResour
ces()DQGWKHRFODVV
7RDFFHVVWKHGDWDLQWKHUHVGLUHFWRU\DWUDGLWLRQDO-DYDGHYHORSHUPLJKWWKLQNDERXW
ZULWLQJFRGHWREXLOGUHODWLYHUHVRXUFHILOHSDWKVDQGWKHQXVLQJWKHILOH$3,WRRSHQWKH
UHVRXUFHV$IWHUORDGLQJUHVRXUFHE\WHVWKHDSSOLFDWLRQGHYHORSHUPLJKWH[SHFWWRSDUVH
DQDSSOLFDWLRQVSHFLILFIRUPDWWRILQDOO\JHWDFFHVVWRWKHVDPHLWHPVHYHU\DSSQHHGV
LPDJHV VWULQJV DQG GDWD ILOHV $QWLFLSDWLQJ HDFK DSSOLFDWLRQ¦V QHHG WR ORDG VLPLODU
LQIRUPDWLRQ$QGURLGLQVWHDGLQFOXGHVDXWLOLW\WKDWLQWHJUDWHVZLWK(FOLSVHPDNHVUH
VRXUFHVHDVLO\DFFHVVLEOHWRSURJUDPORJLFDQGVWDQGDUGL]HVSURJUDPUHVRXUFHV
(FOLSVHDQGWKH$QGURLG6'.ZRUNWRJHWKHUWRFUHDWHDGLUHFWRU\FDOOHG JHQZKLFK
FRQWDLQVDFODVVDOZD\VQDPHGRZKLFKUHVLGHVLQWKH-DYDDSSOLFDWLRQSDFNDJHQDPHG
LQWKH$QGURLGPDQLIHVW7KH RFODVVILOHFRQWDLQVILHOGVWKDWXQLTXHO\LGHQWLI\DOOUH
VRXUFHV LQ WKH DSSOLFDWLRQ SDFNDJH VWUXFWXUH $ GHYHORSHU FDOOV WKH
Context.getResources PHWKRG WR REWDLQ DQ LQVWDQFH RI android.content.res.Resour
cesWKDWGLUHFWO\FRQWDLQVDSSOLFDWLRQUHVRXUFHV 0HWKRGVLQWKHContextFODVVFDQEH
FDOOHGGLUHFWO\EHFDXVH Activity¢DQG ServiceDVZHOO¢H[WHQG Context 'HYHORSHUV
WKHQFDOOPHWKRGVRIWKH ResourcesREMHFWWRREWDLQUHVRXUFHVRIWKHGHVLUHGW\SHDV
IROORZV
// code inside an Activity method
String helloWorld = this.getResources().getString(R.string.hello_world);
int anInt = this.getResources().getInteger(R.integer.an_int);
<RXZLOOVHHWKDWWKHRFODVVLVXELTXLWRXVLQ$QGURLGHQDEOLQJHDV\DFFHVVWRUHVRXUFHV
VXFKDVWKHFRPSRQHQWVLQ8,OD\RXWILOHV
The Android Application Runtime Environment
$QGURLG¦VXQLTXHDSSOLFDWLRQFRPSRQHQWDUFKLWHFWXUHLVLQSDUWDSURGXFWRIWKHZD\
$QGURLGLPSOHPHQWVDPXOWLSURFHVVLQJHQYLURQPHQW,QRUGHUWRPDNHWKDWHQYLURQ
PHQWVXLWDEOHIRUPXOWLSOHDSSOLFDWLRQVIURPPXOWLSOHYHQGRUVZLWKDPLQLPDOUHTXLUH
PHQWWRWUXVWHDFKYHQGRU$QGURLGH[HFXWHVPXOWLSOHLQVWDQFHVRIWKH'DOYLN90RQH
IRUHDFKWDVN,Q£&RPSRQHQW/LIH&\FOHV¤RQSDJHDQGLQODWHUFKDSWHUVZHZLOO
H[SORUHKRZFRPSRQHQWOLIHF\FOHVHQDEOH$QGURLGWRHQKDQFHWKHZD\JDUEDJHFRO
OHFWLRQZRUNVZLWKLQDSSOLFDWLRQKHDSVDQGKRZLWHQDEOHVDPHPRU\UHFRYHU\VWUDWHJ\
DFURVVPXOWLSOHKHDSV
$VDUHVXOWRIWKLVVLPSOHDQGUHOLDEOHDSSURDFKWRPXOWLSURFHVVLQJ$QGURLGPXVWHI
ILFLHQWO\GLYLGHPHPRU\LQWRPXOWLSOHKHDSV(DFKKHDSVKRXOGEHUHODWLYHO\VPDOOVR
WKDW PDQ\ DSSOLFDWLRQV FDQ ILW LQ PHPRU\ DW WKH VDPH WLPH :LWKLQ HDFK KHDS WKH
FRPSRQHQWOLIHF\FOHHQDEOHVFRPSRQHQWVQRWLQXVH¢HVSHFLDOO\FXUUHQWO\LQDFWLYHXVHU
88 | Chapter 3:ಗThe Ingredients of an Android Application
LQWHUIDFH FRPSRQHQWV¢WR EH JDUEDJHFROOHFWHG ZKHQ KHDS VSDFH LV WLJKW DQG WKHQ
UHVWRUHGZKHQQHHGHG7KLVLQWXUQPRWLYDWHVDGDWDEDVHFHQWULFDSSURDFKWRGDWD
PRGHOVZKHUHPRVWGDWDLVLQKHUHQWO\SHUVLVWHQWDWDOOWLPHVVRPHWKLQJ\RXZLOOUHDGD
ORWPRUHDERXWWKURXJKRXWWKLVERRNDQGHVSHFLDOO\LQ&KDSWHU
The Dalvik VM
$QGURLG¦VDSSURDFKWRPXOWLSURFHVVLQJXVLQJPXOWLSOHSURFHVVHVDQGPXOWLSOHLQVWDQ
FHVRID90UHTXLUHVWKDWHDFKLQVWDQFHRIWKH90EHVSDFHHIILFLHQW7KLVLVDFKLHYHG
SDUWO\WKURXJKWKHFRPSRQHQWOLIHF\FOHZKLFKHQDEOHVREMHFWVWREHJDUEDJHFROOHFWHG
DQG UHFUHDWHG DQG SDUWO\ E\ WKH 90 LWVHOI $QGURLG XVHV WKH 'DOYLN 90 WR UXQ D
E\WHFRGHV\VWHPGHYHORSHGVSHFLILFDOO\IRU$QGURLGFDOOHGGH['H[E\WHFRGHVDUHDS
SUR[LPDWHO\WZLFHDVVSDFHHIILFLHQWDV-DYDE\WHFRGHVLQKHUHQWO\KDOYLQJWKHPHPRU\
RYHUKHDG RI -DYD FODVVHV IRU HDFK SURFHVV $QGURLG V\VWHPV DOVR XVH FRS\RQZULWH
PHPRU\ WR VKDUH KHDS PHPRU\ DPRQJ PXOWLSOH LQVWDQFHV RI WKH VDPH 'DOYLN
H[HFXWDEOH
Zygote: Forking a New Process
,WZRXOGDOVREHLQHIILFLHQWIRUHDFKQHZSURFHVVWRORDGDOOWKHQHFHVVDU\EDVHFODVVHV
HDFKWLPHLWVWDUWHGDQHZLQVWDQFHRIWKH906LQFH$QGURLGSXWVHDFKDSSOLFDWLRQLQ
DVHSDUDWHSURFHVVLWFDQWDNHDGYDQWDJHRIWKHIRUNRSHUDWLRQLQWKHXQGHUO\LQJ/LQX[
RSHUDWLQJV\VWHPWRVSDZQQHZSURFHVVHVIURPDWHPSODWHSURFHVVWKDWLVLQWKHRSWLPDO
VWDWHIRUODXQFKLQJDQHZ90LQVWDQFH7KLVWHPSODWHSURFHVVLVFDOOHG=\JRWH,WLVDQ
LQVWDQFHRIWKH'DOYLN90WKDWFRQWDLQVDVHWRISUHORDGHGFODVVHVWKDWDORQJZLWKWKH
UHVWRIWKHVWDWHRIWKH=\JRWHSURFHVVDUHGXSOLFDWHGLQWRFRSLHVRI=\JRWHFUHDWHGE\
IRUNLQJ
Sandboxing: Processes and Users
$QGURLGVHFXULW\UHOLHVKHDYLO\RQVHFXULW\UHVWULFWLRQVDWWKHOHYHORIWKH/LQX[RSHUDWLQJ
V\VWHPVSHFLILFDOO\RQSURFHVVDQGXVHUOHYHOERXQGDULHV6LQFH$QGURLGLVGHVLJQHG
IRUSHUVRQDOGHYLFHV¢WKDWLVGHYLFHVWKDWDUHRZQHGDQGXVHGE\RQHSHUVRQ¢$QGURLG
PDNHVDQLQWHUHVWLQJXVH/LQX[¦VLQKHUHQWPXOWLXVHUVXSSRUW$QGURLGFUHDWHVDQHZ
XVHUIRUHDFKDSSOLFDWLRQYHQGRU7KLVPHDQVHDFKDSSOLFDWLRQUXQVZLWKGLIIHUHQWXVHU
SULYLOHJHV H[FHSWIRUWKRVHVLJQHGE\WKHVDPHYHQGRU )LOHVRZQHGE\RQHDSSOLFDWLRQ
DUHE\GHIDXOWLQDFFHVVLEOHE\RWKHUDSSOLFDWLRQV
7KHHTXLYDOHQWEHKDYLRURQ:LQGRZVZRXOGEHDVWKRXJK\RXZHUHUXQQLQJ\RXUZRUG
SURFHVVRUDV\RXURZQXVHUDQG\RXUZHEEURZVHUDVDFRZRUNHU¦VXVHU<RXZRXOG
KDYH WR ORJ RXW DQG WKHQ VZLWFK XVHUV WR VHH HLWKHU WKH ZRUG SURFHVVRU RU WKH ZHE
EURZVHUEXW\RXZRXOGQRWEHDEOHWRVHHERWKDWRQFH$QGURLGDOORZVDVLQJOHORJJHG
LQSKRQHXVHUWRVHHPXOWLSOHDSSOLFDWLRQVWKDWDUHUXQQLQJDVGLIIHUHQW/LQX[OHYHOXVHUV
The Android Application Runtime Environment | 89
7KHQHWHIIHFWLVLQFUHDVHGVHFXULW\DVDUHVXOWRIHDFKDSSOLFDWLRQUXQQLQJLQLWVRZQ
£VLOR¤
'HVNWRS RSHUDWLQJ V\VWHPV KDYH W\SLFDOO\ QRW WDNHQ DSSOLFDWLRQ VDQGER[LQJ WR WKLV
H[WHQW¢RQFHDQDSSOLFDWLRQLVLQVWDOOHGLWLVWUXVWHGZLWKDOORIDXVHU¦VGDWD$QGURLG¦V
GHVLJQHUVHQYLVLRQHGDZRUOGRIQXPHURXVVPDOODSSOLFDWLRQVIURPQXPHURXVYHQGRUV
ZKR FDQQRW DOO EH YHWWHG IRU WUXVWZRUWKLQHVV +HQFH DSSOLFDWLRQV GRQ¦W KDYH GLUHFW
DFFHVVWRRWKHUDSSOLFDWLRQV¦GDWD
$FRPSOHWHGHVFULSWLRQRI$QGURLGVHFXULW\FDQEHIRXQGLQWKH$QGURLGGRFXPHQWDWLRQ
DWKWWSGHYHORSHUDQGURLGFRPJXLGHWRSLFVVHFXULW\VHFXULW\KWPO
Component Life Cycles
(DUOLHUZHPHQWLRQHGOLIHF\FOHVIRUFRPSRQHQWV)RULQVWDQFH onCreateVWDUWVDQDS
SOLFDWLRQ&RPSRQHQWOLIHF\FOHVKDYHWZRSXUSRVHVWKH\IDFLOLWDWHHIILFLHQWXVHRIHDFK
DSSOLFDWLRQ¦VPHPRU\RUKHDSVSDFHDQGWKH\HQDEOHWKHVWDWHRIHQWLUHSURFHVVHVWR
EHSUHVHUYHGDQGUHVWRUHGVRWKDWWKH$QGURLGV\VWHPFDQUXQPRUHDSSOLFDWLRQVWKDQ
FDQILWLQPHPRU\
The Activity Life Cycle
7KHPRVWFRPSOH[FRPSRQHQWOLIHF\FOHLVWKHDFWLYLW\OLIHF\FOH+HUHZHZLOOGLDJUDP
LWDQGWDNHDORRNDWKRZWKHVHVWDWHWUDQVLWLRQVDUHKDQGOHGLQFRGH,Q)LJXUH\RX
VHHWKHVWDWHVDQGVWDWHWUDQVLWLRQVLQWKHDFWLYLW\OLIHF\FOH7KHNH\HOHPHQWVRIKDQGOLQJ
OLIHF\FOHVWDWHWUDQVLWLRQVDUHVHOHFWLQJZKLFKOLIHF\FOHFDOOEDFNV\RXQHHGWRLPSOHPHQW
DQGNQRZLQJZKHQWKH\DUHFDOOHG
)LJXUH$FWLYLW\OLIHF\FOHVWDWHV
90 | Chapter 3:ಗThe Ingredients of an Android Application
,Q&KDSWHUZHZLOOUHYLVLWWKLVWRSLFLQGHWDLO)RUQRZOHW¦VORRNDWWZRPHWKRGVRI
WKHActivityFODVV7KHUXQWLPHFDOOVWKHILUVWWRZDUQ\RXUDSSOLFDWLRQWRVDYHLWVVWDWH
,WFDOOVWKHVHFRQGWRDOORZDQHZActivityLQVWDQFHWRUHVWRUHWKHVWDWHRIRQHWKDWKDV
EHHQGHVWUR\HG7KHPHWKRGLPSOHPHQWDWLRQVLQWKHIROORZLQJFRGHVQLSSHWVDUHWDNHQ
IURP&KDSWHUZKHUH\RXFDQVHHWKHIXOOSURJUDPOLVWLQJLQFOXGLQJWKHPHPEHU
YDULDEOHVWRZKLFKWKHFRGHUHIHUV
@Override
protected void onSaveInstanceState(Bundle outState) {
// Save instance-specific state
outState.putString("answer", state);
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState");
}
7KHUXQWLPHFDOOVonSaveInstanceStatePHWKRGZKHQLWGHWHUPLQHVWKDWLWPLJKWKDYH
WRGHVWUR\WKHDFWLYLW\EXWZDQWVWREHDEOHWRUHVWRUHLWODWHU7KDW¦VDQLPSRUWDQW
GLVWLQFWLRQ IURP RWKHU OLIH F\FOH PHWKRGV WKDW DUH FDOOHG RQ VWDWH WUDQVLWLRQV ,I IRU
H[DPSOHDQDFWLYLW\LVH[SOLFLWO\HQGLQJWKHUHLVQRQHHGWRUHVWRUHVWDWHHYHQWKRXJK
LWZLOOSDVVWKURXJKWKHSDXVHGVWDWHDQGKDYHLWVonPausePHWKRGFDOOHG$VWKHSUHYLRXV
FRGHVQLSSHWVKRZVWKHZRUN\RXQHHGWRGRLQ\RXUonSaveInstanceStatePHWKRGLV
WRVDYHDQ\VWDWHWKDWZLOOOHWWKHXVHUFRQWLQXHXVLQJWKHDSSOLFDWLRQODWHUKRSHIXOO\
QRWHYHQDZDUHWKDWLWPLJKWKDYHEHHQGHVWUR\HGDQGUHVWRUHGVLQFHWKHSUHYLRXVXVH
@Override
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
// Restore state; we know savedState is not null
String answer = savedState.getString("answer");
// ...
Log.i(TAG, "onRestoreInstanceState"
+ (null == savedState ? "" : RESTORE) + " " + answer);
}
7KH onRestoreInstanceStatePHWKRGLVFDOOHGZKHQDQDFWLYLW\WKDWZDVGHVWUR\HGLV
EHLQJUHFUHDWHG$QHZLQVWDQFHRI\RXUDSSOLFDWLRQ¦V ActivityLVWKHUHIRUHUXQQLQJ
7KHGDWD\RXVWRUHGLQWKHSUHYLRXVLQVWDQFHRIWKHDFWLYLW\WKURXJKonSaveInstanceS
tateLVSDVVHGWRWKHQHZLQVWDQFHYLDWKHonRestoreInstanceStatePHWKRG
<RXPLJKWWKLQNWKDWZLWKVXFKDFRPSOH[OLIHF\FOHDQGVWULQJHQWUHTXLUHPHQWVWR
DGKHUHWRKHDSXWLOL]DWLRQOLPLWDWLRQVWKH$QGURLGDFWLYLW\OLIHF\FOHZRXOGEHUHDGLO\
DSSDUHQWLQ$QGURLGDSSOLFDWLRQFRGHDQGWKDW\RXZLOOVSHQGDORWRIWLPHDQGHIIRUW
FDWHULQJWRDFWLYLW\OLIHF\FOHUHTXLUHPHQWV<HWWKLVLVQRWWKHFDVH
,QDORWRI$QGURLGFRGHHVSHFLDOO\LQVPDOOH[DPSOHVYHU\IHZOLIHF\FOHFDOOEDFNVDUH
LPSOHPHQWHG7KDWLVEHFDXVHWKHActivitySDUHQWFODVVKDQGOHVOLIHF\FOHFDOOEDFNVWKH
ViewFODVVDQGWKHFKLOGUHQRIWKH ViewFODVVDQGDOVRVDYHVWKHLUVWDWHDVVKRZQLQ
)LJXUH7KLVPHDQVWKDWLQPDQ\VLWXDWLRQVWKH$QGURLGViewFODVVHVSURYLGHDOOWKH
QHFHVVDU\XVHULQWHUIDFHIXQFWLRQDOLW\DQGWKDW$QGURLGDSSOLFDWLRQVGRQRWQHHGWR
H[SOLFLWO\KDQGOHPRVWOLIHF\FOHFDOOEDFNV
Component Life Cycles | 91
)LJXUH6DYLQJWKHVWDWHRIWKHXVHULQWHUIDFH
7KLVLVHVVHQWLDOO\JRRGEHFDXVHLWPDNHV$QGURLGSURJUDPPLQJDORWPRUHFRQYHQLHQW
$OORIZKDW\RXVHHGLDJUDPPHGLQ)LJXUHKDSSHQVZLWKRXW\RXZULWLQJDQ\FRGH
%XWLWKDVDEDGVLGHWRREHFDXVHLWOHDGVSURJUDPPHUVGRZQWKHSDWKRILJQRULQJWKH
DFWLYLW\OLIHF\FOHXQWLOWKH\KDYHFRGHGWKHPVHOYHVLQWRDEXJJ\PHVV7KLVLVZK\ZH
HPSKDVL]HXQGHUVWDQGLQJOLIHF\FOHVKHUHDQGZK\LQ&KDSWHUZHVKRZKRZWR
KDQGOHDOOOLIHF\FOHFDOOEDFNVDQGORJWKHP6WDUWLQJZLWKFRPSOHWHDZDUHQHVVRIWKH
DFWLYLW\OLIHF\FOHLVSUREDEO\WKHPRVWLPSRUWDQWWKLQJ\RXFDQGRWRSUHYHQWEXJVWKDW
DUHGLIILFXOWWRGLDJQRVH
Packaging an Android Application: The .apk File
$QGURLGSURYLGHVDQDSSOLFDWLRQFDOOHG apkbuilderIRUJHQHUDWLQJLQVWDOODEOH$QGURLG
DSSOLFDWLRQILOHVZKLFKKDYHWKHH[WHQVLRQDSN$QDSNILOHLVLQ=,3ILOHIRUPDWMXVW
OLNHPDQ\RWKHU-DYDRULHQWHGDSSOLFDWLRQIRUPDWVDQGFRQWDLQVWKHDSSOLFDWLRQPDQ
LIHVWFRPSLOHGDSSOLFDWLRQFODVVHVDQGDSSOLFDWLRQUHVRXUFHV$QGURLGSURYLGHVWKH
XWLOLW\ aaptIRUSDFNDJLQJWKHILOHVWKDWPDNHXSDQDSNILOHEXWGHYHORSHUVW\SLFDOO\
SUHIHUWRDOORZWKHLUGHYHORSPHQWHQYLURQPHQWWRXVHWKLVXWLOLW\WREXLOGWKHLUDSSOL
FDWLRQVIRUWKHP0RVWXVHUVVLPSO\UHO\RQWKHLU,'(WREXLOGWKHLUDSN
2QFHDGHYHORSHUKDVFUHDWHGDQDSNILOHKHFDQFKRRVHWRPDNHLWDYDLODEOHIRULQ
VWDOODWLRQRQWRDGHYLFHLQRQHRIVHYHUDOZD\V
‡ 8VLQJWKHDGELQWHUIDFHGLUHFWRU\RUPRUHFRPPRQO\E\XVLQJDQ,'(
‡ 8VLQJDQ6'FDUG
92 | Chapter 3:ಗThe Ingredients of an Android Application
Download from Wow! eBook <www.wowebook.com>
‡ 0DNLQJWKHILOHDYDLODEOHRQDZHEVHUYHU
‡ 8SORDGLQJWKHILOHWRWKH$QGURLG0DUNHWDQGWKHQVHOHFWLQJ,QVWDOO
On Porting Software to Android
,QWKLVFKDSWHU\RXOHDUQHGWKDW$QGURLGKDVDQDSSOLFDWLRQDUFKLWHFWXUHUDGLFDOO\GLI
IHUHQWIURPWKHW\SLFDOGHVNWRSDSSOLFDWLRQDUFKLWHFWXUHDQGHYHQTXLWHGLIIHUHQWIURP
PRVWRWKHUV\VWHPVRQVPDOOGHYLFHVLQFOXGLQJWKHL26RSHUDWLQJV\VWHPXVHGLQWKH
L3KRQHL3RG7RXFKDQGL3DG,I\RXDWWHPSWWRSRUWVRIWZDUHE\VXEYHUWLQJWKH$Q
GURLGDSSOLFDWLRQDUFKLWHFWXUHDQGIRUFHILWWLQJDFRQYHQWLRQDODSSOLFDWLRQDUFKLWHFWXUH
LQWRDQ$QGURLGDSSOLFDWLRQLQRUGHUWRIDFLOLWDWHDPHWKRGE\PHWKRGWUDQVOLWHUDWLRQ
IURP2EMHFWLYH&&RU&RGGVDUHWKHHIIRUWZLOOFRPHWRJULHI
,I\RXZDQWWRSRUWH[LVWLQJVRIWZDUHWR$QGURLGILUVWWDNHLWDSDUWWKHGDWDPRGHOWKH
XVHU LQWHUIDFH DQG PDMRU QRQLQWHUDFWLYH PRGXOHV DQG OLEUDULHV VKRXOG EH SRUWHG RU
UHLPSOHPHQWHGLQWKH$QGURLGDSSOLFDWLRQPRGHOGHSHQGLQJRQKRZWKH\ILW$QGURLG
GRHVKDYHVLPLODULWLHVWRRWKHUPRGHUQPDQDJHGDSSOLFDWLRQUXQWLPHHQYLURQPHQWVDQG
ODQJXDJHV\VWHPV2QFH\RXXQGHUVWDQG$QGURLGLQJUHDWHUGHSWK\RXZLOOEHHTXLSSHG
WRVHHDUFKLWHFWXUDODQDORJLHVZLWKRWKHUSODWIRUPVDQGPDNHEHWWHULPSOHPHQWDWLRQ
FKRLFHVZKHQSRUWLQJ
On Porting Software to Android | 93
CHAPTER 4
Getting Your Application into
Users’ Hands
7KLVFKDSWHUFRYHUVHYHU\WKLQJLWWDNHVWRJHW\RXUDSSOLFDWLRQLQWRXVHUV¦KDQGV(DUOLHU
LQWKLVERRNZHWROG\RXHYHU\WKLQJ\RXQHHGHGWRJHWVWDUWHGUHDGLQJH[DPSOHFRGH
DQGFUHDWLQJVLPSOHSURJUDPV+HUHZHFRPSOHWHWKHSLFWXUHZLWKDOOWKHRWKHURSHU
DWLRQV\RXQHHGWRSHUIRUPWRZLGHO\GLVWULEXWH\RXUDSSOLFDWLRQVVHOOWKHP LIWKDWLV
\RXUDLP DQGVXEVHTXHQWO\JHWSDLGE\*RRJOHZKLFKRSHUDWHVWKH$QGURLG0DUNHW
<RXPD\QRWEHUHDG\WRSXW\RXUDSSOLFDWLRQLQWRWKH$QGURLG0DUNHWEXWNHHSLQJ
WKLVSURFHVVLQPLQGZLOOVKDSHWKHZD\\RXGHVLJQDQGLPSOHPHQW\RXUDSSOLFDWLRQ
&RPPHUFHKDVFRQVLGHUDWLRQVWKDWDUHGLVWLQFWIURPPRVWRWKHUDVSHFWVRIVRIWZDUH
GHYHORSPHQWLQFOXGLQJLGHQWLI\LQJ\RXUVHOIWRWKH$QGURLG0DUNHWDQGWR\RXUFXV
WRPHUVREWDLQLQJSHUPLVVLRQWRXVHFHUWDLQ$3,VSURWHFWLQJ\RXULGHQWLW\DQGSUH
SDULQJ\RXUDSSWREHUXQRQDYDULHW\RIKDUGZDUHDVZHOODVEHLQJXSGDWHGRYHUWLPH
Application Signing
$SSOLFDWLRQVLJQLQJRUFRGHVLJQLQJHQDEOHV$QGURLGGHYLFHVWKH$QGURLG0DUNHW
DQGDOWHUQDWLYHPHDQVRIGLVWULEXWLRQWRNQRZZKLFKDSSOLFDWLRQVRULJLQDWHZLWKWKH
RZQHURIDVLJQLQJFHUWLILFDWHDQGWREHFHUWDLQWKHFRGHKDVQRWEHHQPRGLILHGVLQFH
LWZDVVLJQHG
Public Key Encryption and Cryptographic Signing
3XEOLFNH\FU\SWRJUDSK\GHSHQGVRQWKLVPDWKHPDWLFDOSULQFLSOHLWLVHDV\WRPXOWLSO\
ODUJHSULPHQXPEHUVWRJHWKHUEXWLWLVH[WUHPHO\GLIILFXOWWRIDFWRUWKHSURGXFWRIODUJH
SULPHV7KHPXOWLSOLFDWLRQPLJKWWDNHPLOOLVHFRQGVZKLOHIDFWRULQJZRXOGWDNHKXQ
GUHGVWRPLOOLRQVRI\HDUVDQGZRXOGUHTXLUHDQDVWURQRPLFDOO\ODUJHFRPSXWHU
7KLVDV\PPHWU\EHWZHHQPXOWLSOLFDWLRQDQGIDFWRULQJPHDQVWKDWDNH\PDGHZLWKWKH
SURGXFWRIWZRODUJHSULPHQXPEHUVFDQEHPDGHSXEOLF7KHNQRZOHGJHWKDWHQDEOHV
95
HQFU\SWHGPHVVDJHVWREHGHFU\SWHGLVWKHSDLURIODUJHSULPHVWKDWDUHSDUWRIWKHSULYDWH
NH\7KDWPHDQVWKDWGRFXPHQWVHQFU\SWHGZLWKWKHSXEOLFNH\DUHVHFXUHDQGRQO\
WKHSRVVHVVRURIWKHSULYDWHNH\FDQGHFU\SWWKHP
6LJQLQJZKLFKLVZKDWZHZLOOGRWR$QGURLGDSSOLFDWLRQVGHSHQGVRQUHODWHGSURS
HUWLHVRISXEOLFNH\HQFU\SWLRQ
7KHVWHSVWRVLJQDGRFXPHQWDUH
&RPSXWHDXQLTXHQXPEHU¢DKDVK¢IURPWKHGRFXPHQW7KLVLVDOVRNQRZQDV
DPHVVDJHGLJHVW
£(QFU\SW¤WKHPHVVDJHGLJHVWZLWKWKHVLJQHU¦VSULYDWHNH\7KLVLVWKHVLJQDWXUH
9RLOj <RX QRZ KDYH D QXPEHU¢D VLJQDWXUH¢WKDW LV WLHG WR WKH GRFXPHQW E\ WKH
KDVKLQJDOJRULWKPDQGWLHGWRWKHVLJQHU¦VSULYDWHNH\
7KHVWHSVWRYHULI\DVLJQHGGRFXPHQWDUH
&RPSXWHDXQLTXHQXPEHU¢DKDVK¢IURPWKHGRFXPHQW
£'HFU\SW¤WKHVLJQDWXUHXVLQJWKHSXEOLFNH\ZKLFKVKRXOGDOVRUHVXOWLQWKHVDPH
QXPEHUDVWKHKDVK
1RZ\RXNQRZVRPHLQWHUHVWLQJIDFWVWKHGRFXPHQW¢LQRXUFDVHDQDSSOLFDWLRQ¢
FDPHIURPWKHSHUVRQZLWKWKHSULYDWHNH\FRUUHVSRQGLQJWRWKHSXEOLFNH\\RXXVHG
LQWKHYHULILFDWLRQ$QG\RXNQRZWKDWWKHGRFXPHQWZDVQRWDOWHUHGRWKHUZLVHWKH
KDVKGHFU\SWHGIURPWKHVLJQDWXUHZRXOGQRWEHWKHVDPHDVWKHRQHFRPSXWHGIURP
WKHGRFXPHQW
9HULI\LQJDVLJQDWXUHDOVRYHULILHVWKDWWKHVLJQDWXUHZDVQRWFRSLHGWRDGLIIHUHQWGRFX
PHQW6LJQDWXUHVDUHXQDOWHUDEO\WLHGWRWKHGRFXPHQWIURPZKLFKWKH\ZHUHFUHDWHG
<RXPD\KDYHQRWLFHGZHSXWWKHZRUGVHQFU\SWDQGGHFU\SWLQTXRWHV
ZKHQZHVDLGWKHPHVVDJHGLJHVWRUKDVKLVHQFU\SWHG7KLVLVEHFDXVH
LW¦V QRW HQFU\SWLRQ LQ WKH ZD\ \RX QRUPDOO\ XVH D SXEOLFSULYDWH NH\
V\VWHP¢WRNHHSSU\LQJH\HVDZD\IURPDPHVVDJHE\HQFU\SWLQJLWZLWK
WKHSXEOLFNH\VRWKDWRQO\WKHSHUVRQZLWKWKHSULYDWHNH\FDQUHDGWKH
PHVVDJH
+HUH£HQFU\SW¤MXVWPHDQV£FRPSXWHDQXPEHU¤<RXDUHQRWKLGLQJ
LQIRUPDWLRQZKHQ\RX£HQFU\SW¤DKDVKRUPHVVDJHGLJHVWZLWKDVLJQHU¦V
SULYDWHNH\7KHUHDVRQ\RXXVHWKHZRUGVHQFU\SWDQGGHFU\SWLVWKDW
\RXJHWWKHVDPHKDVKRUPHVVDJHGLJHVWZKHQ\RXGHFU\SWZLWKWKH
SXEOLFNH\
$Q\RQHZLWKWKHSXEOLFNH\DQGDSXEOLVKHGDOJRULWKPFDQ£GHFU\SW¤¢
ZKLFKLVWKHSRLQWLQYHULILFDWLRQWRVHHWKDW\RXJRWWKHVDPHKDVKWKH
VHQGHUVLJQHGZKLFKDOVRSURYHVWKDWWKHVHQGHULVLQSRVVHVVLRQRID
SULYDWHNH\FRUUHVSRQGLQJWRWKHSXEOLFNH\DQGSURYHVWKDWWKHGRFX
PHQWLVZKDWWKHVHQGHUVLJQHG
96 | Chapter 4:ಗGetting Your Application into Users’ Hands
%HFDXVHYHULILFDWLRQFDQEHFRPSXWHGXVLQJDSXEOLFNH\\RXU$QGURLGV\VWHP¢DQG
DQ\RWKHULQWHUHVWHGSDUW\¢FDQYHULI\WKDWDQDSSOLFDWLRQZDVVLJQHGZLWKDSDUWLFXODU
NH\DQGWKDWLWZDVQRWPRGLILHGVLQFHLWZDVVLJQHG
0RUHJHQHUDOO\DQ\HOHFWURQLFGRFXPHQW¢DQ\VHWRIELWV¢FDQEHFU\SWRJUDSKLFDOO\
VLJQHGDQGFU\SWRJUDSKLFVLJQDWXUHVRU£GLJLWDOVLJQDWXUHV¤FDQEHXVHGWRVLJQGRFX
PHQWVLQDZD\WKDWFDQOHJDOO\VXEVWLWXWHIRUDSHUVRQ¦VKDQGZULWWHQVLJQDWXUH
How Signatures Protect Software Users, Publishers, and
Secure Communications
$VDXVHURIFRPSXWHUVRIWZDUH\RXPD\DOUHDG\KDYHEHHQWKLQNLQJ£,WZRXOGEHQLFH
WRNQRZZKHUHP\VRIWZDUHFRPHVIURPDQGWKDWLWKDVQRWEHHQPRGLILHGHQURXWHWR
P\GHYLFH¤6LJQHGDSSOLFDWLRQVHQDEOH\RXWRKDYHWKLVFRQILGHQFH7KLVLVDIRUPRI
FRQILGHQFHEDVHGRQFU\SWRJUDSKLFVLJQDWXUHVVLPLODUWRRQH\RXDOUHDG\XVH:KHQ
\RX EURZVH WKH :HE \RX DOUHDG\ UHO\ RQ FU\SWRJUDSKLF VLJQDWXUHV WR WUXVW WKDW WKH
HFRPPHUFHVLWH\RXDUHFRPPXQLFDWLQJZLWKLVDXWKHQWLFDQGQRWDURJXHLPSRVWRU
VHW XS WR WDNH \RXU PRQH\ DQG UXQ ,Q WKH FDVH RI HFRPPHUFH WKH FOLHQW YHULILHV D
VLJQDWXUHRIWKHVHUYHU¦VFHUWLILFDWHXVLQJDSXEOLFNH\IURPDFHUWLILFDWHDXWKRULW\<RXU
EURZVHUFRPHVZLWKNH\VIURPVHYHUDOFHUWLILFDWHDXWKRULWLHVXVHGIRUWKLVSXUSRVH
7KHUROHRIWKHFHUWLILFDWHDXWKRULW\LVWRFRQVROLGDWHWKHQXPEHURISDUWLHV\RXQHHGWR
WUXVW\RXWUXVW\RXUEURZVHUYHQGRUWRXVHRQO\NH\VIURPUHSXWDEOHFHUWLILFDWHDX
WKRULWLHVDQGHFRPPHUFHYHQGRUVREWDLQFHUWLILFDWHVIURPDXWKRULWLHVEURZVHUYHQGRUV
WUXVW7KHFHUWLILFDWHDXWKRULWLHVKDYHDUHVSRQVLELOLW\WRYHULI\WKDWWKHSHRSOHFODLPLQJ
WREHIRUH[DPSOH$PD]RQFRPDUHLQIDFW$PD]RQFRP1RZZKHQ\RXUEURZVHU
LQLWLDWHVDVHFXUHVHVVLRQZLWK$PD]RQFRP\RXNQRZWZRWKLQJV\RXUGDWDLVVHFXUHG
IURPHDYHVGURSSLQJE\HQFU\SWLRQWKDWRQO\WKHHFRPPHUFHYHQGRU¦VVHUYHUFDQGH
FU\SW DQG \RX DUH UHDVRQDEO\ VXUH WKDW WKH VHUYHU \RX DUH FRQQHFWLQJ WR LV XVLQJ D
FHUWLILFDWHLVVXHGE\DFHUWLILFDWHDXWKRULW\WRWKHFRPSDQ\\RXZDQWWRFRPPXQLFDWH
ZLWKEHFDXVHWKHFHUWLILFDWHDXWKRULW\KDVWDNHQVWHSVWRDVVXUHLWVHOIWKDWLWLVVXHVFHU
WLILFDWHVWRNQRZQSDUWLHV
Self-signed certificates for Android software
,QVLJQLQJ$QGURLGVRIWZDUHWKHVLJQLQJFHUWLILFDWHGRHVQRWKDYHWRFRPHIURPDFHU
WLILFDWHDXWKRULW\,WFDQEHFUHDWHGE\WKHVRIWZDUHSXEOLVKHU¢LQWKLVFDVH\RX8QOLNH
HFRPPHUFHWUDQVDFWLRQVZKHUH\RXKDYHWKHDGGLWLRQDOUHTXLUHPHQWWKDW\RXZDQWWR
HQVXUHWKDWHDFKDQGHYHU\FRQQHFWLRQ\RXUEURZVHUPDNHVLVWRWKHDXWKHQWLF$PD
]RQFRPSHUKDSVWKURXJKDOLQNRIXQNQRZQSURYHQDQFHWKHDFWRIXVLQJVRIWZDUH
GRHVQRWGHSHQGDVFULWLFDOO\RQNQRZLQJWKHLGHQWLW\RIWKHVLJQLQJSDUW\
)RURUJDQL]DWLRQVFRQVLGHULQJXVLQJDVLJQDWXUHLVVXHGE\DFHUWLILFDWHDXWKRULW\WKH
*RRJOH GRFXPHQWDWLRQ H[SOLFLWO\ PHQWLRQV WKDW WKHUH LV QR QHHG WR KDYH \RXU
Application Signing | 97
DSSOLFDWLRQVLJQHGXVLQJDFHUWLILFDWHDXWKRULW\DQGWKDWVHOIFHUWLILFDWLRQLVWKHLQIRUPDO
VWDQGDUGIRU$QGURLGDSSOLFDWLRQV
,QDGGLWLRQWRLQLWLDOO\YHULI\LQJDSSOLFDWLRQGHYHORSHULGHQWLW\GLJLWDOVLJQDWXUHVRQ
$QGURLGDUHDOVRXVHGGXULQJDSSOLFDWLRQXSJUDGHVWRHQVXUHWKDWDQDSSOLFDWLRQXS
JUDGHVKRXOGEHSHUPLWWHGWRDFFHVVILOHVFUHDWHGE\DQHDUOLHUYHUVLRQRIWKHDSSOLFDWLRQ
DQGWKDWWKHXSJUDGLQJDSSOLFDWLRQLVQRWDFWXDOO\DPDOLFLRXVDSSOLFDWLRQWU\LQJWRVWHDO
XVHUGDWD
$VORQJDV\RXDUHFRQILGHQWWKDWXSGDWHVWRWKHVRIWZDUHFRPHIURPWKHVDPHSDUW\
\RXREWDLQHGWKHVRIWZDUHIURPLQWKHILUVWSODFH\RXFDQEHUHDVRQDEO\VXUHWKHSUR
JUDPV\RXDUHXVLQJDUHVDIHDQGWKDWWKHSXEOLVKHURIWKDWVRIWZDUHLVNQRZQWRWKH
GLVWULEXWRURIWKHVRIWZDUHZKLFKLVWKH$QGURLG0DUNHW
,QDGGLWLRQWRWKHDVVXUDQFHRIXSGDWHVIURPWKHRULJLQDOSXEOLVKHU$QGURLGDSSOLFD
WLRQVDUHVDQGER[HGDQGUHTXLUHSHUPLVVLRQVDVGHVFULEHGDWKWWSGHYHORSHUDQGURLG
FRPJXLGHWRSLFVVHFXULW\VHFXULW\KWPOWRDFFHVVIXQFWLRQDOLW\WKDWFRXOGFRPSURPLVH
\RXUGDWDRUFDXVHFKDUJHDEOHHYHQWVRQ\RXUPRELOHVHUYLFH
Signing an Application
7KHFRQFHSWVEHKLQGFU\SWRJUDSKLFVLJQLQJDUHVXEWOHDQGFRPSOH[%XWWKHFRPSOH[LW\
LVPDQDJHGE\WKH6'.WRROV:KHQ\RXFRPSLOHDQGUXQ$QGURLGFRGHRQDGHYLFHRU
RQDQHPXODWRU\RXDUHUXQQLQJVLJQHGFRGH
Debug certificates
,I\RXKDYHEHHQIROORZLQJWKHH[DPSOHVLQWKLVERRNDQGKDYHFUHDWHGDQ$QGURLG
SURMHFWDQGUXQLWLQDQHPXODWRURUGHYLFH\RXPD\KDYHQRWLFHG\RXGLGQ¦WQHHGWR
FUHDWHDFHUWLILFDWHDQGWKDW\RXUDSSOLFDWLRQLVLQVWDOODEOHRQDQ$QGURLGKDQGVHWGH
VSLWH WKH IDFW WKDW DOO $QGURLG FRGH PXVW EH VLJQHG 7KLV FRQYHQLHQFH LV DFKLHYHG
WKURXJKWKHXVHRIDQDXWRPDWLFDOO\FUHDWHGGHEXJFHUWLILFDWH/HW¦VWDNHDORRNDWWKH
GHEXJFHUWLILFDWH
/RRNLQWKHDQGURLGIROGHULQ\RXUKRPHIROGHU7KHUH\RXZLOOILQGDILOHQDPHGGH
EXJNH\VWRUH8VLQJWKHkeytoolFRPPDQG\RXFDQILQGRXWZKDWLVLQVLGHWKLVILOH
keytool -list -keystore debug.keystore
:KHQ\RXDUHSURPSWHGIRUDSDVVZRUGHQWHUandroid<RXZLOOVHHRXWSXWWKDWORRNV
OLNHWKLV
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
androiddebugkey, May 13, 2010, PrivateKeyEntry,
Certificate fingerprint (MD5): 95:04:04:F4:51:0B:98:46:14:74:58:15:D3:CA:73:CE
98 | Chapter 4:ಗGetting Your Application into Users’ Hands
7KHNH\VWRUHW\SHDQGSURYLGHULQGLFDWHWKHNH\VWRUHLVD-DYDNH\VWRUHFRPSDWLEOHZLWK
WKH-DYD&U\SWRJUDSK\$UFKLWHFWXUHDQG-DYDFODVVHVWKDWHQDEOH$QGURLGWRXVHFRGH
VLJQLQJ DQG RWKHU FU\SWRJUDSK\ WRROV 0RUH LQIRUPDWLRQ RQ WKH -DYD &U\SWRJUDSK\
$UFKLWHFWXUHLVDYDLODEOHDWKWWSGRZQORDGRUDFOHFRPMDYDVHGRFVWHFKQRWHVWRROVVR
ODULVNH\WRROKWPO
7KH keytool FRPPDQG LV SDUW RI WKH -'. DQG LV GHVFULEHG EULHIO\ LQ £NH\
WRRO¤RQSDJHDQGLQJUHDWHUGHWDLODWKWWSGHYHORSHUDQGURLGFRPJXLGHSXEOLVKLQJ
DSSVLJQLQJKWPOFHUW'HWDLOHGGRFXPHQWDWLRQRQkeytoolFDQDOVREHIRXQGDWKWWS
GRZQORDGRUDFOHFRPMDYDVHGRFVWHFKQRWHVWRROVVRODULVNH\WRROKWPO
7KHODVWOLQHSURGXFHGE\WKHlistRSWLRQLQkeytoolLVDFHUWLILFDWHILQJHUSULQW7KLVLV
DXQLTXHQXPEHUJHQHUDWHGIURPDNH\<RXZLOOVHHRQHZD\LQZKLFKWKLVQXPEHULV
XVHGLQ£*RRJOH0DSV$3,.H\V¤RQSDJHZKHUH\RXZLOOXVHLWWRJHWDQ$3,NH\
7KLVFHUWLILFDWHH[SLUHVLQDVKRUWHQRXJKLQWHUYDOWKDWLWFDQQRWEHXVHGWRGLVWULEXWH
$QGURLGVRIWZDUHRWKHUWKDQIRUWHVWLQJ'RQRWPLVWDNHWKHFRQYHQLHQFHRIXVLQJD
GHEXJFHUWLILFDWHIRUVLJQLQJVRIWZDUHDVDQLQGLFDWLRQWKDW\RXFDQGRZLWKRXWDVLJQLQJ
FHUWLILFDWHIRUGLVWULEXWLQJ\RXUDSSOLFDWLRQV
Creating a self-signed certificate
5HDG\WRVLJQVRPHFRGHIRUUHOHDVH")LUVWFUHDWHDSULYDWHNH\XVLQJWKHkeytoolFRP
PDQGWKXVO\
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name \
-keyalg RSA -keysize 2048 -validity 50000
7KH \FKDUDFWHULQGLFDWHVDOLQHEUHDNDQGLVYDOLGIRUPXOWLOLQHFRP
PDQGVRQ8QL[DQG0DF26;+RZHYHU\RXZLOOQHHGWRW\SHWKLVDOO
RQRQHOLQHZLWKRXWWKH\RQ:LQGRZV
<RXFDQVXEVWLWXWHDQDPHRI\RXUFKRLFHIRUmy-release-keyDQGDQDOLDVRI\RXUFKRLFH
IRUalias_name7KH-keysizeDQG-validitySDUDPHWHUVVKRXOGUHPDLQDVVKRZQLQWKH
SUHFHGLQJFRGH
$VVKRZQLQWKHIROORZLQJFRGHkeytoolZLOODVN\RXIRUDSDVVZRUGIRUWKHNH\VWRUH
ZKLFK\RXZLOOQHHGWRUHPHPEHUZKHQDFFHVVLQJLWDQGDVHULHVRITXHVWLRQVDERXW
\RX \RXU RUJDQL]DWLRQDO VWUXFWXUH DQG \RXU ORFDWLRQ keytool JHQHUDWHV D SULYDWH
NH\XVDEOHDVDVLJQLQJFHUWLILFDWHZLWKDYDOLGOLIHVSDQRIDERXW\HDUVDQGSXWVLW
LQWKHILOHQDPHGmy-release_keyNH\VWRUH
example-user@default-hostname:~$ keytool -genkey -v \
-keystore example-release-key.keystore -alias example_alias_name \
-keyalg RSA -keysize 2048 -validity 50000
Enter keystore password:
Re-enter new password:
What is your first and last name?
Application Signing | 99
[Unknown]: Example Examplenik
What is the name of your organizational unit?
[Unknown]: Example
What is the name of your organization?
[Unknown]: Example
What is the name of your City or Locality?
[Unknown]: Example
What is the name of your State or Province?
[Unknown]: Massachusetts
What is the two-letter country code for this unit?
[Unknown]: US
Is CN=Example Examplenik, OU=Example, O=Example, L=Example, ST=Massachusetts,
C=US correct?
[no]: yes
Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a
validity of 50,000 days for: CN=Example Examplenik, OU=Example, O=Example,
L=Example, ST=Massachusetts, C=US
Enter key password for <example_alias_name>
(RETURN if same as keystore password):
Re-enter new password:
[Storing example-release-key.keystore]
<RXQRZKDYHDYDOLGNH\LQDNH\VWRUH
Don’t lose it!
:KLOHFU\SWRJUDSKLFGLJLWDOVLJQDWXUHVDUHLQPDQ\ZD\VPRUHUHOLDEOHDQGVHFXUHWKDQ
DKDQGZULWWHQVLJQDWXUHWKHUHLVRQHZD\LQZKLFKWKH\GLIIHU\RXFDQORVH\RXUDELOLW\
WRVLJQDGRFXPHQWGLJLWDOO\
,I\RXORVH\RXUVLJQLQJFHUWLILFDWH\RXORVH\RXULGHQWLW\WR$QGURLGGHYLFHVDQGWKH
$QGURLG0DUNHW7KLVPHDQVWKDWGHVSLWHWKHIDFWWKDW\RXFRPSLOHDQGUHOHDVHWKH
VDPHFRGHDVEHIRUH\RXFDQQRWXVHWKHVHQHZO\FRPSLOHGDSSOLFDWLRQVWRXSGDWHDS
SOLFDWLRQVLQWKHILHOGVLQFHQHLWKHU$QGURLGGHYLFHVQRUWKH$QGURLG0DUNHWZLOOUHF
RJQL]H\RXDVWKHVDPHSXEOLVKHU
.HHSPXOWLSOHEDFNXSFRSLHVRI\RXUVLJQLQJFHUWLILFDWHRQPXOWLSOHW\SHVRIPHGLD
LQFOXGLQJSDSHULQPXOWLSOHORFDWLRQV$QGNHHSWKRVHEDFNXSVVHFXUH,I\RXUVLJQLQJ
FHUWLILFDWHLVXVHGE\SHRSOHRWKHUWKDQ\RXWKH\FDQUHSODFH\RXUSURJUDPVRQ\RXU
FXVWRPHUV¦$QGURLGGHYLFHV
'HWDLOHGUHFRPPHQGDWLRQVIURPWKH$QGURLG'HYHORSHUVVLWHUHJDUGLQJVHFXULQJ\RXU
VLJQLQJ FHUWLILFDWH DUH DYDLODEOH DW KWWSGHYHORSHUDQGURLGFRPJXLGHSXEOLVKLQJDSS
VLJQLQJKWPOVHFXUHNH\
&RQYHUVHO\\RXUFU\SWRJUDSKLFVLJQDWXUHLV\RXUVLJQDWXUHVROHO\EH
FDXVHLWLVLQ\RXUSRVVHVVLRQ8SWRWKHWLPH\RXZDQWWRSXEOLVKDQ
$QGURLGDSSOLFDWLRQDQGFRQWLQXHWREHLGHQWLILHGDVWKHSXEOLVKHU\RX
FDQJHQHUDWHXVHDQGGLVFDUGVLJQDWXUHVDVPXFKDV\RXOLNH'RQ¦WEH
DIUDLGWRH[SHULPHQWDQGOHDUQ
100 | Chapter 4:ಗGetting Your Application into Users’ Hands
Using a self-signed certificate to sign an application
1RZLW¦VWLPHWRVLJQDQDSSOLFDWLRQ,Q(FOLSVHVHOHFWWKHSURMHFWRIWKHDSSOLFDWLRQ
\RXZDQWWRVLJQIRUUHOHDVHDQGVHOHFWWKH)LOHൺ([SRUWFRPPDQG£:K\WKH¥H[SRUW¦
FRPPDQG"¤\RXPD\DVN$IWHUDOOLI\RXZDQWWRJLYHVRPHRQH\RXUDSSWRWU\RXW
\RXFDQMXVWJLYHKHUDFRS\RIWKHDSNILOHLQWKHELQGLUHFWRU\RIWKHSURMHFWILOHKLHU
DUFK\,WLVDVDUELWUDU\DVLWVHHPVWKH£H[SRUW¤GLDORJLVDJUDEEDJRIIXQFWLRQDOLW\
DQGLWZDVDFRQYHQLHQWSODFHWRSXWDSURFHGXUHWKDWLVQ¦WTXLWHWKHVDPHDV£GHSOR\LQJ¤
,QWKLVH[DPSOHZHXVHWKH7HVW$FWLYLW\SURMHFWEXW\RXFDQXVHDQ\DSSOLFDWLRQ¢\RXU
RZQRUDQ\SURMHFWIURPWKHH[DPSOHVLQWKLVERRN
<RXZLOOEHSUHVHQWHGZLWKDOLVWRIRSWLRQVIRUH[SRUWLQJRUJDQL]HGLQWRIROGHUV6HOHFW
WKH$QGURLGIROGHUDQGVHOHFW([SRUW$QGURLG$SSOLFDWLRQ DVVKRZQLQ)LJXUH DQGFOLFNRQWKH1H[WEXWWRQ
)LJXUH£([SRUWLQJ¤DQ$QGURLGDSSOLFDWLRQ
Application Signing | 101
)LUVW\RXZLOOVHHLI\RXUDSSOLFDWLRQKDVDQ\HUURUVLQFRQILJXUDWLRQWKDWPLJKWSUHYHQW
LWIURPEHLQJUHDG\WRSXEOLVKVXFKDVKDYLQJWKH debuggableDWWULEXWHVHWWR trueLQ
WKHPDQLIHVW,I\RXUDSSLVUHDG\WRJR\RXZLOOVHHWKHGLDORJLQ)LJXUHZKLFK
GLVSOD\VQRHUURUV
)LJXUH$Q$QGURLGDSSOLFDWLRQWKDWKDVQRSUREOHPVSUHYHQWLQJVLJQLQJDQGSXEOLVKLQJ
6XEVHTXHQWGLDORJER[HVLQWKLVPXOWLVWHSVHTXHQFHIRFXVRQVLJQLQJ7KHLQIRUPDWLRQ
UHTXHVWHGPLUURUVWKHLQIRUPDWLRQ\RXHQWHUHGWRFUHDWH\RXUUHOHDVHNH\LQ£&UHDWLQJ
DVHOIVLJQHGFHUWLILFDWH¤RQSDJH
102 | Chapter 4:ಗGetting Your Application into Users’ Hands
1H[W\RXZLOOVHOHFW\RXUNH\VWRUHDVVKRZQLQ)LJXUH7KHNH\VWRUHLVWKHILOH
KROGLQJ\RXUNH\
)LJXUH6HOHFWLQJWKHNH\VWRUH
2QFH\RXKDYHHQWHUHGWKHQDPHRIWKHNH\VWRUHDQGWKHSDVVZRUGFOLFN1H[WDQG
SURFHHGWRWKHQH[WVWHSVHOHFWLQJWKHDOLDVRIWKHNH\DQGHQWHULQJWKHSDVVZRUGIRU
WKHDOLDVDVVKRZQLQ)LJXUH
Application Signing | 103
)LJXUH6HOHFWLQJWKHNH\DOLDV
,I\RXIROORZHGWKHVWHSVLQ£&UHDWLQJDVHOIVLJQHGFHUWLILFDWH¤RQSDJH\RXKDYH
RQO\RQHNH\ZLWKRQHDOLDVLQ\RXUNH\VWRUH(QWHUWKHSDVVZRUGDQGFOLFN1H[W7KH
QH[WVWHSLVWRVSHFLI\WKHGHVWLQDWLRQDSNILOHDQGSDVVVRPHFKHFNVWRGHWHUPLQHLI
DQ\WKLQJHOVHPLJKWEHZURQJZLWK\RXUDSS,IHYHU\WKLQJLVLQRUGHU\RXZLOOVHHD
VFUHHQUHVHPEOLQJWKDWVKRZQLQ)LJXUH
:KHQ\RXFOLFN)LQLVK\RXZLOOJHWDVLJQHGDSNILOHLQWKHVSHFLILHGORFDWLRQ
104 | Chapter 4:ಗGetting Your Application into Users’ Hands
)LJXUH6HOHFWLQJWKHGHVWLQDWLRQDQGILQDOFKHFNV
Placing an Application for Distribution in the Android Market
3XWWLQJDQDSSOLFDWLRQRQWKH$QGURLG0DUNHWLVUHPDUNDEO\HDV\7KHRQO\SUHUHTXLVLWH
LVWKDW\RXKDYHD*RRJOHDFFRXQWVXFKDVD*PDLODFFRXQW$FUHGLWFDUGWUDQVDFWLRQ
DQGVRPHLQIRUPDWLRQDERXW\RXUVHOIDUHDOO\RXQHHGWRVWDUWXSORDGLQJDSSOLFDWLRQV
WRWKH$QGURLG0DUNHW&KDUJLQJIRUDSSOLFDWLRQVDQGJHWWLQJSDLGWDNHVRQO\VOLJKWO\
PRUHLQIRUPDWLRQDQGHIIRUW¢\RXGRQ¦WHYHQQHHGDZHEVLWHRUDFRUSRUDWHHQWLW\
&RQVXOWLQJDODZ\HUEHIRUHVHOOLQJSURGXFWVLVDJRRGLGHD$ODZ\HUPD\VXJJHVWVHWWLQJ
XSDFRUSRUDWLRQDQGRWKHUZD\VWRSURWHFW\RXUSHUVRQDODVVHWVIURPOLDELOLWLHVUHVXOWLQJ
IURPFRPPHUFLDODFWLYLWLHV
Placing an Application for Distribution in the Android Market | 105
Becoming an Official Android Developer
7KH$QGURLG0DUNHWVLWHLVZKHUH\RXEHFRPHDQRIILFLDO$QGURLGGHYHORSHU<RXFDQ
VLJQXSDWKWWSPDUNHWDQGURLGFRPSXEOLVKVLJQXS
7KLVVLWHZLOODVN\RXIRULGHQWLI\LQJLQIRUPDWLRQDQGZLOODVN\RXWRSD\DIHHXVLQJ
*RRJOH&KHFNRXW7KLVWUDQVDFWLRQFRQILUPVWKDW\RXKDYHDPHWKRGRISD\PHQWVXFK
DVDFUHGLWFDUGDFFHSWHGE\*RRJOH&KHFNRXW2QFH\RXDUHVLJQHGXSDVDGHYHORSHU
\RXFDQXVH\RXU*RRJOHDFFRXQWWRORJLQWRWKH$QGURLG0DUNHWVLWH
$WWKLVSRLQW*RRJOHKDVUHDVRQDEOHDVVXUDQFHWKDW\RXDUHZKR\RXVD\\RXDUHD
ILQDQFLDO WUDQVDFWLRQ OLQNHG WR VRPH HQWLW\ WKDW FDQ SD\ RII D FUHGLW FDUG ELOO 7KLV
FRPELQHGZLWKWKHIDFWWKDW\RXUDSSOLFDWLRQVDUHVLJQHGPHDQV*RRJOHLVDOVRFRQIL
GHQWWKDWWKHNH\\RXFUHDWHGWRVLJQ\RXUDSSOLFDWLRQVLVLQWKHSRVVHVVLRQRIWKHSHUVRQ
ZKRFUHDWHGWKH$QGURLG0DUNHWDFFRXQWIRUWKHSXUSRVHRIXSORDGLQJDSSOLFDWLRQVWR
WKH$QGURLG0DUNHW,I\RXWXUQRXWWREHDVSDPPHURUDVRXUFHRIEDGZDUH\RXZLOO
EHVKXWGRZQDQG\RXZLOOQHHGWRILQGDQRWKHULGHQWLW\ZLWKZKLFKWRFUHDWHDQRWKHU
*RRJOH&KHFNRXWDFFRXQWDQG$QGURLG0DUNHWDFFRXQW
Uploading Applications in the Market
7KHSDJHKWWSVPDUNHWDQGURLGFRPSXEOLVK+RPH$SS(GLWRU3ODFHLVZKHUH\RXXS
ORDGDSSOLFDWLRQV2QLW\RXZLOOVHHWKHODWHVWUHTXLUHPHQWVDQGRSWLRQVIRUSURYLGLQJ
LQIRUPDWLRQ DERXW \RXU DSSOLFDWLRQ 7KH SDJH KDV XSORDG EXWWRQV IRU WKH DSSOLFD
WLRQ¦VDSNILOHSOXVVFUHHQVKRWVYLGHRVDQGVLPLODUFRQWHQWPRVWRIZKLFKLVRSWLRQDO
:KHQ\RXKDYHDQDSSOLFDWLRQ\RXZRXOGOLNHWROHDYHXSRQWKH0DUNHWIRURWKHUVWR
GRZQORDG\RXVKRXOGUHDGWKHGHVFULSWLRQVRIWKHNLQGVRISURPRWLRQDODQGH[SODQ
DWRU\PDWHULDO\RXFDQXSORDGDQGPDNHXVHRIWKHP)RUQRZOHW¦VJHWRXUDSSXS
ZLWKWKHPLQLPXPUHTXLUHPHQWVPHW
7KHILUVWWKLQJWRGRLVWRXSORDGDQDSNILOH7RWU\LWRXW\RXFDQXVHWKHDSNILOH\RX
FUHDWHG LI \RX IROORZHG DORQJ LQ £8VLQJ D VHOIVLJQHG FHUWLILFDWH WR VLJQ DQ DSSOLFD
WLRQ¤RQSDJH'RQ¦WZRUU\WKDWWKLVLVQRW\RXUDSSOLFDWLRQDQGWKDWLWLVMXVWDQ
H[DPSOH<RXFDQSXEOLVKLWDQGWKHQXQSXEOLVKLWULJKWDZD\DV\RXZLOOVHHIURPWKH
LQVWUXFWLRQVLQWKHUHVWRIWKLVVHFWLRQ
0RVWUHTXLUHGLQIRUPDWLRQLVHLWKHUSDUWRI\RXUSURILOHDVDQ$QGURLGGHYHORSHURU
SDUW RI WKH DSSOLFDWLRQ PDQLIHVW $V RI WKLV ZULWLQJ WKH UHTXLUHG XSORDGV DUH WZR
VFUHHQVKRWVDQGDQLFRQLPDJH<RXZLOOILQGXVDEOHLPDJHVLQWKHGRFIROGHURIWKH
H[DPSOHSURMHFW,IWKHVHUHTXLUHPHQWVFKDQJH¢DQGWKH$QGURLG0DUNHWKDVFKDQJHG
VXEVWDQWLDOO\VLQFHLWZDVILUVWLQWURGXFHG¢\RXZLOOILQGRXWLI\RXKDYHVNLSSHGDQ\
UHTXLUHGILHOGVRUXSORDGVZKHQ\RXFOLFNWKH3XEOLVKEXWWRQDWWKHERWWRPRIWKHSDJH
$Q\WKLQJ \RX PLVVHG ZLOO EH KLJKOLJKWHG DQG \RX FDQ JR EDFN DQG ILOO LQ ILHOGV RU
SHUIRUPXSORDGVDVQHHGHGWRPDNH\RXUDSSOLFDWLRQUHDG\IRUSXEOLFDWLRQ
&OLFNWKH3XEOLVKEXWWRQ
106 | Chapter 4:ಗGetting Your Application into Users’ Hands
&RQJUDWXODWLRQV\RXKDYHSXEOLVKHGDQ$QGURLGDSSOLFDWLRQ,I\RXJREDFNWRKWWSV
PDUNHWDQGURLGFRPSXEOLVK+RPH\RXZLOOVHHIURPWKHOLVWLQJRIDSSOLFDWLRQVWKDW
\RXKDYHRQHSXEOLVKHGDSSOLFDWLRQ LI\RXKDYHQRWSUHYLRXVO\SXEOLVKHGDQDSSOLFD
WLRQ ,I\RXJRWRKWWSVPDUNHWDQGURLGFRPDQGVHDUFKIRUVD\\RXUQDPHWKHVHDUFK
IXQFWLRQVKRXOGILQGWKHDSSOLFDWLRQ\RXMXVWSXEOLVKHGDQGOLVWLWWKHZD\DSRWHQWLDO
FXVWRPHUPLJKWVHHLWLIKHZHUHWRILQGLWLQWKH$QGURLG0DUNHW)URPWKHUH\RXFDQ
FOLFNWKURXJKWRWKHDSSOLFDWLRQ¦VSDJHLQWKH$QGURLG0DUNHW
1RZ\RXFDQJREDFNWRWKH£+RPH¤SDJHZKHUH\RXUDSSOLFDWLRQLVOLVWHGDQGVHOHFW
LWE\FOLFNLQJRQWKHOLQNLQWKHOLVWLQJ7KLVWDNHV\RXWRDSDJHZKHUHWKHLQIRUPDWLRQ
\RXHQWHUHGZKHQ\RX SXEOLVKHG \RXU DSS LV GLVSOD\HG LQ VXFKDZD\WKDW\RXFDQ
PRGLI\LWDQGXSGDWHWKHDSSOLFDWLRQ¦VOLVWLQJ<RXFDQDOVRXQSXEOLVK\RXUDSSOLFDWLRQ
IURPWKLVSDJHXVLQJWKH8QSXEOLVKEXWWRQDWWKHERWWRPRIWKHSDJH:KHZ<RX
WKRXJKW\RXPLJKWVWDUWJHWWLQJFXVWRPHUVXSSRUWLQTXLULHV
$QDSSOLFDWLRQWKDWKDVEHHQXQSXEOLVKHGLVQRWUHPRYHGIURPWKHPDUNHWV\VWHP,W
LVVWLOOOLVWHGDPRQJ\RXUDSSOLFDWLRQVEXWLVQRWPDGHDYDLODEOHIRUGRZQORDG<RXFDQ
UHYHUVH\RXUGHFLVLRQWRXQSXEOLVKDWDQ\WLPHE\XVLQJWKH3XEOLVKEXWWRQ
Getting Paid
*RRJOH&KHFNRXWLVWKHSD\PHQWPHFKDQLVPIRUWKH$QGURLG0DUNHW7KDWLVWKH$Q
GURLG0DUNHWSURYLGHVDVWUHDPOLQHGZD\WRVLJQXSDVD*RRJOH&KHFNRXWPHUFKDQW
,I\RXHOHFWWREHDSXEOLVKHURISDLGDSSOLFDWLRQV\RXZLOOEHGLUHFWHGWRDSDJHZKHUH
\RXFDQFUHDWHD£PHUFKDQWDFFRXQW¤7KLVPD\VRXQGDELWLQWLPLGDWLQJEXW*RRJOH
KDVPDGHLWHDV\WRJHWSDLG<RXGRQ¦WQHHGWRIRUPDFRUSRUDWLRQRUJHWDEXVLQHVV
EDQNDFFRXQW
<RXVKRXOGFRQVXOWDODZ\HUDERXWIRUPLQJDFRUSRUDWHHQWLW\IRU\RXU
EXVLQHVV DQG \RX VKRXOG VHJUHJDWH \RXU EXVLQHVV ILQDQFHV IURP \RXU
SHUVRQDODFFRXQWV
7KHSURFHVVRIJHWWLQJDPHUFKDQWDFFRXQWDPRXQWVWRHQWHULQJVRPHPRUHLQIRUPDWLRQ
¢PRVWLPSRUWDQWO\\RXUWD[,'ZKLFKFDQEH\RXU6RFLDO6HFXULW\QXPEHU¢VRWKDW
LQFRPHIURP\RXUVDOHVFDQEHUHSRUWHG
*HWWLQJSDLGLQYROYHVOLQNLQJDEDQNDFFRXQWWR\RXU*RRJOH&KHFNRXWPHUFKDQWDF
FRXQW3D\PHQWVWR*RRJOH&KHFNRXWIRUVDOHVRI\RXUDSSZLOOEHGHSRVLWHGLQ\RXU
EDQNDFFRXQW$IXOOGHVFULSWLRQRIWHUPVRIVHUYLFHSD\PHQWWHUPVDQGVLPLODULQIRU
PDWLRQFDQEHIRXQGLQWKHVHOOHUV¦VHFWLRQRIWKH*RRJOH&KHFNRXWVLWHDWKWWSFKHFN
RXWJRRJOHFRPVXSSRUWVHOOELQDQVZHUS\"KO HQ DQVZHU Placing an Application for Distribution in the Android Market | 107
Google Maps API Keys
$ *RRJOH 0DSV $3, NH\ FRPELQHG ZLWK WKH NH\V \RX XVH IRU VLJQLQJ DSSOLFDWLRQV
LGHQWLILHV\RXWR*RRJOHDQGHQDEOHV*RRJOHWRHQIRUFHWKHWHUPVRIVHUYLFHIRU*RRJOH
0DSV*RRJOH0DSVUHOLHVRQLQIRUPDWLRQ*RRJOHFROOHFWVDQGEX\VDWVLJQLILFDQWH[
SHQVHDQGPXVWEHSURWHFWHGIURPPLVDSSURSULDWLRQDQGRWKHUPLVXVH
,I\RXKDYHEHHQGHYHORSLQJDQDSSOLFDWLRQXVLQJWKH*RRJOH0DSV$3,\RXZLOOKDYH
REWDLQHGDQ$3,NH\OLQNHGWRWKHGHEXJVLJQDWXUHIRU\RXUDSSOLFDWLRQ<RXFDQ¦WXVH
WKLV$3,NH\ZKHQ\RXVKLS\RXUDSSOLFDWLRQ7KH*RRJOH0DSV$3,DQGWKHUHTXLUH
PHQWVIRUXVLQJLWDUHGHVFULEHGLQ&KDSWHU
:KHQ\RXVKLS\RXUDSSOLFDWLRQ\RXZLOOQHHGD*RRJOH0DSV$3,NH\OLQNHGWRWKH
VLJQLQJ NH\ \RX XVHG IRU GLVWULEXWLQJ \RXU DSSOLFDWLRQ 7KDW LV \RX ZLOO QHHG D
QHZ$3,NH\WKDWLVPDGHXVLQJDQ0'ILQJHUSULQWRI\RXUVLJQLQJNH\8VLQJWKH
keytoolFRPPDQG¦VlistRSWLRQ\RXFDQJHWWKH0'ILQJHUSULQWRI\RXUVLJQLQJNH\
WKXVO\
keytool -list -keystore my-release-key.keystore
<RXZLOOJHWWKLVNH\WKHVDPHZD\\RXJRWWKH$3,NH\IRUXVHZLWK\RXUGHEXJVLJQDWXUH
E\YLVLWLQJWKH$QGURLG0DSV$3,.H\6LJQXSSDJHDWKWWSFRGHJRRJOHFRPDQGURLG
PDSVDSLVLJQXSKWPODQGXVLQJWKH0'ILQJHUSULQWRI\RXUVLJQLQJNH\LQWKHIRUP
DVVKRZQLQ)LJXUH
)LJXUH*HWWLQJD*RRJOH0DSV$3,NH\
:KHQ\RXFOLFNWKH*HQHUDWH$3,.H\EXWWRQ\RXZLOOJHWDZHESDJHVKRZLQJWKH$3,
NH\JHQHUDWHGIURP\RXUVLJQLQJFHUWLILFDWH¦VILQJHUSULQWDVVKRZQLQ)LJXUH
<RXUHDOO\KDYHWRFUHDWH\RXUVHOIVLJQLQJFHUWLILFDWHDQG*RRJOH0DSV
$3,NH\V\RXUVHOI<RXFDQQRWFRS\WKHPIURPWKHVFUHHQVKRWVKHUH
\RXFDQQRWXVHNH\VIURPH[DPSOHFRGH\RXGRZQORDGDQG\RXFDQQRW
XVHGHEXJNH\VZKHQUHOHDVLQJDSURGXFW
108 | Chapter 4:ಗGetting Your Application into Users’ Hands
)LJXUH7KH$QGURLG0DSV$3,NH\JHQHUDWHGIURP\RXUVHOIVLJQLQJFHUWLILFDWH
Specifying API-Level Compatibility
$WDQ\RQHWLPHPXOWLSOHYHUVLRQVRI$QGURLGFDQEHDYDLODEOHDQGQRWDOOWKHSUR
VSHFWLYHXVHUVRI\RXUDSSOLFDWLRQZLOOKDYHWKHPRVWUHFHQWYHUVLRQ%\VSHFLI\LQJDS
SOLFDWLRQFRPSDWLELOLW\LQWKHPDQLIHVW\RXFDQFRQWUROZKLFK$QGURLGV\VWHPVFDQ
LQVWDOO\RXUDSSOLFDWLRQSUHYHQWLQJLWVXVHLQV\VWHPVWKDWDUHLQFRPSDWLEOHZLWKWKH
$3,V\RXDUHXVLQJ
,Q WKH H[DPSOH LQ £0DNLQJ DQ $QGURLG 3URMHFW¤ RQ SDJH WKH VDPH $3, OHYHO LV
VSHFLILHGIRUWKHEXLOGWDUJHWDVIRUWKH0LQ6'.9HUVLRQILHOG7KLVPHDQVWKHSURJUDP
ZLOORQO\UXQRQV\VWHPVZLWKWKHVSHFLILHG$3,OHYHORUKLJKHU
6LQFH\RXFDQGHWHFWWKH$3,OHYHODWUXQWLPHWKHUHPD\EHFDVHVZKHUH\RXZDQWWR
VKLSRQHDSSOLFDWLRQIRUV\VWHPVZLWKDORZHU$3,OHYHOWKDQ\RXXVHDQGWRWHVWIRUWKH
$3,OHYHODQGRQO\XVHPHWKRGVDQGFODVVHVRIKLJKHU$3,OHYHOVLIWKH\DUHDYDLODEOH,Q
WKHVHFDVHV\RXZRXOGVSHFLI\DKLJKHUEXLOGWDUJHW$3,OHYHOWKDQWKH0LQ6'.9HUVLRQ
Compatibility with Many Kinds of Screens
$QGURLGZDVEXLOWWRDFFRPPRGDWHPXOWLSOHVFUHHQVL]HVDQGFKDQJHVLQVFUHHQRULHQ
WDWLRQ7KHEHVWZD\WRDFFRPPRGDWHVFUHHQVL]HGLIIHUHQFHVDPRQJ$QGURLGGHYLFHV
LVWRHQDEOH\RXUOD\RXWVWREHDVIOH[LEOHDVSRVVLEOH7KHLPDJHV\RXUDSSOLFDWLRQXVHV
Compatibility with Many Kinds of Screens | 109
PD\QRWORRNRSWLPDOLQYHU\ODUJHRUXQXVXDOO\VPDOOFRQILJXUDWLRQVEXWLWLVSRVVLEOH
WRVSHFLI\OD\RXWVWKDWDUHXVDEOHDWVFUHHQVL]HVUDQJLQJIURPWKHVPDOOHVWVFUHHQRI
PRGHUDWHUHVROXWLRQXSWRDÜ+'GLVSOD\
,QRWKHUZRUGVGRQ¦WVWDUWE\GHVLJQLQJPXOWLSOHOD\RXWVDQGPXOWLSOHJUDSKLFDODVVHWV
IRUGLIIHUHQWVFUHHQVL]HV6WDUWE\DFFRPPRGDWLQJDZLGHUDQJHRIVFUHHQVL]HVZHOO
HQRXJKIRU\RXUDSSOLFDWLRQWRUHPDLQXVDEOH
Testing for Screen Size Compatibility
7HVWLQJLVNH\WRHQVXULQJVFUHHQFRPSDWLELOLW\7KH6'.DQG$9'0DQDJHUSURYLGHV
FRQILJXUDWLRQVIRUDUDQJHRIVFUHHQVL]HVWKDWFRYHUDOOWKHVPDUWSKRQHVRQZKLFK$Q
GURLGUXQV$VGHVFULEHGLQ£0DNLQJDQ$QGURLG9LUWXDO'HYLFH $9' ¤RQSDJH
\RXFDQVSHFLI\SUHVHWDQGFXVWRPVFUHHQVL]HVZKHQFUHDWLQJDQ$QGURLGYLUWXDOGHYLFH
Resource Qualifiers and Screen Sizes
2QFH\RXKDYHOD\RXWVWKDWFDQKDQGOHWKHPDMRULW\RIFDVHV\RXPD\ZDQWWRLPSURYH
WKH ZD\ \RXU DSSOLFDWLRQ ORRNV RQ VSHFLILF GLVSOD\V <RX PD\ QHHG WR XVH VHSDUDWH
OD\RXWVLQFDVHVZKHUH\RXZDQWWRWDNHDGYDQWDJHRIJUHDWHUVFUHHQUHDOHVWDWHRWKHU
WKDQE\MXVWVSUHDGLQJDOD\RXWDFURVVWKHVFUHHQ DVHSDUDWHSUHYLHZSDQHIRUH[DPSOH ,QWKHVHFDVHVRULQFDVHVRIVSHFLDOL]HGDSSVWKDWPLJKWEHXVHGIRUXQXVXDOO\VPDOO
GLVSOD\V\RXFDQGHVLJQOD\RXWVIRUVSHFLILFVLWXDWLRQVXVLQJUHVRXUFHTXDOLILHUV
5HVRXUFHTXDOLILHUVDUHDVHWRIQDPLQJUXOHVIRUUHVRXUFHGLUHFWRULHVWKDWHQDEOH\RXWR
SURYLGHDOWHUQDWLYHUHVRXUFHVIRUWKHFRQGLWLRQVVSHFLILHGE\WKHTXDOLILHUVXFKDVKLJK
RUORZSL[HOGHQVLW\ODQJXDJHFRXQWU\DQGFHUWDLQKDUGZDUHUHVRXUFHDYDLODELOLW\
7KHIXOOUDQJHRIUHVRXUFHTXDOLILHUVLVGHVFULEHGDWKWWSGHYHORSHUDQGURLGFRPJXLGH
WRSLFVUHVRXUFHVSURYLGLQJUHVRXUFHVKWPO$OWHUQDWLYH5HVRXUFHV
110 | Chapter 4:ಗGetting Your Application into Users’ Hands
CHAPTER 5
Eclipse for Android
Software Development
(FOLSVHLVDFRQWURYHUVLDOWRSLF,WLVDJUHDWRSHQVRXUFHVXFFHVVVWRU\LWLVWKHPRVW
ZLGHO\XVHG-DYD,QWHJUDWHG'HYHORSPHQW(QYLURQPHQW ,'( LWLVSRZHUIXODQGLWLV
WKHFHQWHURIWKHODUJHVWHFRV\VWHPRIDGGRQVDQGGHULYDWLYHSURGXFWVDYDLODEOHIRU
VRIWZDUHGHYHORSPHQW7KHVHDUHWKHUHDVRQV(FOLSVHZDVFKRVHQDVWKHGHYHORSPHQW
WDUJHWIRUSOXJLQVWKDWFXVWRPL]HLWIRU$QGURLGVRIWZDUHGHYHORSPHQW%XW(FOLSVHKDV
EHHQFULWLFL]HGIRUEHLQJXQIULHQGO\DQGGLIILFXOWWROHDUQ
(FOLSVHLVQ¦WOLNHPRVW*8,VRIWZDUHWKDWWDNHVSDLQVWRSURWHFWWKHXVHUIURPLQYRNLQJ
RSHUDWLRQVWKDWFDQQRWVXFFHHG(FOLSVH¦VGHYHORSHUVIDYRUPRGXODULW\DQGSRZHURYHU
VPRRWKLQJWKHVKDUSHGJHV)RUH[DPSOHRQHRIWKHILUVWWKLQJV\RXPD\KDYHQRWLFHG
LQUXQQLQJDQH[DPSOHSURJUDPLVWKDW(FOLSVHRIIHUVWRGRWKLQJVZLWK\RXU$QGURLG
SURJUDPWKDWGRQ¦WPDNHPXFKVHQVHOLNHUXQQLQJLWRQDVHUYHURUDVDQDSSOHWDV
VKRZQLQ)LJXUH
)LJXUH5XQQLQJ(FOLSVHDVDQDSSOHWDWDVNWKDWLVERXQGWRIDLO
:HDUHQRWKHUHWRFULWLFL]H(FOLSVHQRUUDWLRQDOL]HRQLWVEHKDOI%XWZHZLOOH[SODLQ
ZK\(FOLSVHGRHVWKLQJVOLNHWKLV:HZLOOH[SODLQKRZ(FOLSVHFRPSRQHQWVILWWRJHWKHU
111
DQGZRUNWRJHWKHU:HZLOOIDPLOLDUL]H\RXZLWKZKDW\RXDUHORRNLQJDWZKHQ\RX
ODXQFK(FOLSVHDQGVWDUWFRGLQJ:LWKWKLVNQRZOHGJH\RXZLOOEHEHWWHUHTXLSSHGWR
PDNHHIIHFWLYHXVHRI(FOLSVHDQGOHVVOLNHO\WRILQGLWIUXVWUDWLQJ
'RFXPHQWDWLRQIRU(FOLSVHLVDYDLODEOHDWKWWSZZZHFOLSVHRUJGRFXPHQWDWLRQ
Eclipse Concepts and Terminology
(FOLSVHKDVLWVRZQQRPHQFODWXUHEHKLQGZKLFKDUHWKHFRQFHSWVWKDWDUHNH\WRXQ
GHUVWDQGLQJLW7KHVHFRQFHSWVGHYHORSHGRYHUDYHU\ORQJSURGXFWOLIHVSDQRULJLQDWLQJ
ZLWK9LVXDO$JH¢DVRIWZDUHGHYHORSPHQWWRROZULWWHQLQWKH6PDOO7DONODQJXDJHLQWKH
PLGV7KHFXUUHQWLPSOHPHQWDWLRQRI(FOLSVHLVZULWWHQLQWKH-DYDODQJXDJHEDVHG
RQDIUDPHZRUNFDOOHG(TXLQR[ZKLFKLPSOHPHQWVDVSHFLILFDWLRQIRUPRGXODU-DYD
VRIWZDUHV\VWHPVFDOOHG26*L26*LLVDZD\RIVSHFLI\LQJLQDPDQLIHVWWKHOLIHF\FOH
DQGGHSHQGHQFLHVRIG\QDPLFDOO\ORDGHGPRGXOHVFDOOHGEXQGOHV7KDWLV(FOLSVHLVD
FROOHFWLRQRIPRGXOHVLQDIUDPHZRUN:KHQPRGXOHVDUHDGGHGRUUHPRYHGLIWKH\
KDYHGHSHQGHQFLHVRQRWKHUPRGXOHVWKRVHGHSHQGHQFLHVZLOOEHVDWLVILHGDXWRPDWL
FDOO\LISRVVLEOH
)XUWKHULQIRUPDWLRQRQWKH(TXLQR[26*LLPSOHPHQWDWLRQLQFOXGLQJDGHWDLOHGH[
SODQDWLRQRIZKDWKDSSHQVZKHQ(FOLSVHVWDUWVXSLVDYDLODEOHDWKWWSHFOLSVHRUJHTXL
QR[GRFXPHQWVTXLFNVWDUWSKS
Plug-ins
:KHQ\RXVHWXS\RXU$QGURLGVRIWZDUHGHYHORSPHQWWRROV\RXDGGHGSOXJLQVWR
(FOLSVHWKH$QGURLG'HYHORSPHQW7RROV $'7 SOXJLQV3OXJLQVDUH26*LEXQGOHV
7KH$QGURLG6'.DGGVWZRSOXJLQVWR(FOLSVH<RXFDQILQGWKHPE\VKRZLQJWKH
3OXJLQVYLHZE\VHOHFWLQJ:LQGRZൺ6KRZ9LHZൺ2WKHUDQGH[SDQGLQJWKH£3OXJ
LQGHYHORSPHQW¤LWHP7KHQVHOHFW3OXJLQVIURPWKHOLVWRIYLHZV<RXZLOOVHHWKHOLVW
VKRZQLQ)LJXUH
1RWHWKDWLQWKLVFKDSWHUDQGLQRWKHUSODFHVLQWKLVERRN(FOLSVHYLHZ
VFUHHQVKRWVDUHVKRZQLQ£GHWDFKHG¤PRGH¢LQDVHSDUDWHZLQGRZ¢
VRWKDWZHGRQRWQHHGWRWULPWKHVXUURXQGLQJYLHZVDQGWRROEDUVRXW
RIVFUHHQVKRWV7KHZD\DYLHZDSSHDUVRQ\RXUVFUHHQGHSHQGVRQWKH
(FOLSVHSHUVSHFWLYH\RXDUHXVLQJDQGWKHRWKHUYLHZVLQWKDWSHUVSHFWLYH
5LJKWFOLFNLQJRQDYLHZWLWOHSRSVXSDPHQXZLWKRSWLRQVIRUKRZWR
GLVSOD\WKHYLHZLQFOXGLQJWKH'HWDFKHGRSWLRQ
3OXJLQVDUHOLVWHGDOSKDEHWLFDOO\VRQHDUWKHWRSRIWKHOLVW\RXZLOOVHHWKHWZRSOXJ
LQV UHTXLUHG IRU ZRUNLQJ ZLWK WKH $QGURLG 6'. com.android.ide.eclipse.adt DQG
com.android.ide.eclipse.ddms.HHSWKH3OXJLQVYLHZRSHQ/DWHULQWKLVFKDSWHUZH
112 | Chapter 5:ಗEclipse for Android Software Development
)LJXUH$OLVWRIDOOWKHSOXJLQVLQDQ(FOLSVHHQYLURQPHQW
ZLOOORRNDWVRPHLQIRUPDWLRQDERXWWKRVHSOXJLQVWRVHHKRZWKH\PRGLI\WKH(FOLSVH
HQYLURQPHQW<RXFDQDOVRORRNDWWKLVOLVWRISOXJLQVDQGVHHWKDW(FOLSVHLVLQIDFW
PDGHRISOXJLQVDOOWKHZD\GRZQWRWKH(TXLQR[26*LLPSOHPHQWDWLRQ
Workspaces
(FOLSVHNHHSVDORWRIVWDWHDQGZRUNVSDFHVDUHZKHUHLWLVNHSW:KHQ\RXILUVWUXQ
(FOLSVHLWZLOODVNLI\RXZDQWWRFUHDWHDZRUNVSDFH7KHUHDIWHUZKHQ\RXVWDUW(FOLSVH
LWSLFNVXSULJKWZKHUH\RXOHIWRIIZLWKDOOWKHSURMHFWVILOHVDQGYLHZVDV\RXOHIW
WKHPE\UHDGLQJLWVSUHYLRXVVWDWHIURPDZRUNVSDFH(FOLSVHLPSOHPHQWVZRUNVSDFHV
XVLQJGLUHFWRULHV
(YHU\SURMHFWEHORQJVWRDZRUNVSDFH%\GHIDXOWQHZSURMHFWVDUHGLUHFWRULHVFUHDWHG
LQVLGHWKHZRUNVSDFHGLUHFWRU\(YHQLI\RXFUHDWHDSURMHFWIURPVRXUFHWKDWLVQRWLQ
WKHZRUNVSDFHGLUHFWRU\PRVWRIWKHPHWDLQIRUPDWLRQDERXWWKDWSURMHFWLVNHSWLQWKH
ZRUNVSDFH
Eclipse Concepts and Terminology | 113
:RUNVSDFHVDUHLQGHSHQGHQW6HWWLQJVWKDW\RXVHWXSLQRQHZRUNVSDFHVWD\LQWKDW
ZRUNVSDFH<RXFDQXVHPXOWLSOHZRUNVSDFHVWRVHSDUDWHSURMHFWVWKDWWDUJHWGLIIHUHQW
SODWIRUPV DQG WKDW PD\ XVH PDUNHGO\ GLIIHUHQW HQYLURQPHQWV¢IRU H[DPSOH 5DLOV
SURMHFWVDQG$QGURLGSURMHFWV<RXFDQXVHPXOWLSOHZRUNVSDFHVWRUXQPRUHWKDQRQH
LQVWDQFHRI(FOLSVH6XSSRVH\RXKDYH(FOLSVHEDVHGWRROVIRUVRPHZHEDSSOLFDWLRQ
IUDPHZRUNWKDWDUHQRWFRPSDWLEOHZLWKWKHYHUVLRQRI(FOLSVH\RXDUHXVLQJIRU$QGURLG
GHYHORSPHQW%\XVLQJDVHSDUDWHZRUNVSDFHIRU$QGURLGGHYHORSPHQW\RXFDQPDLQ
WDLQVHSDUDWHVWDWHDQGHYHQUXQERWK(FOLSVHYHUVLRQVDWWKHVDPHWLPH
Java Environments
7KUHHGLVWLQFW-DYDHQYLURQPHQWVDUHXVHGLQ-DYDVRIWZDUHGHYHORSPHQWLQ(FOLSVH
Eclipse’s Java Runtime Environment
7KHILUVWHQYLURQPHQWLVWKDWLQZKLFK(FOLSVHLWVHOILVUXQQLQJ,Q£7KH(FOLSVH,QWH
JUDWHG'HYHORSPHQW(QYLURQPHQW ,'( ¤RQSDJHZHFRYHUHGLQVWDOOLQJ-DYDGHYHO
RSPHQW WRROV DQG UXQWLPH HQYLURQPHQWV LI \RXU V\VWHP GRHV QRW DOUHDG\ KDYH RQH
LQVWDOOHG,I\RXQHHGWRXVHDGLIIHUHQW-DYDUXQWLPHIRU(FOLSVH\RXFDQFRQILJXUHWKLV
FKRLFHLQ\RXUHFOLSVHLQLILOHLQWKHIROGHUZKHUH(FOLSVHLVLQVWDOOHG,I(FOLSVHLVUXQQLQJ
RXWRIPHPRU\IRULQVWDQFHWKLVLVWKHHQYLURQPHQW\RXZLOOZDQWWRDGMXVW
The Java compiler
7KHVHFRQGHQYLURQPHQWLVXVHGWRFRPSLOH\RXUFRGH(FOLSVHFRPHVZLWKLWVRZQ
LQFUHPHQWDO-DYDFRPSLOHU,QDGGLWLRQWRSURGXFLQJWKHFRPSLOHG-DYDFODVVILOHVLW
FUHDWHVWKHHUURUPHVVDJHVGLVSOD\HGLQWKH-DYDHGLWRUDQGSURGXFHVWKHW\SLQJLQIRU
PDWLRQ(FOLSVHXVHVIRUVXJJHVWLRQVDXWRFRPSOHWLRQDQGVRRQ7KLVHQYLURQPHQWLV
FRQILJXUHGXVLQJWKH-DYDൺ&RPSLOHUQRGHLQWKH3UHIHUHQFHVSDQHEXW\RXFDQRYHUULGH
WKHGHIDXOWVIRUDVSHFLILFSURMHFWIURPWKHSURMHFW¦VSUHIHUHQFHV
,QDGGLWLRQWKLVHQYLURQPHQWFRQWDLQVDGHVFULSWLRQRIWKHOLEUDULHVDJDLQVWZKLFKWKH
DSSOLFDWLRQLVFRPSLOHG,I\RXORRNDWWKH3UHIHUHQFHVൺ%XLOG3DWKIRUDQ$QGURLGDS
SOLFDWLRQ\RXZLOOILQGWKDWWKHUHLVQR-DYDUXQWLPHLQFOXGHGLQWKHOLVWRIOLEUDULHVRQ
ZKLFKWKHSURMHFWGHSHQGV,QVWHDGDQ$QGURLGSURMHFWGHSHQGVRQDYHUVLRQRIWKH
$QGURLGOLEUDULHV%HFDXVHWKH$QGURLGWRROVDUHEROWHGRQWR(FOLSVHWKRXJK\RXFDQ¦W
GLUHFWO\FKDQJHWKH$QGURLGOLEUDU\YHUVLRQIURPWKH%XLOG3DWKSDQH,I\RXQHHGWRGR
WKDW\RX¦OOKDYHWRRSHQWKH$QGURLGSUHIHUHQFHVSDQH
The application runtime
7KHWKLUGHQYLURQPHQWLVWKHRQHLQZKLFK\RXUDSSOLFDWLRQUXQV¢LQWKLVFDVHRQHRI
WKH$QGURLGHPXODWRUV,QVHWWLQJXS\RXUGHYHORSPHQWHQYLURQPHQW¢HLWKHUZKHQ\RX
LQVWDOOHGWKH6'.RUZKHQ\RXVHWXSWKH$'7SOXJLQ¢\RXVHWXSRQHRUPRUH$QGURLG
9LUWXDO'HYLFHV $9'V :KHQ\RXFUHDWHDQHZ$QGURLGSURMHFW\RXDVVRFLDWHLWZLWK
RQHRIWKH$9'V7KHSOXJLQXVHVWKHDSSURSULDWHSURILOHWRVHWXSERWKWKHFRPSLODWLRQ
114 | Chapter 5:ಗEclipse for Android Software Development
HQYLURQPHQWDQGWKHHPXODWRUXVHGIRUUXQQLQJWKHDSSOLFDWLRQUHGXFLQJWKHFKDQFH
IRUDPLVPDWFKEHWZHHQWKHUXQWLPHHQYLURQPHQWDQDSSOLFDWLRQFRPSLOHGDJDLQVWWKH
$QGURLGOLEUDULHVPD\QRWUXQRQDSODWIRUP
Projects
)RUVRIWZDUHGHYHORSHUV(FOLSVHSURMHFWVFRUUHVSRQGWRSURJUDPVWKH\DUHGHYHORSLQJ
)RU$QGURLGVRIWZDUHGHYHORSHUVWKH\FRUUHVSRQGWR$QGURLGDSSOLFDWLRQV:LWKLQ
(FOLSVHSURMHFWVDUHKRZ(FOLSVHSOXJLQVNQRZZKLFKVRIWZDUHWRRSHUDWHRQZKHQ
\RXFUHDWHDQ$QGURLGSURMHFWWKHSURMHFWGDWDLQFOXGHVLQIRUPDWLRQWKDW(FOLSVHXVHV
WRVHOHFWFRGHIURPYDULRXVSOXJLQVWRSHUIRUPYDULRXVRSHUDWLRQV7KH$'7SOXJLQV
DUHLQYRNHGWRKHOSFUHDWHDSURMHFWZLWKWKHULJKWVHWRIILOHVDQGGLUHFWRU\VWUXFWXUHIRU
DQ$QGURLGDSSOLFDWLRQ:KHQ\RXZRUNRQWKHILOHVLQDQ$QGURLGSURMHFWWKHULJKW
HGLWRUVDUHXVHGZKHQ\RXRSHQ;0/ILOHVVXFKDVOD\RXWVDQGWKHPDQLIHVW:KHQ\RX
PRGLI\ILOHVLQDSURMHFWWKHULJKWEXLOGHUVDUHFDOOHGWREXLOGWKHDSSOLFDWLRQ
Builders and Artifacts
7KH(FOLSVHIUDPHZRUNGHILQHVWKHFRQFHSWRID£EXLOGHU¤XVHGWRJHQHUDWHSURMHFW
DUWLIDFWV IURP WKHLU VRXUFHV $UWLIDFWV DUH ILOHV EXLOW IURP VRXUFH ILOHV 7KH $QGURLG
(FOLSVHSOXJLQGHILQHVVHYHUDOQHZEXLOGHUVWKDWFUHDWHGH[ILOHVIURPFODVVILOHVFUHDWH
-DYDFRQVWDQWVWKDWLGHQWLI\UHVRXUFHVVSHFLILHGLQ;0/FUHDWHDSNILOHVDQGSHUIRUP
RWKHU$QGURLGVSHFLILFRSHUDWLRQVWKDWDUHSDUWRIWXUQLQJFRGHLQWRDQLQVWDOODEOHSDFN
DJH(FOLSVHZLOOUHJHQHUDWHWKHLQVWDOODEOHDSSOLFDWLRQZKHQHYHU\RXPDNHFKDQJHV
<RXVKRXOGDOZD\VEHDEOHWRUXQLWRUGHEXJLW
7KHWUDQVIRUPDWLRQRIFODVVILOHVZKLFKDUHWKHRXWSXWRIWKH-DYDFRPSLOHUWRGH[
ILOHVZKLFKDUHE\WHFRGHLQWHUSUHWHGE\WKH'DOYLNYLUWXDOPDFKLQH 90 LVDQHDWWULFN
LWHQDEOHV\RXWRSURJUDPLQ-DYDXVLQJWKHYHU\KLJKO\GHYHORSHGHGLWLQJDQGUHIDF
WRULQJWRROVDVZHOODVQXPHURXVRWKHUWRROVFUHDWHGWRHQKDQFHWKHSURGXFWLYLW\DQG
UHOLDELOLW\RI-DYDFRGLQJ
Extensions
([WHQVLRQVDUHDOOWKHSODFHVZKHUHDSOXJLQH[WHQGV(FOLSVHIXQFWLRQDOLW\<RXZRQ¦W
PDQLSXODWHRUFKDQJHH[WHQVLRQVDVDQ$QGURLGVRIWZDUHGHYHORSHUEXWZKLOHZHKDYH
WKDW3OXJLQVYLHZRSHQOHW¦VWDNHDEULHIORRNDWVRPHRIWKHH[WHQVLRQVWKH$QGURLG
SOXJLQVDGG7KLVZLOOJLYH\RXDPRUHFRQFUHWHLGHDRIWKHUHODWLRQVKLSRIWKH$'7
SOXJLQV DQG WKH UHVW RI WKH (FOLSVH V\VWHP ,Q WKH 3OXJLQV YLHZ DV VKRZQ LQ )LJ
XUHGRXEOHFOLFNRQWKHSOXJLQQDPHGcom.android.ide.eclipse.adtDQG\RXZLOO
VHHDQ([WHQVLRQVYLHZOLVWLQJWKHH[WHQVLRQVLQWKHSOXJLQDVVKRZQLQ)LJXUH
)RU H[DPSOH \RX FDQ VHOHFW HDFK H[WHQVLRQ QDPHG org.eclipse.core.resources
.buildersDQGRQWKHULJKWVLGHRIWKH([WHQVLRQVYLHZLWZLOOVKRZ\RXWKHH[WHQVLRQ
QDPHV $QGURLG 5HVRXUFH 0DQDJHU $QGURLG 3UH &RPSLOHU DQG $QGURLG 3DFNDJH
Eclipse Concepts and Terminology | 115
)LJXUH$OLVWRIH[WHQVLRQVLQWKH$'7SOXJLQ
%XLOGHU7KHVHDUHWKHH[WHQVLRQVQHHGHGWRSURFHVV$QGURLGUHVRXUFHVSUHFRPSLOH
$,'/ $QGURLG,QWHUIDFH'HILQLWLRQ/DQJXDJH ZKLFKLVGHVFULEHGLQ&KDSWHULQWR
-DYDFRGHDQGWXUQFODVVILOHVZKLFKDUHFUHDWHGXVLQJWKH-DYDEXLOGHULQWRGH[ILOHV
DVZHOODVEXLOGWKHDSNILOHZKLFKFDQEHGHSOR\HGWRDQ$QGURLGGHYLFHRU$9'
,I\RXH[SDQGWKH org.eclipse.ui.editorsLWHP\RXZLOOVHHDOLVWRIWKHHGLWRUVWKH
$'7SOXJLQDGGVWRWKH(FOLSVHV\VWHPWKH$QGURLG0DQLIHVW(GLWRU$QGURLG5H
VRXUFH(GLWRU$QGURLG/D\RXW(GLWRU$QGURLG0HQX(GLWRUDQG$QGURLG;0/5H
VRXUFHV(GLWRU7KHUHDUHPDQ\RWKHUH[WHQVLRQVLQWKLVOLVWDQGWKLVVKRXOGJLYH\RX
DQLGHDRIWKHDPRXQWRIFRGHWKDWLVUHTXLUHGWRWXUQ(FOLSVHLQWRDWRROIRU$QGURLG
VRIWZDUHGHYHORSPHQW7KHRQHVZH¦YHH[SORUHGKHUHDUHHQRXJKWRUHYHDOVRPHRIWKH
PRVWLPSRUWDQWDVSHFWVKRZ$QGURLGSURJUDPVJHWEXLOWDQGZKDWLVDGGHGWRWKH
116 | Chapter 5:ಗEclipse for Android Software Development
Download from Wow! eBook <www.wowebook.com>
(FOLSVHHQYLURQPHQWWRKHOS\RXHGLW$QGURLGVSHFLILFILOHV¢LQFOXGLQJWKH;0/ILOHV
WKDWFRPSULVHWKHPDQLIHVWOD\RXWVDQGRWKHUUHVRXUFHV
,I\RXH[SORUHWKHRWKHU$'7SOXJLQVLPLODUO\\RXZLOOVHHKRZ'DOYLN'HEXJ0RQLWRU
6HUYLFH ''06 IHDWXUHVDUHDGGHGWR(FOLSVH
Associations
$VVRFLDWLRQVDUHKRZILOHVZLWKLQDSURMHFWDUHDVVRFLDWHGZLWKDPRQJRWKHUWKLQJVWKH
HGLWRUVWKDWRSHUDWHRQWKHP)RUH[DPSOH-DYDILOHVZLWKLQDQ$QGURLGSURMHFWDUH
HGLWHGZLWKWKH-DYDHGLWRUWKHVDPHDVDQ\-DYDSURMHFWEXW;0/ILOHVDUHHGLWHGZLWK
DQ$QGURLGVSHFLILF;0/HGLWRUZKLFKFRXOGEHWKH$QGURLG0DQLIHVW(GLWRURUWKH
$QGURLG5HVRXUFH(GLWRU7KHVHHGLWRUVNQRZKRZWRHGLWVSHFLILFVWUXFWXUHVLQWKHVH
ILOHVEXWWKH\IDOOVKRUWLQRWKHUDUHDVVXFKDVJHQHUDOSXUSRVHVWUXFWXUHHGLWLQJZLWK
WKH2XWOLQHYLHZ,I\RXZDQWHGWRRSHQDQ$QGURLG;0/ILOHZLWKDQ;0/HGLWRURWKHU
WKDQWKHRQHWKHDVVRFLDWLRQIRUWKHILOHFDOOVIRU\RXFDQRYHUULGHDVVRFLDWLRQVZLWKWKH
2SHQ:LWKFRPPDQGLQWKHFRQWH[WPHQXIRUDVRXUFHILOHZKLFKSRSVXSZKHQ\RX
ULJKWFOLFNRQWKHILOHLQWKH3DFNDJH([SORUHUYLHZ
7KH2SHQ:LWKFRPPDQGVKRZV\RXDFKRLFHRIHGLWRUVWKDWDUHOLNHO\WRZRUNRQWKH
ILOH\RXVHOHFWHG,I\RXVHOHFWWKH2WKHURSWLRQ\RXZLOOVHHDOLVWRIDOOHGLWRUVLQ\RXU
(FOLSVHFRQILJXUDWLRQDQGEHRIIHUHGWKHRSWLRQRIRSHQLQJWKHVHOHFWHGILOHZLWKDQ
H[WHUQDOSURJUDP
Eclipse Views and Perspectives
,QDGGLWLRQWRXQGHUVWDQGLQJWKHZD\WKH$'7SOXJLQVPRGLI\(FOLSVHVRPHIDPLOLDULW\
ZLWK(FOLSVH¦VV\VWHPRIYLHZVDQGSHUVSHFWLYHVZLOOKHOS\RXUHFRJQL]HZKDW\RXDUH
ORRNLQJDWZKHQ\RXXVH(FOLSVHLQ$QGURLGVRIWZDUHGHYHORSPHQW$Q(FOLSVHYLHZLV
DSDUWRIWKH(FOLSVHZLQGRZWKDWGLVSOD\VLQIRUPDWLRQRIDFHUWDLQW\SHRULQDFHUWDLQ
ZD\DOLVWRISURMHFWVDQGSURMHFWILOHVDOLVWRIHUURUVLQFRGHDKLHUDUFKLFDOYLHZRI
HQWLWLHVLQDFODVVDQGVRRQ$SHUVSHFWLYHLVDQDUUDQJHPHQWRIYLHZVGHVLJQHGIRUD
SDUWLFXODUSXUSRVHVXFKDVHGLWLQJ-DYDRUGHEXJJLQJ
,I \RXU (FOLSVH HQYLURQPHQW GRHV QRW UHVXOW LQ WKH VDPH VHW RI YLHZV VKRZQ LQ WKH
H[DPSOHVKHUHRUOLVWHGDPRQJWKHPDLQYLHZVGRQ¦WEHDODUPHG'LIIHUHQWVHWVRISOXJ
LQVFDQUHVXOWLQGLIIHUHQWEHKDYLRULQFOXGLQJWKHVHWRIGHIDXOWYLHZVLQVRPHSHUVSHF
WLYHV7KHPRVWLPSRUWDQWSHUVSHFWLYHVIRU-DYDFRGLQJDUHWKH3DFNDJH([SORUHU(GLWRU
DQG2XWOLQHYLHZVDQGWKRVHVKRXOGEHSUHVHQWLQ\RXU(FOLSVHHQYLURQPHQW
:KHQ\RXILUVWVWDUW(FOLSVH DIWHU\RXJHWSDVWWKH:HOFRPHVFUHHQ EXWEHIRUH\RX
KDYHFUHDWHGDQ\SURMHFWV\RXVKRXOGVHHVRPHWKLQJVLPLODUWR)LJXUH
7KHZRUNVSDFH SLFWXUHG KHUH LV D OLWWOH PRUHFUDPSHGWKDQZKDW\RXZLOOSUREDEO\
H[SHULHQFH0RVWFRGHUVXVHODUJHUVFUHHQVLQRUGHUWRVHHWKHLQIRUPDWLRQLQWKHYLHZV
VXUURXQGLQJ WKH HGLWRU WKDW JRHV LQ WKH PLGGOH RI DQ (FOLSVH SHUVSHFWLYH DQG OHDYH
Eclipse Views and Perspectives | 117
)LJXUH$QHPSW\ZRUNVSDFHZLWKWKH$'7SOXJLQFRQILJXUHG
HQRXJKURRPWRVHHDQDGHTXDWHDPRXQWRIFRGH:HOHIWWKHVHSHUVSHFWLYHVDWWKH
GHIDXOWPLQLPXPVL]HLQRUGHUWRILWWKHVFUHHQVKRWVRQWKHSDJH
$W\SLFDO-DYDHGLWLQJSHUVSHFWLYHLQ(FOLSVHORRNVOLNHWKHRQHLQ)LJXUHZLWKYLHZV
IRUH[SORULQJWKHFRQWHQWVRISURMHFWVDOLVWRIWDVNVWKHRXWSXWRIEXLOGHUVDQGRWKHU
RSHUDWLRQVDQGVRRQ<RXFDQVHHWKDWVRPHFKDQJHVIURPWKHGHIDXOWVHWRIYLHZV
ZHUHPDGHLQFUHDWLQJDQ$QGURLGSURMHFWDQGHGLWLQJD-DYDVRXUFHILOHLQDQ$QGURLG
SURMHFW/HW¦VWDNHDORRNDWWKHYLHZVWKDWDUHGLVSOD\HGE\GHIDXOWKHUH
The Package Explorer View
(FOLSVHLVPRUHWKDQMXVWDQHGLWRUZLWKDORWRIFKURPHDURXQGWKHHGLWLQJZLQGRZ
0RVWRIWKHYLHZVGLVSOD\HGDURXQGWKHHGLWRULQDQ(FOLSVHSHUVSHFWLYHKDYHWKHJRDO
RIVSHHGLQJQDYLJDWLRQLQWKHSURMHFWDQGLQWKHSURMHFW¦VILOHV7KH3DFNDJH([SORUHU
YLHZZLOORIWHQEH\RXUVWDUWLQJSRLQWZKHQHGLWLQJVRXUFHILOHVDQGUXQQLQJDQGGH
EXJJLQJ\RXUSURMHFWV
The Task List View
7KH7DVN/LVWYLHZOLVWVWDVNVWKDW\RXPD\KDYHFUHDWHGXVLQJWKH1HZ7DVNFRPPDQG
LQWKHYLHZ¦VWRROEDURUE\WXUQLQJDQLWHPLQWKH3UREOHPVYLHZLQWRDWDVN<RXFDQ
118 | Chapter 5:ಗEclipse for Android Software Development
)LJXUH7KH-DYDHGLWLQJSHUVSHFWLYHZLWKDQ$QGURLGSURMHFWDQGDQ$QGURLGVRXUFHILOHLQWKH
-DYDHGLWRU
OLQNWKHWDVNOLVWZLWKDVRXUFHFRGHUHSRVLWRU\RUEXJWUDFNHULQRUGHUWRVKDUHLWZLWK
RWKHUSHRSOHZRUNLQJRQDSURMHFWZLWK\RX&XULRXVO\WKH7DVN/LVWYLHZGRHVQRWOLVW
WKHTODOLWHPVPDQ\FRGHUVXVHWRLQVHUWWDVNUHPLQGHUVLQWRFRGH7KHVHDUHSDUVHGE\
WKH-DYDHGLWRUDQGDUHPDUNHGZLWKLFRQVLQWKHOHIWPDUJLQ7KHUHPD\EHVRPHWKLQJ
DERXWWKHLPSOHPHQWDWLRQRIWKHSOXJLQVWKDWLPSOHPHQWWKHVHIHDWXUHVWKDWPDNHVLW
GLIILFXOWWRSUHVHQWDOOWDVNVLQRQHSODFH
The Outline View
$SURJUDPLVERWKLWVVRXUFHFRGH¢ZKLFKLVXVXDOO\RUGLQDU\WH[W¢DQGWKHVWUXFWXUH
LQWRZKLFKLWLVSDUVHGZKLFKFRQVLVWVLQWKHFDVHRI-DYDRIILHOGVDQGPHWKRGV7KH
2XWOLQHYLHZVKRZVWKHVWUXFWXUHRID-DYDFODVVDQGHQDEOHV\RXWRRSHUDWHRQWKDW
VWUXFWXUHZLWKPDQ\RIWKHVDPHFRPPDQGV\RXZRXOGDSSO\WRWKHVHOHFWLRQLQDQ
(GLWRUYLHZ7KH-DYDHGLWRUUHOLHVRQNQRZLQJWKHXQGHUO\LQJVWUXFWXUHWRR%XWWKH
2XWOLQHYLHZHQDEOHV\RXWRVHHWKDWVWUXFWXUHH[SOLFLWO\ODLGRXWLQDKLHUDUFK\ZLWK
LFRQVWKDWLQGLFDWHW\SHDQGVFRSHLQIRUPDWLRQWRWKHOHIWRIWKHQDPHRIHDFKLWHPLQ
WKLVVWUXFWXUHGYLHZ0RUHLQIRUPDWLRQRQWKH2XWOLQHYLHZLVDYDLODEOHDWKWWSKHOS
HFOLSVHRUJKHOLRVWRSLFRUJHFOLSVHMGWGRFXVHUUHIHUHQFHYLHZVUHIYLHZRXWOLQHKWP
Eclipse Views and Perspectives | 119
The Problems View
7KH(FOLSVHFRQFHSWRI£EXLOGHUV¤JHQHUDOL]HVWKHLGHDRIFRPSLOLQJVRXUFHILOHVLQWR
REMHFWVRUPRUHJHQHUDOO\LQ(FOLSVHSDUODQFHDUWLIDFWV3UREOHPVDUHZKDWSUHYHQWWKLV
IURPKDSSHQLQJVPRRWKO\3UREOHPVFDQEHFRPSLOHUHUURUVRUDQ\RWKHUHUURUIURPD
EXLOGHU6RPHWLPHVSUREOHPVSUHYHQWDEXLOGHUIURPFRPSOHWLQJDQDUWLIDFWDQGVRPH
WLPHV WKH\ DUH ZDUQLQJV WKDW GR QRW SUHYHQW DQ DUWLIDFW IURP EHLQJ JHQHUDWHG 7KH
3UREOHPVYLHZGLVSOD\VSUREOHPVDQGHQDEOHVIDVWQDYLJDWLRQWRWKHP5LJKWFOLFNRQ
DSUREOHPWRVHHWKHFRQWH[WPHQXLI\RXZDQWWRIL[WKHSUREOHPULJKWDZD\WKH*R
7RFRPPDQGRSHQVWKHILOHDQGQDYLJDWHVWRWKHOLQHDVVRFLDWHGZLWKWKHSUREOHP,ILW
LVDZDUQLQJWKDWVKRXOGHYHQWXDOO\EHIL[HG\RXFDQWUDFNWKHSUREOHPE\XVLQJWKH
1HZ7DVN)URP0DUNHUšFRPPDQG'RXEOHFOLFNLQJRQDSUREOHPDOVRQDYLJDWHVWR
WKHVRXUFHRIWKHSUREOHP
Java Coding in Eclipse
,I\RXDUHQHZWR-DYDDQG(FOLSVH\RXUILUVWFRQFHUQZLOOEHJHWWLQJWKLQJVULJKW%XW
VRRQHQRXJK\RXUSULPDU\FRQFHUQZLOOEHPDNLQJFRGLQJIDVWDQGHDV\2IDOOSUR
JUDPPLQJODQJXDJHV-DYDKDVOLNHO\KDGWKHPRVWHIIRUWDSSOLHGWRERRVWLQJSURJUDP
PHUSURGXFWLYLW\WKURXJKWRROVOLNH(FOLSVH)RUWKLVUHDVRQWKHVWRU\RI-DYDFRGLQJLQ
(FOLSVH LV D VWRU\ GULYHQ E\ WKH GHVLUH IRU WKH KLJKHVW SRVVLEOH OHYHO RI SURGXFWLYLW\
3URGXFWLYLW\KDVWKUHHNH\DVSHFWVFUHDWLQJQHZFRGHHIILFLHQWO\ILQGLQJFRGH\RXQHHG
WRUHDGRUPRGLI\DQGPDNLQJFKDQJHVWRFRGHWKDWDIIHFWPRUHWKDQMXVWWKHOLQHRI
FRGH\RXDUHHGLWLQJ
Editing Java Code and Code Completion
7KHFHQWUDOSURGXFWLYLW\IHDWXUHIRUHGLWLQJ-DYDFRGHLQDQ\-DYDRULHQWHG,'(LVFRGH
FRPSOHWLRQRULQ(FOLSVHSDUODQFH£FRQWHQWDVVLVW¤1HDUO\DQ\ZKHUHLQD-DYDVRXUFH
ILOH\RXFDQSUHVVWKHNH\ERDUGVKRUWFXW&WUOVSDFHEDUWRGLVSOD\DSRSXSWKDW£SUR
SRVHV¤WRFRPSOHWHZKDW\RXDUHFXUUHQWO\GRLQJ)RUH[DPSOHLI\RXNQRZWKHUHLVD
PHWKRGWRILQGVRPHWKLQJEXW\RXIRUJRWH[DFWO\KRZWKDWJRHVW\SHfiDQGSUHVV&WUO
VSDFHEDU<RXZLOOWKHQVHHVRPHWKLQJVLPLODUWR)LJXUH
,QWKLVFDVHFRQWHQWDVVLVWLVRIIHULQJWRLQVHUWWKHVLJQDWXUHRIDPHWKRGZLWKDSD
UDPHWHUOLVWIRU\RXWRILOOLQ<RXFDQVHHWKDWWKHPHWKRG findViewByIdLVOLVWHGDQG
\RXFDQVHOHFWWKLVFKRLFHLQRUGHUWRDYRLGKDYLQJWRW\SHWKHZKROHPHWKRGQDPHDQG
DUJXPHQWOLVW
+DG\RXSUHVVHG&WUOVSDFHEDUEHIRUHKDYLQJW\SHGDQ\WKLQJDOOWKHFRQVWDQWVDQG
PHWKRGVRIWKHFODVVZRXOGKDYHEHHQRIIHUHGDVSRVVLEOHFRPSOHWLRQVE\FRQWHQWDVVLVW
120 | Chapter 5:ಗEclipse for Android Software Development
)LJXUH2IIHULQJDFRPSOHWLRQLQWKHFRQWHQWDVVLVWSRSXS
Refactoring
-DYDLVVWDWLFDOO\W\SHGZKLFKUHTXLUHVHYHU\REMHFWDQGHYHU\UHIHUHQFHWREHH[SOLFLWO\
GHFODUHGEHIRUHLWLVXVHG7KLVFDQPDNH-DYDORRNEXUHDXFUDWLFDQGLQHOHJDQWDQG
PDNHLWVHHPDVWKRXJKFRGLQJLQ-DYDLVQHHGOHVVO\ZRUG\,'(VOLNH(FOLSVHFRPSHQ
VDWHIRUWKHYHUERVLW\RI-DYDV\QWD[E\SURYLGLQJFRGHFRPSOHWLRQDQGRWKHUVSHHGXSV
IRUFRGHUV7KHUHLVRQHDVSHFWRIFRGLQJSURGXFWLYLW\WKDWZRUNVIDUEHWWHULQVWDWLFDOO\
W\SHGODQJXDJHVUHIDFWRULQJ
5HIDFWRULQJPHDQVPDNLQJFKDQJHVWKDWSUHVHUYHSURJUDPEHKDYLRU7KDWLVUHIDFWRULQJ
GRHVQRWFKDQJHZKDWWKHSURJUDPGRHV,WFKDQJHVKRZWKHSURJUDPLVRUJDQL]HG
(QVXULQJWKDWEHKDYLRUGRHVQRWFKDQJHZKLOHFRGHLVUHRUJDQL]HGHQDEOHVSRZHUIXO
WUDQVIRUPDWLRQVHYHQUHQDPLQJDUHIHUHQFHRUW\SHQDPHFDQEHSHULORXVLI\RXKDYH
WRGRLWZLWKWH[WVXEVWLWXWLRQ%XWZLWKUHIDFWRULQJ\RXDUHDVVXUHGWKDWDOODQGRQO\
WKHULJKWQDPHVDUHPRGLILHG
7ZRIDFWRUVJUHDWO\LPSURYHWKHNLQGVRIUHIDFWRULQJVWKDWFDQEHSHUIRUPHGWKHODQ
JXDJHVKRXOGEHVWDWLFDOO\W\SHGDQGWKH,'(VKRXOGKDYHDFRPSLOHGPRGHORIWKH
SURJUDP%\£PRGHORIWKHSURJUDP¤ZHPHDQDGDWDVWUXFWXUHWKDWUHSUHVHQWVFRP
SLOHGFRGHVXFKWKDWDOOWKHW\SHVDQGUHIHUHQFHVLQWKHSURJUDPFDQEHIRXQGZLWKLQ
WKHLUVFRSH%\NQRZLQJH[DFWW\SHVDQGWKHH[DFWVFRSHRIDW\SHRUUHIHUHQFHWKH,'(
FDQORFDWHHYHU\XVHRIWKDWW\SHRUUHIHUHQFHZLWKRXWDQ\DPELJXLW\
Java Coding in Eclipse | 121
5HIDFWRULQJLVWKHSULPHH[DPSOHRIKRZODQJXDJHVFDQQRORQJHUEHFRPSDUHGRQO\E\
V\QWD[DHVWKHWLFVDQGH[SUHVVLYHSRZHU&RQVHUYDWLYHO\GHVLJQHGODQJXDJHVOLNH-DYD
FDQEHERWKDVVDIHDVSRVVLEOHDQGKLJKO\SURGXFWLYHLQWKHFRQWH[WRIWKHW\SLFDOVHW
RIWRROVDFRGHUKDVDWKHUILQJHUWLSV
Eclipse and Android
7KH$'7SOXJLQDGGVVHYHUDO$QGURLGVSHFLILFWRROVWRWKH(FOLSVHZRUNEHQFK0RVW
RI WKHVH WRROV FDQ EH IRXQG LQ WKH $QGURLG SHUVSHFWLYH :LQGRZൺ2SHQ 3HUVSHF
WLYHൺ2WKHU VHOHFW ''06 (DFK WRRO LV D VHSDUDWH (FOLSVH YLHZ :LQGRZൺ6KRZ
9LHZൺ2WKHUVHOHFW''06 WKRXJKDQGFDQEHDGGHGWRDQ\RWKHUSHUVSHFWLYHDV
FRQYHQLHQFHDQGVFUHHQUHDOHVWDWHGLFWDWH+HUHDUHDIHZRIWKHPRVWXVHIXO
LogCat
'LVSOD\VWKHGHYLFHORJVLQDVFUROOLQJSDQH<RXFDQDGMXVWILOWHULQJVRWKDWRQO\
WKHORJV\RXDUHLQWHUHVWHGLQDUHYLVLEOHRUVRWKDW\RXFDQVHHHYHU\WKLQJGRZQWR
WKHJDUEDJHFROOHFWLRQVDQGOLEUDU\ORDGLQJ
File Explorer
'LVSOD\VWKHILOHH[SORUHU
Heap
'LVSOD\VWKHKHDS
Threads
'LVSOD\VWKUHDGV
Pixel Perfect
'LVSOD\VWKH3L[HO3HUIHFWYLHZ
Layout View
'LVSOD\VWKHOD\RXWYLHZ
avdmgr
'LVSOD\VWKH$QGURLG6'.DQG$9'0DQDJHU
Preventing Bugs and Keeping Your Code Clean
<RXFDQWKLQNRI(FOLSVHDVDVSHFLDOL]HGRSHUDWLQJV\VWHPLWLVPDGHXSRIWKRXVDQGV
RIILOHVKDVLWVRZQILOHV\VWHPDQGUXQVDZHEVHUYHU(FOLSVHLVRSHQDQGYHU\H[WHQ
VLEOH3OXJLQV¢WKH(FOLSVHDQDORJRIDQRSHUDWLQJV\VWHP¦VDSSOLFDWLRQV¢DUHUHODWLYHO\
HDV\WRZULWHDQGWKH(FOLSVHHFRV\VWHPKDVPDQ\PRUHH[WHQVLRQVWKDQDQ\RQH(FOLSVH
XVHUFRXOGHYHULQVWDOODQGXVH%HFDXVH$QGURLGFRGHLVZULWWHQLQ-DYD\RXFDQDSSO\
DOONLQGVRISOXJLQVWR$QGURLGVRIWZDUHGHYHORSPHQW
+HUHZHZLOOH[SORUHDQRIWHQYHU\YDOXDEOHFDWHJRU\RI(FOLSVHH[WHQVLRQVVWDWLFDQD
O\]HUVRUVRXUFHFRGHDQDO\]HUV
122 | Chapter 5:ಗEclipse for Android Software Development
Static Analyzers
$QLQIRUPDOGHILQLWLRQRIVWDWLFDQDO\VLVLVWKDWLWSLFNVXSZKHUHFRPSLOHUZDUQLQJV
OHDYHRII,Q(FOLSVHFRPSLOHUZDUQLQJVDUHLQJHQHUDOYHU\JRRG:KLOHDJRRGFRP
SLOHU FDQ SURYLGH \RX ZLWK ZDUQLQJ PHVVDJHV WKDW DUH KHOSIXO LQ FDWFKLQJ SRWHQWLDO
UXQWLPHSUREOHPVLWLVQ¦WDFRPSLOHU¦VMREWRJRKXQWLQJIRUKLGGHQSUREOHPV6WDWLF
DQDO\]HUVFRYHUWKDWWHUULWRU\
6WDWLFDQDO\]HUVDUHFDOOHG£VWDWLF¤EHFDXVHWKHDQDO\VLVLVSHUIRUPHGRQFRGHWKDWLVQ¦W
UXQQLQJ :KLOH WKH FRPSLOHU SHUIRUPV VRPH IXQFWLRQV WKDW PLJKW FRPH XQGHU WKH
KHDGLQJRIVWDWLFDQDO\VLV¢DQGWKH-DYDFRPSLOHULQ(FOLSVHGRHVDYHU\JRRGMRERI
FOHDQLQJXSDIWHUWKHGHWULWXVRISURJUDPPLQJVXFKDVYDULDEOHVDQGPHWKRGVWKDWDUH
QRWXVHG¢VWDWLFDQDO\]HUVDUHPRUHDPELWLRXV6WDWLFDQDO\]HUVDWWHPSWWRILQGEXJV
UDWKHUWKDQMXVWORRVHHQGV
7KH WKUHH VWDWLF DQDO\VLV WRROV FRYHUHG KHUH DUH WKH WKUHH PRVW ZLGHO\ XVHG LQ -DYD
VRIWZDUHGHYHORSPHQWDQGWKH\LQFOXGHDUDQJHRIDSSOLFDELOLW\DQGDSSURDFKHVWRWKH
SUREOHPRIVWDWLFDQDO\VLV$OOWKUHHRIWKHVHWRROVDUHDOVRRSHQVRXUFHSURMHFWVDQGDOO
WKUHHDUHH[DPSOHVRIWKHNLQGVRI(FOLSVHSOXJLQV\RXPLJKWVHHNRXWDQGDGGWR\RXU
(FOLSVHHQYLURQPHQWWRHQKDQFHSURGXFWLYLW\LQFUHDWLQJ$QGURLGDSSOLFDWLRQV<RX
PD\QRWVWLFNZLWKXVLQJDOOWKUHHEXWLQVWDOOLQJDOOWKUHHLVDJRRGSODFHWRVWDUWH[
SORULQJVWDWLFDQDO\VLV
FindBugs
:HZLOOVWDUWH[SORULQJVWDWLFDQDO\]HUVE\LQVWDOOLQJDQGXVLQJ)LQG%XJV<RXFDQILQG
GRFXPHQWDWLRQDVZHOODVWKHVRXUFHFRGHIRU)LQG%XJVDWKWWSILQGEXJVVRXUFHIRUJH
QHW:HZLOOJRLQWRWKHLQVWDOODWLRQSURFHVVLQVRPHGHWDLOEHFDXVHLWLVVLPLODUWRWKH
LQVWDOODWLRQSURFHVVIRUPRVWNLQGVRI(FOLSVHSOXJLQV7RLQVWDOO)LQG%XJV\RXPXVW
ILUVWDGGWKH)LQG%XJVUHSRVLWRU\WR(FOLSVH¦VOLVWRIVLWHVIURPZKLFKWRLQVWDOOSDFNDJHV
<RXGRWKLVE\XVLQJWKH+HOSൺ,QVWDOO1HZ6RIWZDUH0HQXFRPPDQGDQGFOLFNLQJWKH
$GGšEXWWRQLQWKH,QVWDOOGLDORJ7KLVRSHQVWKH$GG5HSRVLWRU\GLDORJWKDWDOORZV
\RX WR DGG WKH )LQG%XJV UHSRVLWRU\ ORFDWHG DW KWWSILQGEXJVFVXPGHGXHFOLSVH DV
VKRZQLQ)LJXUH
)LJXUH$GGLQJDUHSRVLWRU\IRUWKHSXUSRVHRIDGGLQJDSOXJLQWR\RXU(FOLSVHHQYLURQPHQW
Preventing Bugs and Keeping Your Code Clean | 123
7KHQH[WVWHSLQLQVWDOOLQJ)LQG%XJVLVWRVHOHFWWKHSDFNDJHIURPWKHUHSRVLWRU\DV
VKRZQLQ)LJXUH,QWKLVFDVHWKHUHLVRQO\RQHSDFNDJHWRVHOHFW
)LJXUH6HOHFWLQJWKHRQO\DYDLODEOHSDFNDJHLQWKH)LQG%XJVUHSRVLWRU\
2QFHWKHSDFNDJHKDVEHHQVHOHFWHG\RXFDQDGYDQFHWRWKHQH[WGLDORJZKLFKVKRZV
WKHOLVWRISDFNDJHVWREHLQVWDOOHG,QWKLVFDVHWKHUH¦VRQO\RQHDVVKRZQLQ)LJXUH
124 | Chapter 5:ಗEclipse for Android Software Development
)LJXUH5HYLHZLQJWKDW\RXKDYHVHOHFWHGWKHRQO\DYDLODEOHSDFNDJHLQWKH)LQG%XJVUHSRVLWRU\
$QGWKHUH¦VPRUHWKHQH[WGLDORJLQWKHLQVWDOODWLRQVHTXHQFHHQDEOHV\RXWRUHDGDQG
DFFHSWRUQRWDFFHSWWKHOLFHQVHDJUHHPHQWWKDWDFFRPSDQLHVWKLVSDFNDJHDVVKRZQ
LQ)LJXUH
Preventing Bugs and Keeping Your Code Clean | 125
)LJXUH$FFHSWLQJWKH)LQG%XJVOLFHQVHDJUHHPHQW
7KHUH PD\ EH RQH PRUH KXUGOH WR FURVV LQ LQVWDOOLQJ WKLV (FOLSVH SOXJLQ 6LQFH WKH
SDFNDJHLVQRWVLJQHG\RXJHWDVHFXULW\ZDUQLQJDVVKRZQLQ)LJXUH
)LJXUH7KHVHFXULW\ZDUQLQJGLVSOD\HGZKHQLQVWDOOLQJXQVLJQHGSDFNDJHV
126 | Chapter 5:ಗEclipse for Android Software Development
$QGILQDOO\\RXDUHSURPSWHGWRUHVWDUW(FOLSVHDVVKRZLQ)LJXUH
)LJXUH5HVWDUWLQJ(FOLSVHDIWHULQVWDOOLQJ)LQG%XJV
Applying Static Analysis to Android Code
)LQG%XJVKDVDPHQXFRPPDQGDSHUVSHFWLYHDQGVRPHYLHZV\RXZLOOILQGXVHIXOLQ
ILQGLQJEXJV7RVWDUW)LQG%XJVXVHWKHPHQXFRPPDQGLQWKHFRQWH[WPHQXRID
SURMHFWDVVKRZQLQ)LJXUH
)LJXUH,QYRNLQJ)LQG%XJV
Preventing Bugs and Keeping Your Code Clean | 127
2QFH\RXKDYHUXQ)LQG%XJV\RXFDQFKDQJHWRWKH)LQG%XJVSHUVSHFWLYHDVVKRZQ
LQ)LJXUH7KH)LQG%XJVSHUVSHFWLYHLQFOXGHVYLHZVWKDWGLVSOD\DKLHUDUFKLFDOOLVW
RISRWHQWLDOSUREOHPV)LQG%XJVKDVIRXQGRUJDQL]HGE\W\SHRISUREOHPDQ(GLWRU
YLHZ WKDW LQFOXGHV PDUNHUV IRU WKH SUREOHPV DQG LI \RX RSHQ WKH SURSHUWLHV IRU D
SUREOHPDGHWDLOHGH[SODQDWLRQRIWKHSUREOHPLQFOXGLQJDQH[SODQDWLRQRIZK\)LQG
%XJVFDQUDLVH£IDOVHSRVLWLYHV¤
)LJXUH7KH)LQG%XJVSHUVSHFWLYH
,QWKLVFDVHZHZLOOWDNHDORRNDWWKH£1XOOFKHFNRIDYDOXHSUHYLRXVO\GHUHIHUHQFHG¤
SUREOHPDVVKRZQLQWKH%XJ([SORUHUYLHZLQ)LJXUH
128 | Chapter 5:ಗEclipse for Android Software Development
)LJXUH7KH)LQG%XJV%XJ([SORUHU
9HULI\LQJWKDWDILHOGKDVDQRQQXOOYDOXHILHOGDIWHUDOUHDG\KDYLQJGHUHIHUHQFHGLVQ¦W
V\QWDFWLFDOO\LQFRUUHFW-DYDEXWLWLVDOPRVWFHUWDLQO\HLWKHUXVHOHVVRUDQRXWULJKWHUURU
,QWKHIROORZLQJFRGH\RXFDQVHHWKDWWKHILHOGsavedStateLVXVHGZLWKWKHDVVXPSWLRQ
WKDWLWLVQHYHUQXOOEXWDQXOOFKHFNRFFXUVLQWKHORJJLQJFDOO
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
// Restore state; we know savedState is not null
String answer = savedState.getString("answer");
// This is a gratuitous test, remove it
Object oldTaskObject = getLastNonConfigurationInstance();
if (null != oldTaskObject) {
int oldtask = ((Integer) oldTaskObject).intValue();
int currentTask = getTaskId();
// Task should not change across a configuration change
assert oldtask == currentTask;
}
Log.i(TAG, "onRestoreInstanceState"
+ (null == savedState ? "" : RESTORE) + " " + answer);
}
,QIDFWsavedStateVKRXOGEHQXOOFKHFNHGEHIRUHLWLVXVHGEHFDXVHWKHYDOXHRIsaved
StateLVQRWVSHFLILHGWREHQRQQXOO:HZLOOFKDQJHWKHDVVLJQPHQWWKDWGLGQRWQXOO
WHVWsavedStateWRWKHIROORZLQJ
String answer = null != savedState ? savedState.getString("answer") : "";
5XQQLQJ)LQG%XJVDJDLQFRQILUPVWKDWWKLVFKDQJHHOLPLQDWHVWKHSRVVLEOHSUREOHP
7KLVLVDJRRGH[DPSOHRIWKHNLQGRIEXJVWDWLFDQDO\VLVFDQILQG,WLVRXWVLGHWKHUHDOP
RIFRPSLOHUZDUQLQJVEHFDXVHWKHUHDUHFDVHVZKHUHWKLVLVH[DFWO\ZKDWWKHSURJUDPPHU
LQWHQGHGEXWDVLPSOHLQIHUHQFHHQDEOHVDVWDWLFDQDO\]HUWRVXJJHVWWKDWWKLVPLJKWEH
DEXJDQGLWYHU\RIWHQLVDEXJ
Preventing Bugs and Keeping Your Code Clean | 129
Limitations of Static Analysis
6WDWLFDQDO\]HUVVXIIHUIURPGHWHFWLQJIDOVHSRVLWLYHVEHFDXVHRIWKHDSSURDFKHVWKH\
WDNHWRILQGLQJZHDNQHVVHVLQFRGH7KLVLVRQHWKLQJWKDWGLIIHUHQWLDWHVVWDWLFDQDO\VLV
IURP FRPSLOHU ZDUQLQJV ,W ZRXOG EH FRQVLGHUHG D EXJ LI D FRPSLOHU HUURU PHVVDJH
LQGLFDWHGDSUREOHPWKDWZDVQ¦WUHDOO\DSUREOHP
2QHRIWKHZHDNHUDVSHFWVRIVWDWLFDQDO\]HUVLVLQILQGLQJFRGHZKHUHFRGLQJFRQYHQ
WLRQVKDYHQRWEHHQREVHUYHG)RUH[DPSOHWKH£&ODVVQDPHVVKRXOGVWDUWZLWKDQXSSHU
FDVHOHWWHU¤ZDUQLQJVKRZQLQ)LJXUHZDVSURYRNHGE\DXWRJHQHUDWHGFRGHZKLFK
FRGHUVVKRXOGQRWKDYHWRLQVSHFWXQOHVVWKH\VXVSHFWEXJVLQWKHFRGHJHQHUDWRU
+LJKO\H[SHULHQFHGFRGHUVRIWHQTXHVWLRQWKHXVHIXOQHVVRIVWDWLFDQDO\]HUVVLQFHWKHLU
FRGHFRQWDLQVUHODWLYHO\IHZSUREOHPVWKDWVWDWLFDQDO\]HUVFDQFDWFKDQGWKHUHIRUHWKH
UHVXOWV KDYH D KLJKHU SURSRUWLRQ RI IDOVH SRVLWLYHV ,W LV DQ DFFHSWHG IDFW WKDW VWDWLF
DQDO\VLVRIFRGHZULWWHQE\KLJKO\H[SHULHQFHGFRGHUVILQGVRQO\DIUDFWLRQRIWKHEXJV
LQWKDWFRGHDQGWKDWLWLVQRVXEVWLWXWHIRUPRGXOHWHVWVDQGJRRGGHEXJJLQJVNLOOV
+RZHYHULI\RXDUHDUHODWLYHQHZFRPHUWR-DYDDVZHOODVWR$QGURLG\RXPD\ILQG
VWDWLFDQDO\]HUVDUHDYHU\XVHIXODGMXQFWWRFRPSLOHUZDUQLQJV
Eclipse Idiosyncrasies and Alternatives
1RZWKDW\RXNQRZWKDWWKH$QGURLG6'.KDVPDQ\FDSDELOLWLHVEXLOWRQ(FOLSVHDQG
KRZWKH(FOLSVHSOXJLQDQGH[WHQVLRQDUFKLWHFWXUHHQDEOHV$QGURLGWRROVWR£KRRN¤
VRPDQ\DVSHFWVRIDQ,'(¦VIXQFWLRQDOLW\\RXPD\EHZRQGHULQJZK\LWRIIHUVWRUXQ
\RXU$QGURLGDSSOLFDWLRQRQDVHUYHURUDVDQDSSOHW,WLVSDUWLFXODUO\WURXEOLQJWRKDYH
DWRROWKDWLVVXSSRVHGWRHQKDQFH\RXUSURGXFWLYLW\OD\DUHGKHUULQJDFURVV\RXUSDWK
LQWKLVZD\VLQFH(FOLSVHH[SHFWV\RXWRILQGWKHULJKWFRPPDQGVLQDVHWRIH[FHS
WLRQDOO\OHQJWK\PHQXV
*RDKHDGVHHZKDWKDSSHQVSLFNDQ\$QGURLGSURMHFWLQ\RXU(FOLSVHZRUNVSDFHULJKW
FOLFNRQWKHSURMHFWQDPHDQGVHOHFW5XQ$Vൺ-DYD$SSOHW<RXZLOOVHHWKHGLDORJVKRZQ
LQ)LJXUH
)LJXUH'LDORJVKRZQZKHQWKHVHOHFWLRQGRHVQRWFRQWDLQDQDSSOHW
130 | Chapter 5:ಗEclipse for Android Software Development
1RKDUPGRQHEXWLWLVDSSDOOLQJ(FOLSVHSOXVZKDWHYHUSOXJLQVDUHLQSOD\DWWKDW
PRPHQWVKRXOGNQRZQRWWRRIIHU\RXDQDFWLRQWKDWIDLOVJXDUDQWHHGRIWKH
WLPH(FOLSVHLVDEDGH[DPSOHGRQ¦WWUHDWWKHXVHUVRI\RXU$QGURLGSURJUDPVWKLVZD\
,IWKHVHOHFWLRQGRHVQRWFRQWDLQDQDSSOHWGRQ¦WRIIHUWKHXVHUDFRPPDQGWRUXQWKH
VHOHFWLRQDVDQDSSOHW7KLVLVDIXQGDPHQWDOSUHFHSWRIJUDSKLFDOXVHULQWHUIDFHVDQG
IRXQGDWLRQDOWRWKHLGHDRIJHQHULFRSHUDWLRQVRQDVHOHFWLRQRQFHWKHXVHUKDVVHOHFWHG
VRPHWKLQJWKHSURJUDPVKRXOGNQRZDOOWKHYDOLGRSHUDWLRQVRQWKDWVHOHFWLRQDQG
SUHVHQWRQO\YDOLGRSHUDWLRQV$JRRGLQWHUIDFH¢HVSHFLDOO\DELJFRPSOH[LQWHUIDFH¢
VKRXOGHQFRXUDJHVDIHH[SORUDWLRQ
:K\GRHV(FOLSVHIDLOWREHDJRRG*8,DSSOLFDWLRQLQVXFKVHHPLQJO\WULYLDOZD\V"6XFK
IDLOXUHLVEDIIOLQJLQOLJKWRIWKHLPSUHVVLYHSRZHUDQGHDVHRIXVHRI(FOLSVHUHIDFWRULQJ
DQGRWKHUIHDWXUHV7KHUHLVQRRQHIDXOWWRSRLQWWR2XUFRQMHFWXUHLVWKDWWKHILQH
JUDLQHGPRGXODULW\RI(FOLSVHZKLFKUHVXOWVLQDQH[SORVLRQRIH[WHQVLRQLQWHUIDFHV
FDXVHVWKLVFRPELQDWLRQRISRZHUIXOIHDWXUHVDQGQLJJOLQJDQQR\DQFHV$WEHVWSOXJ
LQDXWKRUVDUHIDFHGZLWKWRRPDQ\LQWHUIDFHVWRKRRNLQRUGHUWRDFFRPSOLVKDKLJKO\
SROLVKHGXVHUH[SHULHQFH$WZRUVW(FOLSVH¦VDUFKLWHFWXUHPD\PDNHLWSUDFWLFDOO\LP
SRVVLEOHWRGRWKHULJKWWKLQJLQVRPHFDVHV7KLVLVZK\VRPHSHRSOHVHHNDOWHUQDWLYHV
Eclipse Idiosyncrasies and Alternatives | 131
CHAPTER 6
Effective Java for Android
,Q&KDSWHUZHGLVFXVVHGWKHLGLRPDWLFXVHRI-DYD,QWKLVFKDSWHUZH¦OOH[SDQGWKDW
LGHDWROD\RXW-DYDLGLRPVSHUWLQHQWWRWKH$QGURLGSODWIRUP
The Android Framework
7ZHQW\\HDUVDJRDQDSSOLFDWLRQSUREDEO\UDQIURPWKHFRPPDQGOLQHDQGWKHEXONRI
LWVFRGHZDVXQLTXHSURJUDPORJLF7KHVHGD\VWKRXJKDSSOLFDWLRQVQHHGYHU\FRPSOH[
VXSSRUWIRULQWHUDFWLYH8,VQHWZRUNPDQDJHPHQWFDOOKDQGOLQJDQGVRRQ7KHVXS
SRUWORJLFLVWKHVDPHIRUDOODSSOLFDWLRQV7KH$QGURLG)UDPHZRUNDGGUHVVHVWKLVLQD
ZD\ WKDW KDV EHFRPH IDLUO\ FRPPRQ DV DSSOLFDWLRQ HQYLURQPHQWV KDYH EHFRPH LQ
FUHDVLQJO\FRPSOH[WKHVNHOHWRQDSSOLFDWLRQRUDSSOLFDWLRQWHPSODWH
:KHQ\RXEXLOWWKHVLPSOHGHPRDSSOLFDWLRQWKDWYHULILHG\RXU$QGURLG6'.LQVWDOOD
WLRQEDFNLQ&KDSWHU\RXFUHDWHGDFRPSOHWHUXQQLQJDSSOLFDWLRQ,WZDVDEOHWR
PDNH QHWZRUN UHTXHVWV DQG GLVSOD\ RQ DQG KDQGOH LQSXW IURP WKH VFUHHQ ,W FRXOG
KDQGOHLQFRPLQJFDOOVDQGDOWKRXJKWKHUHZDVQRZD\WRXVHLWFKHFN\RXUORFDWLRQ
<RX KDGQ¦W \HW VXSSOLHG DQ\WKLQJ IRU WKH DSSOLFDWLRQ WR GR 7KDW LV WKH VNHOHWRQ
DSSOLFDWLRQ
:LWKLQWKH$QGURLG)UDPHZRUNDGHYHORSHU¦VWDVNLVQRWVRPXFKWREXLOGDFRPSOHWH
SURJUDPDVLWLVWRLPSOHPHQWVSHFLILFEHKDYLRUVDQGWKHQLQMHFWWKHPLQWRWKHVNHOHWRQ
DWWKHFRUUHFWH[WHQVLRQSRLQWV7KHPRWWRRI0DF$SSRQHRIWKHRULJLQDOVNHOHWRQ
DSSOLFDWLRQIUDPHZRUNVZDV£'RQ¦WFDOOXVZH¦OOFDOO\RX¤,IFUHDWLQJ$QGURLGDS
SOLFDWLRQVLVODUJHO\DERXWXQGHUVWDQGLQJKRZWRH[WHQGWKHIUDPHZRUNLWPDNHVVHQVH
WRFRQVLGHUVRPHJHQHULFEHVWSUDFWLFHVIRUPDNLQJWKRVHH[WHQVLRQV
The Android Libraries
$QGURLGLQWURGXFHVVHYHUDOQHZSDFNDJHVWKDWWRJHWKHUZLWKDKDQGIXORISDFNDJHWUHHV
IURPWKHIRUHVWRIWUDGLWLRQDO-DYD -6( SDFNDJHVPDNHXSWKH$3,IRUWKH$QGURLG
5XQWLPH(QYLURQPHQW/HW¦VWDNHDPLQXWHWRVHHZKDW¦VLQWKLVFRPELQHG$3,
133
androidDQGdalvik
7KHVHSDFNDJHWUHHVFRQWDLQWKHHQWLUH$QGURLGVSHFLILFSRUWLRQRIWKH$QGURLG
5XQWLPH(QYLURQPHQW7KHVHOLEUDULHVDUHWKHVXEMHFWRIPXFKRIWKLVERRNDVWKH\
FRQWDLQWKH$QGURLG*8,DQGWH[WKDQGOLQJOLEUDULHV QDPHG android.graphics
android.viewandroid.widgetDQGandroid.text DVZHOODVWKHDSSOLFDWLRQIUDPH
ZRUNOLEUDULHVFDOOHG android.app android.contentDQG android.database7KH\
DOVRFRQWDLQVHYHUDORWKHUNH\PRELOHRULHQWHGIUDPHZRUNVVXFKDV android.tel
ephony DQG android.webkit $ IOXHQW $QGURLG SURJUDPPHU ZLOO KDYH WR EH YHU\
IDPLOLDUZLWKDWOHDVWWKHILUVWIHZRIWKHVHSDFNDJHV7RQDYLJDWHWKH$QGURLGGRF
XPHQWDWLRQIURPDSDFNDJHWUHHSHUVSHFWLYH\RXFDQVWDUWDWWKHWRSRIWKH$QGURLG
GHYHORSHU GRFXPHQWDWLRQ DW KWWSGHYHORSHUDQGURLGFRPUHIHUHQFHSDFNDJHV
KWPO
java
7KLVSDFNDJHFRQWDLQVWKHLPSOHPHQWDWLRQVRIWKHFRUH-DYDUXQWLPHOLEUDULHV7KH
java.langSDFNDJHFRQWDLQVWKHGHILQLWLRQRIWKHFODVVObjectWKHEDVHFODVVIRUDOO
-DYDREMHFWVjavaDOVRFRQWDLQVWKHutilSDFNDJHZKLFKFRQWDLQVWKH-DYD&ROOHF
WLRQVIUDPHZRUNArrayListsMapSetDQGIteratorDQGWKHLULPSOHPHQWDWLRQV
7KH-DYD&ROOHFWLRQV/LEUDU\SURYLGHVDZHOOGHVLJQHGVHWRIGDWDVWUXFWXUHVIRUWKH
-DYDODQJXDJH¢WKH\UHOLHYH\RXRIWKHQHHGWRZULWH\RXURZQOLQNHGOLVWV
$VPHQWLRQHGLQ&KDSWHUWKH utilSDFNDJHFRQWDLQVFROOHFWLRQVIURPWZRGLI
IHUHQWOLQHDJHV6RPHRULJLQDWHIURP-DYDDQGVRPHIURPDPRUHUHFHQWUH
HQJLQHHUHGLGHDRIFROOHFWLRQV7KHFROOHFWLRQV HJVectorDQGHashtable DUH
IXOO\V\QFKURQL]HGDQGDUHOHVVFRQVLVWHQWLQWKHLULQWHUIDFHV7KHQHZHUYHUVLRQV
HJ HashMapDQG ArrayList DUHQRWV\QFKURQL]HGDUHPRUHFRQVLVWHQWDQGDUH
SUHIHUUHG
,QRUGHUWRPDLQWDLQFRPSDWLELOLW\ZLWKWKH-DYDODQJXDJHWKH$QGURLGOLEUDU\DOVR
FRQWDLQVLPSOHPHQWDWLRQVRIVRPHOHJDF\FODVVHVWKDW\RXVKRXOGDYRLGDOWRJHWKHU
7KH&ROOHFWLRQVIUDPHZRUNIRULQVWDQFHFRQWDLQVWKHDictionaryFODVVZKLFKKDV
EHHQ H[SOLFLWO\ GHSUHFDWHG 7KH Enumeration LQWHUIDFH KDV EHHQ VXSHUVHGHG E\
IteratorDQGTimerTaskKDVEHHQUHSODFHGE\ScheduledThreadPoolExecutorIURP
WKH&RQFXUUHQF\IUDPHZRUN7KH$QGURLGUHIHUHQFHGRFXPHQWDWLRQGRHVDJRRG
MRERILGHQWLI\LQJWKHVHOHJDF\W\SHV
java DOVR FRQWDLQV EDVH W\SHV IRU VHYHUDO RWKHU IUHTXHQWO\ XVHG REMHFWV VXFK DV
Currency Date TimeZoneDQG UUIDDVZHOODVEDVLFIUDPHZRUNVIRU,2DQGQHW
ZRUNLQJFRQFXUUHQF\DQGVHFXULW\
7KH awtDQG rmiSDFNDJHVDUHDEVHQWLQWKH$QGURLGYHUVLRQRIWKH javaSDFNDJH
KLHUDUFK\7KH awtSDFNDJHKDVEHHQUHSODFHGE\$QGURLG*8,OLEUDULHV5HPRWH
PHVVDJLQJ KDV QR VLQJOH UHSODFHPHQW EXW LQWHUQDO ServiceProviders XVLQJ
Parcelables GHVFULEHG LQ £6HULDOL]DWLRQ¤ RQ SDJH SURYLGH VLPLODU
IXQFWLRQDOLW\
134 | Chapter 6:ಗEffective Java for Android
javax
7KLVSDFNDJHLVYHU\VLPLODUWRWKHjavaSDFNDJH,WFRQWDLQVSDUWVRIWKH-DYDODQ
JXDJHWKDWDUHRIILFLDOO\RSWLRQDO7KHVHDUHOLEUDULHVZKRVHEHKDYLRULVIXOO\GHILQHG
EXWWKDWDUHQRWUHTXLUHGDVSDUWRIDFRPSOHWHLPSOHPHQWDWLRQRIWKH-DYDODQJXDJH
6LQFHWKH$QGURLG5XQWLPH(QYLURQPHQWGRHVQ¦WLQFOXGHVRPHRIWKHSDUWVWKDW
DUHUHTXLUHGWKHGLVWLQFWLRQH[LVWVLQ$QGURLGRQO\WRNHHSWKH$QGURLGSDFNDJHV
ORRNLQJDVPXFKOLNHWKH-DYDSDFNDJHVDVSRVVLEOH%RWKSDFNDJHWUHHVFRQWDLQ
LPSOHPHQWDWLRQVRIOLEUDULHVGHVFULEHGDVSDUWRIWKH-DYDODQJXDJH
7KHPRVWLPSRUWDQWWKLQJWREHIRXQGLQjavaxLVWKH;0/IUDPHZRUN7KHUHDUH
ERWK6$;DQG'20SDUVHUVDQLPSOHPHQWDWLRQRI;3DWKDQGDQLPSOHPHQWDWLRQ
RI;6/7
,QDGGLWLRQWKH javaxSDFNDJHFRQWDLQVVRPHLPSRUWDQWVHFXULW\H[WHQVLRQVDQG
WKH2SHQ*/$3,$VHDVRQHG-DYDGHYHORSHUZLOOQRWLFHWKDWWKH$QGURLG5XQWLPH
(QYLURQPHQWLPSOHPHQWDWLRQRIWKH javaxSDFNDJHVLVPLVVLQJVHYHUDOLPSRUWDQW
VHFWLRQV QRWDEO\ WKRVH WKDW KDYH WR GR ZLWK 8, DQG PHGLD javax.swing
javax.soundDQGRWKHUVLPLODUVHFWLRQVDUHDOOPLVVLQJ7KHUHDUH$QGURLGVSHFLILF
SDFNDJHVWKDWUHSODFHWKHP
org.apache.http
7KLVSDFNDJHWUHHFRQWDLQVWKHVWDQGDUG$SDFKHLPSOHPHQWDWLRQRIDQ+773FOLHQW
DQGVHUYHU+WWS&RUH7KLVSDFNDJHSURYLGHVHYHU\WKLQJ\RXQHHGWRFRPPXQLFDWH
XVLQJ+773LQFOXGLQJFODVVHVWKDWUHSUHVHQWPHVVDJHVKHDGHUVFRQQHFWLRQVUH
TXHVWVDQGUHVSRQVHV
7KH$SDFKH+WWS&RUHSURMHFWFDQEHIRXQGRQWKH:HEDWKWWSKFDSDFKHRUJ
KWWSFRPSRQHQWVFRUHLQGH[KWPO
org.w3c.domorg.xml.saxorg.xmlpullDQGorg.json
7KHVH SDFNDJHV DUH WKH SXEOLF $3, GHILQLWLRQV IRU VRPH FRPPRQ GDWD IRUPDWV
;0/;0/3XOODQG-621
Extending Android
1RZWKDW\RXKDYHDEDVLFURDGPDSWRWKH$QGURLG)UDPHZRUNWKHREYLRXVTXHVWLRQ
LV£+RZGR,XVHLWWREXLOGP\DSSOLFDWLRQ"¤+RZGR\RXH[WHQGWKHIUDPHZRUN¢
ZKLFK ZH¦YH FKDUDFWHUL]HG DV YHU\ FRPSOH[ EXW D ]RPELH¢WR WXUQ LW LQWR D XVHIXO
DSSOLFDWLRQ"
$V\RXZRXOGH[SHFWWKLVTXHVWLRQKDVVHYHUDODQVZHUV7KH$QGURLGOLEUDULHVDUHRU
JDQL]HGWRDOORZDSSOLFDWLRQVWRREWDLQDFFHVVLQWRWKHIUDPHZRUNDWYDULRXVOHYHOV
Overrides and callbacks
7KHVLPSOHVWDQGHDVLHVWWRLPSOHPHQW¢DQGDFRGHU¦VILUVWFKRLFHIRUDGGLQJQHZEH
KDYLRUV WR WKH IUDPHZRUN¢VKRXOG EH WKH FDOOEDFN 7KH EDVLF LGHD RI D FDOOEDFN D
SDWWHUQTXLWHFRPPRQLQWKH$QGURLGOLEUDULHVZDVDOUHDG\LOOXVWUDWHGLQ&KDSWHU
The Android Framework | 135
7RFUHDWHDFDOOEDFNH[WHQVLRQSRLQWDFODVVGHILQHVWZRWKLQJV)LUVWLWGHILQHVD-DYD
LQWHUIDFH W\SLFDOO\ZLWKDQDPHHQGLQJLQ£+DQGOHU¤£&DOOEDFN¤RU£/LVWHQHU¤ WKDW
GHVFULEHVEXWGRHVQRWLPSOHPHQWWKHFDOOEDFNDFWLRQ,WDOVRGHILQHVDVHWWHUPHWKRG
WKDWWDNHVDVDQDUJXPHQWDQREMHFWLPSOHPHQWLQJWKHLQWHUIDFH
&RQVLGHUDQDSSOLFDWLRQWKDWQHHGVDZD\WRXVHWH[WLQSXWIURPDXVHU7H[WHQWU\
HGLWLQJDQGGLVSOD\RIFRXUVHUHTXLUHDODUJHDQGFRPSOH[VHWRIXVHULQWHUIDFHFODVVHV
$QDSSOLFDWLRQQHHGQRWFRQFHUQLWVHOIZLWKPRVWRIWKDWKRZHYHU,QVWHDGLWDGGVD
OLEUDU\ZLGJHW¢VD\DQEditText¢WRLWVOD\RXW OD\RXWVDQGZLGJHWVDUHGHVFULEHGLQ
£$VVHPEOLQJD*UDSKLFDO,QWHUIDFH¤RQSDJH 7KHIUDPHZRUNKDQGOHVLQVWDQWLDW
LQJWKHZLGJHWGLVSOD\LQJLWRQWKHVFUHHQXSGDWLQJLWVFRQWHQWVZKHQWKHXVHUW\SHV
DQGVRRQ,QIDFWLWGRHVHYHU\WKLQJH[FHSWWKHSDUW\RXUDSSOLFDWLRQDFWXDOO\FDUHV
DERXWKDQGLQJWKHFRQWHQWWH[WWRWKHDSSOLFDWLRQFRGH7KDWLVGRQHZLWKDFDOOEDFN
7KH $QGURLG GRFXPHQWDWLRQ VKRZV WKDW WKH EditText REMHFW GHILQHV WKH PHWKRG
addTextChangedListener WKDW WDNHV DV DQ DUJXPHQW D TextWatcher REMHFW 7KH
TextWatcherGHILQHVPHWKRGVWKDWDUHLQYRNHGZKHQWKHEditTextZLGJHW¦VFRQWHQWWH[W
FKDQJHV7KHVDPSOHDSSOLFDWLRQFRGHPLJKWORRNOLNHWKLV
public class MyModel {
public MyModel(TextView textBox) {
textBox.addTextChangedListener(
new TextWatcher() {
public void afterTextChanged(Editable s) {
handleTextChange(s);
}
public void beforeTextChanged(
CharSequence s,
int start,
int count,
int after)
{ }
public void onTextChanged(
CharSequence s,
int start,
int count,
int after)
{ }
});
}
}
void handleTextChange(Editable s) {
// do something with s, the changed text.
}
MyModelPLJKWEHWKHKHDUWRI\RXUDSSOLFDWLRQ,WLVJRLQJWRWDNHWKHWH[WWKDWWKHXVHU
W\SHVLQDQGGRVRPHWKLQJXVHIXOZLWKLW:KHQLWLVFUHDWHGLWLVSDVVHGDTextBoxIURP
ZKLFKLWZLOOJHWWKHWH[WWKDWWKHXVHUW\SHV%\QRZ\RXDUHDQROGKDQGDWSDUVLQJ
FRGHOLNHWKLVLQLWVFRQVWUXFWRUMyModelFUHDWHVDQHZDQRQ\PRXVLPSOHPHQWDWLRQRI
WKHLQWHUIDFHTextWatcher,WLPSOHPHQWVWKHWKUHHPHWKRGVWKDWWKHLQWHUIDFHUHTXLUHV
136 | Chapter 6:ಗEffective Java for Android
Download from Wow! eBook <www.wowebook.com>
7ZRRIWKHP onTextChangedDQG beforeTextChangedGRQRWKLQJ7KHWKLUGWKRXJK
afterTextChangedFDOOVWKHMyModelPHWKRGhandleTextChange
7KLVDOOZRUNVYHU\QLFHO\3HUKDSVWKHWZRUHTXLUHGPHWKRGVWKDWWKLVSDUWLFXODUDS
SOLFDWLRQGRHVQ¦WKDSSHQWRXVHbeforeTextChangedDQGonTextChangedFOXWWHUWKLQJV
DELW$VLGHIURPWKDWWKRXJKWKHFRGHVHSDUDWHVFRQFHUQVEHDXWLIXOO\MyModelKDVQR
LGHDKRZD TextViewGLVSOD\VWH[WZKHUHLWDSSHDUVRQWKHVFUHHQRUKRZLWJHWVWKH
WH[WWKDWLWFRQWDLQV7KHWLQ\UHOD\FODVVDQDQRQ\PRXVLQVWDQFHRITextWatcherVLPSO\
SDVVHVWKHFKDQJHGWH[WEHWZHHQWKHYLHZDQGMyModelMyModelWKHPRGHOLPSOHPHQ
WDWLRQLVFRQFHUQHGRQO\ZLWKZKDWKDSSHQVZKHQWKHWH[WFKDQJHV
7KLVSURFHVVDWWDFKLQJWKH8,WRLWVEHKDYLRUVLVRIWHQFDOOHGZLULQJXS$OWKRXJKLWLV
TXLWHSRZHUIXOLWLVDOVRTXLWHUHVWULFWLYH7KHFOLHQWFRGH¢WKHFRGHWKDWUHJLVWHUVWR
UHFHLYHWKHFDOOEDFN¢FDQQRWFKDQJHWKHEHKDYLRURIWKHFDOOHU1HLWKHUGRHVWKHFOLHQW
UHFHLYHDQ\VWDWHLQIRUPDWLRQEH\RQGWKHSDUDPHWHUVSDVVHGLQWKHFDOO7KHLQWHUIDFH
W\SH¢TextWatcherLQWKLVFDVH¢UHSUHVHQWVDQH[SOLFLWFRQWUDFWEHWZHHQWKHFDOOEDFN
SURYLGHUDQGWKHFOLHQW
$FWXDOO\ WKHUH LV RQH WKLQJ WKDW D FDOOEDFN FOLHQW FDQ GR WKDW ZLOO DIIHFW WKH FDOOLQJ
VHUYLFHLWFDQUHIXVHWRUHWXUQ&OLHQWFRGHVKRXOGWUHDWWKHFDOOEDFNDVDQRWLILFDWLRQ
RQO\DQGQRWDWWHPSWWRGRDQ\OHQJWK\LQOLQHSURFHVVLQJ,IWKHUHLVDQ\VLJQLILFDQWZRUN
WREHGRQH¢PRUHWKDQDIHZKXQGUHGLQVWUXFWLRQVRUDQ\FDOOVWRVORZVHUYLFHVVXFK
DVWKHILOHV\VWHPRUWKHQHWZRUN¢WKH\VKRXOGEHTXHXHGXSIRUODWHUH[HFXWLRQSURE
DEO\RQDQRWKHUWKUHDG:H¦OOGLVFXVVKRZWRGRWKLVLQGHSWKLQ£$V\QF7DVNDQGWKH
8,7KUHDG¤RQSDJH
%\WKHVDPHWRNHQDVHUYLFHWKDWDWWHPSWVWRVXSSRUWPXOWLSOHFDOOEDFNFOLHQWVPD\ILQG
LWVHOIVWDUYHGIRU&38UHVRXUFHVHYHQLIDOOWKHFOLHQWVDUHUHODWLYHO\ZHOOEHKDYHG:KLOH
addTextChangedListener VXSSRUWV WKH VXEVFULSWLRQ RI PXOWLSOH FOLHQWV PDQ\ RI WKH
FDOOEDFNV LQ WKH $QGURLG OLEUDU\ VXSSRUW RQO\ RQH :LWK WKHVH FDOOEDFNV setOnKey
ListenerIRULQVWDQFH VHWWLQJDQHZFOLHQWIRUDSDUWLFXODUFDOOEDFNRQDSDUWLFXODUREMHFW
UHSODFHVDQ\SUHYLRXVFOLHQW7KHSUHYLRXVO\UHJLVWHUHGFOLHQWZLOOQRORQJHUUHFHLYHDQ\
FDOOEDFNQRWLILFDWLRQV,QIDFWLWZRQ¦WHYHQEHQRWLILHGWKDWLWLVQRORQJHUWKHFOLHQW
7KHQHZO\UHJLVWHUHGFOLHQWZLOOWKHQFHIRUZDUGUHFHLYHDOOQRWLILFDWLRQV7KLVUHVWULF
WLRQLQWKHFRGHUHIOHFWVWKHYHU\UHDOFRQVWUDLQWWKDWDFDOOEDFNFDQQRWDFWXDOO\VXSSRUW
DQXQOLPLWHGQXPEHURIFOLHQWV,I\RXUFRGHPXVWIDQQRWLILFDWLRQVRXWWRPXOWLSOH
UHFLSLHQWV\RXZLOOKDYHWRLPSOHPHQWDZD\RIGRLQJLWVRWKDWLWLVVDIHLQWKHFRQWH[W
RI\RXUDSSOLFDWLRQ
7KHFDOOEDFNSDWWHUQDSSHDUVWKURXJKRXWWKH$QGURLGOLEUDULHV%HFDXVHWKHLGLRPLV
IDPLOLDUWRDOO$QGURLGGHYHORSHUVLWPDNHVDORWRIVHQVHWRGHVLJQ\RXURZQDSSOLFDWLRQ
FRGHWKLVZD\WRR:KHQHYHURQHFODVVPLJKWQHHGQRWLILFDWLRQVRIFKDQJHVLQDQRWKHU¢
HVSHFLDOO\LIWKHDVVRFLDWLRQFKDQJHVG\QDPLFDOO\DWUXQWLPH¢FRQVLGHULPSOHPHQWLQJ
WKH UHODWLRQVKLS DV D FDOOEDFN ,I WKH UHODWLRQVKLS LV QRW G\QDPLF FRQVLGHU XVLQJ
GHSHQGHQF\LQMHFWLRQ¢DFRQVWUXFWRUSDUDPHWHUDQGDILQDOILHOG¢WRPDNHWKHUHTXLUHG
UHODWLRQVKLSSHUPDQHQW
The Android Framework | 137
Using polymorphism and composition
,Q$QGURLGGHYHORSPHQWDVLQRWKHUREMHFWRULHQWHGHQYLURQPHQWVSRO\PRUSKLVPDQG
FRPSRVLWLRQDUHFRPSHOOLQJWRROVIRUH[WHQGLQJWKHHQYLURQPHQW%\GHVLJQWKHSUH
YLRXVH[DPSOHGHPRQVWUDWHVERWK/HW¦VSDXVHIRUDVHFRQGWRUHLQIRUFHWKHFRQFHSWV
DQGUHVWDWHWKHLUYDOXHDVGHVLJQJRDOV
7KHDQRQ\PRXVLQVWDQFHRITextWatcherWKDWLVSDVVHGWRaddTextChangedListenerDVD
FDOOEDFNREMHFWXVHVFRPSRVLWLRQWRLPSOHPHQWLWVEHKDYLRU7KHLQVWDQFHGRHVQRW
LWVHOILPSOHPHQWDQ\EHKDYLRU,QVWHDGLWGHOHJDWHVWRWKH handleTextChangePHWKRG
LQMyModelSUHIHUULQJKDVDLPSOHPHQWDWLRQWRLVD7KLVNHHSVFRQFHUQVFOHDUDQGVHS
DUDWH,I MyModelLVHYHUH[WHQGHGIRUH[DPSOHWRXVHWH[WWKDWFRPHVIURPDQRWKHU
VRXUFHWKHQHZVRXUFHZLOODOVRXVH handleTextChange,WZRQ¦WEHQHFHVVDU\WRWUDFN
GRZQFRGHLQVHYHUDODQRQ\PRXVFODVVHV
7KHH[DPSOHDOVRGHPRQVWUDWHVWKHXVHRISRO\PRUSKLVP7KHLQVWDQFHSDVVHGLQWR
WKHaddTextChangedListenerPHWKRGLVVWURQJO\DQGVWDWLFDOO\W\SHG,WLVDQDQRQ\PRXV
VXEW\SHRITextWatcher,WVSDUWLFXODULPSOHPHQWDWLRQ¢LQWKLVFDVHGHOHJDWLRQWRWKH
handleTextChangeLQMyModel¢LVQHDUO\FHUWDLQWREHXQOLNHDQ\RWKHULPSOHPHQWDWLRQ
RIWKDWLQWHUIDFH6LQFHLWLVDQLPSOHPHQWDWLRQRIWKHTextWatcherLQWHUIDFHWKRXJKLW
LVVWDWLFDOO\W\SHGQRPDWWHUKRZLWGRHVLWVMRE7KHFRPSLOHUFDQJXDUDQWHHWKDWWKH
addTextChangedListenerLQ EditTextLVSDVVHGRQO\REMHFWVWKDWDUHDWOHDVWLQWHQGHG
WRGRWKHULJKWMRE7KHLPSOHPHQWDWLRQPLJKWKDYHEXJVEXWDWOHDVWaddTextChanged
ListenerZLOOQHYHUEHSDVVHGVD\DQREMHFWLQWHQGHGWRUHVSRQGWRQHWZRUNHYHQWV
7KDWLVZKDWSRO\PRUSKLVPLVDOODERXW
,WLVZRUWKPHQWLRQLQJRQHSDUWLFXODUDQWLSDWWHUQLQWKLVFRQWH[WEHFDXVHLWLVVRFRP
PRQ 0DQ\ GHYHORSHUV ILQG DQRQ\PRXV FODVVHV WR EH D YHUERVH DQG FOXPV\ ZD\ RI
HVVHQWLDOO\SDVVLQJDSRLQWHUWRDIXQFWLRQ,QRUGHUWRDYRLGXVLQJWKHPWKH\VNLSWKH
PHVVHQJHUREMHFWDOWRJHWKHUOLNHWKLV
// !!! Anti-pattern warning
public class MyModel implements TextWatcher {
public MyModel(TextView textBox) {
textBox.addTextChangedListener(this);
}
public void afterTextChanged(Editable s) {
handleTextChange(s);
}
public void beforeTextChanged(
CharSequence s,
int start,
int count,
int after)
{ }
public void onTextChanged(
CharSequence s,
int start,
138 | Chapter 6:ಗEffective Java for Android
{ }
int count,
int after)
void handleTextChange(Editable s) {
// do something with s, the changed text.
}
}
6RPHWLPHVWKLVDSSURDFKPDNHVVHQVH,IWKHFDOOEDFNFOLHQW MyModelLQWKLVFDVHLV
VPDOOVLPSOHDQGXVHGLQRQO\RQHRUWZRFRQWH[WVWKLVFRGHLVFOHDUDQGWRWKHSRLQW
2QWKHRWKHUKDQGLI DVWKHQDPHMyModelVXJJHVWV WKHFODVVZLOOEHXVHGEURDGO\DQG
LQDZLGHYDULHW\RIFLUFXPVWDQFHVHOLPLQDWLQJWKHPHVVHQJHUFODVVHVEUHDNVHQFDSVX
ODWLRQDQGOLPLWVH[WHQVLRQ2EYLRXVO\LW¦VJRLQJWREHPHVV\WRH[WHQGWKLVLPSOHPHQ
WDWLRQWRKDQGOHLQSXWIURPDVHFRQGTextBoxWKDWUHTXLUHVGLIIHUHQWEHKDYLRU
1HDUO\DVEDGWKRXJKLVVRPHWKLQJFDOOHGLQWHUIDFHSROOXWLRQZKLFKKDSSHQVZKHQ
WKLVLGHDLVWDNHQWRDQH[WUHPH,WORRNVOLNHWKLV
// !!! Anti-pattern ALERT!
public class MyModel
implements TextWatcher, OnKeyListener, View.OnTouchListener,
OnFocusChangeListener, Button.OnClickListener
{
// ....
}
&RGHOLNHWKLVLVVHGXFWLYHO\HOHJDQWLQDFHUWDLQZD\DQGIDLUO\FRPPRQ8QIRUWX
QDWHO\WKRXJKMyModelLVQRZYHU\WLJKWO\FRXSOHGWRHYHU\RQHRIWKHHYHQWVLWKDQGOHV
$VXVXDOWKHUHDUHQRKDUGDQGIDVWUXOHVDERXWLQWHUIDFHSROOXWLRQ7KHUHLVDVDOUHDG\
QRWHGORWVRIZRUNLQJFRGHWKDWORRNVMXVWOLNHWKLV6WLOOVPDOOHULQWHUIDFHVDUHOHVV
IUDJLOHDQGHDVLHUWRFKDQJH:KHQDQREMHFW¦VLQWHUIDFHH[SDQGVEH\RQGJRRGWDVWH
FRQVLGHUXVLQJFRPSRVLWLRQWRVSOLWLWXSLQWRPDQDJHDEOHSLHFHV
Extending Android classes
:KLOHFDOOEDFNVSURYLGHDFOHDUZHOOGHILQHGPHDQVRIH[WHQGLQJFODVVEHKDYLRUWKHUH
DUHFLUFXPVWDQFHVLQZKLFKWKH\GRQRWSURYLGHVXIILFLHQWIOH[LELOLW\$QREYLRXVSURE
OHPZLWKWKHFDOOEDFNSDWWHUQLVWKDWVRPHWLPHV\RXUFRGHQHHGVWRVHL]HFRQWURODWVRPH
SRLQWQRWIRUHVHHQE\WKHOLEUDU\GHVLJQHUV,IWKHVHUYLFHGRHVQ¦WGHILQHDFDOOEDFN\RX¦OO
QHHGVRPHRWKHUZD\WRLQMHFW\RXUFRGHLQWRWKHIORZRIFRQWURO2QHVROXWLRQLVWR
FUHDWHDVXEFODVV
6RPHFODVVHVLQWKH$QGURLGOLEUDU\ZHUHVSHFLILFDOO\GHVLJQHGWREHVXEFODVVHG HJ
WKHBaseAdapterFODVVIURPandroid.widgetsDQGAsyncTaskGHVFULEHGVKRUWO\ ,QJHQ
HUDOKRZHYHUVXEFODVVLQJLVQRWVRPHWKLQJWKDWDGHVLJQHUVKRXOGGROLJKWO\
$VXEFODVVFDQFRPSOHWHO\UHSODFHWKHEHKDYLRURIDQ\QRQILQDOPHWKRGLQLWVVXSHUFODVV
DQGWKXVFRPSOHWHO\YLRODWHWKHFODVVDUFKLWHFWXUDOFRQWUDFW1RWKLQJLQWKH-DYDW\SLQJ
V\VWHPZLOOSUHYHQWDVXEFODVVRI TextBoxIRUH[DPSOHIURPRYHUULGLQJWKH addText
The Android Framework | 139
ChangedListenerPHWKRGVRWKDWLWLJQRUHVLWVDUJXPHQWDQGGRHVQRWQRWLI\FDOOEDFN
FOLHQWVRIFKDQJHVLQWH[WER[FRQWHQW <RXPLJKWLPDJLQHIRUH[DPSOHDQLPSOH
PHQWDWLRQRID£VDIH¤WH[WER[WKDWGRHVQRWUHYHDOLWVFRQWHQW
6XFKDYLRODWLRQRIFRQWUDFW¢DQGLWLVQ¦WDOZD\VHDV\WRUHFRJQL]HWKHGHWDLOVRIWKH
FRQWUDFW¢FDQJLYHULVHWRWZRFODVVHVRIEXJVERWKTXLWHGLIILFXOWWRILQG7KHILUVWDQG
PRUHREYLRXVSUREOHPRFFXUVZKHQDGHYHORSHUXVHVDURJXHVXEFODVVOLNHWKHVDIHWH[W
ER[GHVFULEHGHDUOLHU
6XSSRVH D GHYHORSHU FRQVWUXFWV D YLHZ FRQWDLQLQJ VHYHUDO ZLGJHWV DQG XVHV WKH add
TextChangedListener PHWKRG RQ HDFK WR UHJLVWHU IRU LWV FDOOEDFNV 'XULQJ WHVWLQJ
WKRXJKKHGLVFRYHUVWKDWVRPHZLGJHWVDUHQ¦WZRUNLQJDVH[SHFWHG+HH[DPLQHVKLV
FRGH IRU KRXUV EHIRUH LW RFFXUV WR KLP WKDW £LW¦V DV WKRXJK WKDW PHWKRG LVQ¦W GRLQJ
DQ\WKLQJ¤6XGGHQO\GDZQEUHDNVDQGKHORRNVDWWKHVRXUFHIRUWKHZLGJHWWRFRQILUP
WKDWLWKDVEURNHQWKHFODVVVHPDQWLFFRQWUDFW*UUU
0RUHLQVLGLRXVWKDQWKLVWKRXJKLVWKDWWKH$QGURLG)UDPHZRUNLWVHOIPLJKWFKDQJH
EHWZHHQ UHOHDVHV RI WKH 6'. 3HUKDSV WKH LPSOHPHQWDWLRQ RI WKH addTextChanged
ListenerPHWKRGFKDQJHV0D\EHFRGHLQVRPHRWKHUSDUWRIWKH$QGURLG)UDPHZRUN
VWDUWVWRFDOO addTextChangedListenerH[SHFWLQJQRUPDOEHKDYLRU6XGGHQO\EHFDXVH
WKHVXEFODVVRYHUULGHVWKHPHWKRGWKHHQWLUHDSSOLFDWLRQIDLOVLQVSHFWDFXODUZD\V
<RXFDQPLQLPL]HWKHGDQJHURIWKLVNLQGRISUREOHPE\FDOOLQJVXSHULPSOHPHQWDWLRQ
IRUDQRYHUULGGHQPHWKRGOLNHWKLV
public void addTextChangedListener(TextWatcher watcher) {
// your code here...
super.addTextChangedListener(watcher)
// more of your code here...
}
7KLVJXDUDQWHHVWKDW\RXULPSOHPHQWDWLRQDXJPHQWVEXWGRHVQRWUHSODFHH[LVWLQJEH
KDYLRUHYHQDVRYHUWLPHWKHVXSHUFODVVLPSOHPHQWDWLRQFKDQJHV7KHUHLVDFRGLQJ
UXOHHQIRUFHGLQVRPHGHYHORSHUFRPPXQLWLHVFDOOHG£'HVLJQIRU([WHQVLRQ¤7KHUXOH
PDQGDWHVWKDWDOOPHWKRGVEHHLWKHUDEVWUDFWRUILQDO:KLOHWKLVPD\VHHPGUDFRQLDQ
FRQVLGHUWKDWDQRYHUULGLQJPHWKRGE\GHILQLWLRQEUHDNVWKHREMHFW¦VVHPDQWLFFRQWUDFW
XQOHVVLWDWOHDVWFDOOVWKHVXSHULPSOHPHQWDWLRQ
Organizing Java Source
&KDSWHULQWURGXFHGWKHEDVLFVRIWKH$QGURLG6'.&KDSWHUQDUURZHGWKHIRFXV
ZLWK D FORVHU ORRN DW RQH RI WKH PRVW FRPPRQ WRROV IRU $QGURLG GHYHORSPHQW WKH
(FOLSVH,'(/HW¦VPRYHRQHVWHSFORVHUDQGORRNDWWKHRUJDQL]DWLRQRIFRGHZLWKLQD
SURMHFW
7RUHLWHUDWHDSURMHFWDVLQWURGXFHGLQ£3URMHFWV¤RQSDJHLVDZRUNVSDFHGHYRWHG
WRSURGXFLQJDVLQJOHGHSOR\DEOHDUWLIDFW,QWKHZLGHUZRUOGRI-DYDWKDWDUWLIDFWPLJKW
EHQRPRUHWKDQDOLEUDU\ DMDUILOHWKDWFDQQRWEHUXQE\LWVHOIEXWWKDWLPSOHPHQWV
140 | Chapter 6:ಗEffective Java for Android
VRPHVSHFLILFIXQFWLRQDOLW\ ,WPLJKWRQWKHRWKHUKDQGEHDGHSOR\DEOHZHEDSSOL
FDWLRQRUDGRXEOHFOLFNDEOHGHVNWRSDSSOLFDWLRQ
,Q WKH $QGURLG VSDFH WKH DUWLIDFW LV PRVW OLNHO\ WR EH D VLQJOH UXQQDEOH VHUYLFH D
ContentProviderDServiceRUDQActivity$FRQWHQWSURYLGHUWKDWLVXVHGE\DVLQJOH
DFWLYLW\FHUWDLQO\PLJKWVWDUWLWVOLIHDVDSDUWRIWKHDFWLYLW\SURMHFW$VVRRQDVDVHFRQG
DFWLYLW\QHHGVWRXVHLWWKRXJKLWLVWLPHWRFRQVLGHUUHIDFWRULQJLWLQWRLWVRZQSURMHFW
7UDGLWLRQDOO\WKH-DYDFRPSLOHUH[SHFWVGLUHFWRU\WUHHVWRKROGWKHVRXUFH MDYD ILOHV
WKDW LW SDUVHV DQG WKH ELQDU\ FODVV ILOHV WKDW LW SURGXFHV DV RXWSXW :KLOH LW¦V QRW
QHFHVVDU\LW¦VPXFKHDVLHUWRPDQDJHDSURMHFWLIWKRVHWUHHVKDYHGLIIHUHQWURRWVFRP
PRQO\GLUHFWRULHVQDPHGVUFDQGELQUHVSHFWLYHO\
,QDQ$QGURLGSURMHFWWKHUHDUHWZRRWKHULPSRUWDQWGLUHFWRU\WUHHVUHVDQGJHQ7KH
ILUVWRIWKHVHUHVFRQWDLQVGHILQLWLRQVIRUVWDWLFUHVRXUFHVFRORUVFRQVWDQWVWULQJVOD\
RXWVDQGVRRQ$QGURLGWRROVSUHSURFHVVWKHVHGHILQLWLRQVDQGWXUQWKHPLQWRKLJKO\
RSWLPL]HGUHSUHVHQWDWLRQVDQGWKH-DYDVRXUFHWKURXJKZKLFKDSSOLFDWLRQFRGHUHIHUV
WRWKHP7KHDXWRJHQHUDWHGFRGHDORQJZLWKFRGHFUHDWHGIRU$,'/REMHFWV VHH£$,'/
DQG5HPRWH3URFHGXUH&DOOV¤RQSDJH LVSXWLQWRWKHJHQGLUHFWRU\7KHFRPSLOHU
FRPSLOHVWKHFRGHIURPERWKGLUHFWRULHVWRSURGXFHWKHFRQWHQWVRIELQ7KHIXOOVWUXF
WXUHRIDSURMHFWZDVGHVFULEHGLQGHWDLOLQ&KDSWHU
:KHQ\RXDGG\RXUSURMHFWWRDUHYLVLRQFRQWUROV\VWHPOLNH*LW6XE
YHUVLRQRU3HUIRUFHEHVXUHWRH[FOXGHWKHELQDQGJHQGLUHFWRULHV
<RXUDSSOLFDWLRQVRXUFHFRGHJRHVLQWKH VUFGLUHFWRU\$VQRWHGLQ &KDSWHU\RX
VKRXOGSXWDOO\RXUFRGHLQWRDSDFNDJHZKRVHQDPHLVGHULYHGIURPWKHGRPDLQQDPH
RIWKHRZQHURIWKHFRGH6XSSRVHIRULQVWDQFHWKDW\RXDUHDGHYHORSHUDWODUJHGRLQJ
EXVLQHVV DV awesome-android.net <RX DUH XQGHU FRQWUDFW WR GHYHORS D ZHDWKHU
SUHGLFWLRQDSSOLFDWLRQIRUvoracious-carrier.com<RXZLOOSUREDEO\FKRRVHWRSXWDOO
\RXU FRGH LQWR WKH SDFNDJH com.voraciouscarrier.weatherprediction RU SRVVLEO\
com.voracious_carrier.weather_prediction$OWKRXJKWKHFKDUDFWHU£¤LVSHUIHFWO\OH
JDOLQD'16GRPDLQQDPHLWLVQRWOHJDOLQD-DYDSDFNDJHQDPH7KH8,IRUWKLV
DPELWLRXV DSSOLFDWLRQ PLJKW JR LQ com.voraciouscarrier.weatherprediction.ui DQG
WKHPRGHOLQcom.voraciouscarrier.weatherprediction.futureweather
,I\RXORRNLQVLGHWKHVUFGLUHFWRU\LQ\RXUSURMHFW\RXZLOOVHHWKDWLWFRQWDLQVDVLQJOH
GLUHFWRU\ FRP FRP LQ WXUQ FRQWDLQV WKH GLUHFWRU\ YRUDFLRXVFDUULHU DQG VR RQ 7KH
VRXUFHGLUHFWRU\WUHHPLUURUVWKHSDFNDJHWUHH7KH-DYDFRPSLOHUH[SHFWVWKLVRUJDQL
]DWLRQDQGPD\EHXQDEOHWRFRPSLOH\RXUFRGHLILWLVYLRODWHG
(YHQWXDOO\ZKHQWKH)XWXUH:HDWKHUFRQWHQWSURYLGHUEHFRPHVYDOXDEOHRQLWVRZQ
\RX¦OOZDQWWRIDFWRULWRXWLQWRDQHZSURMHFWZLWKDSDFNDJHQDPHVSDFHWKDWLVQRW
UHVWULFWHGE\WKHQDPHRIWKHDSSOLFDWLRQLQZKLFKLWZDVRULJLQDOO\FUHDWHG'RLQJWKLV
Organizing Java Source | 141
E\KDQGLVDQLJKWPDUH<RXKDYHWRFUHDWHDQHZGLUHFWRU\VWUXFWXUHFRUUHFWO\SODFH
WKHILOHVZLWKLQWKDWVWUXFWXUHFRUUHFWWKHSDFNDJHQDPHVWKDWDUHDWWKHKHDGRIHDFK
VRXUFHILOHDQGILQDOO\FRUUHFWDQ\UHIHUHQFHVWRWKLQJVWKDWKDYHPRYHG
(FOLSVHUHIDFWRULQJWRROVDUH\RXUEHVWIULHQG:LWKMXVWDIHZFOLFNV\RXFDQFUHDWHD
QHZSURMHFWIRUWKHQRZVWDQGDORQHVXEWUHHFXWDQGSDVWHWKHFRQWHQWSURYLGHUFRGH
LQWRLWDQGWKHQUHQDPHWKHSDFNDJHVDVDSSURSULDWH(FOLSVHZLOOIL[PRVWWKLQJVLQ
FOXGLQJWKHFKDQJHGUHIHUHQFHV
,W¦VZRUWKDUHPLQGHUWKDWVKRUWFXWWLQJSDFNDJHQDPHV¢XVLQJDSDFNDJHQDPHGMXVW
weatherpredictionIRULQVWDQFH¢LVDEDGLGHD(YHQLI\RXDUHSUHWW\VXUHWKHFRGH\RX
DUHFUHDWLQJZLOOQHYHUEHXVHGRXWVLGHLWVFXUUHQWFRQWH[W\RXPD\ZDQWWRXVHH[WHU
QDOO\SURGXFHGFRGHLQWKDWFRQWH[W'RQ¦WVHW\RXUVHOIXSIRUDQDPHFROOLVLRQ
Concurrency in Android
$VPHQWLRQHGLQ&KDSWHUZULWLQJFRUUHFWFRQFXUUHQWSURJUDPVFDQEHYHU\GLIILFXOW
7KH$QGURLGOLEUDULHVSURYLGHVRPHFRQYHQLHQWWRROVWRPDNHFRQFXUUHQF\ERWKHDVLHU
DQGVDIHU
:KHQ GLVFXVVLQJ FRQFXUUHQW SURJUDPV GHYHORSHUV JHW LQWR WKH KDELW RI WDONLQJ DV
WKRXJKZULWLQJFRGHZLWKPXOWLSOHWKUHDGVDFWXDOO\FDXVHVWKRVHWKUHDGVWRH[HFXWHDW
WKHVDPHWLPH¢DVWKRXJKWKUHDGLQJDFWXDOO\PDNHVWKHSURJUDPUXQIDVWHU2IFRXUVH
LWLVQ¦WTXLWHWKDWVLPSOH8QOHVVWKHUHDUHPXOWLSOHSURFHVVRUVWRH[HFXWHWKHWKUHDGV
DSURJUDPWKDWQHHGVWRSHUIRUPPXOWLSOHXQUHODWHGFRPSXWHERXQGWDVNVZLOOFRP
SOHWHWKRVHWDVNVQRPRUHTXLFNO\LIWKH\DUHLPSOHPHQWHGDVVHSDUDWHWKUHDGVWKDQLW
ZLOOLIWKH\DUHRQWKHVDPHWKUHDG,QIDFWRQDVLQJOHSURFHVVRUWKHFRQFXUUHQWYHUVLRQ
PD\ DFWXDOO\ UXQ VRPHZKDW PRUH VORZO\ EHFDXVH RI WKH RYHUKHDG GXH WR FRQWH[W
VZLWFKLQJ
0XOWLWKUHDGHG-DYDDSSOLFDWLRQVZHUHDURXQGIRUDORQJWLPHEHIRUHPRVWSHRSOHFRXOG
DIIRUGPDFKLQHVZLWKPRUHWKDQRQHSURFHVVRURQZKLFKWRUXQWKHP,QWKH$QGURLG
ZRUOG PXOWLWKUHDGLQJ LV DQ HVVHQWLDO WRRO HYHQ WKRXJK WKH PDMRULW\ RI GHYLFHV ZLOO
SUREDEO\KDYHRQO\DVLQJOH&38IRUDQRWKHU\HDURUVR6RZKDWLVWKHSRLQWRIFRQ
FXUUHQF\LIQRWWRPDNHDSURJUDPUXQIDVWHU"
,I\RX¦YHEHHQSURJUDPPLQJIRUDQ\OHQJWKRIWLPHDWDOO\RXSUREDEO\GRQ¦WHYHQWKLQN
DERXWKRZDEVROXWHO\HVVHQWLDOLWLVWKDWWKHVWDWHPHQWVLQ\RXUFRGHDUHH[HFXWHGLQD
ULJLGVHTXHQWLDORUGHU7KHH[HFXWLRQRIDQ\JLYHQVWDWHPHQWPXVWXQFRQGLWLRQDOO\
KDSSHQEHIRUHWKHH[HFXWLRQRIWKHQH[WVWDWHPHQW7KUHDGVDUHQRPRUHWKDQDQH[SOLFLW
ZD\RIUHOD[LQJWKLVFRQVWUDLQW7KH\DUHWKHDEVWUDFWLRQWKDWGHYHORSHUVXVHWRPDNHLW
SRVVLEOHWRZULWHFRGHWKDWLVVWLOORUGHUHGORJLFDODQGHDV\WRUHDGHYHQZKHQWDVNV
HPERGLHGE\WKHFRGHDUHQRWUHODWHGE\RUGHULQJ
([HFXWLQJLQGHSHQGHQWWKUHDGVFRQFXUUHQWO\GRHVQ¦WLQWURGXFHDQ\LQWULQVLFFRPSOH[
LW\ZKHQWKHWKUHDGVDUHFRPSOHWHO\LQGHSHQGHQW HJLIRQHLVUXQQLQJRQ\RXUFRP
142 | Chapter 6:ಗEffective Java for Android
SXWHU DQG WKH RWKHU LV UXQQLQJ RQ PLQH :KHQ WZR FRQFXUUHQW SURFHVVHV QHHG WR
FROODERUDWHKRZHYHUWKH\KDYHWRUHQGH]YRXV)RULQVWDQFHGDWDIURPWKHQHWZRUN
PLJKWKDYHWREHGLVSOD\HGRQWKHVFUHHQRUXVHULQSXWSXVKHGWRDGDWDVWRUH$UUDQJLQJ
WKHUHQGH]YRXVHVSHFLDOO\LQWKHFRQWH[WRIFRGHRSWLPL]HUVSLSHOLQHGSURFHVVRUVDQG
PXOWLOD\HUHGPHPRU\FDFKHFDQEHTXLWHFRPSOH[7KLVFDQEHFRPHSDLQIXOO\DSSDUHQW
ZKHQDSURJUDPWKDWKDVUXQDSSDUHQWO\ZLWKRXWSUREOHPRQDVLQJOHSURFHVVRUVXG
GHQO\ IDLOV LQ VWUDQJH DQG GLIILFXOWWRGHEXJ ZD\V ZKHQ UXQ LQ D PXOWLSURFHVVRU
HQYLURQPHQW
7KHUHQGH]YRXVSURFHVVPDNLQJGDWDRUVWDWHIURPRQHWKUHDGYLVLEOHWRDQRWKHULV
XVXDOO\FDOOHGSXEOLVKLQJDUHIHUHQFH:KHQHYHURQHWKUHDGVWRUHVVWDWHLQDZD\WKDW
PDNHVLWYLVLEOHIURPDQRWKHUWKUHDGLWLVVDLGWREHSXEOLVKLQJDUHIHUHQFHWRWKDWVWDWH
$VPHQWLRQHGLQ&KDSWHUWKHRQO\ZD\WKDWDUHIHUHQFHFDQEHSXEOLVKHGVDIHO\LVLI
DOOWKUHDGVWKDWUHIHUWRWKHGDWDV\QFKURQL]HRQWKHVDPHREMHFWGXULQJXVH$Q\WKLQJ
HOVHLVLQFRUUHFWDQGXQVDIH
AsyncTask and the UI Thread
,I\RX¦YHZRUNHGZLWKDQ\PRGHUQ*8,IUDPHZRUNWKH$QGURLG8,ZLOOORRNHQWLUHO\
IDPLOLDU,WLVHYHQWGULYHQEXLOWRQDOLEUDU\RIQHVWDEOHFRPSRQHQWVDQGPRVWUHOHYDQW
KHUHVLQJOHWKUHDGHG'HVLJQHUVGLVFRYHUHG\HDUVDJRWKDWEHFDXVHD*8,PXVWUHVSRQG
WRDV\QFKURQRXVHYHQWVIURPPXOWLSOHVRXUFHVLWLVQHDUO\LPSRVVLEOHWRDYRLGGHDGORFN
LIWKH8,LVPXOWLWKUHDGHG,QVWHDGDVLQJOHWKUHDGRZQVERWKWKHLQSXW WRXFKVFUHHQ
NH\SDGHWF DQGRXWSXWGHYLFHV GLVSOD\HWF DQGH[HFXWHVUHTXHVWVIURPHDFKVH
TXHQWLDOO\XVXDOO\LQWKHRUGHUWKH\ZHUHUHFHLYHG
:KLOHWKH8,UXQVRQDVLQJOHWKUHDGQHDUO\DQ\QRQWULYLDO$QGURLGDSSOLFDWLRQZLOOEH
PXOWLWKUHDGHG7KH8,PXVWIRULQVWDQFHUHVSRQGWRWKHXVHUDQGDQLPDWHWKHGLVSOD\
UHJDUGOHVV RI ZKHWKHU WKH FRGH WKDW UHWULHYHV GDWD IURP WKH QHWZRUN LV FXUUHQWO\
SURFHVVLQJLQFRPLQJGDWD7KH8,PXVWEHTXLFNDQGUHVSRQVLYHDQGFDQQRWIXQGD
PHQWDOO\EHRUGHUHGZLWKUHVSHFWWRRWKHUORQJUXQQLQJSURFHVVHV7KHORQJUXQQLQJ
SURFHVVHVPXVWEHUXQDV\QFKURQRXVO\
2QHFRQYHQLHQWWRROIRULPSOHPHQWLQJDQDV\QFKURQRXVWDVNLQWKH$QGURLGV\VWHPLV
LQIDFWFDOOHGAsyncTask,WFRPSOHWHO\KLGHVPDQ\RIWKHGHWDLOVRIWKHWKUHDGVXVHGWR
UXQWKHWDVN
/HW¦VFRQVLGHUDYHU\VLPSOLVWLFDSSOLFDWLRQWKDWLQLWLDOL]HVDJDPHHQJLQHGLVSOD\LQJ
VRPHLQWHUVWLWLDOJUDSKLFZKLOHWKHFRQWHQWORDGV)LJXUHVKRZVDYHU\EDVLFH[DPSOH
RIVXFKDQDSSOLFDWLRQ:KHQ\RXSXVKWKHEXWWRQLWLQLWLDOL]HVWKHJDPHOHYHODQGWKHQ
GLVSOD\VDZHOFRPHPHVVDJHLQDWH[WER[
Concurrency in Android | 143
)LJXUH6LPSOHDSSOLFDWLRQWRLQLWLDOL]HDJDPH
+HUH LV WKH ERLOHUSODWH FRGH IRU WKH DSSOLFDWLRQ $OO WKDW LV PLVVLQJ LV WKH FRGH WKDW
DFWXDOO\LQLWLDOL]HVWKHJDPHDQGXSGDWHVWKHWH[WER[
/** AsyncTaskDemo */
public class AsyncTaskDemo extends Activity {
int mInFlight;
/** @see android.app.Activity#onCreate(android.os.Bundle) */
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.asyncdemo);
final View root = findViewById(R.id.root);
final Drawable bg = root.getBackground();
final TextView msg = ((TextView) findViewById(R.id.msg));
final Game game = Game.newGame();
}
((Button) findViewById(R.id.start)).setOnClickListener(
new View.OnClickListener() {
@Override public void onClick(View v) {
// !!! initialize the game here!
} });
144 | Chapter 6:ಗEffective Java for Android
1RZ OHW¦V VXSSRVH IRU WKLV H[DPSOH WKDW ZH VLPSO\ ZDQW WR GLVSOD\ DQ DQLPDWHG
EDFNJURXQG WKHFUDZOLQJGRWVLQ)LJXUH ZKLOHWKHXVHUZDLWVIRUWKHJDPHWRLQL
WLDOL]H+HUH¦VDVNHWFKRIWKHQHFHVVDU\FRGH
/**
* Synchronous request to remote service
* DO NOT USE!!
*/
void initGame(
View root,
Drawable bg,
Game game,
TextView resp,
String level)
{
// if the animation hasn't been started yet,
// do so now
if (0 >= mInFlight++ ) {
root.setBackgroundResource(R.anim.dots);
((AnimationDrawable) root.getBackground()).start();
}
// initialize the game and get the welcome message
String msg = game.initialize(level);
// if this is the last running initialization
// remove and clean up the animation
if (0 >= --mInFlight) {
((AnimationDrawable) root.getBackground()).stop();
root.setBackgroundDrawable(bg);
}
resp.setText(msg);
}
7KLVLVSUHWW\VWUDLJKWIRUZDUG7KHXVHUPLJKWPDVKWKHVWDUWEXWWRQVRWKHUHPLJKWEH
PXOWLSOHLQLWLDOL]DWLRQVLQIOLJKW,IWKHLQWHUVWLWLDOEDFNJURXQGLVQRWDOUHDG\VKRZLQJ
VKRZLWDQGUHPHPEHUWKDWWKHUHLVRQHPRUHJDPHVWDUWLQJXS1H[WPDNHWKHVORZ
FDOOWRWKHJDPHHQJLQHLQLWLDOL]HU2QFHWKHJDPHFRPSOHWHVLWVLQLWLDOL]DWLRQFOHDQXS
,IWKLVLVWKHODVWJDPHWRFRPSOHWHLQLWLDOL]DWLRQFOHDUWKHLQWHUVWLWLDODQLPDWLRQ)LQDOO\
GLVSOD\WKHJUHHWLQJPHVVDJHLQWKHWH[WER[
:KLOHWKLVFRGHLVYHU\QHDUO\ZKDWLVQHHGHGWRPDNHWKHH[DPSOHDSSOLFDWLRQZRUN
DVVSHFLILHGLWEUHDNVGRZQLQRQHYHU\LPSRUWDQWZD\LWEORFNVWKH8,WKUHDGIRUWKH
HQWLUHGXUDWLRQRIWKHFDOOWRgame.initialize7KDWKDVDOOVRUWVRIXQSOHDVDQWHIIHFWV
7KHPRVWDSSDUHQWRIWKHVHLVWKDWWKHEDFNJURXQGDQLPDWLRQZRQ¦WZRUN(YHQWKRXJK
WKH ORJLF IRU VHWWLQJ XS DQG UXQQLQJ WKH DQLPDWLRQ LV YHU\ QHDUO\ FRUUHFW WKH FRGH
VSHFLILHVTXLWHFOHDUO\WKDWQRWKLQJHOVHFDQKDSSHQLQWKH8,XQWLOWKHFDOOWRWKHUHPRWH
VHUYLFHLVFRPSOHWH
,WJHWVZRUVH 7KH$QGURLG)UDPHZRUN DFWXDOO\ PRQLWRUV DSSOLFDWLRQ8,WKUHDGVWR
SUHYHQWEURNHQRUPDOLFLRXVSURJUDPVIURPKDQJLQJDGHYLFH,IDQDSSOLFDWLRQWDNHV
Concurrency in Android | 145
WRRORQJWRUHVSRQGWRLQSXWWKHIUDPHZRUNZLOOVXVSHQGLWDOHUWWKHXVHUWKDWWKHUHLV
DSUREOHPDQGRIIHUKHUDFKDQFHWRIRUFHLWWRFORVH,I\RXEXLOGDQGUXQWKLVH[DPSOH
DSSOLFDWLRQZLWK initGameLPSOHPHQWHGDVVKRZQLQWKHH[DPSOH WU\LWLW¦VDFWXDOO\
VRPHZKDWLQVWUXFWLYH WKHILUVWWLPH\RXFOLFNWKH6HQG5HTXHVWEXWWRQWKH8,ZLOO
IUHH]H,I\RXFOLFNDFRXSOHPRUHWLPHV\RXZLOOVHHDQDOHUWVLPLODUWRWKHRQHVKRZQ
LQ)LJXUH
)LJXUH8QUHVSRQVLYHDSSOLFDWLRQ
AsyncTaskWRWKHUHVFXH$QGURLGSURYLGHVWKLVFODVVDVDUHODWLYHO\VDIHSRZHUIXODQG
HDV\WRXVH ZD\ WR UXQ EDFNJURXQG WDVNV FRUUHFWO\ +HUH LV D UHLPSOHPHQWDWLRQ RI
initGameDVDQAsyncTask
private final class AsyncInitGame
extends AsyncTask<String, Void, String>
{
private final View root;
private final Game game;
private final TextView message;
private final Drawable bg;
public AsyncInitGame(
View root,
Drawable bg,
Game game,
TextView msg)
{
this.root = root;
this.bg = bg;
this.game = game;
this.message = msg;
146 | Chapter 6:ಗEffective Java for Android
}
// runs on the UI thread
@Override protected void onPreExecute() {
if (0 >= mInFlight++) {
root.setBackgroundResource(R.anim.dots);
((AnimationDrawable) root.getBackground()).start();
}
}
// runs on the UI thread
@Override protected void onPostExecute(String msg) {
if (0 >= --mInFlight) {
((AnimationDrawable) root.getBackground()).stop();
root.setBackgroundDrawable(bg);
}
message.setText(msg);
}
// runs on a background thread
@Override protected String doInBackground(String... args) {
return ((1 != args.length) || (null == args[0]))
? null
: game.initialize(args[0]);
}
}
7KLVFRGHLVQHDUO\LGHQWLFDOWRWKHILUVWH[DPSOH,WKDVEHHQGLYLGHGLQWRWKUHHPHWKRGV
WKDWH[HFXWHQHDUO\WKHVDPHFRGHLQWKHVDPHRUGHUDVLQinitGame
7KLV AsyncTask LV FUHDWHG RQ WKH 8, WKUHDG :KHQ WKH 8, WKUHDG LQYRNHV WKH WDVN¦V
executePHWKRGILUVWWKHonPreExecutePHWKRGLVFDOOHGRQWKH8,WKUHDG7KLVDOORZV
WKHWDVNWRLQLWLDOL]HLWVHOIDQGLWVHQYLURQPHQW¢LQWKLVFDVHLQVWDOOLQJWKHEDFNJURXQG
DQLPDWLRQ1H[WWKH AsyncTaskFUHDWHVDQHZEDFNJURXQGWKUHDGWRUXQWKH doInBack
groundPHWKRGFRQFXUUHQWO\:KHQHYHQWXDOO\doInBackgroundFRPSOHWHVWKHEDFN
JURXQGWKUHDGLVGHOHWHGDQGWKHonPostExecutePHWKRGLVLQYRNHGRQFHDJDLQLQWKH
8,WKUHDG
$VVXPLQJWKDWWKLVLPSOHPHQWDWLRQRIDQ AsyncTaskLVFRUUHFWWKHFOLFNOLVWHQHUQHHG
RQO\FUHDWHDQLQVWDQFHDQGLQYRNHLWOLNHWKLV
((Button) findViewById(R.id.start)).setOnClickListener(
new View.OnClickListener() {
@Override public void onClick(View v) {
new AsyncInitGame(
root,
bg,
game,
msg)
.execute("basic");
} });
,QIDFWAsyncInitGameLVFRPSOHWHFRUUHFWDQGUHOLDEOH/HW¦VH[DPLQHLWLQPRUHGHWDLO
Concurrency in Android | 147
)LUVWQRWLFHWKDWWKHEDVHFODVVAsyncTaskLVDEVWUDFW7KHRQO\ZD\WRXVHLWLVWRFUHDWH
DVXEFODVVVSHFLDOL]HGWRSHUIRUPVRPHVSHFLILFMRE DQLVDUHODWLRQVKLSQRWDKDVD
UHODWLRQVKLS 7\SLFDOO\WKHVXEFODVVZLOOEHVLPSOHDQRQ\PRXVDQGGHILQHRQO\DIHZ
PHWKRGV$UHJDUGIRUJRRGVW\OHDQGVHSDUDWLRQRIFRQFHUQVDQDORJRXVWRWKHLVVXHV
PHQWLRQHGLQ &KDSWHU VXJJHVWV NHHSLQJ WKH VXEFODVV VPDOODQGGHOHJDWLQJLPSOH
PHQWDWLRQWRWKHFODVVHVWKDWRZQWKH8,DQGWKHDV\QFKURQRXVWDVNUHVSHFWLYHO\,Q
WKHH[DPSOHIRULQVWDQFHdoInBackgroundLVVLPSO\DSUR[\WRWKHGameFODVV
,QJHQHUDODQ AsyncTaskWDNHVDVHWRISDUDPHWHUVDQGUHWXUQVDUHVXOW%HFDXVHWKH
SDUDPHWHUVKDYHWREHSDVVHGEHWZHHQWKUHDGVDQGWKHUHVXOWUHWXUQHGEHWZHHQWKUHDGV
VRPHKDQGVKDNLQJLVQHFHVVDU\WRHQVXUHWKUHDGVDIHW\$Q AsyncTaskLVLQYRNHGE\
FDOOLQJ LWV execute PHWKRG ZLWK VRPH SDUDPHWHUV 7KRVH SDUDPHWHUV DUH HYHQWXDOO\
SDVVHGRQE\WKHAsyncTaskPHFKDQLVPWRWKHdoInBackgroundPHWKRGZKHQLWUXQV
RQ D EDFNJURXQG WKUHDG ,Q WXUQ doInBackground SURGXFHV D UHVXOW 7KH AsyncTask
PHFKDQLVPUHWXUQVWKDWUHVXOWE\SDVVLQJLWDVWKHDUJXPHQWWR doPostExecuteUXQLQ
WKHVDPHWKUHDGDVWKHRULJLQDOexecute)LJXUHVKRZVWKHGDWDIORZ
)LJXUH'DWDIORZLQ$V\QF7DVN
,QDGGLWLRQWRPDNLQJWKLVGDWDIORZWKUHDGVDIH AsyncTaskDOVRPDNHVLWW\SHVDIH
AsyncTaskLVDFODVVLFH[DPSOHRIDW\SHVDIHWHPSODWHSDWWHUQ7KHDEVWUDFWEDVHFODVV
AsyncTask XVHV-DYDJHQHULFVWRDOORZLPSOHPHQWDWLRQVWRVSHFLI\WKHW\SHVRIWKHWDVN
SDUDPHWHUVDQGUHVXOW
:KHQGHILQLQJDFRQFUHWHVXEFODVVRIAsyncTask\RXSURYLGHDFWXDOW\SHVIRUParams
ProgressDQGResultWKHW\SHYDULDEOHVLQWKHGHILQLWLRQRIAsyncTask7KHILUVWDQGODVW
RIWKHVHW\SHYDULDEOHV ParamsDQGResult DUHWKHW\SHVRIWKHWDVNSDUDPHWHUVDQGWKH
UHVXOWUHVSHFWLYHO\:H¦OOJHWWRWKDWPLGGOHW\SHYDULDEOHLQDPLQXWH
7KHFRQFUHWHW\SHERXQGWRParamsLVWKHW\SHRIWKHSDUDPHWHUVWRexecuteDQGWKXV
WKHW\SHRIWKHSDUDPHWHUVWR doInBackground6LPLODUO\WKHFRQFUHWHW\SHERXQGWR
ResultLVWKHW\SHRIWKHUHWXUQYDOXHIURP doInBackgroundDQGWKXVWKHW\SHRIWKH
SDUDPHWHUWRonPostExecute
148 | Chapter 6:ಗEffective Java for Android
7KLVLVDOODELWKDUGWRSDUVHDQGWKHILUVWH[DPSOHAsyncInitGameGLGQ¦WKHOSPXFK
EHFDXVHWKHLQSXWSDUDPHWHUDQGWKHUHVXOWDUHERWKRIWKHVDPHW\SHString+HUHDUH
DFRXSOHRIH[DPSOHVLQZKLFKWKHSDUDPHWHUDQGUHVXOWW\SHVDUHGLIIHUHQW7KH\SURYLGH
DEHWWHULOOXVWUDWLRQRIWKHXVHRIWKHJHQHULFW\SHYDULDEOHV
public class AsyncDBReq
extends AsyncTask<PreparedStatement, Void, ResultSet>
{
@Override
protected ResultSet doInBackground(PreparedStatement... q) {
// implementation...
}
}
@Override
protected void onPostExecute(ResultSet result) {
// implementation...
}
public class AsyncHttpReq
extends AsyncTask<HttpRequest, Void, HttpResponse>
{
@Override
protected HttpResponse doInBackground(HttpRequest... req) {
// implementation...
}
}
@Override
protected void onPostExecute(HttpResponse result) {
// implementation...
}
,QWKHILUVWH[DPSOHWKHDUJXPHQWWRWKHexecutePHWKRGRIDQAsyncDBReqLQVWDQFHZLOO
EHRQHRUPRUH PreparedStatementYDULDEOHV7KHLPSOHPHQWDWLRQRI doInBackground
IRUDQLQVWDQFHRI AsyncDBReqZLOOWDNHWKRVH PreparedStatementSDUDPHWHUVDVLWVDU
JXPHQWVDQGZLOOUHWXUQDResultSet7KHLQVWDQFHonPostExecutePHWKRGZLOOWDNHWKDW
ResultSetDVDSDUDPHWHUDQGXVHLWDSSURSULDWHO\
6LPLODUO\LQWKHVHFRQGH[DPSOHWKHFDOOWRWKH executePHWKRGRIDQ AsyncHttpReq
LQVWDQFHZLOOWDNHRQHRUPRUH HttpRequestYDULDEOHV doInBackgroundWDNHVWKRVHUH
TXHVWV DV LWV SDUDPHWHUV DQG UHWXUQV DQ HttpResponse onPostExecute KDQGOHV WKH
HttpResponse
1RWHWKDW DQ LQVWDQFH RI DQ AsyncTaskFDQ EHUXQRQO\RQFH&DOOLQJ
execute RQ D WDVN D VHFRQG WLPH ZLOO FDXVH LW WR WKURZ DQ Illegal
StateException(DFKWDVNLQYRFDWLRQUHTXLUHVDQHZLQVWDQFH
$VPXFKDV AsyncTask VLPSOLILHV FRQFXUUHQW SURFHVVLQJ LWV FRQWUDFWLPSRVHVVWURQJ
FRQVWUDLQWVWKDWFDQQRWEHYHULILHGDXWRPDWLFDOO\,WLVDEVROXWHO\HVVHQWLDOWRWDNHJUHDW
FDUH QRW WR YLRODWH WKHVH FRQVWUDLQWV 9LRODWLRQV ZLOO FDXVH H[DFWO\ WKH VRUW RI EXJ
Concurrency in Android | 149
GHVFULEHGDWWKHEHJLQQLQJRIWKLVVHFWLRQIDLOXUHVWKDWDUHLQWHUPLWWHQWDQGYHU\GLIILFXOW
WRILQG
7KHPRVWREYLRXVRIWKHVHFRQVWUDLQWVLVWKDWWKHdoInBackgroundPHWKRGVLQFHLWLVUXQ
RQDGLIIHUHQWWKUHDGPXVWPDNHRQO\WKUHDGVDIHUHIHUHQFHVWRYDULDEOHVLQKHULWHGLQWR
LWVVFRSH+HUHIRUH[DPSOHLVDPLVWDNHWKDWLVHDV\WRPDNH
// ... some class
int mCount;
public void initButton1( Button button) {
mCount = 0;
button.setOnClickListener(
new View.OnClickListener() {
@SuppressWarnings("unchecked")
@Override public void onClick(View v) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... args) {
mCount++; // !!! NOT THREAD SAFE!
return null;
}
}.execute();
} });
}
$OWKRXJKWKHUHLVQRWKLQJWRDOHUW\RXWRWKHSUREOHP¢QRFRPSLOHUHUURUQRUXQWLPH
ZDUQLQJSUREDEO\QRWHYHQDQLPPHGLDWHIDLOXUHZKHQWKHEXJLVGULYHQ¢WKLVFRGHLV
DEVROXWHO\LQFRUUHFW7KHYDULDEOHmCountLVEHLQJDFFHVVHGIURPWZRGLIIHUHQWWKUHDGV
ZLWKRXWV\QFKURQL]DWLRQ
,QOLJKWRIWKLVLWPD\EHDVXUSULVHWRVHHWKDWDFFHVVWRmInFlightLVQRWV\QFKURQL]HG
LQ AsyncTaskDemo 7KLV LV DFWXDOO\ 2. 7KH AsyncTask FRQWUDFW JXDUDQWHHV WKDW
onPreExecuteDQGonPostExecuteZLOOEHUXQRQWKHVDPHWKUHDGWKHWKUHDGIURPZKLFK
executeZDVFDOOHG8QOLNHmCountmInFlightLVDFFHVVHGIURPRQO\DVLQJOHWKUHDGDQG
KDVQRQHHGIRUV\QFKURQL]DWLRQ
3UREDEO\WKHPRVWSHUQLFLRXVZD\WRFDXVHWKHNLQGRIFRQFXUUHQF\SUREOHPZH¦YHMXVW
ZDUQHG\RXDERXWLVE\KROGLQJDUHIHUHQFHWRDSDUDPHWHU7KLVFRGHIRULQVWDQFHLV
LQFRUUHFW&DQ\RXVHHZK\"
public void initButton(
Button button,
final Map<String, String> vals)
{
button.setOnClickListener(
new View.OnClickListener() {
@Override public void onClick(View v) {
new AsyncTask<Map<String, String>, Void, Void>() {
@Override
protected Void doInBackground(
Map<String, String>... params)
150 | Chapter 6:ಗEffective Java for Android
{
}
// implementation, uses the params Map
}
}.execute(vals);
vals.clear(); // !!! THIS IS NOT THREAD SAFE !!!
} });
7KHSUREOHPLVSUHWW\VXEWOH,I\RXQRWLFHGWKDWWKHDUJXPHQWWRinitButtonvalsLV
EHLQJUHIHUHQFHGFRQFXUUHQWO\ZLWKRXWV\QFKURQL]DWLRQ\RXDUHFRUUHFW,WLVSDVVHG
LQWR WKH AsyncTask DV WKH DUJXPHQW WR execute ZKHQ WKH WDVN LV LQYRNHG 7KH
AsyncTaskIUDPHZRUNFDQJXDUDQWHHWKDWWKLVUHIHUHQFHLVSXEOLVKHGFRUUHFWO\RQWRWKH
EDFNJURXQG WKUHDG ZKHQ doInBackground LV FDOOHG ,W FDQQRW KRZHYHU GR DQ\WKLQJ
DERXWWKHUHIHUHQFHWRvalsWKDWLVUHWDLQHGDQGXVHGODWHULQWKHinitButtonPHWKRG
7KHFDOOWR vals.clearPRGLILHVVWDWHWKDWLVEHLQJXVHGRQDQRWKHUWKUHDGZLWKRXW
V\QFKURQL]DWLRQ,WLVWKHUHIRUHQRWWKUHDGVDIH
7KHEHVWVROXWLRQWRWKLVSUREOHPLVWRPDNHVXUHWKHDUJXPHQWVWRAsyncTaskDUHLP
PXWDEOH,IWKH\FDQ¦WEHFKDQJHG¢OLNHDStringDQIntegerRUD32-2ZLWKRQO\ILQDO
ILHOGV¢WKH\DUHWKUHDGVDIHDQGQHHGQRIXUWKHUFDUH7KHRQO\ZD\WREHFHUWDLQWKDW
DPXWDEOHREMHFWSDVVHGWRDQ AsyncTaskLVWKUHDGVDIHLVWRPDNHVXUHWKDWRQO\WKH
AsyncTaskKROGVDUHIHUHQFH%HFDXVHWKHSDUDPHWHUvalsLVSDVVHGLQWRWKHinitButton
PHWKRGLQWKHSUHYLRXVH[DPSOH )LJXUH LWLVFRPSOHWHO\LPSRVVLEOHWRJXDUDQWHH
WKDWWKHUHDUHQRGDQJOLQJUHIHUHQFHVWRLW(YHQUHPRYLQJWKHFDOOWRvals.clearZRXOG
QRWJXDUDQWHHWKDWWKLVFRGHZDVFRUUHFWEHFDXVHWKHFDOOHURIinitButtonPLJKWKROG
DUHIHUHQFHWRWKHPDSWKDWLVHYHQWXDOO\SDVVHGDVWKHSDUDPHWHUvals7KHRQO\ZD\WR
PDNHWKLVFRGHFRUUHFWLVWRPDNHDFRPSOHWH GHHS FRS\RIWKHPDSDQGDOOWKHREMHFWV
LWFRQWDLQV
'HYHORSHUVIDPLOLDUZLWKWKH-DYD&ROOHFWLRQVSDFNDJHPLJKWDUJXHWKDWDQDOWHUQDWLYH
WR PDNLQJ D FRPSOHWH GHHS FRS\ RI WKH PDS SDUDPHWHU ZRXOG EH WR ZUDS LW LQ DQ
unmodifiableMapOLNHWKLV
public void initButton(
Button button,
final Map<String, String> vals)
{
button.setOnClickListener(
new View.OnClickListener() {
@Override public void onClick(View v) {
new AsyncTask<Map<String, String>, Void, Void>() {
@Override
protected Void doInBackground(
Map<String, String>... params)
{
// implementation, uses the params Map
}
}.execute(Collections.unmodifiableMap(vals));
vals.clear(); // !!! STILL NOT THREAD SAFE !!!
} });
}
Concurrency in Android | 151
8QIRUWXQDWHO\WKLVLVVWLOOQRWFRUUHFW Collections.unmodifiableMapSURYLGHVDQLP
PXWDEOHYLHZRIWKHPDSLWZUDSV,WGRHVQRWKRZHYHUSUHYHQWSURFHVVHVZLWKDFFHVV
WRDUHIHUHQFHWRWKHRULJLQDOPXWDEOHREMHFWIURPFKDQJLQJWKDWREMHFWDWDQ\WLPH,Q
WKHSUHFHGLQJH[DPSOHDOWKRXJKWKH AsyncTaskFDQQRWFKDQJHWKHPDSYDOXHSDVVHG
WRLWLQWKH executePHWKRGWKH onClickListenerPHWKRGVWLOOFKDQJHVWKHPDSUHIHU
HQFHGE\valsDWWKHVDPHWLPHWKHEDFNJURXQGWKUHDGXVHVLWZLWKRXWV\QFKURQL]DWLRQ
%RRP
7RFORVHWKLVVHFWLRQQRWHWKDW AsyncTaskKDVRQHPRUHPHWKRGQRWXVHGLQWKHH[
DPSOH onProgressUpdate,WLVWKHUHWRDOORZWKHORQJUXQQLQJWDVNVWRSXVKSHULRGLF
VWDWXVVDIHO\EDFNWRWKH8,WKUHDG+HUHLVKRZ\RXPLJKWXVHLWWRLPSOHPHQWDSURJUHVV
EDUVKRZLQJWKHXVHUKRZPXFKORQJHUWKHJDPHLQLWLDOL]DWLRQSURFHVVZLOOWDNH
public class AsyncTaskDemoWithProgress extends Activity {
private final class AsyncInit
extends AsyncTask<String, Integer, String>
implements Game.InitProgressListener
{
private final View root;
private final Game game;
private final TextView message;
private final Drawable bg;
public AsyncInit(
View root,
Drawable bg,
Game game,
TextView msg)
{
this.root = root;
this.bg = bg;
this.game = game;
this.message = msg;
}
// runs on the UI thread
@Override protected void onPreExecute() {
if (0 >= mInFlight++) {
root.setBackgroundResource(R.anim.dots);
((AnimationDrawable) root.getBackground()).start();
}
}
// runs on the UI thread
@Override protected void onPostExecute(String msg) {
if (0 >= --mInFlight) {
((AnimationDrawable) root.getBackground()).stop();
root.setBackgroundDrawable(bg);
}
message.setText(msg);
}
152 | Chapter 6:ಗEffective Java for Android
// runs on its own thread
@Override protected String doInBackground(String... args) {
return ((1 != args.length) || (null == args[0]))
? null
: game.initialize(args[0], this);
}
// runs on the UI thread
@Override protected void onProgressUpdate(Integer... vals) {
updateProgressBar(vals[0].intValue());
}
// runs on the UI thread
@Override public void onInitProgress(int pctComplete) {
publishProgress(Integer.valueOf(pctComplete));
}
}
int mInFlight;
int mComplete;
/** @see android.app.Activity#onCreate(android.os.Bundle) */
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.asyncdemoprogress);
final View root = findViewById(R.id.root);
final Drawable bg = root.getBackground();
final TextView msg = ((TextView) findViewById(R.id.msg));
final Game game = Game.newGame();
((Button) findViewById(R.id.start)).setOnClickListener(
new View.OnClickListener() {
@Override public void onClick(View v) {
mComplete = 0;
new AsyncInit(
root,
bg,
game,
msg)
.execute("basic");
} });
}
void updateProgressBar(int progress) {
int p = progress;
if (mComplete < p) {
mComplete = p;
((ProgressBar) findViewById(R.id.progress))
.setProgress(p);
Concurrency in Android | 153
}
}
}
7KLV H[DPSOH SUHVXPHV WKDW JDPH LQLWLDOL]DWLRQ WDNHV DV DQ DUJXPHQW D Game.Init
ProgressListener7KHLQLWLDOL]DWLRQSURFHVVSHULRGLFDOO\FDOOVWKHOLVWHQHU¦V onInitPro
gressPHWKRGWRQRWLI\LWRIKRZPXFKZRUNKDVEHHQFRPSOHWHG,QWKLVH[DPSOHWKHQ
onInitProgressZLOOEHFDOOHGIURPEHQHDWKdoInBackgroundLQWKHFDOOWUHHDQGWKHUHIRUH
RQ WKH EDFNJURXQG WKUHDG ,I onInitProgress ZHUH WR FDOO AsyncTaskDemoWith
Progress.updateProgressBarGLUHFWO\WKHVXEVHTXHQWFDOOWRbar.setStatusZRXOGDOVR
WDNHSODFHRQWKHEDFNJURXQGWKUHDGYLRODWLQJWKHUXOHWKDWRQO\WKH8,WKUHDGFDQ
PRGLI\ViewREMHFWV,WZRXOGFDXVHDQH[FHSWLRQOLNHWKLV
11-30 02:42:37.471: ERROR/AndroidRuntime(162):
android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
,QRUGHUWRFRUUHFWO\SXEOLVKWKHSURJUHVVEDFNWRWKH8,WKUHDGonInitProgressLQVWHDG
FDOOV WKH AsyncTask PHWKRG publishProgress 7KH AsyncTask KDQGOHV WKH GHWDLOV RI
VFKHGXOLQJ publishProgressRQWKH8,WKUHDGVRWKDW onProgressUpdateFDQVDIHO\XVH
ViewPHWKRGV
/HW¦VOHDYHWKLVGHWDLOHGORRNLQWRWKHAsyncTaskE\VXPPDUL]LQJVRPHRIWKHNH\SRLQWV
LWLOOXVWUDWHG
‡ 7KH$QGURLG8,LVVLQJOHWKUHDGHG7RXVHLWZHOODGHYHORSHUPXVWEHFRPIRUWDEOH
ZLWKWKHWDVNTXHXHLGLRP
‡ ,QRUGHUWRUHWDLQ8,OLYHQHVVWDVNVWKDWWDNHPRUHWKDQDFRXSOHRIPLOOLVHFRQGV
RUDIHZKXQGUHGLQVWUXFWLRQVVKRXOGQRWEHUXQRQWKH8,WKUHDG
‡ &RQFXUUHQWSURJUDPPLQJLVUHDOO\WULFN\,W¦VDPD]LQJO\HDV\WRJHWLWZURQJDQG
YHU\KDUGWRFKHFNIRUPLVWDNHV
‡ AsyncTaskLVDFRQYHQLHQWWRROIRUUXQQLQJVPDOODV\QFKURQRXVWDVNV-XVWUHPHP
EHUWKDWWKH doInBackgroundPHWKRGUXQVRQDGLIIHUHQWWKUHDG,WPXVWQRWZULWH
DQ\VWDWHYLVLEOHIURPDQRWKHUWKUHDGRUUHDGDQ\VWDWHZULWDEOHIURPDQRWKHUWKUHDG
7KLVLQFOXGHVLWVSDUDPHWHUV
‡ ,PPXWDEOHREMHFWVDUHDQHVVHQWLDOWRROIRUSDVVLQJLQIRUPDWLRQEHWZHHQFRQFXU
UHQWWKUHDGV
Threads in an Android Process
7RJHWKHUAsyncTaskDQGContentProviderIRUPDYHU\SRZHUIXOLGLRPDQGFDQEHDGDS
WHGWRDZLGHYDULHW\RIFRPPRQDSSOLFDWLRQDUFKLWHFWXUHV1HDUO\DQ\09&SDWWHUQLQ
ZKLFKWKH9LHZSROOVWKH0RGHOFDQ DQGSUREDEO\VKRXOG EHLPSOHPHQWHGWKLVZD\
,QDQDSSOLFDWLRQZKRVHDUFKLWHFWXUHUHTXLUHVWKH0RGHOWRSXVKFKDQJHVWRWKH9LHZ
RULQZKLFKWKH0RGHOLVORQJOLYHGDQGFRQWLQXRXVO\UXQQLQJ AsyncTaskPD\QRWEH
VXIILFLHQW
154 | Chapter 6:ಗEffective Java for Android
5HFDOOWKDWFDUGLQDOUXOHIRUVKDULQJGDWDEHWZHHQWKUHDGVWKDWZHLQWURGXFHGEDFNLQ
£6\QFKURQL]DWLRQDQG7KUHDG6DIHW\¤RQSDJH,QLWVIXOOJHQHUDOLW\WKDWUXOHLVSUHWW\
RQHURXV7KHLQYHVWLJDWLRQRIAsyncTaskLQWKHSUHFHGLQJVHFWLRQKRZHYHULOOXVWUDWHG
RQHLGLRPWKDWVLPSOLILHVFRUUHFWFRRUGLQDWLRQRIFRQFXUUHQWWDVNVLQ$QGURLGWKHKHDY\
OLIWLQJRISXEOLVKLQJVWDWHIURPRQHWKUHDGLQWRDQRWKHUZDVFRPSOHWHO\KLGGHQLQWKH
LPSOHPHQWDWLRQRIDWHPSODWHFODVV$WWKHVDPHWLPHWKHGLVFXVVLRQDOVRUHLQIRUFHG
VRPHRIWKHSLWIDOOVRIFRQFXUUHQF\WKDWOLHLQZDLWWRHQWUDSWKHLQFDXWLRXVFRGHU7KHUH
DUHRWKHULGLRPVWKDWDUHVDIHDQGWKDWFDQVLPSOLI\VSHFLILFFODVVHVRIFRQFXUUHQWSURE
OHPV2QHRIWKHP¢DFRPPRQLGLRPLQ-DYDSURJUDPPLQJLQJHQHUDO¢LVEDNHGLQWR
WKH$QGURLG)UDPHZRUN,WLVVRPHWLPHVFDOOHGWKUHDGFRQILQHPHQW
6XSSRVHWKDWDWKUHDGWKH'%0LQGHUFUHDWHVDQREMHFWDQGPRGLILHVLWRYHUDSHULRG
RI WLPH $IWHU LW KDV FRPSOHWHG LWV ZRUN LW PXVW SDVV WKH REMHFW WR DQRWKHU WKUHDG
'%9LHZHU IRU IXUWKHU SURFHVVLQJ ,Q RUGHU WR GR WKLV XVLQJ WKUHDG FRQILQHPHQW
'%0LQGHUDQG'%9LHZHUPXVWVKDUHDGURSSRLQWDQGDQDVVRFLDWHGORFN7KHSURFHVV
ORRNVOLNHWKLV
'%0LQGHUVHL]HVWKHORFNDQGVWRUHVDUHIHUHQFHWRWKHREMHFWLQWKHGURS
'%0LQGHUGHVWUR\VDOOLWVUHIHUHQFHVWRWKHREMHFW
'%0LQGHUUHOHDVHVWKHORFN
'%9LHZHUVHL]HVWKHORFNDQGQRWLFHVWKDWWKHUHLVDQREMHFWUHIHUHQFHLQWKHGURS
'%9LHZHUUHFRYHUVWKHUHIHUHQFHIURPWKHGURSDQGWKHQFOHDUVWKHGURS
'%9LHZHUUHOHDVHVWKHORFN
7KLVSURFHVVZRUNVIRUDQ\REMHFWUHJDUGOHVVRIZKHWKHUWKDWREMHFWLVWKUHDGVDIHLWVHOI
7KLVLVEHFDXVHWKHRQO\VWDWHWKDWLVHYHUVKDUHGDPRQJPXOWLSOHWKUHDGVLVWKHGURS
ER[%RWKWKUHDGVFRUUHFWO\VHL]HDVLQJOHORFNEHIRUHDFFHVVLQJLW:KHQ'%0LQGHULV
GRQHZLWKDQREMHFWLWSDVVHVLWWR'%9LHZHUDQGUHWDLQVQRUHIHUHQFHVWKHVWDWHRIWKH
SDVVHGREMHFWLVQHYHUVKDUHGE\PXOWLSOHWKUHDGV
7KUHDGFRQILQHPHQWLVDVXUSULVLQJO\SRZHUIXOWULFN,PSOHPHQWDWLRQVXVXDOO\PDNH
WKHVKDUHGGURSDQRUGHUHGWDVNTXHXH0XOWLSOHWKUHDGVPD\FRQWHQGIRUWKHORFNEXW
HDFKKROGVLWRQO\ORQJHQRXJKWRHQTXHXHDWDVN2QHRUPRUHZRUNHUWKUHDGVVHL]H
WKHTXHXHWRUHPRYHWDVNVIRUH[HFXWLRQ7KLVLVDSDWWHUQWKDWLVVRPHWLPHVFDOOHGWKH
SURGXFHUFRQVXPHUPRGHO$VORQJDVDXQLWRIZRUNFDQSURFHHGHQWLUHO\LQWKHFRQWH[W
RIWKHZRUNHUWKUHDGWKDWFODLPVLWWKHUHLVQRQHHGIRUIXUWKHUV\QFKURQL]DWLRQ,I\RX
ORRNLQWRWKHLPSOHPHQWDWLRQRIAsyncTask\RXZLOOGLVFRYHUWKDWWKLVLVH[DFWO\KRZLW
ZRUNV
7KUHDGFRQILQHPHQWLVVRXVHIXOWKDW$QGURLGKDVEDNHGLWLQWRLWVIUDPHZRUNLQWKH
FODVVFDOOHGLooper:KHQLQLWLDOL]HGDVDLooperD-DYDWKUHDGWXUQVLQWRDWDVNTXHXH
,WVSHQGVLWVHQWLUHOLIHUHPRYLQJWKLQJVIURPDORFDOTXHXHDQGH[HFXWLQJWKHP2WKHU
WKUHDGVHQTXHXHZRUNDVGHVFULEHGHDUOLHUIRUWKHLQLWLDOL]HGWKUHDGWRSURFHVV$VORQJ
DVWKHHQTXHXLQJWKUHDGGHOHWHVDOOUHIHUHQFHVWRWKHREMHFWLWHQTXHXHVERWKWKUHDGV
FDQ EH FRGHG ZLWKRXW IXUWKHU FRQFHUQ IRU FRQFXUUHQF\ ,Q DGGLWLRQ WR PDNLQJ LW
Concurrency in Android | 155
Download from Wow! eBook <www.wowebook.com>
GUDPDWLFDOO\HDVLHUWRPDNHSURJUDPVWKDWDUHFRUUHFWWKLVDOVRUHPRYHVDQ\LQHIILFLHQF\
WKDWPLJKWEHFDXVHGE\H[WHQVLYHV\QFKURQL]DWLRQ
3HUKDSVWKLVGHVFULSWLRQRIDWDVNTXHXHEULQJVWRPLQGDFRQVWUXFWWRZKLFKZHDOOXGHG
HDUOLHU LQ WKLV FKDSWHU" $QGURLG¦V VLQJOHWKUHDGHG HYHQWGULYHQ 8, LV VLPSO\ D
Looper:KHQLWODXQFKHVD ContextWKHV\VWHPGRHVVRPHERRNNHHSLQJDQGWKHQLQL
WLDOL]HVWKHODXQFKWKUHDGDVDLooper7KDWWKUHDGEHFRPHVWKHPDLQWKUHDGIRUDVHUYLFH
DQGWKH8,WKUHDGIRUDQDFWLYLW\,QDQDFWLYLW\WKH8,IUDPHZRUNSUHVHUYHVDUHIHUHQFH
WRWKLVWKUHDGDQGLWVWDVNTXHXHEHFRPHVWKH8,HYHQWTXHXHDOOWKHH[WHUQDOGULYHUV
WKHVFUHHQWKHNH\ERDUGWKHFDOOKDQGOHUDQGVRRQHQTXHXHDFWLRQVRQWKLVTXHXH
7KHRWKHUKDOIRILooperLVHandler$HandlerFUHDWHGRQDLooperWKUHDGSURYLGHVD
SRUWDOWRWKHLooperTXHXH:KHQDLooperWKUHDGZLVKHVWRDOORZVRPHRWKHUHQTXHXHG
WKUHDGDFFHVVWRLWVWDVNTXHXHLWFUHDWHVDQHZHandlerDQGSDVVHVLWWRWKHRWKHUWKUHDG
7KHUHDUHVHYHUDOVKRUWFXWVWKDWPDNHLWHDVLHUWRXVHDHandlerView.post(Runnable)
View.postDelayed(Runnable, long)DQGActivity.runOnUiThread(Runnable)
7KHUHLV\HWDQRWKHUFRQYHQLHQWDQGSRZHUIXOSDUDGLJPLQWKH$QGURLGWRRONLWIRULQ
WHUSURFHVVFRPPXQLFDWLRQDQGZRUNVKDULQJWKHContentProviderZKLFKZH¦OOGLVFXVV
LQ&KDSWHU&RQVLGHUZKHWKHUDFRQWHQWSURYLGHUFDQILW\RXUQHHGVEHIRUH\RXEXLOG
\RXURZQDUFKLWHFWXUHRQWKHORZOHYHOFRPSRQHQWVGLVFXVVHGLQWKLVVHFWLRQ&RQWHQW
SURYLGHUVDUHIOH[LEOHDQGH[WHQVLEOHDQGKDQGOHFRQFXUUHQWSURFHVVLQJLQDZD\WKDW
LVIDVWHQRXJKIRUDOOEXWWKHPRVWWLPHVHQVLWLYHDSSOLFDWLRQV
Serialization
6HULDOL]DWLRQLVFRQYHUWLQJGDWDIURPDIDVWHIILFLHQWLQWHUQDOUHSUHVHQWDWLRQWRVRPH
WKLQJWKDWFDQEHNHSWLQDSHUVLVWHQWVWRUHRUWUDQVPLWWHGRYHUDQHWZRUN&RQYHUWLQJ
GDWDWRLWVVHULDOL]HGIRUPLVRIWHQFDOOHGPDUVKDOLQJLW&RQYHUWLQJLWEDFNWRLWVOLYHLQ
PHPRU\UHSUHVHQWDWLRQLVFDOOHGGHVHULDOL]LQJRUXQPDUVKDOLQJ
([DFWO\KRZGDWDLVVHULDOL]HGGHSHQGVRQWKHUHDVRQIRUVHULDOL]LQJLW'DWDVHULDOL]HG
IRUWUDQVPLVVLRQRYHUDQHWZRUNIRULQVWDQFHPD\QRWQHHGWREHOHJLEOHLQIOLJKW'DWD
VHULDOL]HGIRUVWRUDJHLQDGDWDEDVHKRZHYHUZLOOEHIDUPRUHXVHIXOLIWKHUHSUHVHQWDWLRQ
SHUPLWV64/TXHULHVWKDWDUHHDV\WRFRQVWUXFWDQGPDNHVHQVH,QWKHIRUPHUFDVHWKH
VHULDOL]DWLRQIRUPDWPLJKWEHELQDU\,QWKHODWWHULWLVOLNHO\WREHODEHOHGWH[W
7KH$QGURLGHQYLURQPHQWDGGUHVVHVIRXUFRPPRQXVHVIRUVHULDOL]DWLRQ
/LIHF\FOHPDQDJHPHQW
8QOLNHODUJHUGHYLFHV¢ODSWRSDQGGHVNWRSPDFKLQHVIRULQVWDQFH¢$QGURLGGH
YLFHVFDQQRWFRXQWRQEHLQJDEOHWRVZDSDQDSSOLFDWLRQWRDIDVWEDFNLQJVWRUH
ZKHQWKDWDSSOLFDWLRQEHFRPHVLQDFWLYH,QVWHDGWKHIUDPHZRUNSURYLGHVDQREMHFW
FDOOHG D Bundle :KHQ DQ DSSOLFDWLRQ LV VXVSHQGHG LW ZULWHV LWV VWDWH LQWR WKH
Bundle:KHQWKHDSSOLFDWLRQLVUHFUHDWHGWKH$QGURLG)UDPHZRUNSURPLVHVWR
VXSSO\DFRS\RIWKHVDPHBundleGXULQJLWVLQLWLDOL]DWLRQ$QDSSOLFDWLRQPXVWEH
156 | Chapter 6:ಗEffective Java for Android
DEOHWRVHULDOL]HDQ\WKLQJLWZDQWVWRNHHSDFURVVLWVVXVSHQVLRQDQGWRVWRUHWKH
VHULDOL]HGYHUVLRQLQWKHBundle
3HUVLVWHQFH
,QDGGLWLRQWRWKHLPPHGLDWHDSSOLFDWLRQVWDWHNHSWLQDBundlePRVWDSSOLFDWLRQV
PDQDJHVRPHNLQGRISHUVLVWHQWGDWDVWRUH7KLVGDWDVWRUHLVPRVWOLNHO\DQ64/LWH
GDWDEDVHZUDSSHGLQDContentProvider$SSOLFDWLRQVPXVWFRQYHUWEDFNDQGIRUWK
EHWZHHQWKHLQWHUQDOUHSUHVHQWDWLRQRIREMHFWGDWDDQGWKHUHSUHVHQWDWLRQVRIWKRVH
VDPH REMHFWV LQ WKH GDWDEDVH ,Q ODUJHU V\VWHPV WKLV SURFHVV¢FDOOHG REMHFW
UHODWLRQDOPDSSLQJRUMXVW250¢LVVXSSRUWHGE\IUDPHZRUNVVXFKDV+LEHUQDWH
DQGL%$7,6$QGURLG¦VORFDOGDWDVWRUHLVVLPSOHUDQGOLJKWHUZHLJKW,WLVGHVFULEHG
LQ&KDSWHU
/RFDOLQWHUSURFHVVFRPPXQLFDWLRQ
7KH$QGURLG)UDPHZRUNSURPRWHVDQDUFKLWHFWXUHWKDWEUHDNVODUJHUPRQROLWKLF
DSSOLFDWLRQVLQWRVPDOOHUFRPSRQHQWV8,VFRQWHQWSURYLGHUVDQGVHUYLFHV7KHVH
FRPSRQHQWVGRQRWKDYHDFFHVVWRHDFKRWKHU¦VPHPRU\VSDFHDQGPXVWSDVVLQ
IRUPDWLRQDFURVVSURFHVVERXQGDULHVDVVHULDOL]HGPHVVDJHV$QGURLGSURYLGHVD
KLJKO\RSWLPL]HGWRROIRUWKLV$,'/
1HWZRUNFRPPXQLFDWLRQ
7KLVLVWKHSDUWWKDWPDNHVPRELOHGHYLFHVH[FLWLQJ7KHDELOLW\WRFRQQHFWWRWKH
,QWHUQHWDQGWRXVHWKHLQFUHGLEOHYDULHW\RIVHUYLFHVDYDLODEOHWKHUHLVZKDW$QGURLG
LVDOODERXW$SSOLFDWLRQVQHHGWREHDEOHWRKDQGOHWKHSURWRFROVLPSRVHGE\DQ\
H[WHUQDOVHUYLFHZKLFKLQFOXGHVWUDQVODWLQJLQWHUQDOLQIRUPDWLRQLQWRTXHULHVWR
WKRVHVHUYLFHVDQGUHWUDQVODWLQJWKHUHVSRQVH
7KHIROORZLQJVHFWLRQVGHVFULEHWKHYDULRXVFODVVHVDW\RXUGLVSRVDOIRUDFKLHYLQJWKHVH
JRDOV
Java Serialization
-DYDGHILQHVDVHULDOL]DWLRQIUDPHZRUNWKURXJKWKHSerializablePDUNHULQWHUIDFHDQG
WKHSDLURIVHULDOL]DWLRQW\SHVFDOOHG ObjectOutputStreamDQG ObjectInputStream%H
FDXVH-DYDVHULDOL]DWLRQPRVWO\MXVWZRUNVHYHQH[SHULHQFHG-DYDSURJUDPPHUVPD\
QRWUHFRJQL]HLWVFRPSOH[LW\,WLVFHUWDLQO\RXWVLGHWKHVFRSHRIWKLVERRN-RVK%ORFK
GHYRWHVQHDUO\RIKLVVHPLQDOERRN(IIHFWLYH-DYD 3UHQWLFH+DOO WRDGLVFXVVLRQ
RI-DYD¦VVHULDOL]DWLRQIUDPHZRUNDQGKRZWRXVHLWFRUUHFWO\7KHFKDSWHULVZRUWKZKLOH
UHDGLQJ DV D ZD\ WR XQGHUVWDQG WKH LVVXHV HYHQ LI \RX GRQ¦W H[SHFW WR XVH -DYD¦V
IUDPHZRUN
$QGURLGGRHVVXSSRUW-DYDVHULDOL]DWLRQ7KH BundleW\SHIRULQVWDQFHKDVWKHSDLU
RI PHWKRGV putSerializable DQG getSerializable ZKLFK UHVSHFWLYHO\ DGG D -DYD
SerializableWRDQGUHFRYHULWIURPDBundle)RUH[DPSOH
public class JSerialize extends Activity {
public static final String APP_STATE
= "com.oreilly.android.app.state";
Serialization | 157
private static class AppState implements Serializable {
// definitions, getters and setters
// for application state parameters here.
// ...
}
private AppState applicationState;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedAppState) {
super.onCreate(savedAppState);
applicationState = (null == savedAppState)
? new AppState(/* ... */)
: (AppState) savedAppState.getSerializable(APP_STATE);
setContentView(R.layout.main);
}
// ...
/**
* @see android.app.Activity#onSaveInstanceState(android.os.Bundle)
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(APP_STATE, applicationState);
}
}
,QWKLVH[DPSOHWKHDSSOLFDWLRQNHHSVVRPHJOREDOVWDWHLQIRUPDWLRQ¢SHUKDSVDOLVW
RIUHFHQWO\XVHGLWHPV¢DVDSerializableREMHFW:KHQDJSerializeDFWLYLW\LVSDXVHG
VRWKDWDQRWKHUDFWLYLW\FDQUHSODFHLWLQPHPRU\WKH$QGURLG)UDPHZRUNLQYRNHVWKH
JSerializeFDOOEDFNPHWKRG onSaveInstanceStateSDVVLQJD BundleREMHFW7KHFDOO
EDFNPHWKRGXVHV Bundle.putSerializableWRVDYHWKHVWDWHRIWKHREMHFWLQWRWKH Bun
dle:KHQ JSerializeLVUHVXPHGWKH onCreatePHWKRGUHWULHYHVWKHVWDWHIURPWKH
BundleXVLQJgetSerializable
AIDL and Remote Procedure Calls
,QRUGHUWRGHFODUHDQ$,'/LQWHUIDFH\RX¦OOQHHGVHYHUDOWKLQJV
‡ $Q$,'/ILOHWKDWGHVFULEHVWKH$3,
‡ )RUHYHU\QRQVLPSOHW\SHXVHGLQWKH$3,DVXEFODVVRI ParcelableGHILQLQJWKH
W\SHDQGDQ$,'/ILOHQDPLQJWKHW\SHDVSDUFHODEOH2QHFDXWLRQZKHQGRLQJ
WKLV\RXPXVWEHZLOOLQJWRGLVWULEXWHWKHVRXUFHIRUWKRVHFODVVHVWRDOOFOLHQWVWKDW
VHULDOL]HWKHP
‡ $VHUYLFHWKDWUHWXUQVDQLPSOHPHQWDWLRQRIWKH$3,VWXELQUHVSRQVHWR onBind
onBindPXVWEHSUHSDUHGWRUHWXUQWKHFRUUHFWLPSOHPHQWDWLRQIRUHDFKLQWHQWZLWK
158 | Chapter 6:ಗEffective Java for Android
ZKLFKLWPLJKWEHFDOOHG7KHUHWXUQHGLQVWDQFHSURYLGHVWKHDFWXDOLPSOHPHQWD
WLRQVRIWKH$3,PHWKRGV
‡ 2Q WKH FOLHQW DQ LPSOHPHQWDWLRQ RI ServiceConnection onServiceConnected
VKRXOGFDVWWKHSDVVHGELQGHUXVLQJAPI.Stub.asInterface(binder)DQGVDYHWKH
UHVXOWDVDUHIHUHQFHWRWKHVHUYLFH$3, onServiceDisconnectedPXVWQXOOWKHUHI
HUHQFH ,W FDOOV bindService ZLWK DQ Intent WKDW WKH $3, VHUYLFH SURYLGHV WKH
ServiceConnectionDQGIODJVWKDWFRQWUROVHUYLFHFUHDWLRQ
‡ %LQGLQJWKDWLVDV\QFKURQRXV-XVWEHFDXVHbindServiceUHWXUQVWUXHGRHVQRWPHDQ
WKDW\RXKDYHDUHIHUHQFHWRWKHVHUYLFH\HW<RXPXVWUHOHDVHWKHWKUHDGDQGZDLW
IRUWKHLQYRFDWLRQRIonServiceConnectedWRXVHWKHVHUYLFH
Parcelable
$OWKRXJKWKH$QGURLG)UDPHZRUNVXSSRUWV-DYDVHULDOL]DWLRQLWLVXVXDOO\QRWWKHEHVW
FKRLFHDVDZD\WRPDUVKDOSURJUDPVWDWH$QGURLG¦VRZQLQWHUQDOVHULDOL]DWLRQSURWRFRO
ParcelableLVOLJKWZHLJKWKLJKO\RSWLPL]HGDQGRQO\VOLJKWO\PRUHGLIILFXOWWRXVH,W
LVWKHEHVWFKRLFHIRUORFDOLQWHUSURFHVVFRPPXQLFDWLRQ)RUUHDVRQVWKDWZLOOEHFRPH
DSSDUHQW ZKHQ ZH UHYLVLW Parcelable REMHFWV LQ £&ODVVHV 7KDW 6XSSRUW 6HULDOL]D
WLRQ¤ RQ SDJH WKH\ FDQQRW EH XVHG WR VWRUH REMHFWV EH\RQG WKH OLIHWLPH RI DQ
DSSOLFDWLRQ7KH\DUHQRWDQDSSURSULDWHFKRLFHIRUPDUVKDOLQJVWDWHWRVD\DGDWDEDVH
RUDILOH
+HUH¦VDYHU\VLPSOHREMHFWWKDWKROGVVRPHVWDWH/HW¦VVHHZKDWLWWDNHVWRPDNHLW
£SDUFHODEOH¤
public class SimpleParcelable {
public enum State { BEGIN, MIDDLE, END; }
private State state;
private Date date;
State getState() { return state; }
void setState(State state) { this.state = state; }
}
Date getDate() { return date; }
void setDate(Date date) { this.date = date; }
$QREMHFWPXVWPHHWWKUHHUHTXLUHPHQWVLQRUGHUWREHSDUFHODEOH
‡ ,WPXVWLPSOHPHQWWKHParcelableLQWHUIDFH
‡ ,W PXVW KDYH D PDUVKDOHU DQ LPSOHPHQWDWLRQ RI WKH LQWHUIDFH PHWKRG writeTo
Parcel
‡ ,WPXVWKDYHDQXQPDUVKDOHUDpublic static finalYDULDEOHQDPHGCREATORFRQ
WDLQLQJDUHIHUHQFHWRDQLPSOHPHQWDWLRQRIParcelable.Creator
Serialization | 159
7KHLQWHUIDFHPHWKRGwriteToParcelLVWKHPDUVKDOHU,WLVFDOOHGIRUDQREMHFWZKHQLW
LVQHFHVVDU\WRVHULDOL]HWKDWREMHFWWRDParcel7KHPDUVKDOHU¦VMRELVWRZULWHHYHU\WKLQJ
QHFHVVDU\WRUHFRQVWUXFWWKHREMHFWVWDWHWRWKHSDVVHGParcel7\SLFDOO\WKLVZLOOPHDQ
H[SUHVVLQJWKHREMHFWVWDWHLQWHUPVRIWKHVL[SULPLWLYHGDWDW\SHV byte double int
floatlongDQGString+HUH¦VWKHVDPHVLPSOHREMHFWEXWWKLVWLPHZLWKWKHPDUVKDOHU
DGGHG
public class SimpleParcelable implements Parcelable {
public enum State { BEGIN, MIDDLE, END; }
private static final Map<State, String> marshalState;
static {
Map<State, String> m = new HashMap<State, String>();
m.put(State.BEGIN, "begin");
m.put(State.MIDDLE, "middle");
m.put(State.END, "end");
marshalState = Collections.unmodifiableMap(m);
}
private State state;
private Date date;
@Override
public void writeToParcel(Parcel dest, int flags) {
// translate the Date to a long
dest.writeLong(
(null == date)
? -1
: date.getTime());
}
dest.writeString(
(null == state)
? ""
: marshalState.get(state));
State getState() { return state; }
void setState(State state) { this.state = state; }
}
Date getDate() { return date; }
void setDate(Date date) { this.date = date; }
2IFRXUVHWKHH[DFWLPSOHPHQWDWLRQRIwriteToParcelZLOOGHSHQGRQWKHFRQWHQWVRI
WKHREMHFWEHLQJVHULDOL]HG,QWKLVFDVHWKHSimpleParcelableREMHFWKDVWZRSLHFHVRI
VWDWHDQGZULWHVERWKRIWKHPLQWRWKHSDVVHGParcel
&KRRVLQJDUHSUHVHQWDWLRQIRUPRVWVLPSOHGDWDW\SHVXVXDOO\ZRQ¦WUHTXLUHDQ\WKLQJ
PRUHWKDQDOLWWOHLQJHQXLW\7KHDateLQWKLVH[DPSOHIRULQVWDQFHLVHDVLO\UHSUHVHQWHG
E\LWVWLPHVLQFHWKHPLOOHQQLXP
%H VXUH WKRXJK WR WKLQN DERXW IXWXUH FKDQJHV WR GDWD ZKHQ SLFNLQJ WKH VHULDOL]HG
UHSUHVHQWDWLRQ&HUWDLQO\LWZRXOGKDYHEHHQPXFKHDVLHULQWKLVH[DPSOHWRUHSUHVHQW
160 | Chapter 6:ಗEffective Java for Android
stateDVDQintZKRVHYDOXHZDVREWDLQHGE\FDOOLQJstate.ordinal'RLQJVRKRZHYHU
ZRXOGPDNHLWPXFKKDUGHUWRPDLQWDLQIRUZDUGFRPSDWLELOLW\IRUWKHREMHFW6XSSRVH
LW EHFRPHV QHFHVVDU\ DW VRPH SRLQW WR DGG D QHZ VWDWH State.INIT EHIRUH
State.BEGIN7KLVWULYLDOFKDQJHPDNHVQHZYHUVLRQVRIWKHREMHFWFRPSOHWHO\LQFRP
SDWLEOHZLWKHDUOLHUYHUVLRQV$VLPLODULIVOLJKWO\ZHDNHUDUJXPHQWDSSOLHVWRXVLQJ
state.toStringWRFUHDWHWKHPDUVKDOHGUHSUHVHQWDWLRQRIWKHVWDWH
7KHPDSSLQJEHWZHHQDQREMHFWDQGLWVUHSUHVHQWDWLRQLQD ParcelLVSDUWRIWKHSDU
WLFXODUVHULDOL]DWLRQSURFHVV,WLVQRWDQLQKHUHQWDWWULEXWHRIWKHREMHFW,WLVHQWLUHO\
SRVVLEOHWKDWDJLYHQREMHFWKDVFRPSOHWHO\GLIIHUHQWUHSUHVHQWDWLRQVZKHQVHULDOL]HGE\
GLIIHUHQWVHULDOL]HUV7RLOOXVWUDWHWKLVSULQFLSOH¢WKRXJKLWLVSUREDEO\RYHUNLOOJLYHQ
WKDWWKHW\SHStateLVORFDOO\GHILQHG¢WKHPDSXVHGWRPDUVKDOstateLVDQLQGHSHQGHQW
DQGH[SOLFLWO\GHILQHGPHPEHURIWKHSDUFHODEOHFODVV
SimpleParcelable DV VKRZQ HDUOLHU FRPSLOHV ZLWKRXW HUURUV ,W FRXOG HYHQ EH PDU
VKDOHGWRDSDUFHO$V\HWWKRXJKWKHUHLVQRZD\WRJHWLWEDFNRXW)RUWKDWZHQHHG
WKHXQPDUVKDOHU
public class SimpleParcelable implements Parcelable {
// Code elided...
private static final Map<String, State> unmarshalState;
static {
Map<String, State> m = new HashMap<String, State>();
m.put("begin", State.BEGIN);
m.put("middle", State.MIDDLE);
m.put("end", State.END);
unmarshalState = Collections.unmodifiableMap(m);
}
// Unmarshaler
public static final Parcelable.Creator<SimpleParcelable> CREATOR
= new Parcelable.Creator<SimpleParcelable>() {
public SimpleParcelable createFromParcel(Parcel src) {
return new SimpleParcelable(
src.readLong(),
src.readString());
}
public SimpleParcelable[] newArray(int size) {
return new SimpleParcelable[size];
}
};
private State state;
private Date date;
public SimpleParcelable(long date, String state) {
if (0 <= date) { this.date = new Date(date); }
if ((null != state) && (0 < state.length())) {
this.state = unmarshalState.get(state);
}
Serialization | 161
}
// Code elided...
}
7KLVVQLSSHWVKRZVRQO\WKHQHZO\DGGHGXQPDUVKDOHUFRGHWKHSXEOLFVWDWLF final
ILHOGFDOOHGCREATORDQGLWVFROODERUDWRUV7KHILHOGLVDUHIHUHQFHWRDQLPSOHPHQWDWLRQ
RIParcelable.Creator<T>ZKHUHTLVWKHW\SHRIWKHSDUFHODEOHREMHFWWREHXQPDUVKDOHG
LQWKLVFDVH SimpleParcelable ,W¦VLPSRUWDQWWRJHWDOOWKHVHWKLQJVH[DFWO\ULJKW,I
CREATORLVSURWHFWHGLQVWHDGRISXEOLFQRWVWDWLFRUVSHOOHG£&UHDWRU¤WKHIUDPHZRUN
ZLOOEHXQDEOHWRXQPDUVKDOWKHREMHFW
7KH LPSOHPHQWDWLRQ RI Parcelable.Creator<T> LV DQ REMHFW ZLWK D VLQJOH PHWKRG
createFromParcelZKLFKXQPDUVKDOVDVLQJOHLQVWDQFHIURPWKHParcel7KHLGLRPDWLF
ZD\WRGRWKLVLVWRUHDGHDFKSLHFHRIVWDWHIURPWKHParcelLQH[DFWO\WKHVDPHRUGHU
DVLWZDVZULWWHQLQ writeToParcel DJDLQWKLVLVLPSRUWDQW DQGWKHQWRFDOODFRQ
VWUXFWRUZLWKWKHXQPDUVKDOHGVWDWH6LQFHWKHXQPDUVKDOLQJFRQVWUXFWRULVFDOOHGIURP
FODVVVFRSHLWFDQEHSDFNDJHSURWHFWHGRUHYHQSULYDWH
Classes That Support Serialization
7KH3DUFHO$3,LVQRWOLPLWHGWRWKHVL[SULPLWLYHW\SHVPHQWLRQHGLQWKHSUHYLRXVVHF
WLRQ7KH$QGURLGGRFXPHQWDWLRQJLYHVWKHFRPSOHWHOLVWRISDUFHODEOHW\SHVEXWLWLV
KHOSIXOWRWKLQNRIWKHPDVGLYLGHGLQWRIRXUJURXSV
7KHILUVWJURXSVLPSOHW\SHVFRQVLVWVRInullWKHVL[SULPLWLYHV intfloatHWF DQG
WKHER[HGYHUVLRQVRIWKHVL[SULPLWLYHV IntegerFloatHWF 7KH QH[W JURXS FRQVLVWV RI REMHFW W\SHV LPSOHPHQWLQJ Serializable RU Parcelable
7KHVHREMHFWVDUHQRWVLPSOHEXWWKH\NQRZKRZWRVHULDOL]HWKHPVHOYHV
$QRWKHU JURXS FROOHFWLRQ W\SHV FRYHUV DUUD\V OLVWV PDSV EXQGOHV DQG VSDUVH
DUUD\VRIWKHSUHFHGLQJWZRW\SHV int[] float[] ArrayList<?> HashMap<String, ?>
Bundle<?>SparseArray<?>HWF )LQDOO\WKHUHDUHVRPHVSHFLDOFDVHVCharSequenceDQGDFWLYHREMHFWV IBinder :KLOHDOOWKHVHW\SHVFDQEHPDUVKDOHGLQWRDParcelWKHUHDUHWZRWRDYRLGLISRVVLEOH
SerializableDQGMap$VPHQWLRQHGHDUOLHU$QGURLGVXSSRUWVQDWLYH-DYDVHULDOL]DWLRQ
,WVLPSOHPHQWDWLRQLVQRWQHDUO\DVHIILFLHQWDVWKHUHVWRI Parcelable,PSOHPHQWLQJ
SerializableLQDQREMHFWLVQRWDQHIIHFWLYHZD\WRPDNHLWSDUFHODEOH,QVWHDGREMHFWV
VKRXOGLPSOHPHQW ParcelableDQGDGGD CREATORREMHFWDQGD writeToParcelPHWKRG
DVGHVFULEHGLQ£3DUFHODEOH¤RQSDJH7KLVFDQEHDWHGLRXVWDVNLIWKHREMHFWKLHU
DUFK\LVFRPSOH[EXWWKHSHUIRUPDQFHJDLQVDUHXVXDOO\ZHOOZRUWKLW
7KHRWKHUSDUFHODEOHW\SHWRDYRLGLVWKHMapParcelGRHVQ¦WDFWXDOO\VXSSRUWPDSVLQ
JHQHUDORQO\WKRVHZLWKNH\VWKDWDUHVWULQJV7KH$QGURLGVSHFLILFBundleW\SHSURYLGHV
WKHVDPHIXQFWLRQDOLW\¢DPDSZLWKVWULQJNH\V¢EXWLVLQDGGLWLRQW\SHVDIH2EMHFWV
162 | Chapter 6:ಗEffective Java for Android
DUHDGGHGWRDBundleZLWKPHWKRGVVXFKDVputDoubleDQGputSparseParcelableArray
RQH IRU HDFK SDUFHODEOH W\SH &RUUHVSRQGLQJ PHWKRGV VXFK DV getDouble DQG get
SparseParcelableArrayJHWWKHREMHFWVEDFNRXW$BundleLVMXVWOLNHDPDSH[FHSWWKDW
LWFDQKROGGLIIHUHQWW\SHVRIREMHFWVIRUGLIIHUHQWNH\VLQDZD\WKDWLVSHUIHFWO\W\SH
VDIH8VLQJD BundleHOLPLQDWHVWKHHQWLUHFODVVRIKDUGWRILQGHUURUVWKDWDULVHZKHQ
VD\DVHULDOL]HGfloatLVPLVWDNHQO\LQWHUSUHWHGDVDQint
7\SH VDIHW\ LV DOVR D UHDVRQ WR SUHIHU WKH PHWKRGV writeTypedArray DQG writeTyped
ListWRWKHLUXQW\SHGDQDORJVwriteArrayDQGwriteList
Serialization and the Application Life Cycle
$VPHQWLRQHGHDUOLHUDQ$QGURLGDSSOLFDWLRQPD\QRWKDYHWKHOX[XU\RIYLUWXDOPHP
RU\ 2Q D VPDOO GHYLFH WKHUH LV QR VHFRQGDU\ VWRUH WR ZKLFK D UXQQLQJ EXW KLGGHQ
DSSOLFDWLRQFDQEHSXVKHGWRPDNHURRPIRUDQHZYLVLEOHDSSOLFDWLRQ6WLOODJRRG
XVHUH[SHULHQFHGHPDQGVWKDWZKHQWKHXVHUUHWXUQVWRDQDSSOLFDWLRQLWORRNVWKHZD\
LWGLGZKHQKHOHIWLW7KHUHVSRQVLELOLW\IRUSUHVHUYLQJVWDWHDFURVVVXVSHQVLRQIDOOVWR
WKH DSSOLFDWLRQ LWVHOI )RUWXQDWHO\ WKH $QGURLG )UDPHZRUN PDNHV SUHVHUYLQJ VWDWH
VWUDLJKWIRUZDUG
7KHH[DPSOHLQ£-DYD6HULDOL]DWLRQ¤RQSDJHVKRZHGWKHJHQHUDOIUDPHZRUNPHFK
DQLVPWKDWDOORZVDQDSSOLFDWLRQWRSUHVHUYHVWDWHDFURVVVXVSHQVLRQV:KHQHYHUWKH
DSSOLFDWLRQLVHYLFWHGIURPPHPRU\LWV onSaveInstanceStatePHWKRGLVFDOOHGZLWKD
BundleWRZKLFKWKHDSSOLFDWLRQFDQZULWHDQ\QHFHVVDU\VWDWH:KHQWKHDSSOLFDWLRQLV
UHVWDUWHG WKH IUDPHZRUN SDVVHV WKH VDPH Bundle WR WKH onCreate PHWKRG VR WKDW
WKH DSSOLFDWLRQ FDQ UHVWRUH LWV VWDWH %\ VHQVLEO\ FDFKLQJ FRQWHQW GDWD LQ D Content
Provider DQG VDYLQJ OLJKWZHLJKW VWDWH HJ WKH FXUUHQWO\ YLVLEOH SDJH WR WKH
onSaveInstanceBundleDQDSSOLFDWLRQFDQUHVXPHZLWKRXWLQWHUUXSWLRQ
7KH IUDPHZRUN SURYLGHV RQH PRUH WRRO IRU SUHVHUYLQJ DSSOLFDWLRQ VWDWH 7KH View
FODVV¢WKH EDVH W\SH IRU HYHU\WKLQJ YLVLEOH RQ WKH VFUHHQ¢KDV D KRRN PHWKRG
onSaveInstanceStateWKDWLVFDOOHGDVSDUWRIWKHSURFHVVRIHYLFWLQJDQDSSOLFDWLRQIURP
PHPRU\ ,Q IDFW LW LV FDOOHG IURP Activity.onSaveInstanceState ZKLFK LV ZK\
\RXU DSSOLFDWLRQ¦V LPSOHPHQWDWLRQ RI WKDW PHWKRG VKRXOG DOZD\V FDOO super.onSave
InstanceState
7KLVPHWKRGDOORZVVWDWHSUHVHUYDWLRQDWWKHYHU\ILQHVWOHYHO$QHPDLODSSOLFDWLRQIRU
LQVWDQFHPLJKWXVHLWWRSUHVHUYHWKHH[DFWORFDWLRQRIWKHFXUVRULQWKHWH[WRIDQXQVHQW
PDLOPHVVDJH
Serialization | 163
PART II
About the Android Framework
7KH$QGURLG)UDPHZRUNLVWKHVHWRIEDVHFODVVHVWKDWXQGHUOLH$QGURLGDSSOLFDWLRQV
DQGWKHSDUWVRI$QGURLGV\VWHPVRIWZDUHWKDWFRPSULVHWKH$QGURLGXVHUODQG+HUH
ZHRUJDQL]HRXUSUHVHQWDWLRQRIWKH$QGURLG$3,VDURXQGWKHJRDORIHQDEOLQJ\RXWR
LPSOHPHQW DSSOLFDWLRQV WKDW WDNH PD[LPXP DGYDQWDJH RI WKH $QGURLG V\VWHP
DUFKLWHFWXUH
CHAPTER 7
Building a View
$QGURLGFRPHVZLWKPDQ\UHTXLUHPHQWVWKDWKHUDOGFRPSOH[LW\LQWKHXVHULQWHUIDFH
LW¦VDPXOWLSURFHVVLQJV\VWHPWKDWVXSSRUWVPXOWLSOHFRQFXUUHQWDSSOLFDWLRQVDFFHSWV
PXOWLSOHIRUPVRILQSXWLVKLJKO\LQWHUDFWLYHDQGLVIOH[LEOHHQRXJKWRVXSSRUWDZLGH
UDQJHRIGHYLFHVQRZDQGLQWKHIXWXUH7KHXVHULQWHUIDFHLVERWKULFKDQGHDV\WRXVH
7KLVFKDSWHUSURYLGHV\RXZLWKWKHWHFKQLTXHVIRULPSOHPHQWLQJDJUDSKLFDOLQWHUIDFH
RQ$QGURLG,WH[SODLQVWKHDUFKLWHFWXUHRIWKH$QGURLG8,WRRONLWZKLOHVKRZLQJ\RX
LQSUDFWLFDOWHUPVKRZWRXVHEDVLFLQWHUIDFHHOHPHQWVVXFKDVEXWWRQVDQGWH[WER[HV
,WDOVRFRYHUVHYHQWKDQGOLQJXVLQJPXOWLSOHWKUHDGVWRRIIORDGORQJUXQQLQJWDVNVVR
WKDW WKH 8, GRHVQ¦W IUHH]H DQG RWKHU WRSLFV WKDW PDNH XVHU LQWHUIDFHV SOHDVDQW DQG
SHUIRUPDQW
Android GUI Architecture
7KH$QGURLGHQYLURQPHQWDGGV\HWDQRWKHU*8,WRRONLWWRWKH-DYDHFRV\VWHPMRLQLQJ
$:76ZLQJ6:7/:8,7DQGRWKHUV,I\RXKDYHZRUNHGZLWKDQ\RIWKHVHWKH
$QGURLG8,IUDPHZRUNZLOOORRNIDPLOLDU/LNHWKHPLWLVVLQJOHWKUHDGHGHYHQWGULYHQ
DQGEXLOWRQDOLEUDU\RIQHVWDEOHFRPSRQHQWV
7KH$QGURLG8,IUDPHZRUNLVOLNHRWKHU-DYD8,IUDPHZRUNVRUJDQL]HGDURXQGWKH
FRPPRQ0RGHO9LHZ&RQWUROOHUSDWWHUQLOOXVWUDWHGLQ)LJXUH,WSURYLGHVVWUXFWXUH
DQGWRROVIRUEXLOGLQJD&RQWUROOHUWKDWKDQGOHVXVHULQSXW OLNHNH\SUHVVHVDQGVFUHHQ
WDSV DQGD9LHZWKDWUHQGHUVJUDSKLFDOLQIRUPDWLRQWRWKHVFUHHQ
The Model
7KH0RGHOLVWKHJXWVRI\RXUDSSOLFDWLRQ¢ZKDWLWDFWXDOO\GRHV,WPLJKWEHIRULQ
VWDQFHWKHGDWDEDVHRIPXVLFRQ\RXUGHYLFHDQGWKHFRGHIRUSOD\LQJWKHPXVLF,W
PLJKWEH\RXUOLVWRIFRQWDFWVDQGWKHFRGHWKDWSODFHVSKRQHFDOOVRUVHQGV,0VWRWKHP
,WLVWKHVXEMHFWRIDODUJHSDUWRIWKHUHVWRIWKLVERRN
167
)LJXUH0RGHO9LHZ&RQWUROOHUFRQFHSW
:KLOHDSDUWLFXODUDSSOLFDWLRQ¦V9LHZDQG&RQWUROOHUZLOOQHFHVVDULO\UHIOHFWWKH0RGHO
WKH\PDQLSXODWHDVLQJOH0RGHOPLJKWEHXVHGE\VHYHUDOGLIIHUHQWDSSOLFDWLRQV&RQ
VLGHUIRULQVWDQFHDQ03SOD\HUDQGDQDSSOLFDWLRQWKDWFRQYHUWV03ILOHVLQWR:$9
ILOHV)RUERWKDSSOLFDWLRQVWKH0RGHOLQFOXGHVWKH03ILOHIRUPDW7KHIRUPHUDS
SOLFDWLRQKRZHYHUKDVWKHIDPLOLDU6WRS6WDUWDQG3DXVHFRQWUROVDQGSOD\VWXQHV
7KHODWWHUPD\QRWSURGXFHDQ\VRXQGDWDOO,QVWHDGLWZLOOKDYHFRQWUROVIRUWKLQJV
VXFKDVELWUDWH7KH0RGHOLVDOODERXWWKHGDWD
The View
7KH9LHZLVWKHYLVXDOL]DWLRQRIWKH0RGHO0RUHJHQHUDOO\DYLHZLVWKHSRUWLRQRIWKH
DSSOLFDWLRQUHVSRQVLEOHIRUUHQGHULQJWKHGLVSOD\VHQGLQJDXGLRWRWKHVSHDNHUVJHQ
HUDWLQJWDFWLOHIHHGEDFNDQGVRRQ7KHJUDSKLFDOSRUWLRQRIWKH$QGURLG8,IUDPHZRUN
GHVFULEHGLQGHWDLOLQ&KDSWHULVLPSOHPHQWHGDVDWUHHRIVXEFODVVHVRIWKHViewFODVV
*UDSKLFDOO\HDFKREMHFWUHSUHVHQWVDUHFWDQJXODUDUHDRQWKHVFUHHQWKDWLVFRPSOHWHO\
ZLWKLQWKHUHFWDQJXODUDUHDUHSUHVHQWHGE\LWVSDUHQWLQWKHWUHH7KHURRWRIWKLVWUHHLV
WKHDSSOLFDWLRQZLQGRZ
$VDQH[DPSOHWKHGLVSOD\LQDK\SRWKHWLFDO03SOD\HUPLJKWFRQWDLQDFRPSRQHQW
WKDWVKRZVWKHDOEXPFRYHUIRUWKHFXUUHQWO\SOD\LQJWXQH$QRWKHU9LHZPLJKWGLVSOD\
WKHQDPHRIWKHFXUUHQWO\SOD\LQJVRQJZKLOHDWKLUGFRQWDLQVVXEYLHZVVXFKDVWKH3OD\
3DXVHDQG6WRSEXWWRQV
7KH8,IUDPHZRUNSDLQWVWKHVFUHHQE\ZDONLQJWKHYLHZWUHHDVNLQJHDFKFRPSRQHQW
WRGUDZLWVHOILQDSUHRUGHUWUDYHUVDO,QRWKHUZRUGVHDFK9LHZGUDZVLWVHOIDQGWKHQ
DVNVHDFKRILWVFKLOGUHQWRGRWKHVDPH:KHQWKHZKROHWUHHKDVEHHQUHQGHUHGWKH
168 | Chapter 7:ಗBuilding a View
VPDOOHUQHVWHGFRPSRQHQWVWKDWDUHWKHOHDYHVRIWKHWUHH¢DQGWKDWZHUHWKHUHIRUH
SDLQWHGODWHU¢DSSHDUWREHSDLQWHGRQWRSRIWKHFRPSRQHQWVWKDWDUHQHDUHUWRWKH
URRWDQGWKDWZHUHSDLQWHGILUVW
7KH$QGURLG8,IUDPHZRUNLVDFWXDOO\PRUHHIILFLHQWWKDQWKLVVLPSOLILHGGHVFULSWLRQ
,WGRHVQRWSDLQWDQDUHDRIDSDUHQW9LHZLILWFDQEHFHUWDLQWKDWVRPHFKLOGZLOOODWHU
SDLQWWKHVDPHDUHD,WZRXOGEHDZDVWHRIWLPHWRSDLQWWKHEDFNJURXQGXQGHUQHDWK
DQRSDTXHREMHFW,WZRXOGDOVREHDZDVWHRIWLPHWRUHSDLQWSRUWLRQVRID9LHZWKDW
KDYHQRWFKDQJHG
The Controller
7KH &RQWUROOHU LV WKHSRUWLRQRI DQ DSSOLFDWLRQ WKDW UHVSRQGVWRH[WHUQDODFWLRQVD
NH\VWURNHDVFUHHQWDSDQLQFRPLQJFDOODQGVRIRUWK,WLVLPSOHPHQWHGDVDQHYHQW
TXHXH(DFKH[WHUQDODFWLRQLVUHSUHVHQWHGDVDXQLTXHHYHQWLQWKHTXHXH7KHIUDPH
ZRUNUHPRYHVHDFKHYHQWIURPWKHTXHXHLQRUGHUDQGGLVSDWFKHVLW
)RUH[DPSOHZKHQDXVHUSUHVVHVDNH\RQKHUSKRQHWKH$QGURLGV\VWHPJHQHUDWHVD
KeyEventDQGDGGVLWWRWKHHYHQWTXHXH(YHQWXDOO\DIWHUSUHYLRXVO\HQTXHXHGHYHQWV
KDYHEHHQSURFHVVHGWKH KeyEventLVUHPRYHGIURPWKHTXHXHDQGSDVVHGDVWKHSD
UDPHWHURIDFDOOWRWKHdispatchKeyEventPHWKRGRIWKHViewWKDWLVFXUUHQWO\VHOHFWHG
2QFHDQHYHQWLVGLVSDWFKHGWRWKHLQIRFXVFRPSRQHQWWKHFRPSRQHQWPD\WDNHDS
SURSULDWHDFWLRQWRFKDQJHWKHLQWHUQDOVWDWHRIWKHSURJUDP,QDQ03SOD\HUDSSOL
FDWLRQIRULQVWDQFHZKHQWKHXVHUWDSVD3OD\3DXVHEXWWRQRQWKHVFUHHQDQGWKHHYHQW
LVGLVSDWFKHGWRWKDWEXWWRQ¦VREMHFWWKHKDQGOHUPHWKRGPLJKWXSGDWHWKH0RGHOWR
UHVXPHSOD\LQJVRPHSUHYLRXVO\VHOHFWHGWXQH
7KLVFKDSWHUGHVFULEHVWKHFRQVWUXFWLRQRIWKH&RQWUROOHUIRUDQ$QGURLGDSSOLFDWLRQ
Putting It Together
:HQRZKDYHDOOWKHFRQFHSWVQHFHVVDU\WRGHVFULEHWKHFRPSOHWH8,V\VWHP:KHQDQ
H[WHUQDODFWLRQRFFXUV¢ZKHQWKHXVHUVFUROOVGUDJVRUSUHVVHVDEXWWRQDFDOOFRPHV
LQRUDQ03SOD\HUDUULYHVDWWKHHQGRILWVSOD\OLVW¢WKH$QGURLGV\VWHPHQTXHXHVDQ
HYHQWUHSUHVHQWLQJWKHDFWLRQRQWKHHYHQWTXHXH(YHQWXDOO\WKHHYHQWLVGHTXHXHG¢
ILUVWLQILUVWRXW¢DQGGLVSDWFKHGWRDQDSSURSULDWHHYHQWKDQGOHU7KHKDQGOHUZKLFK
LVRIWHQFRGH\RXZULWHDVSDUWRI\RXUDSSOLFDWLRQUHVSRQGVWRWKHHYHQWE\QRWLI\LQJ
WKH0RGHOWKDWWKHUHKDVEHHQDFKDQJHLQVWDWH7KH0RGHOWDNHVWKHDSSURSULDWHDFWLRQ
1HDUO\DQ\FKDQJHLQ0RGHOVWDWHZLOOUHTXLUHDFRUUHVSRQGLQJFKDQJHLQWKHYLHZ,Q
UHVSRQVHWRDNH\SUHVVIRULQVWDQFHDQEditTextFRPSRQHQWPXVWVKRZWKHQHZO\W\SHG
FKDUDFWHUDWWKHLQVHUWSRLQW6LPLODUO\LQDSKRQHERRNDSSOLFDWLRQFOLFNLQJRQDFRQ
WDFWZLOOFDXVHWKDWFRQWDFWWREHKLJKOLJKWHGDQGWKHSUHYLRXVO\KLJKOLJKWHGFRQWDFWWR
KDYHLWVKLJKOLJKWLQJUHPRYHG
Android GUI Architecture | 169
:KHQWKH0RGHOXSGDWHVLWRZQVWDWHLWDOPRVWFHUWDLQO\ZLOOKDYHWRFKDQJHWKHFXUUHQW
GLVSOD\WRUHIOHFWWKHLQWHUQDOFKDQJH,QRUGHUWRXSGDWHWKHGLVSOD\WKH0RGHOPXVW
QRWLI\WKH8,IUDPHZRUNWKDWVRPHSRUWLRQRIWKHGLVSOD\LVQRZVWDOHDQGKDVWREH
UHGUDZQ7KHUHGUDZUHTXHVWLVDFWXDOO\QRWKLQJPRUHWKDQDQRWKHUHYHQWHQTXHXHGLQ
WKHVDPHIUDPHZRUNHYHQWTXHXHWKDWKHOGWKH&RQWUROOHUHYHQWDPRPHQWDJR7KH
UHGUDZHYHQWLVSURFHVVHGLQRUGHUOLNHDQ\RWKHU8,HYHQW
(YHQWXDOO\WKHUHGUDZHYHQWLVUHPRYHGIURPWKHTXHXHDQGGLVSDWFKHG7KHHYHQW
KDQGOHUIRUDUHGUDZHYHQWLVWKH View7KHWUHHRIYLHZVLVUHGUDZQHDFK9LHZLVUH
VSRQVLEOHH[DFWO\IRUUHQGHULQJLWVFXUUHQWVWDWHDWWKHWLPHLWLVGUDZQ
7R PDNH WKLV FRQFUHWH ZH FDQ WUDFH WKH F\FOH WKURXJK D K\SRWKHWLFDO 03 SOD\HU
DSSOLFDWLRQ
:KHQ WKH XVHU WDSV WKH VFUHHQ LPDJH RI WKH 3OD\3DXVH EXWWRQ WKH IUDPHZRUN
FUHDWHVDQHZMotionEventFRQWDLQLQJDPRQJRWKHUWKLQJVWKHVFUHHQFRRUGLQDWHV
RIWKHWDS7KHIUDPHZRUNHQTXHXHVWKHQHZHYHQWDWWKHHQGRIWKHHYHQWTXHXH
$VGHVFULEHGLQ£7KH&RQWUROOHU¤RQSDJHZKHQWKHHYHQWSHUFRODWHVWKURXJK
WKHTXHXHWKHIUDPHZRUNUHPRYHVLWDQGSDVVHVLWGRZQWKHYLHZWUHHWRWKHOHDI
ZLGJHWZLWKLQZKRVHERXQGLQJUHFWDQJOHWKHWDSRFFXUUHG
%HFDXVHWKHEXWWRQZLGJHWUHSUHVHQWVWKH3OD\3DXVHEXWWRQWKHDSSOLFDWLRQEXW
WRQKDQGOLQJFRGHWHOOVWKHFRUH WKHPRGHO WKDWLWVKRXOGUHVXPHSOD\LQJDWXQH
7KHDSSOLFDWLRQPRGHOFRGHVWDUWVSOD\LQJWKHVHOHFWHGWXQH,QDGGLWLRQLWVHQGV
DUHGUDZUHTXHVWWRWKH8,IUDPHZRUN
7KHUHGUDZUHTXHVWLVDGGHGWRWKHHYHQWTXHXHDQGHYHQWXDOO\SURFHVVHGDVGH
VFULEHGLQ£7KH9LHZ¤RQSDJH
7KHVFUHHQJHWVUHGUDZQZLWKWKH3OD\EXWWRQLQLWVSOD\LQJVWDWHDQGHYHU\WKLQJLV
DJDLQLQV\QF
8,FRPSRQHQWREMHFWVVXFKDVEXWWRQVDQGWH[WER[HVDFWXDOO\LPSOHPHQWERWK9LHZ
DQG&RQWUROOHUPHWKRGV7KLVRQO\PDNHVVHQVH:KHQ\RXDGGD ButtonWR\RXUDS
SOLFDWLRQ¦V8,\RXZDQWLWWRDSSHDURQWKHVFUHHQDVZHOODVGRVRPHWKLQJZKHQWKH
XVHUSXVKHVLW(YHQWKRXJKWKHWZRORJLFDOHOHPHQWVRIWKH8,WKH9LHZDQGWKH&RQ
WUROOHU DUH LPSOHPHQWHG LQ WKH VDPH REMHFW \RX VKRXOG WDNH FDUH WKDW WKH\ GR QRW
GLUHFWO\LQWHUDFW&RQWUROOHUPHWKRGVIRULQVWDQFHVKRXOGQHYHUGLUHFWO\FKDQJHWKH
GLVSOD\/HDYHLWWRWKHFRGHWKDWDFWXDOO\FKDQJHVVWDWHWRUHTXHVWDUHGUDZDQGWUXVW
WKDWODWHUFDOOVWRUHQGHULQJPHWKRGVZLOODOORZWKHFRPSRQHQWWRUHIOHFWWKHQHZVWDWH
&RGLQJLQWKLVZD\PLQLPL]HVV\QFKURQL]DWLRQSUREOHPVDQGKHOSVWRNHHS\RXUSUR
JUDPUREXVWDQGEXJIUHH
7KHUHLVRQHPRUHDVSHFWRIWKH$QGURLG8,IUDPHZRUNWKDWLVLPSRUWDQWWRUHFDOOLWLV
VLQJOHWKUHDGHG$VLQJOHWKUHDGUHPRYHVHYHQWVIURPWKHHYHQWTXHXHWRPDNH&RQ
WUROOHUFDOOEDFNVDQGWRUHQGHUWKHYLHZ7KLVLVVLJQLILFDQWIRUVHYHUDOUHDVRQV
170 | Chapter 7:ಗBuilding a View
7KH VLPSOHVW FRQVHTXHQFH RI D VLQJOHWKUHDGHG 8, LV WKDW LW LV QRW QHFHVVDU\ WR XVH
synchronizedEORFNVWRFRRUGLQDWHVWDWHEHWZHHQWKH9LHZDQGWKH&RQWUROOHU7KLVLV
DYDOXDEOHRSWLPL]DWLRQ
$QRWKHUDGYDQWDJHRIDVLQJOHWKUHDGHG8,LVWKDWWKHDSSOLFDWLRQLVJXDUDQWHHGWKDW
HDFKHYHQWRQWKHHYHQWTXHXHLVSURFHVVHGFRPSOHWHO\DQGLQWKHRUGHULQZKLFKLWZDV
HQTXHXHG7KDWPD\VHHPIDLUO\REYLRXVEXWLWVLPSOLFDWLRQVPDNHFRGLQJWKH8,PXFK
HDVLHU:KHQD8,FRPSRQHQWLVFDOOHGWRKDQGOHDQHYHQWLWLVJXDUDQWHHGWKDWQRRWKHU
8,SURFHVVLQJZLOOWDNHSODFHXQWLOLWUHWXUQV7KDWPHDQVIRULQVWDQFHWKDWDFRPSR
QHQWWKDWUHTXHVWVPXOWLSOHFKDQJHVLQWKHSURJUDPVWDWH¢HDFKRIZKLFKFDXVHVDFRU
UHVSRQGLQJUHTXHVWWKDWWKHVFUHHQEHUHSDLQWHG¢LVJXDUDQWHHGWKDWWKHUHSDLQWZLOO
QRWVWDUWXQWLOLWKDVFRPSOHWHGSURFHVVLQJSHUIRUPHGDOOLWVXSGDWHVDQGUHWXUQHG,Q
VKRUW8,FDOOEDFNVDUHDWRPLF
7KHWKLUGUHDVRQWRUHPHPEHUWKDWRQO\DVLQJOHWKUHDGLVGHTXHXLQJDQGGLVSDWFKLQJ
HYHQWVIURPWKH8,HYHQWTXHXHLVWKDWLI\RXUFRGHVWDOOVWKDWWKUHDGIRUDQ\UHDVRQ
\RXU8,ZLOOIUHH]H,IDFRPSRQHQW¦VUHVSRQVHWRDQHYHQWLVVLPSOH¢FKDQJLQJWKHVWDWH
RIYDULDEOHVFUHDWLQJQHZREMHFWVDQGVRRQ¢LWLVSHUIHFWO\FRUUHFWWRGRWKDWSURFHVVLQJ
RQWKHPDLQHYHQWWKUHDG,IRQWKHRWKHUKDQGWKHKDQGOHUPXVWUHWULHYHDUHVSRQVH
IURPVRPHGLVWDQWQHWZRUNVHUYLFHRUUXQDFRPSOH[GDWDEDVHTXHU\WKHHQWLUH8,ZLOO
EHFRPHXQUHVSRQVLYHXQWLOWKHUHTXHVWFRPSOHWHV7KDWGHILQLWHO\GRHVQRWPDNHIRUD
JUHDWXVHUH[SHULHQFH/RQJUXQQLQJWDVNVPXVWEHGHOHJDWHGWRDQRWKHUWKUHDGDV
GHVFULEHGLQ£$GYDQFHG:LULQJ)RFXVDQG7KUHDGLQJ¤RQSDJH
Assembling a Graphical Interface
7KH$QGURLG8,IUDPHZRUNSURYLGHVERWKDFRPSOHWHVHWRIGUDZLQJWRROVZLWKZKLFK
WREXLOGD8,DQGDULFKFROOHFWLRQRISUHEXLOWFRPSRQHQWVEDVHGRQWKHVHWRROV$VZH
ZLOOVHHLQ&KDSWHUWKHIUDPHZRUNJUDSKLFVWRROVSURYLGHSOHQW\RIVXSSRUWIRUDS
SOLFDWLRQVWKDWQHHGWRFUHDWHWKHLURZQFRQWUROVRUWRUHQGHUVSHFLDOYLHZV2QWKHRWKHU
KDQGPDQ\DSSOLFDWLRQVPD\ZRUNYHU\ZHOOXVLQJRQO\FDQQHGYLHZVIURPWKHWRRONLW
,QIDFWWKH MapActivityDQG MyLocationOverlayFODVVHVPDNHLWSRVVLEOHWRFUHDWHH[
WUHPHO\VRSKLVWLFDWHGDSSOLFDWLRQVZLWKRXWGRLQJDQ\FXVWRPGUDZLQJDWDOO
:H¦YHDOUHDG\XVHGWKHWHUPZLGJHWRQFHRUWZLFHZLWKRXWH[SOLFLWO\GHILQLQJLW5HFDOO
WKDWWKHVFUHHQLVUHQGHUHGE\DWUHHRIFRPSRQHQWV,QWKH$QGURLG8,IUDPHZRUNWKHVH
FRPSRQHQWVDUHDOOVXEFODVVHVRIandroid.view.View7KHYLHZVWKDWDUHOHDYHVRUQHDUO\
OHDYHV GR PRVW RI WKH DFWXDO GUDZLQJ DQG DUH LQ WKH FRQWH[W RI DQ DSSOLFDWLRQ 8,
FRPPRQO\FDOOHGZLGJHWV
7KHLQWHUQDOQRGHVVRPHWLPHVFDOOHGFRQWDLQHUYLHZVDUHVSHFLDOFRPSRQHQWVWKDWFDQ
KDYHRWKHUFRPSRQHQWVDVFKLOGUHQ,QWKH$QGURLG8,IUDPHZRUNFRQWDLQHUYLHZVDUH
VXEFODVVHVRI android.view.ViewGroupZKLFKRIFRXUVHLVLQWXUQDVXEFODVVRI View
7KH\W\SLFDOO\GRYHU\OLWWOHGUDZLQJ,QVWHDGWKH\DUHUHVSRQVLEOHIRUDUUDQJLQJWKHLU
Assembling a Graphical Interface | 171
FKLOGYLHZVRQWKHVFUHHQDQGNHHSLQJWKHPDUUDQJHGDVWKH9LHZFKDQJHVVKDSHRUL
HQWDWLRQDQGVRRQ'RLQJWKLVFDQEHFRPSOH[
7RFUHDWHFRPSOH[GLVSOD\V\RXQHHGWRDVVHPEOHDWUHHRIFRQWDLQHUVIRUWKHYLHZV\RX
ZDQWWRXVHLQ\RXUDSSOLFDWLRQ([DPSOHVKRZVDQDSSOLFDWLRQZLWKDYLHZWUHH
WKDWLVWKUHHOD\HUVGHHS$YHUWLFDOOLQHDUOD\RXWFRQWDLQVWZRKRUL]RQWDOOLQHDUOD\RXWV
(DFKKRUL]RQWDOOD\RXWLQWXUQFRQWDLQVWZRZLGJHWV
([DPSOH$FRPSOH[YLHZWUHH
package com.oreilly.android.intro;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
public class AndroidDemo extends Activity {
private LinearLayout root;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
LinearLayout.LayoutParams containerParams
= new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0.0F);
LinearLayout.LayoutParams widgetParams
= new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT,
1.0F);
root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(Color.LTGRAY);
root.setLayoutParams(containerParams);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setBackgroundColor(Color.GRAY);
ll.setLayoutParams(containerParams);
root.addView(ll);
EditText tb = new EditText(this);
tb.setText(R.string.defaultLeftText);
172 | Chapter 7:ಗBuilding a View
tb.setFocusable(false);
tb.setLayoutParams(widgetParams);
ll.addView(tb);
tb = new EditText(this);
tb.setText(R.string.defaultRightText);
tb.setFocusable(false);
tb.setLayoutParams(widgetParams);
ll.addView(tb);
ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setBackgroundColor(Color.DKGRAY);
ll.setLayoutParams(containerParams);
root.addView(ll);
Button b = new Button(this);
b.setText(R.string.labelRed);
b.setTextColor(Color.RED);
b.setLayoutParams(widgetParams);
ll.addView(b);
b = new Button(this);
b.setText(R.string.labelGreen);
b.setTextColor(Color.GREEN);
b.setLayoutParams(widgetParams);
ll.addView(b);
}
setContentView(root);
}
1RWHWKDWWKHFRGHSUHVHUYHVDUHIHUHQFHWRWKHURRWRIWKHYLHZWUHHIRUODWHUXVH
7KLVH[DPSOHXVHVWKUHHLinearLayoutYLHZV$LinearLayoutMXVWDVLWVQDPHLPSOLHV
LVD9LHZWKDWGLVSOD\VLWVFKLOGUHQLQDURZRUFROXPQDVGHWHUPLQHGE\LWVRULHQWDWLRQ
SURSHUW\7KHFKLOGYLHZVDUHGLVSOD\HGLQWKHRUGHULQZKLFKWKH\DUHDGGHGWRWKH
LinearLayout UHJDUGOHVV RI WKH RUGHU LQ ZKLFK WKH\ ZHUH FUHDWHG LQ WKH GLUHFWLRQV
FRPPRQ IRU :HVWHUQ UHDGHUV OHIW WR ULJKW DQG WRS WR ERWWRP 7KH EXWWRQ ODEHOHG
£*UHHQ¤IRULQVWDQFHLVLQWKHORZHUULJKWFRUQHURIWKLVOD\RXWEHFDXVHLWLVWKHVHFRQG
WKLQJDGGHGWRWKHKRUL]RQWDOLinearLayoutYLHZZKLFKZDVLQWXUQWKHVHFRQGWKLQJ
DGGHGWRWKHURRWYHUWLFDOLinearLayout
)LJXUHVKRZVZKDWWKHUHVXOWVPLJKWORRNOLNHWRWKHXVHU7KHVHYHQYLHZVLQWKH
WUHHDUHVWUXFWXUHGDVVKRZQLQ)LJXUH
7KH$QGURLG)UDPHZRUNSURYLGHVDFRQYHQLHQWFDSDELOLW\IRUVHSDUDWLQJGDWDUHVRXUFHV
IURPFRGH7KLVLVSDUWLFXODUO\XVHIXOLQEXLOGLQJ9LHZOD\RXWV7KHSUHYLRXVH[DPSOH
FDQEHUHSODFHGZLWKWKHGUDPDWLFDOO\VLPSOHUFRGHLQ([DPSOHDQGWKH;0/GHI
LQLWLRQRIWKH9LHZOD\RXWLQ([DPSOH
Assembling a Graphical Interface | 173
)LJXUH+RZSDQHOVDSSHDUWRWKHYLHZHU
)LJXUH+LHUDUFK\RISDQHOVLQWKH9LHZ
([DPSOH$FRPSOH[9LHZXVLQJDOD\RXWUHVRXUFH
package com.oreilly.android.intro;
import android.app.Activity;
import android.os.Bundle;
/**
* Android UI demo program
*/
public class AndroidDemo extends Activity {
private LinearLayout root;
@Override public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
root = (LinearLayout) findViewById(R.id.root);
174 | Chapter 7:ಗBuilding a View
}
}
([DPSOH;0/GHILQLWLRQRIDFRPSOH[9LHZOD\RXWUHVRXUFH
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:orientation="vertical"
android:background="@drawable/lt_gray"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:background="@drawable/gray"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/text1"
android:text="@string/defaultLeftText"
android:focusable="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<EditText
android:id="@+id/text2"
android:text="@string/defaultRightText"
android:focusable="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:background="@drawable/dk_gray"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button1"
android:text="@string/labelRed"
android:textColor="@drawable/red"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<Button
android:id="@+id/button2"
android:text="@string/labelGreen"
android:textColor="@drawable/green"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
Assembling a Graphical Interface | 175
</LinearLayout>
</LinearLayout>
7KLVYHUVLRQRIWKHFRGHOLNHWKHILUVWRQHDOVRSUHVHUYHVDUHIHUHQFHWRWKHURRWRIWKH
YLHZWUHH,WGRHVWKLVE\WDJJLQJDZLGJHWLQWKH;0/OD\RXW WKHURRWLinearLayoutLQ
WKLVFDVH ZLWKDQ android:idWDJDQGWKHQXVLQJWKH findViewByIdPHWKRGIURPWKH
ActivityFODVVWRUHFRYHUWKHUHIHUHQFH
,WLVDYHU\JRRGLGHDWRJHWLQWRWKHKDELWRIXVLQJDUHVRXUFHWRGHILQH\RXUYLHZWUHH
OD\RXW'RLQJVRDOORZV\RXWRVHSDUDWHWKHYLVXDOOD\RXWRID9LHZIURPWKHFRGHWKDW
EULQJVLWWROLIH<RXFDQWLQNHUZLWKWKHOD\RXWRIDVFUHHQZLWKRXWUHFRPSLOLQJ0RVW
LPSRUWDQWO\WKRXJK\RXFDQEXLOG\RXU8,XVLQJWRROVWKDWDOORZ\RXWRFRPSRVH
VFUHHQVXVLQJDYLVXDO8,HGLWRU
$W*RRJOH,2WKH$QGURLG7RROVWHDPLQWURGXFHGDQHZOD\RXW
HGLWRU WKDW LV UHDOO\ H[FLWLQJ ,W FDQ HYHQ SUHYLHZ DQLPDWLRQV DQG
GHYHORSHUFUHDWHGYLHZVPRVWGHYHORSHUVVKRXOGQHYHUQHHGWRORRNDW
;0/OHWDORQHLQOLQHFRGHIRUOD\LQJRXWYLHZVHYHUDJDLQ
Wiring Up the Controller
£$VVHPEOLQJ D *UDSKLFDO ,QWHUIDFH¤ RQ SDJH GHPRQVWUDWHG D 9LHZ ZLWK WZR
EXWWRQV $OWKRXJK WKH EXWWRQV ORRN QLFH¢WKH\ HYHQ EHFRPH KLJKOLJKWHG ZKHQ
FOLFNHG¢WKH\DUHQ¦WYHU\XVHIXO&OLFNLQJWKHPGRHVQ¦WDFWXDOO\GRDQ\WKLQJ
£7KH&RQWUROOHU¤RQSDJHGHVFULEHGKRZWKH$QGURLG)UDPHZRUNWUDQVODWHVH[
WHUQDODFWLRQV VFUHHQWDSVNH\SUHVVHVHWF LQWRHYHQWVWKDWDUHHQTXHXHGDQGWKHQ
SDVVHGLQWRWKHDSSOLFDWLRQ([DPSOHVKRZVKRZWRDGGDQHYHQWKDQGOHUWRRQHRI
WKHEXWWRQVLQWKHGHPRVRWKDWLWGRHVVRPHWKLQJZKHQLWLVFOLFNHG
([DPSOH:LULQJXSDEXWWRQ
@Override public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
final EditText tb1 = (EditText) findViewById(R.id.text1);
final EditText tb2 = (EditText) findViewById(R.id.text2);
}
((Button) findViewById(R.id.button2)).setOnClickListener(
new Button.OnClickListener() {
// mRand is a class data member
@Override public void onClick(View arg0) {
tb1.setText(String.valueOf(mRand.nextInt(200)));
tb2.setText(String.valueOf(mRand.nextInt(200)));
}
}
);
176 | Chapter 7:ಗBuilding a View
:KHQUXQWKLVYHUVLRQRIWKHDSSOLFDWLRQVWLOOORRNVDORWOLNH)LJXUH8QOLNHWKH
HDUOLHUH[DPSOHWKRXJKLQWKLVYHUVLRQHYHU\WLPHDXVHUFOLFNVWKHEXWWRQODEHOHG
£*UHHQ¤WKHQXPEHUVLQWKHEditTextER[HVFKDQJH7KLVLVLOOXVWUDWHGLQ)LJXUH
)LJXUH:RUNLQJEXWWRQ
:KLOHVLPSO\FKDQJLQJQXPEHUVLVQ¦WYHU\LQWHUHVWLQJWKLVVPDOOH[DPSOHGHPRQVWUDWHV
WKHVWDQGDUGPHFKDQLVPWKDWDQDSSOLFDWLRQXVHVWRUHVSRQGWR8,HYHQWV,WLVLPSRUWDQW
WR QRWH WKDW DSSHDUDQFHV QRWZLWKVWDQGLQJ WKLV H[DPSOH GRHV QRW YLRODWH WKH 09&
VHSDUDWLRQRIFRQFHUQV,QUHVSRQVHWRWKHFDOOWRsetTextLQWKLVLPSOHPHQWDWLRQRIWKH
OnClickListenerWKH EditTextREMHFWXSGDWHVDQLQWHUQDOUHSUHVHQWDWLRQRIWKHWH[WLW
VKRXOGGLVSOD\DQGWKHQFDOOVLWVRZQinvalidatePHWKRG,WGRHVQRWLPPHGLDWHO\GUDZ
RQWKHVFUHHQ9HU\IHZUXOHVLQSURJUDPPLQJDUHDEVROXWH7KHDGPRQLWLRQWRVHSDUDWH
WKH0RGHOWKH9LHZDQGWKH&RQWUROOHUFRPHVSUHWW\FORVH
,QWKHH[DPSOHWKHLQVWDQFHRIWKHButtonFODVVLVZLUHGWRLWVEHKDYLRUXVLQJDFDOOEDFN
DVGHVFULEHGLQ£2YHUULGHVDQGFDOOEDFNV¤RQSDJH ButtonLVDVXEFODVVRI View
ZKLFKGHILQHVDQLQWHUIDFHQDPHG OnClickListenerDQGDPHWKRGQDPHG setOnClick
ListenerZLWKZKLFKWRUHJLVWHUWKHOLVWHQHU7KH OnClickListenerLQWHUIDFHGHILQHVD
VLQJOHPHWKRGonClick:KHQDButtonUHFHLYHVDQHYHQWIURPWKHIUDPHZRUNLQDG
GLWLRQWRDQ\RWKHUSURFHVVLQJLWPLJKWGRLWH[DPLQHVWKHHYHQWWRVHHLILWTXDOLILHVDV
D£FOLFN¤ 7KHEXWWRQLQRXUILUVWH[DPSOHZRXOGEHFRPHKLJKOLJKWHGZKHQSUHVVHG
HYHQEHIRUHWKHOLVWHQHUZDVDGGHG ,IWKHHYHQWGRHVTXDOLI\DVDFOLFNDQGLIDFOLFN
OLVWHQHUKDVEHHQLQVWDOOHGWKDWOLVWHQHU¦VonClickPHWKRGLVLQYRNHG
7KHFOLFNOLVWHQHULVIUHHWRLPSOHPHQWDQ\FXVWRPEHKDYLRUQHHGHG,QWKHH[DPSOH
WKHFXVWRPEHKDYLRUFUHDWHVWZRUDQGRPQXPEHUVEHWZHHQDQGDQGSXWVRQH
LQWRHDFKRIWKHWZRWH[WER[HV,QVWHDGRIVXEFODVVLQJButtonDQGRYHUULGLQJLWVHYHQW
SURFHVVLQJPHWKRGVDOOWKDWLVQHFHVVDU\WRH[WHQGLWVEHKDYLRULVWRUHJLVWHUDFOLFN
OLVWHQHUWKDWLPSOHPHQWVWKHGHVLUHGEHKDYLRU&HUWDLQO\DORWHDVLHU
7KHFOLFNKDQGOHULVHVSHFLDOO\LQWHUHVWLQJEHFDXVHDWWKHKHDUWRIWKH$QGURLGV\VWHP¢
WKHIUDPHZRUNHYHQWTXHXH¢WKHUHLVQRVXFKWKLQJDVDFOLFNHYHQW,QVWHDGViewHYHQW
SURFHVVLQJV\QWKHVL]HVWKHFRQFHSWRID£FOLFN¤IURPRWKHUHYHQWV,IWKHGHYLFHKDVD
WRXFKVHQVLWLYHVFUHHQIRULQVWDQFHDVLQJOHWDSLVFRQVLGHUHGDFOLFN,IWKHGHYLFHKDV
DFHQWHUNH\LQLWV'SDGRUDQ(QWHUNH\SUHVVLQJDQGUHOHDVLQJHLWKHUZLOODOVRUHJLVWHU
Wiring Up the Controller | 177
DVDFOLFN9LHZFOLHQWVQHHGQRWFRQFHUQWKHPVHOYHVZLWKZKDWH[DFWO\DFOLFNLVRUKRZ
LWLVJHQHUDWHGRQDSDUWLFXODUGHYLFH7KH\QHHGRQO\KDQGOHWKHKLJKHUOHYHOFRQFHSW
OHDYLQJWKHGHWDLOVWRWKHIUDPHZRUN
$ViewFDQKDYHRQO\RQHonClickListener&DOOLQJsetOnClickListenerDVHFRQGWLPH
RQDJLYHQ ViewZLOOUHPRYHWKHROGOLVWHQHUDQGLQVWDOOWKHQHZRQH2QWKHRWKHU
KDQGDVLQJOHOLVWHQHUFDQOLVWHQWRPRUHWKDQRQHView7KHFRGHLQ([DPSOHIRU
LQVWDQFH LV SDUW RI DQRWKHU DSSOLFDWLRQ WKDW ORRNV H[DFWO\ OLNH ([DPSOH ,Q WKLV
YHUVLRQWKRXJKSXVKLQJHLWKHURIWKHEXWWRQVZLOOXSGDWHWKHWH[WER[
7KLVFDSDELOLW\FDQEHYHU\FRQYHQLHQWLQDQDSSOLFDWLRQLQZKLFKVHYHUDODFWLRQVSUR
GXFH WKH VDPH EHKDYLRU 'R QRW EH WHPSWHG WKRXJK WR FUHDWH D VLQJOH HQRUPRXV
OLVWHQHULQDOORI\RXUZLGJHWV<RXUFRGHZLOOEHHDVLHUWRPDLQWDLQDQGPRGLI\LILW
FRQWDLQVPXOWLSOHVPDOOHUOLVWHQHUVHDFKLPSOHPHQWLQJDVLQJOHFOHDUEHKDYLRU
([DPSOH/LVWHQLQJWRPXOWLSOHEXWWRQV
@Override public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
final EditText tb1 = (EditText) findViewById(R.id.text1);
final EditText tb2 = (EditText) findViewById(R.id.text2);
Button.OnClickListener listener = new Button.OnClickListener() {
@Override public void onClick(View arg0) {
tb1.setText(String.valueOf(rand.nextInt(200)));
tb2.setText(String.valueOf(rand.nextInt(200)));
} };
}
((Button) findViewById(R.id.button1)).setOnClickListener(listener);
((Button) findViewById(R.id.button2)).setOnClickListener(listener);
Listening to the Model
7KH$QGURLG8,IUDPHZRUNXVHVWKHKDQGOHULQVWDOODWLRQSDWWHUQSHUYDVLYHO\$OWKRXJK
RXUHDUOLHUH[DPSOHVZHUHDOOButtonYLHZVPDQ\RWKHU$QGURLGZLGJHWVGHILQHOLVWHQHUV
7KH ViewFODVVGHILQHVVHYHUDOHYHQWVDQGOLVWHQHUVWKDWDUHXELTXLWRXVDQGZKLFKZH
ZLOOH[SORUHLQIXUWKHUGHWDLOLQDPRPHQW2WKHUFODVVHVKRZHYHUGHILQHRWKHUVSH
FLDOL]HGW\SHVRIHYHQWVDQGSURYLGHKDQGOHUVIRUWKRVHHYHQWVWKDWDUHPHDQLQJIXORQO\
IRUWKRVHFODVVHV7KLVLVDVWDQGDUGLGLRPWKDWDOORZVFOLHQWVWRFXVWRPL]HWKHEHKDYLRU
RIDZLGJHWZLWKRXWKDYLQJWRVXEFODVVLW
7KLV SDWWHUQ LV DOVR DQ H[FHOOHQW ZD\ IRU \RXU SURJUDP WR KDQGOH LWV RZQ H[WHUQDO
DV\QFKURQRXVDFWLRQV:KHWKHUUHVSRQGLQJWRDFKDQJHLQVWDWHRQDUHPRWHVHUYHURU
DQXSGDWHIURPDORFDWLRQEDVHGVHUYLFH\RXUDSSOLFDWLRQFDQGHILQHLWVRZQHYHQWVDQG
OLVWHQHUVWRDOORZLWVFOLHQWVWRUHDFW
178 | Chapter 7:ಗBuilding a View
Download from Wow! eBook <www.wowebook.com>
7KHH[DPSOHVVRIDUKDYHEHHQHOHPHQWDU\DQGKDYHFXWVHYHUDOFRUQHUV:KLOHWKH\
GHPRQVWUDWHFRQQHFWLQJD9LHZDQGD&RQWUROOHUWKH\KDYHQRWKDGUHDOPRGHOV ([
DPSOHDFWXDOO\XVHGDStringRZQHGE\WKHLPSOHPHQWDWLRQRIEditTextDVDPRGHO 7RFRQWLQXHZH¦UHJRLQJWRKDYHWRWDNHDEULHIGHWRXUWREXLOGDUHDOXVDEOHPRGHO
7KHIROORZLQJWZRFODVVHVVKRZQLQ([DPSOHFRPSULVHD0RGHOWKDWZLOOVXSSRUW
H[WHQVLRQVWRWKHGHPRDSSOLFDWLRQ7KH\SURYLGHDIDFLOLW\IRUVWRULQJDOLVWRIREMHFWV
HDFKRIZKLFKKDV[DQG\FRRUGLQDWHVDFRORUDQGDVL]H7KH\DOVRSURYLGHDZD\WR
UHJLVWHU D OLVWHQHU DQG DQ LQWHUIDFH WKDW WKH OLVWHQHU PXVW LPSOHPHQW 7KH FRPPRQ
/LVWHQHUPRGHOXQGHUOLHVWKHVHH[DPSOHVVRWKH\DUHIDLUO\VWUDLJKWIRUZDUG
([DPSOH7KH'RWVPRGHO
package com.oreilly.android.intro.model;
/** A dot: the coordinates, color and size. */
public final class Dot {
private final float x, y;
private final int color;
private final int diameter;
/**
* @param x horizontal coordinate.
* @param y vertical coordinate.
* @param color the color.
* @param diameter dot diameter.
*/
public Dot(float x, float y, int color, int diameter) {
this.x = x;
this.y = y;
this.color = color;
this.diameter = diameter;
}
/** @return the horizontal coordinate. */
public float getX() { return x; }
/** @return the vertical coordinate. */
public float getY() { return y; }
/** @return the color. */
public int getColor() { return color; }
}
/** @return the dot diameter. */
public int getDiameter() { return diameter; }
package com.oreilly.android.intro.model;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
Wiring Up the Controller | 179
/** A list of dots. */
public class Dots {
/** DotChangeListener. */
public interface DotsChangeListener {
/** @param dots the dots that changed. */
void onDotsChange(Dots dots);
}
private final LinkedList<Dot> dots = new LinkedList<Dot>();
private final List<Dot> safeDots = Collections.unmodifiableList(dots);
private DotsChangeListener dotsChangeListener;
/** @param l the new change listener. */
public void setDotsChangeListener(DotsChangeListener l) {
dotsChangeListener = l;
}
/** @return the most recently added dot, or null. */
public Dot getLastDot() {
return (dots.size() <= 0) ? null : dots.getLast();
}
/** @return the list of dots. */
public List<Dot> getDots() { return safeDots; }
/**
* @param x dot horizontal coordinate.
* @param y dot vertical coordinate.
* @param color dot color.
* @param diameter dot size.
*/
public void addDot(float x, float y, int color, int diameter) {
dots.add(new Dot(x, y, color, diameter));
notifyListener();
}
/** Delete all the dots. */
public void clearDots() {
dots.clear();
notifyListener();
}
private void notifyListener() {
if (null != dotsChangeListener) {
dotsChangeListener.onDotsChange(this);
}
}
}
,QDGGLWLRQWRXVLQJWKLVPRGHOWKHQH[WH[DPSOHDOVRLQWURGXFHVDOLEUDU\ZLGJHWXVHG
WRYLHZLWWKHDotView,WVMRELVWRGUDZWKHGRWVUHSUHVHQWHGLQWKHPRGHOLQWKHFRUUHFW
180 | Chapter 7:ಗBuilding a View
FRORUDWWKHFRUUHFWFRRUGLQDWHV7KHFRPSOHWHVRXUFHIRUWKHDSSOLFDWLRQLVRQWKH
ZHEVLWHIRUWKLVERRN
([DPSOHVKRZVWKHQHZGHPRDSSOLFDWLRQDIWHUDGGLQJWKHQHZ0RGHODQGYLHZ
([DPSOH7KH'RWVGHPR
package com.oreilly.android.intro;
import java.util.Random;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.oreilly.android.intro.model.Dot;
import com.oreilly.android.intro.model.Dots;
import com.oreilly.android.intro.view.DotView;
/** Android UI demo program */
public class TouchMe extends Activity {
public static final int DOT_DIAMETER = 6;
private final Random rand = new Random();
final Dots dotModel = new Dots();
DotView dotView;
/** Called when the activity is first created. */
@Override public void onCreate(Bundle state) {
super.onCreate(state);
dotView = new DotView(this, dotModel);
// install the View
setContentView(R.layout.main);
((LinearLayout) findViewById(R.id.root)).addView(dotView, 0);
// wire up the Controller
((Button) findViewById(R.id.button1)).setOnClickListener(
new Button.OnClickListener() {
@Override public void onClick(View v) {
makeDot(dots, dotView, Color.RED);
} });
((Button) findViewById(R.id.button2)).setOnClickListener(
new Button.OnClickListener() {
@Override public void onClick(View v) {
makeDot(dots, dotView, Color.GREEN);
} });
Wiring Up the Controller | 181
final EditText tb1 = (EditText) findViewById(R.id.text1);
final EditText tb2 = (EditText) findViewById(R.id.text2);
dots.setDotsChangeListener(new Dots.DotsChangeListener() {
@Override public void onDotsChange(Dots d) {
Dot d = dots.getLastDot();
tb1.setText((null == d) ? "" : String.valueOf(d.getX()));
tb2.setText((null == d) ? "" : String.valueOf(d.getY()));
dotView.invalidate();
} });
}
/**
* @param dots the dots we're drawing
* @param view the view in which we're drawing dots
* @param color the color of the dot
*/
void makeDot(Dots dots, DotView view, int color) {
int pad = (DOT_DIAMETER + 2) * 2;
dots.addDot(
DOT_DIAMETER + (rand.nextFloat() * (view.getWidth() - pad)),
DOT_DIAMETER + (rand.nextFloat() * (view.getHeight() - pad)),
color,
DOT_DIAMETER);
}
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
7KHQHZDotViewLVDGGHGWRWKHWRSRIWKHOD\RXWREWDLQHGIURPWKH;0/GHILQLWLRQ
onClickListenerFDOOEDFNVDUHDGGHGWRWKH£5HG¤DQG£*UHHQ¤EXWWRQV7KHVHHYHQW
KDQGOHUVGLIIHUIURPWKRVHLQWKHSUHYLRXVH[DPSOHRQO\LQWKDWKHUHWKHLUEHKDYLRU
LVSUR[LHGWRWKHORFDOPHWKRGmakeDot7KLVQHZPHWKRGFUHDWHVDGRW LWHP $FDOOWRmakeDotLVPDGHZLWKLQonClick WRWDNHSODFHZKHQWKHEXWWRQLVFOLFNHG 7KHPRVWVXEVWDQWLDOFKDQJHWRWKHH[DPSOHWKLVLVZKHUHWKH0RGHOLVZLUHGWRWKH
9LHZXVLQJDFDOOEDFNWRLQVWDOOD dotsChangeListener:KHQWKH0RGHOFKDQJHV
WKLVQHZOLVWHQHULVFDOOHG,WLQVWDOOVWKH[DQG\FRRUGLQDWHVRIWKHODVWGRWLQWRWKH
OHIWDQGULJKWWH[WER[HVUHVSHFWLYHO\DQGUHTXHVWVWKDWWKHDotViewUHGUDZLWVHOI WKH
invalidateFDOO 7KLVLVWKHGHILQLWLRQRImakeDot7KLVQHZPHWKRGFUHDWHVDGRWFKHFNLQJWRPDNH
VXUHLWLVZLWKLQWKH DotView¦VERUGHUVDQGDGGVLWWRWKHPRGHO,WDOVRDOORZVWKH
GRW¦VFRORUWREHVSHFLILHGDVDSDUDPHWHU
)LJXUHVKRZVZKDWWKHDSSOLFDWLRQORRNVOLNHZKHQUXQ
182 | Chapter 7:ಗBuilding a View
)LJXUH5XQQLQJWKH'RWVGHPR
3XVKLQJ WKH EXWWRQ ODEHOHG £5HG¤ DGGV D QHZ UHG GRW WR WKH DotView 3XVKLQJ WKH
£*UHHQ¤EXWWRQDGGVDJUHHQRQH7KHWH[WILHOGVFRQWDLQWKHFRRUGLQDWHVRIWKHODVWGRW
DGGHG
7KHEDVLFVWUXFWXUHRI([DPSOHLVVWLOOUHFRJQL]DEOHZLWKVRPHH[WHQVLRQV
+HUHLVWKHFKDLQRIHYHQWVWKDWUHVXOWVIURPFOLFNLQJIRULQVWDQFHWKH£*UHHQ¤EXWWRQ
:KHQWKHEXWWRQLVFOLFNHGLWVonClickHandlerLVFDOOHG
7KLVFDXVHVDFDOOWR makeDotZLWKWKHFRORUDUJXPHQW Color.GREEN7KH makeDot
PHWKRGJHQHUDWHVUDQGRPFRRUGLQDWHVDQGDGGVDQHZJUHHQDotWRWKH0RGHODW
WKRVHFRRUGLQDWHV
:KHQWKH0RGHOLVXSGDWHGLWFDOOVLWVonDotsChangeListener
7KHOLVWHQHUXSGDWHVWKHYDOXHVLQWKHWH[WYLHZVDQGUHTXHVWVWKDWWKHDotViewEH
UHGUDZQ
Listening for Touch Events
0RGLI\LQJWKHGHPRDSSOLFDWLRQWRKDQGOHWDSVDV\RXKDYHVXUHO\JXHVVHGLVMXVWD
PDWWHURIDGGLQJDWDSKDQGOHU7KHFRGHLQ([DPSOHH[WHQGVWKHGHPRDSSOLFDWLRQ
WRSODFHDF\DQGRWLQWKHDotViewDWWKHSRLQWDWZKLFKWKHVFUHHQLVWDSSHG7KLVFRGH
ZRXOG EH DGGHG WR WKH GHPR DSSOLFDWLRQ ([DPSOH DW WKH EHJLQQLQJ RI WKH
onCreateIXQFWLRQULJKWDIWHUWKHFDOOWRLWVSDUHQWPHWKRG1RWLFHWKDWEHFDXVHWKHFRGH
Wiring Up the Controller | 183
WKDWGLVSOD\VWKH[DQG\FRRUGLQDWHVRIWKHPRVWUHFHQWO\DGGHGGRWLVZLUHGRQO\WR
WKHPRGHOLWFRQWLQXHVWRZRUNFRUUHFWO\QRPDWWHUKRZWKH9LHZDGGVWKHGRW
([DPSOH7RXFKDEOHGRWV
dotView.setOnTouchListener(new View.OnTouchListener() {
@Override public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN != event.getAction()) {
return false;
}
dots.addDot(event.getX(), event.getY(), Color.CYAN, DOT_DIAMETER);
return true;
} });
7KHMotionEventSDVVHGWRWKHKDQGOHUKDVVHYHUDORWKHUSURSHUWLHVLQDGGLWLRQWRWKH
ORFDWLRQRIWKHWDSWKDWFDXVHGLW$VWKHH[DPSOHLQGLFDWHVLWDOVRFRQWDLQVWKHHYHQW
W\SHRQHRIDOWNUPMOVERUCANCEL$VLPSOHWDSDFWXDOO\JHQHUDWHVRQHDOWNDQGRQH
UPHYHQW7RXFKLQJDQGGUDJJLQJJHQHUDWHVDDOWNHYHQWDVHULHVRIMOVEHYHQWVDQGD
ILQDOUPHYHQW
7KHJHVWXUHKDQGOLQJIDFLOLWLHVSURYLGHGE\WKH MotionEventDUHYHU\LQWHUHVWLQJ7KH
HYHQWFRQWDLQVWKHVL]HRIWKHWRXFKHGDUHDDQGWKHDPRXQWRISUHVVXUHDSSOLHG7KDW
PHDQV WKDW RQ GHYLFHV WKDW VXSSRUW LW DQ DSSOLFDWLRQ PLJKW EH DEOH WR GLVWLQJXLVK
EHWZHHQDWDSZLWKRQHILQJHUDQGDWDSZLWKWZRILQJHUVRUEHWZHHQDYHU\OLJKWEUXVK
DQGDILUPSXVK
(IILFLHQF\LVVWLOOLPSRUWDQWLQWKHPRELOHZRUOG$8,IUDPHZRUNFRQIURQWVWKHKRUQV
RI D GLOHPPD ZKHQ WUDFNLQJ DQG UHSRUWLQJ WRXFKVFUHHQ HYHQWV 5HSRUWLQJ WRR IHZ
HYHQWVPLJKWPDNHLWLPSRVVLEOHWRIROORZPRWLRQZLWKVXIILFLHQWDFFXUDF\WRGRIRU
LQVWDQFHKDQGZULWLQJUHFRJQLWLRQ2QWKHRWKHUKDQGUHSRUWLQJWRRPDQ\WRXFKVDP
SOHVHDFKLQLWVRZQHYHQWFRXOGORDGDV\VWHPXQDFFHSWDEO\7KH$QGURLG8,IUDPH
ZRUNDGGUHVVHVWKLVSUREOHPE\EXQGOLQJJURXSVRIVDPSOHVWRJHWKHUUHGXFLQJWKHORDG
ZKLOHVWLOOPDLQWDLQLQJDFFXUDF\7RVHHDOOWKHVDPSOHVDVVRFLDWHGZLWKDQHYHQWXVH
WKHKLVWRU\IDFLOLW\LPSOHPHQWHGZLWKWKHPHWKRGVgetHistoricalXgetHistoricalYDQG
VRRQ
([DPSOHVKRZVKRZWRXVHWKHKLVWRU\IDFLOLW\,WH[WHQGVWKHGHPRSURJUDPWR
WUDFNDXVHU¦VJHVWXUHVZKHQKHWRXFKHVWKHVFUHHQ7KHIUDPHZRUNGHOLYHUVVDPSOH
[ DQG \ FRRUGLQDWHV WR WKH onTouch PHWKRG RI DQ REMHFW LQVWDOOHG DV WKH OnTouch
ListenerIRUWKHDotView7KHPHWKRGGLVSOD\VDF\DQGRWIRUHDFKVDPSOH
([DPSOH7UDFNLQJPRWLRQ
private static final class TrackingTouchListener
implements View.OnTouchListener
{
private final Dots mDots;
TrackingTouchListener(Dots dots) { mDots = dots; }
@Override public boolean onTouch(View v, MotionEvent evt) {
184 | Chapter 7:ಗBuilding a View
switch (evt.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
for (int i = 0, n = evt.getHistorySize(); i < n; i++) {
addDot(
mDots,
evt.getHistoricalX(i),
evt.getHistoricalY(i),
evt.getHistoricalPressure(i),
evt.getHistoricalSize(i));
}
break;
}
default:
return false;
addDot(
mDots,
evt.getX(),
evt.getY(),
evt.getPressure(),
evt.getSize());
}
return true;
private void addDot(Dots dots, float x, float y, float p, float s) {
dots.addDot(
x,
y,
Color.CYAN,
(int) ((p * s * Dot.DIAMETER) + 1));
}
}
)LJXUHVKRZVZKDWWKHH[WHQGHGYHUVLRQRIWKHDSSOLFDWLRQPLJKWORRNOLNHDIWHUD
IHZFOLFNVDQGGUDJV
7KHLPSOHPHQWDWLRQXVHVWKHVL]HDQGSUHVVXUHDWDJLYHQORFDWLRQ¦VVDPSOHWRGHWHUPLQH
WKHGLDPHWHURIWKHGRWGUDZQWKHUH8QIRUWXQDWHO\WKH$QGURLGHPXODWRUGRHVQRW
HPXODWHWRXFKSUHVVXUHDQGVL]HVRDOOWKHGRWVKDYHWKHVDPHGLDPHWHU6L]HDQGSUHV
VXUHYDOXHVDUHQRUPDOL]HGDFURVVGHYLFHVDVIORDWLQJSRLQWYDOXHVEHWZHHQDQG
,WLVSRVVLEOHKRZHYHUGHSHQGLQJRQWKHFDOLEUDWLRQRIWKHVFUHHQWKDWHLWKHUYDOXH
PD\DFWXDOO\EHODUJHUWKDQ7KHHPXODWRUDOZD\VUHSRUWVWKHHYHQWSUHVVXUHDQG
VL]HDV]HURWKHLUPLQLPXPYDOXH
7KHORRSWKDWKDQGOHV ACTION_MOVEHYHQWVSURFHVVHVEDWFKHGKLVWRULFDOHYHQWV:KHQ
WRXFKVDPSOHVFKDQJHPRUHTXLFNO\WKDQWKHIUDPHZRUNFDQGHOLYHUWKHPWKHIUDPH
ZRUNEXQGOHVWKHPLQWRDVLQJOHHYHQW7KHMotionEventPHWKRGgetHistorySizeUHWXUQV
Wiring Up the Controller | 185
)LJXUH5XQQLQJWKH'RWVGHPRIRUDQH[WHQGHGWLPH
WKH QXPEHU RI VDPSOHV LQ WKH EDWFK DQG WKH YDULRXV getHistory PHWKRGV JHW WKH
VXEHYHQWVSHFLILFV
'HYLFHVZLWKWUDFNEDOOVDOVRJHQHUDWHMotionEventVZKHQWKHWUDFNEDOOLVPRYHG7KHVH
HYHQWVDUHVLPLODUWRWKRVHJHQHUDWHGE\WDSVRQDWRXFKVHQVLWLYHVFUHHQEXWWKH\DUH
KDQGOHGGLIIHUHQWO\7UDFNEDOOMotionEventVDUHSDVVHGLQWRWKHViewWKURXJKDFDOOWR
dispatchTrackballEvent QRW WR dispatchTouchEvent ZKLFK GHOLYHUHG WDSV :KLOH
dispatchTrackballEventGRHVSDVVWKHHYHQWWRonTrackballEventLWGRHVQRWILUVWSDVV
WKHHYHQWWRDOLVWHQHU1RWRQO\DUHWUDFNEDOOJHQHUDWHGMotionEventVQRWYLVLEOHWKURXJK
WKHQRUPDOWDSKDQGOLQJPDFKLQHU\EXWLQRUGHUWRUHVSRQGWRWKHPDZLGJHWPXVW
VXEFODVVViewDQGRYHUULGHWKHonTrackballEventPHWKRG
MotionEventVJHQHUDWHGE\WKHWUDFNEDOODUHKDQGOHGGLIIHUHQWO\LQ\HWDQRWKHUZD\,I
WKH\DUHQRWFRQVXPHG WREHGHILQHGVKRUWO\ WKH\DUHFRQYHUWHGLQWR'SDGNH\HYHQWV
7KLVPDNHVVHQVHZKHQ\RXFRQVLGHUWKDWPRVWGHYLFHVKDYHHLWKHUD'SDGRUDWUDFN
EDOOEXWQRWERWK:LWKRXWWKLVFRQYHUVLRQLWZRXOGQ¦WEHSRVVLEOHWRJHQHUDWH'SDG
HYHQWVRQDGHYLFHZLWKRQO\DWUDFNEDOO2IFRXUVHLWDOVRLPSOLHVWKDWDQDSSOLFDWLRQ
WKDWKDQGOHVWUDFNEDOOHYHQWVPXVWGRVRFDUHIXOO\OHVWLWEUHDNWKHWUDQVODWLRQ
Listening for Key Events
+DQGOLQJNH\VWURNHLQSXWDFURVVPXOWLSOHSODWIRUPVFDQEHYHU\WULFN\6RPHGHYLFHV
KDYHPDQ\PRUHNH\VWKDQRWKHUVVRPHUHTXLUHWULSOHWDSSLQJIRUFKDUDFWHULQSXWDQG
186 | Chapter 7:ಗBuilding a View
VRRQ7KLVLVDJUHDWH[DPSOHRIVRPHWKLQJWKDWVKRXOGEHOHIWWRWKHIUDPHZRUN¢
EditTextRURQHRILWVVXEFODVVHV¢ZKHQHYHUSRVVLEOH
7RH[WHQGDZLGJHW¦VKeyEventKDQGOLQJXVHWKHViewPHWKRGsetOnKeyListenerWRLQ
VWDOODQOnKeyListener7KHOLVWHQHUZLOOEHFDOOHGZLWKPXOWLSOHKeyEventVIRUHDFKXVHU
NH\VWURNHRQHIRUHDFKDFWLRQW\SHDOWNUPDQGMULTIPLE7KHDFWLRQW\SHVDOWNDQG
UPLQGLFDWHDNH\ZDVSUHVVHGRUUHOHDVHGMXVWDVWKH\GLGIRUWKHMotionEventFODVV$
NH\DFWLRQRI MULTIPLELQGLFDWHVWKDWDNH\LVEHLQJKHOGGRZQ DXWRUHSHDWLQJ 7KH
KeyEventPHWKRGgetRepeatCountJLYHVWKHQXPEHURINH\VWURNHVWKDWDMULTIPLEHYHQW
UHSUHVHQWV
([DPSOHVKRZVDVDPSOHNH\KDQGOHU:KHQDGGHGWRWKHGHPRSURJUDPLWFDXVHV
GRWVWREHDGGHGWRWKHGLVSOD\DWUDQGRPO\FKRVHQFRRUGLQDWHVZKHQNH\VDUHSUHVVHG
DQGUHOHDVHG$PDJHQWDGRWLVDGGHGZKHQWKHVSDFHEDULVSUHVVHGDQGUHOHDVHGD
\HOORZGRWZKHQWKH(QWHUNH\LVSUHVVHGDQGUHOHDVHGDQGDEOXHGRWZKHQDQ\RWKHU
NH\LVSUHVVHGDQGUHOHDVHG
([DPSOH+DQGOLQJNH\V
dotView.setFocusable(true);
dotView.setOnKeyListener(new OnKeyListener() {
@Override public boolean onKey(View v, int keyCode, KeyEvent event) {
if (KeyEvent.ACTION_UP != event.getAction()) {
int color = Color.BLUE;
switch (keyCode) {
case KeyEvent.KEYCODE_SPACE:
color = Color.MAGENTA;
break;
case KeyEvent.KEYCODE_ENTER:
color = Color.YELLOW;
break;
default: ;
}
}
makeDot(dots, dotView, color);
return true;
} });
Alternative Ways to Handle Events
<RX¦YHSUREDEO\QRWLFHGWKDWWKH on...PHWKRGVRIDOOWKHOLVWHQHUVLQWURGXFHGWKXV
IDU¢LQFOXGLQJonKey¢UHWXUQDbooleanYDOXH7KLVLVDSDWWHUQIRUOLVWHQHUVWKDWDOORZV
WKHPWRFRQWUROVXEVHTXHQWHYHQWSURFHVVLQJE\WKHLUFDOOHU
:KHQ D &RQWUROOHU HYHQW LV KDQGHG WR D ZLGJHW WKH IUDPHZRUN FRGH LQ WKH ZLGJHW
GLVSDWFKHV LW GHSHQGLQJ RQ LWV W\SH WR DQ DSSURSULDWH PHWKRG onKeyDown onTouch
EventDQGVRRQ7KHVHPHWKRGVHLWKHULQViewRULQRQHRILWVVXEFODVVHVLPSOHPHQW
WKHZLGJHW¦VEHKDYLRU$VGHVFULEHGHDUOLHUWKRXJKWKHIUDPHZRUNILUVWRIIHUVWKHHYHQW
Wiring Up the Controller | 187
WRDQDSSURSULDWHOLVWHQHU onTouchListeneronKeyListenerHWF LIRQHH[LVWV7KHOLV
WHQHU¦V UHWXUQ YDOXH GHWHUPLQHV ZKHWKHU WKH HYHQW LV WKHQ GLVSDWFKHG WR WKH View
PHWKRGV
,IWKHOLVWHQHUUHWXUQVfalseWKHHYHQWLVGLVSDWFKHGWRWKHViewPHWKRGVDVWKRXJKWKH
KDQGOHUGLGQRWH[LVW,IRQWKHRWKHUKDQGDOLVWHQHUUHWXUQVtrueWKHHYHQWLVVDLGWR
KDYHEHHQFRQVXPHG7KHViewDERUWVDQ\IXUWKHUSURFHVVLQJIRULW7KHViewPHWKRGV
DUHQHYHUFDOOHGDQGKDYHQRRSSRUWXQLW\WRSURFHVVRUUHVSRQGWRWKHHYHQW$VIDUDV
WKHViewPHWKRGVDUHFRQFHUQHGLWLVDVWKRXJKWKHHYHQWGLGQRWH[LVW
7KHUHDUHWKHQWKUHHZD\VWKDWDQHYHQWPLJKWEHSURFHVVHG
1ROLVWHQHU
7KHHYHQWLVGLVSDWFKHGWRWKH ViewPHWKRGVIRUQRUPDOKDQGOLQJ$ZLGJHWLP
SOHPHQWDWLRQPD\RIFRXUVHRYHUULGHWKHVHPHWKRGV
$OLVWHQHUH[LVWVDQGUHWXUQVtrue
/LVWHQHUHYHQWKDQGOLQJFRPSOHWHO\UHSODFHVQRUPDOZLGJHWHYHQWKDQGOLQJ7KH
HYHQWLVQHYHUGLVSDWFKHGWRWKHView
$OLVWHQHUH[LVWVDQGUHWXUQVfalse
7KHHYHQWLVSURFHVVHGE\WKHOLVWHQHUDQGWKHQE\WKH View$IWHUOLVWHQHUHYHQW
KDQGOLQJLVFRPSOHWHGWKHHYHQWLVGLVSDWFKHGWRWKHViewIRUQRUPDOKDQGOLQJ
&RQVLGHUIRULQVWDQFHZKDWZRXOGKDSSHQLIWKHNH\OLVWHQHUIURP([DPSOHZHUH
DGGHGWRDQEditTextZLGJHW6LQFHWKHonKeyPHWKRGDOZD\VUHWXUQVtrueWKHIUDPH
ZRUNZLOODERUWDQ\IXUWKHU KeyEventSURFHVVLQJDVVRRQDVWKHPHWKRGUHWXUQV7KDW
ZRXOGSUHYHQWWKHEditTextNH\KDQGOLQJPHFKDQLVPIURPHYHUVHHLQJWKHNH\HYHQWV
DQG QR WH[W ZRXOG HYHU DSSHDU LQ WKH WH[W ER[ 7KDW LV SUREDEO\ QRW WKH LQWHQGHG
EHKDYLRU
,I WKH onKey PHWKRG LQVWHDG UHWXUQV false IRU VRPH NH\ HYHQWV WKH IUDPHZRUN ZLOO
GLVSDWFKWKRVHHYHQWVWRWKH EditTextZLGJHWIRUFRQWLQXHGSURFHVVLQJ7KH EditText
PHFKDQLVPZLOOVHHWKHHYHQWVDQGWKHDVVRFLDWHGFKDUDFWHUVZLOOEHDSSHQGHGWRWKH
EditTextER[DVH[SHFWHG([DPSOHVKRZVDQH[WHQVLRQRI([DPSOHWKDWLQ
DGGLWLRQ WR DGGLQJ QHZ GRWV WR WKH PRGHO DOVR ILOWHUV WKH FKDUDFWHUV SDVVHG WR WKH
K\SRWKHWLFDOEditTextER[,WDOORZVQXPHULFFKDUDFWHUVWREHSURFHVVHGQRUPDOO\EXW
KLGHVHYHU\WKLQJHOVH
([DPSOH([WHQGHGNH\KDQGOLQJ
new OnKeyListener() {
@Override public boolean onKey(View v, int keyCode, KeyEvent event) {
if (KeyEvent.ACTION_UP != event.getAction()) {
int color = Color.BLUE;
switch (keyCode) {
case KeyEvent.KEYCODE_SPACE:
color = Color.MAGENTA;
break;
case KeyEvent.KEYCODE_ENTER:
color = Color.YELLOW;
188 | Chapter 7:ಗBuilding a View
}
}
break;
default: ;
makeDot(dotModel, dotView, color);
return (keyCode < KeyEvent.KEYCODE_0)
|| (keyCode > KeyEvent.KEYCODE_9);
}
}
,I\RXUDSSOLFDWLRQQHHGVWRLPSOHPHQWHQWLUHO\QHZZD\VRIKDQGOLQJHYHQWV¢VRPH
WKLQJWKDWFDQQRWEHLPSOHPHQWHGUHDVRQDEO\E\DXJPHQWLQJEHKDYLRUDQGILOWHULQJ
XVLQJDQonKeyHandler¢\RXZLOOKDYHWRXQGHUVWDQGDQGRYHUULGHViewNH\HYHQWKDQ
GOLQJ7RVNHWFKWKHSURFHVVHYHQWVDUHGLVSDWFKHGWRWKH ViewWKURXJKWKH Dispatch
KeyEventPHWKRGDispatchKeyEventLPSOHPHQWVWKHEHKDYLRUGHVFULEHGSUHYLRXVO\RI
IHULQJWKHHYHQWWRWKHonKeyHandlerILUVWDQGWKHQLIWKHKDQGOHUUHWXUQVfalseWRWKH
ViewPHWKRGVLPSOHPHQWLQJWKHKeyEvent.CallbackLQWHUIDFHonKeyDownonKeyUpDQG
onKeyMultiple
Advanced Wiring: Focus and Threading
$V GHPRQVWUDWHG LQ ([DPSOH DQG £/LVWHQLQJ IRU 7RXFK (YHQWV¤ RQ SDJH MotionEventsDUHGHOLYHUHGWRWKHZLGJHWZKRVHERXQGLQJUHFWDQJOHFRQWDLQVWKHFRRU
GLQDWHVRIWKHWRXFKWKDWJHQHUDWHGWKHP,WLVQ¦WTXLWHVRREYLRXVKRZWRGHWHUPLQH
ZKLFKZLGJHWVKRXOGUHFHLYHD KeyEvent7RGRWKLVWKH$QGURLG8,IUDPHZRUNOLNH
PRVWRWKHU8,IUDPHZRUNVVXSSRUWVWKHFRQFHSWRIVHOHFWLRQRUIRFXV
,QRUGHUWRDFFHSWIRFXVDZLGJHW¦V focusableDWWULEXWHPXVWEHVHWWR true7KLVFDQ
EHGRQHXVLQJHLWKHUDQ;0/OD\RXWDWWULEXWH WKHEditTextYLHZVLQ([DPSOHKDYH
WKHLUfocusableDWWULEXWHVHWWRfalse RUWKHsetFocusablePHWKRGDVVKRZQLQWKHILUVW
OLQHRI([DPSOH$XVHUFKDQJHVZKLFK ViewKDVIRFXVXVLQJ'SDGNH\VRUE\
WDSSLQJWKHVFUHHQZKHQWRXFKLVVXSSRUWHG
:KHQDZLGJHWLVLQIRFXVLWXVXDOO\UHQGHUVLWVHOIZLWKVRPHNLQGRIKLJKOLJKWLQJWR
SURYLGH IHHGEDFN WKDW LW LV WKH FXUUHQW WDUJHW RI NH\VWURNHV )RU LQVWDQFH ZKHQ DQ
EditTextZLGJHWLVLQIRFXVLWLVGUDZQERWKKLJKOLJKWHGDQGZLWKDFXUVRUDWWKHWH[W
LQVHUWSRVLWLRQ
7RUHFHLYHQRWLILFDWLRQZKHQD9LHZHQWHUVRUOHDYHVIRFXVLQVWDOODQOnFocusChangeLis
tener([DPSOHVKRZVWKHOLVWHQHUQHHGHGWRDGGDIRFXVUHODWHGIHDWXUHWRWKH
GHPRSURJUDP,WFDXVHVDUDQGRPO\SRVLWLRQHGEODFNGRWWREHDGGHGWRWKHDotView
DXWRPDWLFDOO\DWUDQGRPLQWHUYDOVZKHQHYHULWLVLQIRFXV
Wiring Up the Controller | 189
([DPSOH+DQGOLQJIRFXV
dotView.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus && (null != dotGenerator)) {
dotGenerator.done();
dotGenerator = null;
}
else if (hasFocus && (null == dotGenerator)) {
dotGenerator = new DotGenerator(dots, dotView, Color.BLACK);
new Thread(dotGenerator).start();
}
} });
7KHUHVKRXOGEHIHZVXUSULVHVLQWKHOnFocusChangeListener:KHQWKHDotViewFRPHV
LQWRIRFXVLWFUHDWHVWKHDotGeneratorDQGVSDZQVDWKUHDGWRUXQLW:KHQWKHZLGJHW
OHDYHV IRFXV WKH DotGenerator LV VWRSSHG DQG IUHHG 7KH QHZ GDWD PHPEHU dot
Generator ZKRVHGHFODUDWLRQLVQRWVKRZQLQWKHH[DPSOH LVQRQQXOORQO\ZKHQWKH
DotViewLVLQIRFXV7KHUHLVDQRWKHULPSRUWDQWDQGSRZHUIXOWRROLQWKHLPSOHPHQWDWLRQ
RIDotGeneratorDQGZH¦OOUHWXUQWRLWLQDPRPHQW
)RFXVLVWUDQVIHUUHGWRDSDUWLFXODUZLGJHWE\FDOOLQJLWV ViewPHWKRG requestFocus
:KHQrequestFocusLVFDOOHGIRUDQHZWDUJHWZLGJHWWKHUHTXHVWLVSDVVHGXSWKHWUHH
SDUHQWE\SDUHQWWRWKHWUHHURRW7KHURRWUHPHPEHUVZKLFKZLGJHWLVLQIRFXVDQG
SDVVHVVXEVHTXHQWNH\HYHQWVWRLWGLUHFWO\
7KLVLVH[DFWO\KRZWKH8,IUDPHZRUNFKDQJHVIRFXVWRDQHZZLGJHWLQUHVSRQVHWR'
SDGNH\VWURNHV7KHIUDPHZRUNLGHQWLILHVWKHZLGJHWWKDWZLOOQH[WEHLQIRFXVDQGFDOOV
WKDWZLGJHW¦VrequestFocusPHWKRG7KLVFDXVHVWKHSUHYLRXVO\IRFXVHGZLGJHWWRORVH
IRFXVDQGWKHWDUJHWWRJDLQLW
7KHSURFHVVRILGHQWLI\LQJWKHZLGJHWWKDWZLOOJDLQIRFXVLVFRPSOLFDWHG7RGRLWWKH
QDYLJDWLRQDOJRULWKPKDVWRSHUIRUPVRPHWULFN\FDOFXODWLRQVWKDWPD\GHSHQGRQWKH
ORFDWLRQVRIHYHU\RWKHUZLGJHWRQWKHVFUHHQ
&RQVLGHUIRULQVWDQFHZKDWKDSSHQVZKHQWKHULJKW'SDGEXWWRQLVSUHVVHGDQGWKH
IUDPHZRUNDWWHPSWVWRWUDQVIHUIRFXVWRWKHZLGJHWLPPHGLDWHO\WRWKHULJKWRIWKHRQH
WKDWLVFXUUHQWO\LQIRFXV,WLVPD\EHFRPSOHWHO\REYLRXVZKLFKZLGJHWWKDWLVZKHQ
ORRNLQJDWWKHVFUHHQLQWKHYLHZWUHHKRZHYHULWLVQRWQHDUO\VRREYLRXV7KHWDUJHW
ZLGJHWPD\EHDWDQRWKHUOHYHOLQWKHWUHHDQGVHYHUDOEUDQFKHVDZD\,GHQWLI\LQJLW
GHSHQGV RQ WKH H[DFW GLPHQVLRQV RI ZLGJHWV LQ \HW RWKHU GLVWDQW SDUWV RI WKH WUHH
)RUWXQDWHO\GHVSLWHWKHFRQVLGHUDEOHFRPSOH[LW\WKH$QGURLG8,IUDPHZRUNLPSOH
PHQWDWLRQXVXDOO\MXVWZRUNVDVH[SHFWHG
:KHQLWGRHVQRWWKHUHDUHIRXUSURSHUWLHV¢VHWHLWKHUE\DSSOLFDWLRQPHWKRGRUE\
;0/DWWULEXWH¢WKDWFDQEHXVHGWRIRUFHWKHGHVLUHGIRFXVQDYLJDWLRQEHKDYLRU7KH\
DUH nextFocusDown nextFocusLeft nextFocusRight DQG nextFocusUp 6HWWLQJ RQH RI
WKHVHSURSHUWLHVZLWKDUHIHUHQFHWRDVSHFLILFZLGJHWZLOOHQVXUHWKDW'SDGQDYLJDWLRQ
WUDQVIHUVIRFXVGLUHFWO\WRWKDWZLGJHWZKHQQDYLJDWLQJLQWKHUHVSHFWLYHGLUHFWLRQ
190 | Chapter 7:ಗBuilding a View
$QRWKHU FRPSOH[LW\ RI WKH IRFXV PHFKDQLVP LV WKH GLVWLQFWLRQ WKDW WKH $QGURLG 8,
IUDPHZRUN PDNHV EHWZHHQ 'SDG IRFXV DQG WRXFK IRFXV IRU GHYLFHV ZLWK WRXFK
VHQVLWLYHVFUHHQV7RXQGHUVWDQGZK\WKLVLVQHFHVVDU\UHFDOOWKDWRQDVFUHHQWKDWGRHV
QRWDFFHSWWRXFKLQSXWWKHRQO\ZD\WRSXVKDEXWWRQLVWRIRFXVRQLWXVLQJ'SDG
QDYLJDWLRQDQGWKHQWRXVHWKHFHQWHU'SDGNH\WRJHQHUDWHDFOLFN2QDVFUHHQWKDW
GRHV DFFHSW WRXFK HYHQWV KRZHYHU WKHUH LV QR UHDVRQ HYHU WR IRFXV RQ D EXWWRQ
7DSSLQJWKHEXWWRQFOLFNVLWUHJDUGOHVVRIZKLFKZLGJHWKDSSHQVWREHLQIRFXVDWWKH
WLPH(YHQRQDWRXFKVHQVLWLYHVFUHHQKRZHYHULWLVVWLOOQHFHVVDU\WREHDEOHWRIRFXV
RQDZLGJHWWKDWDFFHSWVNH\VWURNHV¢DQ EditTextZLGJHWIRULQVWDQFH¢LQRUGHUWR
LGHQWLI\LWDVWKHWDUJHWIRUVXEVHTXHQWNH\HYHQWV7RKDQGOHERWKNLQGVRIIRFXVFRU
UHFWO\\RXZLOOKDYHWRORRNLQWR ViewKDQGOLQJRI FOCUSABLE_IN_TOUCH_MODEDQGWKH
ViewPHWKRGVisFocusableInTouchModeDQGisInTouchMode
,QDQDSSOLFDWLRQZLWKPXOWLSOHZLQGRZVWKHUHLVDWOHDVWRQHPRUHWZLVWLQWKHIRFXV
PHFKDQLVP,WLVSRVVLEOHIRUDZLQGRZWRORVHIRFXVZLWKRXWQRWLI\LQJWKHFXUUHQWO\LQ
IRFXVZLGJHWLQWKDWZLQGRZWKDWLWVIRFXVKDVEHHQORVW7KLVPDNHVVHQVHZKHQ\RX
WKLQNDERXWLW,IWKHRXWRIIRFXVZLQGRZLVEURXJKWEDFNWRWKHWRSWKHZLGJHWWKDW
ZDVLQIRFXVLQWKDWZLQGRZZLOODJDLQEHLQIRFXVZLWKQRRWKHUDFWLRQ
&RQVLGHUHQWHULQJDIULHQG¦VSKRQHQXPEHULQWRDQDGGUHVVERRNDSSOLFDWLRQ6XSSRVH
\RXPRPHQWDULO\VZLWFKEDFNWRDSKRQHDSSOLFDWLRQWRUHIUHVK\RXUPHPRU\RIWKH
ODVWIHZGLJLWVRIKHUSKRQHQXPEHU<RX¦GEHDQQR\HGLIRQUHWXUQLQJWRWKHDGGUHVV
ERRN\RXKDGWRDJDLQIRFXVRQWKH EditTextER[LQZKLFK\RX¦GEHHQW\SLQJ<RX
H[SHFWWKHVWDWHWREHMXVWDV\RXOHIWLW
2QWKHRWKHUKDQGWKLVEHKDYLRUFDQKDYHVXUSULVLQJVLGHHIIHFWV,QSDUWLFXODUWKH
LPSOHPHQWDWLRQRIWKHDXWRGRWIHDWXUHSUHVHQWHGLQ([DPSOHFRQWLQXHVWRDGG
GRWVWRWKH DotViewHYHQZKHQLWLVKLGGHQE\DQRWKHUZLQGRZ,IDEDFNJURXQGWDVN
VKRXOGUXQRQO\ZKHQDSDUWLFXODUZLGJHWLVYLVLEOHWKDWWDVNPXVWEHFOHDQHGXSZKHQ
WKHZLGJHWORVHVIRFXVZKHQWKHWindowORVHVIRFXVDQGZKHQWKHActivityLVSDXVHG
RUVWRSSHG
0RVWRIWKHLPSOHPHQWDWLRQRIWKHIRFXVPHFKDQLVPLVLQWKHViewGroupFODVVLQPHWK
RGVOLNHrequestFocusDQGrequestChildFocus6KRXOGLWEHQHFHVVDU\WRLPSOHPHQWDQ
HQWLUHO\ QHZ IRFXV PHFKDQLVP \RX¦OO QHHG WR ORRN FDUHIXOO\ DW WKHVH PHWKRGV DQG
RYHUULGHWKHPDSSURSULDWHO\
/HDYLQJWKHVXEMHFWRIIRFXVDQGUHWXUQLQJWRWKHLPSOHPHQWDWLRQRIWKHQHZO\DGGHG
DXWRGRWIHDWXUH([DPSOHVKRZVWKHLPSOHPHQWDWLRQRIDotGenerator
([DPSOH+DQGOLQJWKUHDGV
private final class DotGenerator implements Runnable {
final Dots dots;
final DotView view;
final int color;
private final Handler hdlr = new Handler();
private final Runnable makeDots = new Runnable() {
Wiring Up the Controller | 191
};
public void run() { makeDot(dots, view, color); }
private volatile boolean done;
// Runs on the main thread
DotGenerator(Dots dots, DotView view, int color) {
this.dots = dots;
this.view = view;
this.color = color;
}
// Runs on the main thread
public void done() { done = true; }
// Runs on a different thread!
public void run() {
while (!done) {
try { Thread.sleep(1000); }
catch (InterruptedException e) { }
hdlr.post(makeDots);
}
}
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
$Qandroid.os.HandlerREMHFWLVFUHDWHG
$QHZWKUHDGWKDWZLOOUXQmakeDotLQLWHPLVFUHDWHG
DotGeneratorLVUXQRQWKHPDLQWKUHDG
makeDotLVUXQIURPWKHHandlerFUHDWHGLQLWHP
$QDLYHLPSOHPHQWDWLRQRIDotGeneratorZRXOGVLPSO\FDOOmakeDotGLUHFWO\ZLWKLQLWV
runEORFN'RLQJWKLVZRXOGQ¦WEHVDIHKRZHYHUXQOHVVmakeDotZDVWKUHDGVDIH¢DQG
WKH DotsDQG DotViewFODVVHVWRRIRUWKDWPDWWHU7KLVZRXOGEHWULFN\WRJHWFRUUHFW
DQGKDUGWRPDLQWDLQ,QIDFWWKH$QGURLG8,IUDPHZRUNDFWXDOO\IRUELGVDFFHVVWRD
ViewIURPPXOWLSOHWKUHDGV5XQQLQJWKHQDLYHLPSOHPHQWDWLRQZRXOGFDXVHWKHDS
SOLFDWLRQWRIDLOZLWKDRuntimeExceptionVLPLODUWRWKLV
11-30 02:42:37.471: ERROR/AndroidRuntime(162):
android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
:HPHWWKLVSUREOHPDQGRQHVROXWLRQWKHHandlerLQ&KDSWHU7RJHWDURXQGWKH
UHVWULFWLRQDotGeneratorFUHDWHVDHandlerREMHFWZLWKLQLWVFRQVWUXFWRU$HandlerRE
MHFWLVDVVRFLDWHGZLWKWKHWKUHDGRQZKLFKLWLVFUHDWHGDQGSURYLGHVVDIHFRQFXUUHQW
DFFHVVWRWKHFDQRQLFDOHYHQWTXHXHIRUWKDWWKUHDG
%HFDXVH DotGenerator FUHDWHV D Handler GXULQJ LWV RZQ FRQVWUXFWLRQ WKH Handler LV
DVVRFLDWHGZLWKWKHPDLQWKUHDG1RZ DotGeneratorFDQXVHWKH HandlerWRHQTXHXH
IURPDQRWKHUWKUHDGDRunnableWKDWFDOOVmakeDotIURPWKH8,WKUHDG,WWXUQVRXWDV
192 | Chapter 7:ಗBuilding a View
\RXPLJKWJXHVVWKDWWKHFDQRQLFDOHYHQWTXHXHWRZKLFKWKHHandlerSRLQWVLVH[DFWO\
WKHVDPHRQHWKDWLVXVHGE\WKH8,IUDPHZRUN7KHFDOOWR makeDotLVGHTXHXHGDQG
GLVSDWFKHGOLNHDQ\RWKHU8,HYHQWLQLWVSURSHURUGHU,QWKLVFDVHWKDWFDXVHVLWV
RunnableWREHUXQ makeDotLVFDOOHGIURPWKHPDLQWKUHDGDQGWKH8,VWD\VVLQJOH
WKUHDGHG
,WLVZRUWKUHLWHUDWLQJWKDWWKLVLVDQHVVHQWLDOSDWWHUQIRUFRGLQJZLWKWKH$QGURLG8,
IUDPHZRUN:KHQHYHUSURFHVVLQJWKDWLVVWDUWHGRQEHKDOIRIWKHXVHUPLJKWWDNHPRUH
WKDQDIHZPLOOLVHFRQGVWRFRPSOHWHGRLQJWKDWSURFHVVLQJRQWKHPDLQWKUHDGPLJKW
FDXVHWKHHQWLUH8,WREHFRPHVOXJJLVKRUZRUVHWRIUHH]HIRUDORQJWLPH,IWKHPDLQ
DSSOLFDWLRQWKUHDGGRHVQRWVHUYLFHLWVHYHQWTXHXHIRUDFRXSOHRIVHFRQGVWKH$QGURLG
26ZLOONLOOWKHDSSOLFDWLRQIRUEHLQJXQUHVSRQVLYH7KHHandlerDQGAsyncTaskFODVVHV
DOORZVWKHSURJUDPPHUWRDYRLGWKLVGDQJHUE\GHOHJDWLQJVORZRUORQJUXQQLQJWDVNV
WRRWKHUWKUHDGVVRWKDWWKHPDLQWKUHDGFDQFRQWLQXHWRVHUYLFHWKH8,7KLVH[DPSOH
GHPRQVWUDWHVXVLQJDThreadZLWKDHandlerWKDWSHULRGLFDOO\HQTXHXHVXSGDWHVIRUWKH
8,
7KHGHPRDSSOLFDWLRQWDNHVDVOLJKWVKRUWFXWKHUH,WHQTXHXHVWKHFUHDWLRQRIDQHZ
GRWDQGLWVDGGLWLRQWRWKHGRW0RGHORQWKHPDLQWKUHDG$PRUHFRPSOH[DSSOLFDWLRQ
PLJKWSDVVDPDLQWKUHDGHandlerWRWKHPRGHORQFUHDWLRQDQGSURYLGHDZD\IRUWKH
8,WRJHWDPRGHOWKUHDGHandlerIURPWKHPRGHO7KHPDLQWKUHDGZRXOGUHFHLYHXS
GDWHHYHQWVHQTXHXHGIRULWE\WKHPRGHOXVLQJLWVPDLQWKUHDG Handler7KHPRGHO
UXQQLQJLQLWVRZQWKUHDGZRXOGXVHWKHLooperFODVVWRGHTXHXHDQGGLVSDWFKLQFRPLQJ
PHVVDJHVIURPWKH8,%HIRUHDUFKLWHFWLQJDQ\WKLQJWKDWFRPSOH[WKRXJK\RXVKRXOG
FRQVLGHUXVLQJDServiceRUDContentProvider VHH&KDSWHU 3DVVLQJHYHQWVEHWZHHQWKH8,DQGORQJUXQQLQJWKUHDGVLQWKLVZD\GUDPDWLFDOO\UH
GXFHV WKH FRQVWUDLQWV UHTXLUHG WR PDLQWDLQ WKUHDG VDIHW\ ,Q SDUWLFXODU UHFDOO IURP
&KDSWHUWKDWLIDQHQTXHXLQJWKUHDGUHWDLQVQRUHIHUHQFHVWRDQHQTXHXHGREMHFWRU
LIWKDWREMHFWLVLPPXWDEOHQRDGGLWLRQDOV\QFKURQL]DWLRQLVQHFHVVDU\
The Menu
7KHILQDODVSHFWRIDSSOLFDWLRQFRQWUROZH¦OOFRYHULQWKLVFKDSWHULVWKHPHQX([DP
SOHVKRZVKRZWRLPSOHPHQWDVLPSOHPHQXE\RYHUULGLQJWZRActivityPHWKRGV
([DPSOH,PSOHPHQWLQJDPHQX
@Override public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, CLEAR_MENU_ID, Menu.NONE, "Clear");
return true;
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 1:
dotModel.clearDots();
return true;
The Menu | 193
}
}
default: ;
return false;
:KHQWKLVFRGHLVDGGHGWRWKHTouchMeFODVVFOLFNLQJWKHGHYLFH¦V0HQXNH\ZLOOFDXVH
WKHDSSOLFDWLRQWRSUHVHQWDPHQXDVVKRZQLQ)LJXUH
)LJXUH$VLPSOHPHQX
&OLFNLQJWKH(QWHUNH\RUWDSSLQJWKHPHQXLWHPDJDLQZLOOFOHDUWKHGRWYLHZ
,QWHUHVWLQJO\LI\RXUXQWKLVDSSOLFDWLRQ\RXZLOOILQGWKDWZKLOHWKHDGGHGPHQXLWHP
ZRUNVPRVWRIWKHWLPHLWGRHVQRWZRUNZKHQWKHDotViewLVLQIRFXV&DQ\RXJXHVV
ZK\"
,I\RXJXHVVHGWKDWWKHSUREOHPLVFDXVHGE\WKH OnKeyListenerLQVWDOOHGLQWKH Dot
View\RXDUHFRUUHFW$VLPSOHPHQWHGLQ([DPSOHWKHOLVWHQHUVZDOORZVWKHPHQX
194 | Chapter 7:ಗBuilding a View
NH\ HYHQW E\ UHWXUQLQJ true ZKHQ LW LV FOLFNHG 7KLV SUHYHQWV WKH VWDQGDUG View
SURFHVVLQJ RI WKH PHQX NH\ NH\VWURNH ,Q RUGHU WR PDNH WKH PHQX ZRUN WKH OnKey
ListenerQHHGVDQHZFDVH
([DPSOH,PSURYHGNH\KDQGOLQJ
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
return false;
// ...
7KH$QGURLG8,IUDPHZRUNDOVRVXSSRUWVFRQWH[WXDOPHQXV$ContextMenuDSSHDUVLQ
UHVSRQVHWRDORQJFOLFNLQDZLGJHWWKDWVXSSRUWVLW7KHFRGHUHTXLUHGWRDGGDFRQ
WH[WXDOPHQXWRDQDSSOLFDWLRQLVHQWLUHO\DQDORJRXVWRWKDWIRUWKHRSWLRQVPHQXVKRZQ
HDUOLHUH[FHSWWKDWWKHUHVSHFWLYHPHWKRGVDUHonCreateContextMenuDQGonContextItem
Selected 2QH DGGLWLRQDO FDOO LV UHTXLUHG ,Q RUGHU WR VXSSRUW FRQWH[WXDO PHQXV D
ZLGJHW PXVW EH DVVLJQHG D View.OnCreateContextMenuListener E\ FDOOLQJ LWV View
PHWKRGsetOnCreateContextMenuListener)RUWXQDWHO\VLQFHActivityLPSOHPHQWVWKH
View.OnCreateContextMenuListener LQWHUIDFH D FRPPRQ LGLRP ORRNV OLNH WKH FRGH
VKRZQLQ([DPSOH
([DPSOH,QVWDOOLQJD&RQWH[W0HQX/LVWHQHU
findViewById(R.id.ctxtMenuView).setOnCreateContextMenuListener(this);
6LPSO\RYHUULGLQJWKHGHIDXOWHPSW\ActivityLPSOHPHQWDWLRQVRIWKHFRQWH[WPHQX¦V
OLVWHQHUPHWKRGVZLOOJLYH\RXUDSSOLFDWLRQDFRQWH[WPHQX
7KLVFKDSWHUVKRZHGKRZWKH$QGURLG&RQWUROOHULQWHUIDFHZRUNVRYHUDOODQGJDYH\RX
WKHWRROVWRPDQLSXODWHLWVEDVLFFRPSRQHQWVZLQGRZVYLHZVDQGHYHQWV7KHIRO
ORZLQJWZRFKDSWHUVVKRZ\RXKRZWRGR\RXURZQJUDSKLFVSURJUDPPLQJ
The Menu | 195
CHAPTER 8
Fragments and Multiplatform Support
1RZWKDW\RXKDYHZULWWHQVRPH$QGURLGFRGH\RXNQRZWKDWActivityViewDQGWKH
OD\RXWDQGZLGJHWVXEFODVVHVRIViewDUHDPRQJWKHPRVWLPSRUWDQWFODVVHVLQ$QGURLG
7\SLFDOO\DQ$QGURLGXVHULQWHUIDFHLVEXLOWIURPZLGJHWYLHZVRUJDQL]HGLQOD\RXWV
DListViewLQDLinearLayoutIRULQVWDQFH$VLQJOHKLHUDUFK\RIYLHZREMHFWVJHWVORDGHG
IURPDUHVRXUFH RUFUHDWHGE\FRGH ZKHQDQ ActivityLVVWDUWHG,WLVLQLWLDOL]HGDQG
GLVSOD\HGRQWKHGHYLFHVFUHHQ
)RUVPDOOVFUHHQVWKLVLVILQHXVHUVPRYHIURPVFUHHQWRVFUHHQWRDFFHVVGLIIHUHQWSDUWV
RIDSURJUDP¦V8,DQGWKHActivityFODVV $QGURLG¦VFRQFHSWRIDWDVN VXSSRUWVDEDFN
VWDFNWKDWHQDEOHVTXLFNDQGLQWXLWLYHWUDYHUVDOWKURXJKWKHVWULFWO\WUHHVWUXFWXUHGLQ
WHUIDFH7KLVFKDQJHVFRPSOHWHO\KRZHYHUZKHQWKH8,LVVSUHDGRYHUWKHVXUIDFHRID
ODUJHUWDEOHWVFUHHQ6RPHSDUWVRIWKHVFUHHQUHPDLQFRQVWDQWRYHUORQJHUGXUDWLRQV
WKDQRWKHUV6RPHSDUWVRIWKHVFUHHQGHWHUPLQHWKHFRQWHQWVRIRWKHUSDUWV$FDUG
VWDFNPHWDSKRUMXVWGRHVQ¦WFXWLW
,WLVHQWLUHO\SRVVLEOHWRLPSOHPHQW8,VLQZKLFKVRPHSDUWVRIWKHVFUHHQFKDQJHLQ
UHVSRQVHWRDFWLYLWLHVLQDQRWKHUSDUWVLPSO\E\VKRZLQJDQGKLGLQJYLHZV$QGURLG¦V
GHYHORSHUVGHFLGHGKRZHYHUWKDWWKH\QHHGHGPRUHWKDQMXVWFRQYHQWLRQWRHQFRXUDJH
JUHDWODUJHVFUHHQ8,VZLWKDFRQVLVWHQWIHHODQGEHKDYLRU,QRUGHUWRIDFLOLWDWHWKLVQHZ
NLQGRILQWHUDFWLRQWKH\LQWURGXFHGDQHZDIHDWXUHEDVHGRQWKHFragmentFODVVDVSDUW
RIWKH$QGURLG6'. $3,+RQH\FRPE $FragmentREMHFWLVVRPHZKHUHEHWZHHQDViewDQGDQActivity/LNHDViewLWFDQEH
DGGHGWRDViewGroupRUEHSDUWRIDOD\RXW,WLVQ¦WDVXEFODVVRIViewKRZHYHUDQGFDQ
RQO\EHDGGHGWRD ViewGroupXVLQJD FragmentTransaction/LNHDQ ActivityD Frag
mentKDVDOLIHF\FOHDQGLPSOHPHQWVERWKWKH ComponentCallbacksDQG View.OnCreate
ContextMenuListener LQWHUIDFHV 8QOLNH DQ Activity WKRXJK D Fragment LV QRW D
ContextDQGLWVOLIHF\FOHLVGHSHQGHQWRQWKDWRIWKHActivityWRZKLFKLWEHORQJV
)UDJPHQWVFRQVWLWXWHDPDMRUFKDQJHLQWKH$QGURLG$3,,QRUGHUWRHDVHWUDQVLWLRQWR
WKHQHZ$3,*RRJOHSURYLGHVDFRPSDWLELOLW\OLEUDU\WKDWVXSSRUWVWKHIHDWXUHLQYHU
VLRQVDVIDUEDFNDVYHUVLRQRIWKH6'. $3,eFODLU :H¦OOKDYHDORRNDWEDFNZDUG
197
FRPSDWLELOLW\LQDPRPHQW)LUVWWKRXJKOHW¦VORRNDWIUDJPHQWVLQWKHLUQDWLYHHQYL
URQPHQW+RQH\FRPE
Creating a Fragment
/LNHDQ\RWKHUYLHZREMHFWDIUDJPHQWFDQHLWKHUEHSDUWRIWKH;0/GHILQLWLRQRID
OD\RXWRUEHDGGHGWRDYLHZSURJUDPPDWLFDOO\,QDOD\RXWDIUDJPHQWORRNVOLNHWKLV
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment
class="com.oreilly.demo.android.ch085.contactviewer.DateTime"
android:id="@+id/date_time"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
$QDFWLYLW\ZRXOGXVHWKLVOD\RXWLQWKHQRUPDOZD\
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
}
7KLV VKRXOG DOO ORRN SUHWW\ IDPLOLDU E\ QRZ 7KH RQO\ WKLQJ WKDW LV QHZ LV WKH
fragmentWDJLQPDLQ[PO7KHWDJXVHVD classDWWULEXWHWRVSHFLI\WKHIXOO\TXDOLILHG
QDPH RI D FODVV WKDW LPSOHPHQWV WKH IUDJPHQW 7KHUH DUH D FRXSOH RI FRQVWUDLQWV
RQ D IUDJPHQW LPSOHPHQWDWLRQ FODVV ZKLFK LQ WKLV FDVH LV
com.oreilly.demo.android.ch085.contactviewer.DateTime
‡ $FODVVZLWKWKHH[DFWQDPHPXVWH[LVWDQGEHYLVLEOHIURPWKHDSSOLFDWLRQ
‡ 7KHQDPHGFODVVPXVWEHDVXEFODVVRIFragment
$OWKRXJKLWZRXOGEHTXLWHSRVVLEOHWRYHULI\ERWKRIWKHVHWKLQJVVWDWLFDOO\WKHFXUUHQW
$QGURLGWRROVGRQRWGRVR<RX¦OOKDYHWRFKHFNERWKFRQVWUDLQWVE\KDQG
7KH$QGURLG)UDPHZRUNFUHDWHVDQHZLQVWDQFHRIWKHQDPHGFODVVZKHQWKHOD\RXWLV
LQIODWHG7KHLPSOLFDWLRQVRIWKLVFDQEHVXUSULVLQJ7REHJLQLWPHDQVWKHFODVVPXVW
KDYHDQRDUJVFRQVWUXFWRU7KLVLVWKHFRQVWUXFWRUWKDW-DYDVXSSOLHVE\GHIDXOW7KH
$QGURLG'HYHORSHU'RFXPHQWDWLRQUHFRPPHQGV¢VWURQJO\LQIDFW¢DJDLQVWGHILQLQJ
DQ\FRQVWUXFWRUVDWDOOLQVXEFODVVHVRIFragmentEHFDXVHDQHZO\FUHDWHGFragmentREMHFW
PD\ QRW EH LQ D FRQVLVWHQW VWDWH DW FUHDWLRQ 7KH GRFXPHQWDWLRQ UHFRPPHQGV WKDW
IUDJPHQWLQLWLDOL]DWLRQEHSRVWSRQHGXQWLOODWHULQWKHIUDJPHQWOLIHF\FOH
198 | Chapter 8:ಗFragments and Multiplatform Support
1RPDWWHUKRZ\RXXVHWKHIUDJPHQWHOVHZKHUHLQWKHDSSOLFDWLRQLI\RXXVHLWLQD
OD\RXWWKHLQIODWLRQSURFHVVPXVWEHDEOHWRFUHDWHLWZLWKRXWVXSSO\LQJDQ\LQLWLDOL
]DWLRQSDUDPHWHUV$VDFRUROODU\DIUDJPHQWWKDWLVFUHDWHGLQWKLVZD\PXVWEHSUH
SDUHGWRGRVRPHWKLQJVHQVLEOHHYHQZLWKRXWLQLWLDOL]DWLRQ$IUDJPHQWIRULQVWDQFH
WKDWGLVSOD\VFRQWHQWIURPDSDVVHG85/PXVWKDQGOHWKHFDVHZKHUHWKH85/¢DQG
WKHUHIRUHWKHFRQWHQW¢LVHPSW\
+HUHWKHQLVDYHU\VLPSOHIUDJPHQW
public class DateTime extends Fragment {
private String time;
public void onCreate(Bundle state) {
super.onCreate(state);
if (null == time) {
time = new SimpleDateFormat("d MMM yyyy HH:mm:ss")
.format(new Date());
}
}
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle b)
{
View view = inflater.inflate(
R.layout.date_time,
container,
false); //!!! this is important
((TextView) view.findViewById(R.id.last_view_time))
.setText(time);
return view;
}
}
7KLV FRGH GHPRQVWUDWHV VHYHUDO HVVHQWLDO SRLQWV )LUVW MXVW WKH H[LVWHQFH RI DQ
onCreateOLIHF\FOHPHWKRGVKRXOGEULQJWRPLQGWKH ActivityFODVVDQGLWVOLIHF\FOH
PHWKRGV:KLOHWKHOLIHF\FOHRID FragmentLVQRWLGHQWLFDOWRWKDWRIDQ ActivityLW
GRHVKDYHPDQ\RIWKHVDPHPHWKRGV$VIRUDQDFWLYLW\DIUDJPHQW¦VonCreatePHWKRG
LVFDOOHGZKHQWKHIUDJPHQWLVLQLWLDOL]HG7KLVLVDJUHDWSODFHWRGRWKHLQLWLDOL]DWLRQ
WKDWZDVSRVWSRQHGIURPWKHFRQVWUXFWRU7KHH[DPSOHJXDUDQWHHVWKDWWKHYDOXHRIWKH
YDULDEOHtimeWKHWKLQJWKHIUDJPHQWZLOOGLVSOD\LVFRUUHFWO\LQLWLDOL]HG
)UDJPHQWVKDYHDIHZDGGLWLRQDOOLIHF\FOHPHWKRGVLQFOXGLQJonCreateViewDOVRXVHG
LQWKLVH[DPSOH7KHonCreateViewPHWKRGLVFDOOHGZKHQDIUDJPHQW¦VYLHZLVLQLWLDOL]HG
LQFRQWUDVWZLWKonCreateZKLFKLVFDOOHGZKHQWKHIUDJPHQWLWVHOILVLQLWLDOL]HG 1RWLFH
WKDWWKHIUDJPHQWFUHDWHVWKHYLHZLWPDQDJHVE\XVLQJWKHSDVVHG LayoutInflaterWR
LQVWDQWLDWHWKHYLHZVKDUGR.layout.date_time7KLVVLPSOHYLHZVKDUG¢MXVWDSDLURI
Creating a Fragment | 199
TextViewVLQ D RelativeLayout¢LV GHILQHGLQ LWV RZQ ILOH OD\RXWGDWHBWLPH[PO QRW
VKRZQKHUH PXFKDVZDVWKHPDLQOD\RXWVKRZQHDUOLHU
$OVRQRWLFH DQGWKLVLVDELWRIDJRWFKD WKDWWKHUHLVDWKLUGSDUDPHWHUWKH%RROHDQ
false LQ WKDW FDOO WR inflate ,W LV LPSRUWDQW 7KH LQIODWHU PXVW KDYH DFFHVV WR
containerWKHYLHZWKDWZLOOHYHQWXDOO\EHWKHQHZO\FUHDWHGVKDUG¦VSDUHQW,WQHHGV
WKH SDUHQW YLHZ LQ RUGHU WR KDQGOH OD\RXW FRUUHFWO\ 6XSSRVH IRU LQVWDQFH WKDW con
tainerKDSSHQVWREHDRelativeLayoutWKDWVSHFLILHVWKHSRVLWLRQRIWKHQHZO\FUHDWHG
VKDUGXVLQJDlayout_toRightOfGLUHFWLYH
2QWKHRWKHUKDQGWKHIUDJPHQWIUDPHZRUNRZQVDQGPDQDJHVWKHYLHZWKDWLVUHWXUQHG
E\WKHonCreateViewPHWKRG7KHFRGHLQonCreateViewPXVWQRWDWWDFKWKHYLHZVKDUG
WRLWVFRQWDLQHUDVLWQRUPDOO\ZRXOGGXULQJLQIODWLRQ7KDWWKLUGDUJXPHQWLVWKHIODJ
WKDWWHOOVWKHLQIODWHUWKDWWKHIUDJPHQWIUDPHZRUNLVLQFRQWURODQGWKDWLWPXVWQRW
DWWDFKWKHYLHZVKDUGWRWKHFRQWDLQHU
2QFHWKHIUDJPHQW¦VYLHZVKDUGLVFUHDWHGLWVfindViewByIdPHWKRGFDQEHXVHGWRILQG
RWKHUZLGJHWVQHVWHGZLWKLQ7KHH[DPSOHXVHVLWWRORFDWHWKHTextViewWKDWZLOOGLVSOD\
WKHWLPHDQGWRVHWLWVYDOXHIURPWKHYDULDEOHtimeLQLWLDOL]HGLQonCreate
:KHQUXQWKLVDSSOLFDWLRQORRNVOLNH)LJXUH
)LJXUH$VLPSOHIUDJPHQW
200 | Chapter 8:ಗFragments and Multiplatform Support
Download from Wow! eBook <www.wowebook.com>
Fragment Life Cycle
,I\RXUXQWKLVDSSOLFDWLRQDVLWLVGHVFULEHGVRIDUDQGURWDWHWKHVFUHHQZKLOHLWLV
UXQQLQJ\RX¦OOQRWLFHWKDWWKHGLVSOD\HGGDWHFKDQJHVHDFKWLPHWKHVFUHHQLVURWDWHG
5RWDWLQJWKHVFUHHQFDXVHVDQDSSOLFDWLRQWREHGHVWUR\HGDQGUHFUHDWHG7KLVYHUVLRQ
RIWKHH[DPSOHDSSOLFDWLRQORVHVDOOLWVVWDWHHDFKWLPHWKDWKDSSHQV
7KLVLVDJUHDWZD\WRWHVW\RXUDSSOLFDWLRQ3UHVVLQJ&WUO)URWDWHVWKH
HPXODWRUGHJUHHV,QUHVSRQVHWRWKLVURWDWLRQ$QGURLGVWHSVDQDF
WLYLW\WKURXJKQHDUO\LWVHQWLUHOLIHF\FOH:LWKWKLVRQHNH\FKRUG\RX
JHWFRYHUDJHIRUPRVWRI\RXUFRGH
,QWKLVWULYLDOH[DPSOHDSSOLFDWLRQORVLQJVWDWHLVQRWSDUWLFXODUO\VLJQLILFDQW$UHDO
DSSOLFDWLRQKRZHYHUPXVWQRWORVHVWDWH,WZRXOGEHLQFUHGLEO\DQQR\LQJLIIRULQ
VWDQFHURWDWLQJ\RXUSKRQHWRODQGVFDSHPRGHZKLOHORRNLQJDWVRPHZHESDJHFDXVHG
WKHEURZVHUWRUHWXUQWRDKRPHSDJH
7KHDSSOLFDWLRQFDQEHPRGLILHGWRNHHSLWVVWDWHZLWKWZRVPDOOFKDQJHV)LUVWRYHUULGH
WKH DateTimeIUDJPHQW¦VOLIHF\FOHPHWKRG onSaveInstanceStateWRSUHVHUYHLWVVWDWH
6HFRQG FKDQJH WKH onCreate PHWKRG WR UHFRYHU WKH SUHVHUYHG VWDWH $V LW GLG ZLWK
DFWLYLWLHV VHH£7KH$FWLYLW\/LIH&\FOH¤RQSDJH WKH$QGURLG)UDPHZRUNSURYLGHV
D BundleREMHFWWRWKHIRUPHUPHWKRGZKHQLWVXVSHQGVWKHIUDJPHQW,WSURYLGHVWKH
VDPHEXQGOHWRonCreateZKHQUHFRQVWUXFWLQJDFORQHRIDVXVSHQGHGIUDJPHQW
+HUHDUHWKHWZRDIIHFWHGPHWKRGVFKDQJHGWRVXSSRUWVWDWHSUHVHUYDWLRQ
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
if (null != state) { time = state.getString(TAG_DATE_TIME); }
}
if (null == time) {
time = new SimpleDateFormat("d MMM yyyy HH:mm:ss")
.format(new Date());
}
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
state.putString(TAG_DATE_TIME, time);
}
7KDW¦VLW5XQQLQJWKLVYHUVLRQRIWKHSURJUDPWKURXJKLWVOLIHF\FOHZLOOQRORQJHUFDXVH
LWWRORVHLWVVWDWH1RWLFHLQFLGHQWDOO\WKDWEHFDXVHWKHYDULDEOHtime DQGLQJHQHUDO
DQ\IUDJPHQWVWDWH LVLQLWLDOL]HGLQWKHonCreatePHWKRGLWFDQQRWEHGHFODUHGfinal
7KLVUHGXFHVWKHYDOXHRIXVLQJDFRQVWUXFWRUWRVHWXSWKHIUDJPHQWVWDWHDQGLVLQ
Fragment Life Cycle | 201
NHHSLQJZLWKWKHUHFRPPHQGDWLRQWKDWFragmentVXEFODVVHVQRWKDYHDQ\H[SOLFLWFRQ
VWUXFWRUVDWDOO
7KH $QGURLG 'HYHORSHU 'RFXPHQWDWLRQ GHVFULEHV WKH FRPSOHWH IUDJPHQW OLIH F\FOH
2QHRWKHUOLIHF\FOHFDOOEDFNPHWKRGWKRXJKGHVHUYHVVSHFLDOQRWLFH onPause7KH
onPausePHWKRGLVLPSRUWDQWIRUWKHVDPHUHDVRQWKDWLWLVLPSRUWDQWLQDQDFWLYLW\,Q
RUGHUIRUDQDSSOLFDWLRQWRSOD\QLFHO\LQWKH$QGURLGHQYLURQPHQWLWVKRXOGQRWEH
GRLQJWKLQJV XVLQJWKH&38UXQQLQJGRZQWKHEDWWHU\HWF ZKHQLWLVQRWYLVLEOH7KH
$QGURLGHQYLURQPHQWDUUDQJHVWRFDOODIUDJPHQW¦VonPausePHWKRGZKHQHYHUWKHIUDJ
PHQW EHFRPHV LQYLVLEOH ,Q WKLV PHWKRG D IUDJPHQW VKRXOG UHOHDVH DQ\ UHVRXUFHV LW
PLJKWEHKROGLQJWHUPLQDWHDQ\ORQJUXQQLQJSURFHVVHVWKDWLWKDVVWDUWHGDQGVRRQ
The Fragment Manager
$VPHQWLRQHGHDUOLHUIUDJPHQWVFDQEHFUHDWHGSURJUDPPDWLFDOO\DVZHOODVLQOD\RXWV
3URJUDPPDWLFPDQLSXODWLRQRIIUDJPHQWVLVDFFRPSOLVKHGXVLQJDQLQVWDQFHRIWKHFODVV
FragmentManagerREWDLQHGIURPDQActivityXVLQJLWVgetFragmentManagerPHWKRG7KH
IUDJPHQWPDQDJHUKDQGOHVWKUHHLPSRUWDQWJURXSVRIRSHUDWLRQVIUDJPHQWWDJJLQJDQG
ORFDWLRQWUDQVDFWLRQVDQGWKHEDFNVWDFN/HW¦VH[WHQGWKHH[DPSOHSURJUDPWRLQYHV
WLJDWHHDFKLQWXUQ
$GDSWLQJWKHH[DPSOHDSSOLFDWLRQWRXVHSURJUDPPDWLFDOO\FUHDWHGIUDJPHQWVUHTXLUHV
RQO\ WZR FKDQJHV RQH LQ WKH OD\RXW PDLQ[PO DQG WKH RWKHU LQ WKH SimpleFragment
DFWLYLW\ ,Q WKH OD\RXW WKH IUDJPHQW HOHPHQW LV UHSODFHG ZLWK D QHDUO\ LGHQWLFDO
FrameLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/date_time"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/green"
/>
</LinearLayout>
SimpleFragmentZLOOVWLOOXVHWKLVOD\RXWMXVWDVLWGLGEHIRUH1RZWKRXJKWKHOD\RXW
GRHVQRWDXWRPDWLFDOO\FUHDWHDQHZIUDJPHQW,QVWHDGWKHIROORZLQJFRGHGRHVWKDW
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
202 | Chapter 8:ಗFragments and Multiplatform Support
FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if (null == fragMgr.findFragmentByTag(FRAG1_TAG)) {
xact.add(R.id.date_time, new DateTime(), FRAG1_TAG);
}
xact.commit();
}
7KHVHFKDQJHVLQWURGXFHQRQHZDSSOLFDWLRQIHDWXUHV:KHQUXQWKLVYHUVLRQRIWKH
H[DPSOHEHKDYHVH[DFWO\DVGLGWKHRULJLQDOOD\RXWEDVHGYHUVLRQ
7KHLPSRUWDQWIHDWXUHLQWKLVFRGHVQLSSHWLVWKHXVHRIWDJJLQJ,WLVHQWLUHO\SRVVLEOH
WKDWDQDFWLYLW\¦V onCreateZLOOEHFDOOHGZKLOHLWLVVWLOODVVRFLDWHGZLWKDSUHYLRXVO\
FUHDWHGIUDJPHQW6LPSO\DGGLQJDQHZIUDJPHQWZKHQHYHUonCreateLVFDOOHGZLOOOHDN
IUDJPHQWV,QRUGHUWRSUHYHQWWKDWWKHH[DPSOHFRGHPDNHVXVHRIWKHIUDJPHQWPDQ
DJHU¦VWDJJLQJDQGORFDWLRQIHDWXUHV
7KHWKLUGDUJXPHQWWRWKHaddPHWKRGLVDXQLTXHWDJDVVLJQHGWRWKHIUDJPHQWDVLWLV
DGGHGWRWKHDFWLYLW\2QFHWKHWDJKDVEHHQFUHDWHGWKHIUDJPHQWPDQDJHUPHWKRG
findFragmentByTagFDQEHXVHGWRUHFRYHUWKHH[DFWVLQJOHIUDJPHQWWKDWZDVDGGHG
ZLWKWKHJLYHQWDJ7KHH[DPSOHFKHFNVWRVHHLIWKHWDJJHGIUDJPHQWDOUHDG\H[LVWV
EHIRUHLWFUHDWHVDQHZIUDJPHQWLQVWDQFH,IWKHUHLVQRVXFKIUDJPHQWLWFUHDWHVLW,I
WKHIUDJPHQWDOUHDG\H[LVWVQRDFWLRQLVQHFHVVDU\7KLVJXDUDQWHHVWKDWWKHUHLVRQO\D
VLQJOHIUDJPHQWLQDJLYHQUROHDQGSUHYHQWVIUDJPHQWOHDNLQJ
7DJJLQJDQGORFDWLRQFDQEHXVHGIRURWKHUSXUSRVHVDVZHOO:KHQHYHUDQDFWLYLW\
QHHGVWRFRPPXQLFDWHVRPHFKDQJHRIVWDWHWRDQDWWDFKHGIUDJPHQWLWZLOOSUREDEO\
GRVRE\WDJJLQJWKDWIUDJPHQWLQDGYDQFHDQGWKHQXVLQJWKHFragmentManagerWRORRN
XSWKHWDJWRREWDLQDUHIHUHQFHWRWKHIUDJPHQWDWWKHDSSURSULDWHWLPH
Fragment Transactions
,QDGGLWLRQWRXVLQJIUDJPHQWWDJJLQJWKHQHZFRGHDOVRDOOXGHVWRIUDJPHQWWUDQVDF
WLRQV/HW¦VH[WHQGWKHDSSOLFDWLRQRQFHDJDLQWRGHPRQVWUDWHWKHLUYDOXH
%HIRUHZHWDNHRQWUDQVDFWLRQVWKRXJKZHQHHGWRWDNHDEULHIGHWRXU:HQRWHGHDUOLHU
WKDWWKH$QGURLG'HYHORSHU'RFXPHQWDWLRQUHFRPPHQGVWKDWIUDJPHQWVXEFODVVHVQRW
KDYHH[SOLFLWFRQVWUXFWRUV6RKRZGRHVDQH[WHUQDOREMHFWVXSSO\LQLWLDOL]DWLRQVWDWH
IRUDQHZIUDJPHQW"7KHFragmentFODVVVXSSRUWVWZRPHWKRGVsetArgumentsDQGget
ArgumentsWKDWSURYLGHWKLVFDSDELOLW\5HVSHFWLYHO\WKH\DOORZDQH[WHUQDOFDOOHU¢
SUREDEO\WKHIUDJPHQWFUHDWRU¢WRVWRUHDBundleLQWKHIUDJPHQWDQGWKHIUDJPHQWWR
UHFRYHUWKDWEXQGOHDWVRPHODWHUWLPH
7KLVHODERUDWHFRPELQDWLRQRIDQHZLQVWDQFHRIWKHIUDJPHQWDBundleDQGDFDOOWR
setArgumentsIXQFWLRQVYHU\PXFKOLNHDFRQVWUXFWRU,WPDNHVVHQVHWKHQWRFRPELQH
WKHPLQWRDVWDWLFIDFWRU\PHWKRGLQWKHFragmentREMHFWOLNHWKLV
Fragment Transactions | 203
public static DateTime createInstance(Date time) {
Bundle init = new Bundle();
init.putString(
DateTime.TAG_DATE_TIME,
getDateTimeString(time));
DateTime frag = new DateTime();
frag.setArguments(init);
return frag;
}
private static String getDateTimeString(Date time) {
return new SimpleDateFormat("d MMM yyyy HH:mm:ss")
.format(time);
}
1RZ ZH FDQ XVH WKH VWDWLF IDFWRU\ PHWKRG LQ SimpleFragment¦V onCreate PHWKRG WR
FUHDWHDQHZLQVWDQFHRIWKHIUDJPHQWZLWKLWVDUJXPHQWEXQGOHFRUUHFWO\LQLWLDOL]HG
7KLVFRGHLVQHDUO\LGHQWLFDOWRWKHSUHYLHZYHUVLRQH[FHSWWKDWLWQRZXVHVDateTime¦V
VWDWLFIDFWRU\PHWKRGDQGSDVVHVLWDQDUJXPHQW
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if (null == fragMgr.findFragmentByTag(FRAG1_TAG)) {
xact.add(
R.id.date_time,
DateTime.newInstance(new Date()),
FRAG1_TAG);
}
xact.commit();
}
)LQDOO\WKHIUDJPHQWonCreatePHWKRGUHWULHYHVWKHLQLWLDOL]DWLRQGDWDIURPWKHSDVVHG
DUJXPHQWEXQGOHXQOHVVWKHUHLVVWDWHIURPDSUHYLRXVLQFDUQDWLRQ
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
if (null == state) { state = getArguments(); }
if (null != state) { time = state.getString(TAG_DATE_TIME); }
if (null == time) { time = getDateTimeString(new Date()); }
}
2QFHDJDLQWKHDSSOLFDWLRQDVPRGLILHGWRWKLVSRLQWVWLOOEHKDYHVH[DFWO\DVGLGWKH
RULJLQDO7KHLPSOHPHQWDWLRQLVTXLWHGLIIHUHQWWKRXJKDQGPXFKPRUHIOH[LEOH,Q
204 | Chapter 8:ಗFragments and Multiplatform Support
SDUWLFXODUZHQRZKDYHDIUDJPHQWWKDWFDQEHLQLWLDOL]HGH[WHUQDOO\DQGFDQEHXVHG
WRGHPRQVWUDWHWUDQVDFWLRQV
7KHLGHDRIDIUDJPHQWWUDQVDFWLRQLVDVWKHQDPHLPSOLHVWKDWDOOFKDQJHVWDNHSODFH
DVDVLQJOHDWRPLFDFWLRQ7RGHPRQVWUDWHWKLVOHW¦VPDNHRQHILQDOH[WHQVLRQWRWKH
H[DPSOHSURJUDPOHW¦VDGGWKHDELOLW\WRFUHDWHSDLUVRIIUDJPHQWV
+HUH¦VWKHQHZOD\RXW
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="@+id/new_fragments"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="24dp"
android:text="@string/doit"
/>
<FrameLayout
android:id="@+id/date_time2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:background="@color/blue"
/>
<FrameLayout
android:id="@+id/date_time"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:background="@color/green"
/>
</LinearLayout>
+HUHDUHWKHFRUUHVSRQGLQJDGGLWLRQVWRWKHonCreatePHWKRGLQSimpleFragment
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
((Button) findViewById(R.id.new_fragments))
.setOnClickListener(
new Button.OnClickListener() {
@Override
public void onClick(View v) { update(); }
});
Fragment Transactions | 205
Date time = new Date();
FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if (null == fragMgr.findFragmentByTag(FRAG1_TAG)) {
xact.add(
R.id.date_time,
DateTime.newInstance(time),
FRAG1_TAG);
}
if (null == fragMgr.findFragmentByTag(FRAG2_TAG)) {
xact.add(
R.id.date_time2,
DateTime.newInstance(time),
FRAG2_TAG);
}
}
xact.commit();
)LQDOO\ WKH H[DPSOH DSSOLFDWLRQ GRHV VRPHWKLQJ GLIIHUHQW :KHQ UXQ LW ORRNV OLNH
)LJXUH
)LJXUH)UDJPHQWWUDQVDFWLRQV
206 | Chapter 8:ಗFragments and Multiplatform Support
%RWKIUDJPHQWVGLVSOD\WKHH[DFWVDPHGDWHDQGWLPHEHFDXVHDVLQJOHYDOXHLVSDVVHG
WRERWK1HLWKHUYLVLWLQJRWKHUDSSOLFDWLRQVDQGUHWXUQLQJWRWKHGHPRQRUURWDWLQJWKH
GLVSOD\ZLOOFDXVHWKLVDSSOLFDWLRQWRORVHLWVVWDWH,W¦VSUHWW\VROLG6ROHW¦VJLYHWKH
EXWWRQDQLPSOHPHQWDWLRQ+HUHLWLV
void update() {
Date time = new Date();
FragmentTransaction xact
= getFragmentManager().beginTransaction();
xact.replace(
R.id.date_time,
DateTime.newInstance(time),
FRAG1_TAG);
xact.replace(
R.id.date_time2,
DateTime.newInstance(time),
FRAG2_TAG);
xact.addToBackStack(null);
xact.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
xact.commit();
}
7KLVPHWKRGDFWXDOO\PDNHVXVHRIWKHDWRPLFLW\RIIUDJPHQWWUDQVDFWLRQV,WORRNVD
ORWOLNHWKHIUDJPHQWLQLWLDOL]DWLRQFRGHLQSimpleFragment¦VonCreatePHWKRG,QVWHDG
RIXVLQJWKHWUDQVDFWLRQWRDGGQHZIUDJPHQWLQVWDQFHVKRZHYHULWUHSODFHVWKHFXUUHQW
IUDJPHQWV7KHFDOOWRcommitDWWKHHQGRIWKHPHWKRGFDXVHVERWKRIWKHQHZIUDJPHQWV
WREHFRPHYLVLEOHVLPXOWDQHRXVO\7KHEOXHDQGWKHJUHHQWLPHVZLOODOZD\VEHLQV\QF
$IUDJPHQWFUHDWHGLQDOD\RXW XVLQJDQ;0/IUDJPHQWWDJ PXVWQHYHU
EHUHSODFHGZLWKDG\QDPLFDOO\FUHDWHGIUDJPHQW$OWKRXJKLVLWSUHWW\
KDUGWRWHOOMXVWE\ORRNLQJDWWKHPWKHOLIHF\FOHRIRQHLVPXFKGLIIHUHQW
IURPWKDWRIWKHRWKHU7KHUH¦VQRUHDVRQ\RXFDQ¦WXVHERWKLQ\RXU
DSSOLFDWLRQEXWQHYHUUHSODFHRQHZLWKWKHRWKHU$WWHPSWLQJWRXVH
setContentViewIRULQVWDQFHZLWKDOD\RXWWKDWKDVKDGDOD\RXWIUDJ
PHQWUHSODFHGZLWKRQHWKDWZDVSURJUDPPDWLFDOO\FUHDWHGZLOOFDXVH
EXJVWKDWFDQEHGLIILFXOWWRILQGDQGIL[$IUHTXHQWV\PSWRPRIWKLV
NLQGRISUREOHPLVDQ IllegalStateExceptionZLWKWKHPHVVDJH£)UDJ
PHQWGLGQRWFUHDWHDYLHZ¤
7KLVEULQJVXVWRWKHODVWHVVHQWLDOIHDWXUHRIIUDJPHQWVWKHEDFNVWDFN,I\RXUXQVHYHUDO
DFWLYLWLHVLQVHTXHQFH\RXFDQUHWXUQWRWKHPLQUHYHUVHRUGHUXVLQJWKHEDFNEXWWRQ
7KLVEHKDYLRUDOVRDSSOLHVWRIUDJPHQWWUDQVDFWLRQV
,I\RXUXQWKLVDSSOLFDWLRQWKHGLVSOD\ZLOOORRNVRPHWKLQJOLNH)LJXUH:KHQ\RX
SXVKWKHEXWWRQDWWKHWRSRIWKHGLVSOD\WKHEOXHDQGJUHHQIUDJPHQWVZLOOXSGDWH
Fragment Transactions | 207
VLPXOWDQHRXVO\%HWWHU\HWWKRXJKLI\RXSXVKWKHEDFNEXWWRQ WKHOHIWIDFLQJDUURZ
LFRQLQWKHORZHUULJKWFRUQHURIWKHGLVSOD\ \RXZLOOVHHLQUHYHUVHRUGHUHDFKXSGDWH
\RXJHQHUDWHGE\SXVKLQJWKH'R,WEXWWRQ)RULQVWDQFHLIERWKIUDJPHQWVGLVSOD\WKH
WLPH £ $SU ¤ DQG \RX SXVK WKH 'R ,W EXWWRQ WKH GLVSOD\ PLJKW EH
XSGDWHGVRWKDWERWKWKHEOXHDQGWKHJUHHQUHJLRQVVKRZWKHGDWHWLPHDV£$SU
¤,I\RXQRZSXVKWKHEDFNEXWWRQERWKIUDJPHQWVZLOODJDLQGLVSOD\£$SU
¤7KHHQWLUHWUDQVDFWLRQ¢WKHXSGDWHVRIERWKIUDJPHQWV¢LVSXVKHG
RQWRWKHEDFNVWDFNDVDVLQJOHHYHQW:KHQ\RXSXVKWKHEDFNEXWWRQDQHQWLUHWUDQV
DFWLRQLVUHPRYHGUHYHDOLQJWKHHQWLUHVWDWHIURPWKHSUHYLRXVWUDQVDFWLRQ
The Compatibility Package
2QHRIWKHPRVWLPSRUWDQWDVSHFWVRIIUDJPHQWVLVWKDWDOWKRXJKWKH\ZHUHLQWURGXFHG
LQ$QGURLGDQGDUHQRWDYDLODEOHLQSUHYLRXVUHOHDVHVRIWKH$3,*RRJOHSURYLGHV
WKH$QGURLG&RPSDWLELOLW\3DFNDJH $&3 WRPDNHLWSRVVLEOHWRXVHWKHIUDJPHQWIHD
WXUHRQGHYLFHVWKDWDUHVWLOOXVLQJDQROGHUYHUVLRQRI$QGURLG
7KH FRPSDWLELOLW\ SDFNDJH LV QRW D FRPSOHWH ZLQ ,W LV QRW IRUZDUG FRPSDWLEOH $Q
DSSOLFDWLRQWKDWUXQVXVLQJWKH$&3UHTXLUHVWKH$&3HYHQZKHQUXQQLQJRQDQ$Q
GURLG V\VWHP :KHQ FKRRVLQJ DQ LPSOHPHQWDWLRQ VWUDWHJ\ IRU WKH $&3 *RRJOH
IDFHG D FRQXQGUXP (YHQ LI LW KDG EHHQ SRVVLEOH WR LPSOHPHQW WKH $&3 VR WKDW DQ
DSSOLFDWLRQSRUWHGWUDQVSDUHQWO\ZLWKRXWFKDQJHIURP$QGURLGWR$QGURLG
$&3WKHUHZRXOGKDYHEHHQDSUREOHP7KH$&3PXVWEHLQFOXGHGDVSDUWRIDQDS
SOLFDWLRQ,IWKH$&3GHILQHGFODVVHVZLWKQDPHVWKDWDUHLGHQWLFDOWRWKRVHLQ$QGURLG
DQDSSOLFDWLRQWKDWHPEHGGHGLWZRXOGZLWKRXWVRPHVHULRXVFODVVORDGHUWULFNHU\
GHILQHFODVVHVWKDWFROOLGHGZLWKWKHLUV\VWHPGHILQLWLRQV
,QVWHDGWKH$&3XVHVDGLIIHUHQWEDVHSDFNDJHandroid.support.v4LQZKLFKWRGHILQH
WKHFRPSDWLELOLW\IHDWXUHV$SURJUDPGHYHORSHGIRU$QGURLGZLOOQHHGFRGHFKDQJHV
WRXVHWKH$&3<RXZLOOQHHGWRPDNHDWOHDVWWKHIROORZLQJFKDQJHV
‡ &RS\WKH$&3OLEUDU\WR\RXUSURMHFW&UHDWHDGLUHFWRU\QDPHGOLEDWWKHWRSOHYHO
RI \RXU SURMHFW DQG FRS\ DQGURLGVXSSRUWYMDU IURP WKH $QGURLG 6'. IROGHU
H[WUDVDQGURLGFRPSDWLELOLW\YLQWRLW
‡ $GGWKH$&3WR\RXUSURMHFWEXLOGSDWK,Q(FOLSVHVHOHFWWKHOLEUDU\LQWKH3DFNDJH
([SORUHU \RX PD\ KDYH WR UHIUHVK WKH SURMHFW WR VHH LW SUHVV ) RU OHIW
FOLFNൺ5HIUHVK 2QFH LW LV VHOHFWHG \RX VKRXOG EH DEOH WR OHIWFOLFNൺ%XLOG
3DWKൺ$GGWR%XLOG3DWK
‡ &KDQJH \RXU SURMHFW EXLOG WDUJHW IURP $QGURLG WR $QGURLG 3URSHU
WLHVൺ$QGURLG 7KLVZLOOFDXVHPDQ\HUURUVWRDSSHDU
‡ 6RPH LPSRUWV WKDW UHIHU WR DQGURLGDSS ZLOO KDYH WR EH XSGDWHG WR UHIHU WR DQ
GURLGVXSSRUWYDSS3UHVXPLQJ\RXUSURJUDPKDGQRHUURUVEHIRUHFKDQJLQJLWV
EXLOGWDUJHW\RXQHHGRQO\ILQGEURNHQLPSRUWVDQGXSGDWHWKHLUEDVHSDFNDJH
208 | Chapter 8:ಗFragments and Multiplatform Support
‡ $OOWKHDFWLYLWLHVLQWKHDSSOLFDWLRQWKDWXVHIUDJPHQWVPXVWEHXSGDWHGWRWKHVXE
FODVVFragmentActivityLQVWHDGRIActivity
‡ &KDQJHDOOFDOOVWRgetFragmentManagerLQWRFDOOVWRgetSupportFragmentManager
‡ )L[DQ\UHPDLQLQJHUURUVDQGWHVW\RXUSURJUDP
The Compatibility Package | 209
CHAPTER 9
Drawing 2D and 3D Graphics
7KH$QGURLGPHQDJHULHRIZLGJHWVDQGWKHWRROVIRUDVVHPEOLQJWKHPDUHFRQYHQLHQW
DQGSRZHUIXODQGFRYHUDEURDGYDULHW\RIQHHGV:KDWKDSSHQVWKRXJKZKHQQRQH
RIWKHH[LVWLQJZLGJHWVRIIHUZKDW\RXQHHG"0D\EH\RXUDSSOLFDWLRQQHHGVWRUHSUHVHQW
SOD\LQJFDUGVSKDVHVRIWKHPRRQRUWKHSRZHUGLYHUWHGWRWKHPDLQWKUXVWHUVRID
URFNHWVKLS,QWKDWFDVH\RX¦OOKDYHWRNQRZKRZWRUROO\RXURZQ
7KLV FKDSWHU LV DQ RYHUYLHZ RI JUDSKLFV DQG DQLPDWLRQ RQ $QGURLG ,W¦V GLUHFWHG DW
SURJUDPPHUVZLWKVRPHEDFNJURXQGLQJUDSKLFVDQGJRHVLQWRTXLWHDELWRIGHSWK
DERXWZD\VWRWZLVWDQGWXUQWKHGLVSOD\<RXZLOOGHILQLWHO\QHHGWRVXSSOHPHQWWKH
FKDSWHUZLWK$QGURLGGRFXPHQWDWLRQSDUWLFXODUO\EHFDXVHHVSHFLDOO\ZLWKWKHDGYHQW
RI+RQH\FRPEWKHLQWHUIDFHVDUHVWLOOXQGHUJRLQJFKDQJHV%XWWKHWHFKQLTXHVKHUHZLOO
KHOS\RXGD]]OH\RXUXVHUV
Rolling Your Own Widgets
$V PHQWLRQHG HDUOLHU ZLGJHW LV MXVW D FRQYHQLHQW WHUP IRU D VXEFODVV RI
android.view.ViewW\SLFDOO\DOHDIQRGHLQWKHYLHZWUHH,QWHUQDOQRGHVLQWKHYLHZWUHH
WKRXJKWKH\PD\FRQWDLQFRPSOH[FRGHWHQGWRKDYHVLPSOHUXVHULQWHUDFWLRQV7KH
WHUPZLGJHWDOWKRXJKLQIRUPDOLVXVHIXOIRUGLVFXVVLQJWKHZRUNKRUVHSDUWVRIWKHXVHU
LQWHUIDFHWKDWKDYHWKHLQIRUPDWLRQDQGWKHEHKDYLRUXVHUVFDUHDERXW
<RXFDQDFFRPSOLVKDORWZLWKRXWFUHDWLQJDQHZZLGJHW,QWKLVERRNZHKDYHDOUHDG\
FRQVWUXFWHGVHYHUDODSSOLFDWLRQVFRQVLVWLQJHQWLUHO\RIH[LVWLQJZLGJHWVRUVLPSOHVXE
FODVVHVRIH[LVWLQJZLGJHWV7KHFRGHLQWKRVHDSSOLFDWLRQVMXVWEXLOWWUHHVRIYLHZVOD\LQJ
WKHPRXWLQFRGHRUWKURXJKOD\RXWUHVRXUFHVLQ;0/ILOHV
7KHQRQWULYLDO0LFUR-REVDSSOLFDWLRQZKLFKZH¦OOFRYHULQ&KDSWHUKDVDYLHZWKDW
FRQWDLQVDOLVWRIQDPHVFRUUHVSRQGLQJWRORFDWLRQVRQDPDS$VDGGLWLRQDOORFDWLRQV
DUHDGGHGWRWKHPDSQHZQDPHGLVSOD\LQJZLGJHWVDUHDGGHGG\QDPLFDOO\WRWKHOLVW
(YHQ WKLV G\QDPLFDOO\ FKDQJLQJ OD\RXW LV MXVW D XVH RI SUHH[LVWLQJ ZLGJHWV LW LV QRW
FUHDWLQJQHZRQHV7KHWHFKQLTXHVLQ0LFUR-REVDUHILJXUDWLYHO\DGGLQJRUUHPRYLQJ
ER[HVIURPDWUHHOLNHWKHRQHLOOXVWUDWHGLQ)LJXUHRI&KDSWHU
211
,QFRQWUDVWWKLVFKDSWHUVKRZV\RXKRZWRUROO\RXURZQZLGJHWZKLFKLQYROYHVORRNLQJ
XQGHU WKH View KRRG TextView Button DQG DatePicker DUH DOO H[DPSOHV RI ZLGJHWV
SURYLGHGE\WKH$QGURLG8,WRRONLW<RXFDQLPSOHPHQW\RXURZQZLGJHWDVDVXEFODVV
RIRQHRIWKHVHRUDVDGLUHFWVXEFODVVRIView
$PRUHFRPSOH[ZLGJHW¢RQHWKDWFDQQHVWRWKHUZLGJHWV¢ZLOOKDYHWRVXEFODVVView
GroupZKLFKLVLWVHOIDVXEFODVVRI View$YHU\FRPSOH[ZLGJHWSHUKDSVXVHGDVDQ
LQWHUIDFHWRROLPSOHPHQWHGLQVHYHUDOSODFHV HYHQE\PXOWLSOHDSSOLFDWLRQV PLJKWEH
DQHQWLUHSDFNDJHRIFODVVHVRQO\RQHRIZKLFKLVDGHVFHQGDQWRIView
7KLVFKDSWHULVDERXWJUDSKLFVDQGWKHUHIRUHDERXWWKH9LHZSDUWRIWKH0RGHO9LHZ
&RQWUROOHU 09& SDWWHUQ:LGJHWVDOVRFRQWDLQ&RQWUROOHUFRGHZKLFKLVJRRGGHVLJQ
EHFDXVHLWNHHSVWRJHWKHUDOOWKHFRGHUHOHYDQWWRDEHKDYLRUDQGLWVUHSUHVHQWDWLRQRQ
WKHVFUHHQ7KLVSDUWRIWKLVFKDSWHUGLVFXVVHVRQO\WKHLPSOHPHQWDWLRQRIWKH9LHZ
7KHLPSOHPHQWDWLRQRIWKH&RQWUROOHUZDVGLVFXVVHGLQ&KDSWHU
&RQFHQWUDWLQJRQJUDSKLFVWKHQZHFDQEUHDNWKHWDVNVRIWKLVFKDSWHULQWRWZRHV
VHQWLDOSDUWVILQGLQJVSDFHRQWKHVFUHHQDQGGUDZLQJLQWKDWVSDFH7KHILUVWWDVNLV
NQRZQDVOD\RXW$OHDIZLGJHWFDQDVVHUWLWVVSDFHQHHGVE\GHILQLQJDQ onMeasure
PHWKRGWKDWWKH$QGURLG8,IUDPHZRUNZLOOFDOODWWKHULJKWWLPH7KHVHFRQGWDVN
DFWXDOO\UHQGHULQJWKHZLGJHWLVKDQGOHGE\WKHZLGJHW¦VonDrawPHWKRG
Layout
0RVWRIWKHKHDY\OLIWLQJLQWKH$QGURLG)UDPHZRUNOD\RXWPHFKDQLVPLVLPSOHPHQWHG
E\FRQWDLQHUYLHZV$FRQWDLQHUYLHZLVRQHWKDWFRQWDLQVRWKHUYLHZV,WLVDQLQWHUQDO
QRGHLQWKHYLHZWUHHDQGLQWKHVXEFODVVHVRIViewGroup7KHIUDPHZRUNWRRONLWSURYLGHV
DYDULHW\RIVRSKLVWLFDWHGFRQWDLQHUYLHZVWKDWRIIHUSRZHUIXODQGDGDSWDEOHVWUDWHJLHV
IRUDUUDQJLQJDVFUHHQLinearLayoutDQGRelativeLayoutWRQDPHVRPHFRPPRQRQHV
DUHFRQWDLQHUYLHZVWKDWDUHERWKUHODWLYHO\HDV\WRXVHDQGIDLUO\KDUGWRUHLPSOHPHQW
FRUUHFWO\6LQFHFRQYHQLHQWSRZHUIXOFRQWDLQHUYLHZVDOUHDG\H[LVW\RXZLOOSUREDEO\
QHYHUKDYHWRLPSOHPHQWRQHRUWKHOD\RXWDOJRULWKPGLVFXVVHGKHUH8QGHUVWDQGLQJ
KRZLWZRUNVWKRXJK¢KRZWKH$QGURLG8,IUDPHZRUNPDQDJHVWKHOD\RXWSURFHVV¢
ZLOOKHOS\RXEXLOGFRUUHFWUREXVWZLGJHWV
([DPSOHVKRZVZKDWLVSHUKDSVWKHVLPSOHVWZRUNLQJZLGJHWRQHFRXOGGHVLJQ,I
DGGHGWRVRPHActivity¦VYLHZWUHHWKLVZLGJHWZLOOILOOLQWKHVSDFHDOORFDWHGWRLWZLWK
WKHFRORUF\DQ1RWYHU\LQWHUHVWLQJEXWEHIRUHZHPRYHRQWRFUHDWHDQ\WKLQJPRUH
FRPSOH[OHW¦VORRNFDUHIXOO\DWKRZWKLVH[DPSOHIXOILOOVWKHWZREDVLFWDVNVRIOD\RXW
DQGGUDZLQJ:H¦OOVWDUWZLWKWKHOD\RXWSURFHVVZH¦OOGHVFULEHGUDZLQJODWHULQ£&DQ
YDV'UDZLQJ¤RQSDJH
212 | Chapter 9:ಗDrawing 2D and 3D Graphics
([DPSOH$WULYLDOZLGJHW
public class TrivialWidget extends View {
public TrivialWidget(Context context) {
super(context);
setMinimumWidth(100);
setMinimumHeight(20);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getSuggestedMinimumWidth(),
getSuggestedMinimumHeight());
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.CYAN);
}
'\QDPLFOD\RXWLVQHFHVVDU\EHFDXVHWKHVSDFHUHTXLUHPHQWVIRUZLGJHWVFKDQJHG\
QDPLFDOO\6XSSRVHIRULQVWDQFHWKDWDZLGJHWLQD*36HQDEOHGDSSOLFDWLRQGLVSOD\V
WKHQDPHRIWKHFLW\LQZKLFK\RXDUHFXUUHQWO\GULYLQJ$V\RXJRIURP£(O\¤WR£3RVW
0LOOV¤WKHZLGJHWUHFHLYHVQRWLILFDWLRQRIWKHFKDQJHLQORFDWLRQ:KHQLWSUHSDUHVWR
UHGUDZWKHFLW\QDPHWKRXJKLWQRWLFHVWKDWLWGRHVQ¦WKDYHHQRXJKURRPIRUWKHZKROH
QDPHRIWKHQHZWRZQ,WQHHGVWRDVNWKHGLVSOD\WRUHGUDZWKHVFUHHQLQDZD\WKDW
JLYHVLWPRUHVSDFHLIWKDWLVSRVVLEOH
/D\RXWFDQEHDVXUSULVLQJO\FRPSOH[WDVNDQGYHU\GLIILFXOWWRJHWULJKW,WLVSUREDEO\
QRWYHU\KDUGWRPDNHDSDUWLFXODUOHDIZLGJHWORRNULJKWRQDVLQJOHGHYLFH,WFDQEH
YHU\WULFN\RQWKHRWKHUKDQGWRJHWDZLGJHWWKDWPXVWDUUDQJHFKLOGUHQWRORRNULJKW
RQPXOWLSOHGHYLFHVHYHQZKHQWKHGLPHQVLRQVRIWKHVFUHHQFKDQJH
7KHOD\RXWSURFHVVLVLQLWLDWHGZKHQWKH requestLayoutPHWKRGLVLQYRNHGRQVRPH
YLHZLQWKHYLHZWUHH7\SLFDOO\DZLGJHWFDOOV requestLayoutRQLWVHOIZKHQLWQHHGV
PRUHVSDFH7KHPHWKRGFRXOGEHLQYRNHGWKRXJKIURPDQ\SODFHLQDQDSSOLFDWLRQ
WRLQGLFDWHWKDWVRPHYLHZLQWKHFXUUHQWVFUHHQQRORQJHUKDVWKHULJKWDPRXQWRIURRP
7KHrequestLayoutPHWKRGFDXVHVWKH$QGURLG8,IUDPHZRUNWRHQTXHXHDQHYHQWRQ
WKH8,HYHQWTXHXH:KHQWKHHYHQWLVSURFHVVHGLQRUGHUWKHIUDPHZRUNJLYHVHYHU\
FRQWDLQHUYLHZDQRSSRUWXQLW\WRDVNHDFKRILWVFKLOGZLGJHWVKRZPXFKVSDFHLWZRXOG
OLNHIRUGUDZLQJ7KHSURFHVVLVVHSDUDWHGLQWRWZRSKDVHVPHDVXULQJFKLOGYLHZVDQG
WKHQDUUDQJLQJWKHPLQWKHLUQHZSRVLWLRQV$OOYLHZVPXVWLPSOHPHQWWKHILUVWSKDVH
EXWWKHVHFRQGLVQHFHVVDU\RQO\LQWKHLPSOHPHQWDWLRQVRIFRQWDLQHUYLHZVWKDWPXVW
PDQDJHWKHOD\RXWRIFKLOGYLHZV
Rolling Your Own Widgets | 213
Measurement
7KHJRDORIWKHPHDVXUHPHQWSKDVHLVWRSURYLGHHDFKYLHZZLWKDQRSSRUWXQLW\WR
G\QDPLFDOO\UHTXHVWWKHVSDFHLWZRXOGOLNHLGHDOO\IRUGUDZLQJ7KH8,IUDPHZRUN
VWDUWVWKHSURFHVVE\LQYRNLQJWKH measurePHWKRGRIWKHYLHZDWWKHURRWRIWKHYLHZ
WUHH6WDUWLQJWKHUHHDFKFRQWDLQHUYLHZDVNVHDFKRILWVFKLOGUHQKRZPXFKVSDFHLW
ZRXOGSUHIHU7KHFDOOLVSURSDJDWHGWRDOOGHVFHQGDQWVGHSWKILUVWVRWKDWHYHU\FKLOG
JHWVDFKDQFHWRFRPSXWHLWVVL]HEHIRUHLWVSDUHQW7KHSDUHQWFRPSXWHVLWVRZQVL]H
EDVHGRQWKHVL]HVRILWVFKLOGUHQDQGUHSRUWVWKDWWRLWVSDUHQWDQGVRRQXSWKHWUHH
,Q£$VVHPEOLQJD*UDSKLFDO,QWHUIDFH¤RQSDJHIRULQVWDQFHWKHWRSPRVW Linear
LayoutDVNVHDFKQHVWHGLinearLayoutZLGJHWIRULWVSUHIHUUHGGLPHQVLRQV7KH\LQWXUQ
DVNWKHButtonVRUEditTextYLHZVWKH\FRQWDLQIRUWKHLUV(DFKFKLOGUHSRUWVLWVGHVLUHG
VL]HWRLWVSDUHQW7KHSDUHQWVWKHQDGGXSWKHVL]HVRIWKHFKLOGUHQDORQJZLWKDQ\
SDGGLQJWKH\LQVHUWWKHPVHOYHVDQGUHSRUWWKHWRWDOWRWKHWRSPRVWLinearLayout
%HFDXVH WKH IUDPHZRUN PXVW JXDUDQWHH FHUWDLQ EHKDYLRUV IRU DOO ViewV GXULQJ WKLV
SURFHVVWKH measurePHWKRGLVILQDODQGFDQQRWEHRYHUULGGHQ,QVWHDG measureFDOOV
onMeasureZKLFKZLGJHWVPD\RYHUULGHWRFODLPWKHLUVSDFH
7KHDUJXPHQWVWRWKHonMeasurePHWKRGGHVFULEHWKHVSDFHWKHSDUHQWLVZLOOLQJWRPDNH
DYDLODEOH D ZLGWK VSHFLILFDWLRQ DQG D KHLJKW VSHFLILFDWLRQ PHDVXUHG LQ SL[HOV 7KH
IUDPHZRUNDVVXPHVWKDWQRYLHZZLOOHYHUEHVPDOOHUWKDQRUELJJHUWKDQSL[HOV
LQVL]HDQGWKHUHIRUHXVHVWKHKLJKRUGHUELWVRIWKHSDVVHG intSDUDPHWHUWRHQFRGH
WKHPHDVXUHPHQWVSHFLILFDWLRQPRGH,WLVDVWKRXJKonMeasureZHUHDFWXDOO\FDOOHGZLWK
IRXUDUJXPHQWVWKHZLGWKVSHFLILFDWLRQPRGHWKHZLGWKWKHKHLJKWVSHFLILFDWLRQPRGH
DQGWKHKHLJKW'RQRWEHWHPSWHGWRGR\RXURZQELWVKLIWLQJWRVHSDUDWHWKHSDLUVRI
DUJXPHQWV,QVWHDGXVHWKHVWDWLFPHWKRGVMeasureSpec.getModeDQGMeasureSpec.get
Size
7KHVSHFLILFDWLRQPRGHVGHVFULEHKRZWKHFRQWDLQHUYLHZZDQWVWKHFKLOGWRLQWHUSUHW
WKHDVVRFLDWHGVL]H7KHUHDUHWKUHHRIWKHP
MeasureSpec.EXACTLY
7KHFDOOLQJFRQWDLQHUYLHZKDVDOUHDG\GHWHUPLQHGWKHH[DFWVL]HRIWKHFKLOGYLHZ
MeasureSpec.AT_MOST
7KHFDOOLQJFRQWDLQHUYLHZKDVVHWDPD[LPXPVL]HIRUWKLVGLPHQVLRQEXWWKHFKLOG
LVIUHHWRUHTXHVWOHVV
MeasureSpec.UNSPECIFIED
7KHFDOOLQJFRQWDLQHUYLHZKDVQRWLPSRVHGDQ\OLPLWVRQWKHFKLOGWKHFKLOGPD\
UHTXHVWDQ\WKLQJLWFKRRVHV
$ZLGJHWLVDOZD\VUHVSRQVLEOHIRUWHOOLQJLWVSDUHQWLQWKHYLHZWUHHKRZPXFKVSDFHLW
QHHGV,WGRHVWKLVE\FDOOLQJsetMeasuredDimensionsWRVHWLWVKHLJKWDQGZLGWKSURS
HUWLHV7KHSDUHQWFDQODWHUUHWULHYHWKHVHSURSHUWLHVWKURXJKWKHPHWKRGVgetMeasured
HeightDQGgetMeasuredWidth,I\RXULPSOHPHQWDWLRQRYHUULGHVonMeasureEXWGRHVQRW
214 | Chapter 9:ಗDrawing 2D and 3D Graphics
FDOOsetMeasuredDimensionsWKHmeasurePHWKRGZLOOWKURZIllegalStateExceptionLQ
VWHDGRIFRPSOHWLQJQRUPDOO\
7KH GHIDXOW LPSOHPHQWDWLRQ RI onMeasure LQKHULWHG IURP View FDOOV setMeasured
Dimensions ZLWKRQH RI WZRYDOXHV LQ HDFKGLUHFWLRQ ,I WKHSDUHQWVSHFLILHV Measure
Spec.UNSPECIFIEDWKHFKLOG¦V setMeasuredDimensionsPHWKRGXVHVWKHGHIDXOWVL]HRI
WKH YLHZ WKH YDOXH VXSSOLHG E\ HLWKHU getSuggestedMinimumWidth RU getSuggested
MinimumHeight,IWKHSDUHQWVSHFLILHVHLWKHURIWKHRWKHUWZRPRGHVWKHGHIDXOWLPSOH
PHQWDWLRQXVHVWKHVL]HWKDWZDVRIIHUHGE\WKHSDUHQW7KLVLVDYHU\UHDVRQDEOHVWUDWHJ\
DQGDOORZVDW\SLFDOZLGJHWLPSOHPHQWDWLRQWRKDQGOHWKHPHDVXUHPHQWSKDVHFRP
SOHWHO\E\VLPSO\VHWWLQJWKHYDOXHVUHWXUQHGE\getSuggestedMinimumWidthDQGgetSug
gestedMinimumHeight:HXVHGWKDWPLQLPDOVWUDWHJ\LQ([DPSOH
<RXUZLGJHWPD\QRWDFWXDOO\JHWWKHVSDFHLWUHTXHVWV&RQVLGHUDYLHZWKDWLV
SL[HOVZLGHDQGWKDWKDVWKUHHFKLOGUHQ,WLVSUREDEO\REYLRXVKRZWKHSDUHQWVKRXOG
DUUDQJHLWVFKLOGUHQLIWKHVXPRIWKHSL[HOZLGWKVUHTXHVWHGE\WKHFKLOGUHQLVRU
OHVV,IKRZHYHUHDFKFKLOGUHTXHVWVSL[HOVWKHSDUHQWFRQWDLQHUYLHZLVQRWJRLQJ
WREHDEOHWRVDWLVI\WKHPDOO
$FRQWDLQHUYLHZKDVFRPSOHWHFRQWURORIKRZLWDUUDQJHVLWVFKLOGUHQ,WPLJKWLQWKH
FLUFXPVWDQFHVMXVWGHVFULEHGGHFLGHWREH£IDLU¤DQGDOORFDWHSL[HOVWRHDFKFKLOG
,WPLJKWMXVWDVHDVLO\GHFLGHWRDOORFDWHSL[HOVWRWKHOHIWPRVWFKLOGDQGWRHDFK
RIWKHRWKHUWZR,QIDFWLWPLJKWGHFLGHWRJLYHRQHRIWKHFKLOGUHQWKHHQWLUHSL[HOV
DQGQRWKLQJDWDOOWRWKHRWKHUV:KDWHYHULWVPHWKRGWKRXJKLQWKHHQGWKHSDUHQW
GHWHUPLQHVDVL]HDQGORFDWLRQIRUWKHERXQGLQJUHFWDQJOHIRUHDFKFKLOG
$QRWKHUH[DPSOHRIDFRQWDLQHUYLHZ¦VFRQWURORIWKHVSDFHDOORFDWHGWRDZLGJHWFRPHV
IURPWKHH[DPSOHZLGJHWLQ([DPSOH,WDOZD\VUHTXHVWVWKHDPRXQWRIVSDFHLW
SUHIHUVUHJDUGOHVVRIZKDWLWLVRIIHUHG XQOLNHWKHGHIDXOWLPSOHPHQWDWLRQ 7KLVVWUDW
HJ\LVKDQG\WRUHPHPEHUIRUZLGJHWVWKDWZLOOEHDGGHGWRWRRONLWFRQWDLQHUVQRWDEO\
LinearLayout WKDW LPSOHPHQW JUDYLW\ *UDYLW\ LV D SURSHUW\ WKDW VRPH YLHZV XVH WR
VSHFLI\WKHDOLJQPHQWRIWKHLUVXEHOHPHQWV<RXPD\EHVXUSULVHGWKHILUVWWLPH\RX
XVHRQHRIWKHVHFRQWDLQHUVWRILQGWKDWE\GHIDXOWRQO\WKHILUVWRI\RXUFXVWRPZLGJHWV
JHWVGUDZQ<RXFDQIL[WKLVHLWKHUE\XVLQJWKHsetGravityPHWKRGWRFKDQJHWKHSURS
HUW\WRGravity.FILLRUE\PDNLQJ\RXUZLGJHWVLQVLVWHQWDERXWWKHDPRXQWRIVSDFH
WKH\UHTXHVW
,WLVDOVRLPSRUWDQWWRQRWHWKDWDFRQWDLQHUYLHZPD\FDOODFKLOG¦V measurePHWKRG
VHYHUDO WLPHV GXULQJ D VLQJOH PHDVXUHPHQW SKDVH $V SDUW RI LWV LPSOHPHQWDWLRQ RI
onMeasureDFOHYHUFRQWDLQHUYLHZDWWHPSWLQJWROD\RXWDKRUL]RQWDOURZRIZLGJHWV
PLJKW IRU LQVWDQFH FDOO HDFK FKLOG ZLGJHW¦V measure PHWKRG ZLWK PRGH
MEASURE_SPEC.UNSPECIFIEDDQG D ZLGWK RI WR ILQG RXW ZKDWVL]HWKHZLGJHWZRXOG
SUHIHU2QFHLWKDVFROOHFWHGWKHSUHIHUUHGZLGWKVIRUHDFKRILWVFKLOGUHQLWFRXOGFRP
SDUHWKHVXPWRWKHDFWXDOZLGWKDYDLODEOH ZKLFKZDVVSHFLILHGLQLWVSDUHQW¦VFDOOWR
LWVmeasurePHWKRG 1RZLWPLJKWFDOOHDFKFKLOGZLGJHW¦VmeasurePHWKRGDJDLQWKLV
WLPHZLWKWKHPRGHMeasureSpec.AT_MOSTDQGDZLGWKWKDWLVDQDSSURSULDWHSURSRUWLRQ
Rolling Your Own Widgets | 215
RIWKHVSDFHDFWXDOO\DYDLODEOH%HFDXVH measurePD\EHFDOOHGPXOWLSOHWLPHVDQLP
SOHPHQWDWLRQRI onMeasurePXVWEHLGHPSRWHQWDQGPXVWQRWFKDQJHWKHDSSOLFDWLRQ
VWDWH
$QDFWLRQLVVDLGWREH£LGHPSRWHQW¤LIWKHHIIHFWRISHUIRUPLQJLWRQFH
LVWKHVDPHDVWKHHIIHFWRISHUIRUPLQJLWPXOWLSOHWLPHV)RULQVWDQFH
WKHVWDWHPHQW[ LVLGHPSRWHQWEHFDXVHQRPDWWHUKRZPDQ\WLPHV
\RXGRLW[DOZD\VHQGVXSDV[ [KRZHYHULVQRWLGHPSRWHQW
EHFDXVHWKHYDOXHRI[GHSHQGVRQKRZPDQ\WLPHVWKHVWDWHPHQWLV
H[HFXWHG
$ FRQWDLQHU YLHZ¦V LPSOHPHQWDWLRQ RI onMeasure LV OLNHO\ WR EH IDLUO\ FRPSOH[ View
GroupWKHVXSHUFODVVRIDOOFRQWDLQHUYLHZVGRHVQRWVXSSO\DGHIDXOWLPSOHPHQWDWLRQ
(DFK$QGURLG8,IUDPHZRUNFRQWDLQHUYLHZKDVLWVRZQ,I\RXFRQWHPSODWHLPSOH
PHQWLQJDFRQWDLQHUYLHZ\RXPLJKWFRQVLGHUEDVLQJLWRQRQHRIWKHP,ILQVWHDG\RX
LPSOHPHQWPHDVXUHPHQWIURPVFUDWFK\RXDUHVWLOOOLNHO\WRQHHGWRFDOO measureIRU
HDFK FKLOG DQG VKRXOG FRQVLGHU XVLQJ WKH ViewGroup KHOSHU PHWKRGV measureChild
measureChildrenDQGmeasureChildWithMargins$WWKHFRQFOXVLRQRIWKHPHDVXUHPHQW
SKDVHDFRQWDLQHUYLHZOLNHDQ\RWKHUZLGJHWPXVWUHSRUWWKHVSDFHLWQHHGVE\FDOOLQJ
setMeasuredDimensions
Arrangement
2QFHDOOWKHFRQWDLQHUYLHZVLQWKHYLHZWUHHKDYHKDGDFKDQFHWRQHJRWLDWHWKHVL]HV
RI HDFK RI WKHLU FKLOGUHQ WKH IUDPHZRUN EHJLQV WKH VHFRQG SKDVH RI OD\RXW ZKLFK
FRQVLVWVRIDUUDQJLQJWKHFKLOGUHQ$JDLQXQOHVV\RXLPSOHPHQW\RXURZQFRQWDLQHU
YLHZ\RXZLOOSUREDEO\QHYHUKDYHWRLPSOHPHQW\RXURZQDUUDQJHPHQWFRGH7KLV
VHFWLRQGHVFULEHVWKHXQGHUO\LQJSURFHVVVRWKDW\RXFDQEHWWHUXQGHUVWDQGKRZLWPLJKW
DIIHFW\RXUZLGJHWV7KHGHIDXOWPHWKRGLPSOHPHQWHGLQ ViewZLOOZRUNIRUW\SLFDO
OHDIZLGJHWVDVGHPRQVWUDWHGE\([DPSOH
%HFDXVHDYLHZ¦VonMeasurePHWKRGPLJKWEHFDOOHGVHYHUDOWLPHVWKHIUDPHZRUNPXVW
XVHDGLIIHUHQWPHWKRGWRVLJQDOWKDWWKHPHDVXUHPHQWSKDVHLVFRPSOHWHDQGWKDWFRQ
WDLQHUYLHZVPXVWIL[WKHILQDOORFDWLRQVRIWKHLUFKLOGUHQ/LNHWKHPHDVXUHPHQWSKDVH
WKHDUUDQJHPHQWSKDVHLVLPSOHPHQWHGZLWKWZRPHWKRGV7KHIUDPHZRUNLQYRNHVD
ILQDOPHWKRG layoutDWWKHWRSRIWKHYLHZWUHH7KH layoutPHWKRGSHUIRUPVSUR
FHVVLQJFRPPRQWRDOOYLHZVDQGWKHQLQYRNHVonLayoutZKLFKFXVWRPZLGJHWVRYHUULGH
WRLPSOHPHQWWKHLURZQEHKDYLRUV$FXVWRPLPSOHPHQWDWLRQRIonLayoutPXVWDWOHDVW
FDOFXODWHWKHERXQGLQJUHFWDQJOHWKDWLWZLOOVXSSO\WRHDFKFKLOGZKHQLWLVGUDZQDQG
LQWXUQLQYRNHWKHlayoutPHWKRGIRUHDFKFKLOG EHFDXVHWKDWFKLOGPLJKWLQWXUQEH
DSDUHQWWRRWKHUZLGJHWV 7KLVSURFHVVFDQEHFRPSOH[,I\RXUZLGJHWQHHGVWRDUUDQJH
FKLOG YLHZV \RX PLJKW FRQVLGHU EDVLQJ LW RQ DQ H[LVWLQJ FRQWDLQHU VXFK DV Linear
LayoutRURelativeLayout
216 | Chapter 9:ಗDrawing 2D and 3D Graphics
,WLVZRUWKUHLWHUDWLQJWKDWDZLGJHWLVQRWJXDUDQWHHGWRUHFHLYHWKHVSDFHLWUHTXHVWV,W
PXVWEHSUHSDUHGWRGUDZLWVHOILQZKDWHYHUVSDFHLVDFWXDOO\DOORFDWHGWRLW,ILWDWWHPSWV
WRGUDZRXWVLGHWKHVSDFHDOORFDWHGWRLWE\LWVSDUHQWWKHGUDZLQJZLOOEHFOLSSHGE\
WKHFOLSUHFWDQJOH GLVFXVVHGODWHULQWKLVFKDSWHU 7RH[HUWILQHFRQWURO¢WRH[DFWO\ILOO
WKHVSDFHDOORFDWHGWRLWIRULQVWDQFH¢DZLGJHWPXVWHLWKHULPSOHPHQWonLayoutDQG
UHFRUG WKH GLPHQVLRQV RI WKH DOORFDWHG VSDFH RU LQVSHFW WKH FOLS UHFWDQJOH RI WKH
CanvasWKDWLVWKHSDUDPHWHUWRonDraw
Canvas Drawing
1RZWKDWZH¦YHH[SORUHGKRZZLGJHWVDOORFDWHWKHVSDFHRQWKHVFUHHQLQZKLFKWKH\
GUDZWKHPVHOYHVZHFDQWXUQWRFRGLQJVRPHZLGJHWVWKDWDFWXDOO\GRVRPHGUDZLQJ
7KH$QGURLG8,IUDPHZRUNKDQGOHVGUDZLQJLQDZD\WKDWVKRXOGVHHPIDPLOLDUQRZ
WKDW\RX¦YHUHDGDERXWPHDVXUHPHQWDQGDUUDQJHPHQW:KHQVRPHSDUWRIWKHDSSOL
FDWLRQ GHWHUPLQHV WKDW WKH FXUUHQW VFUHHQ GUDZLQJ LV VWDOH EHFDXVH VRPH VWDWH KDV
FKDQJHGLWFDOOVWKH ViewPHWKRG invalidate7KLVFDOOFDXVHVDUHGUDZHYHQWWREH
DGGHGWRWKHHYHQWTXHXH
:KHQHYHQWXDOO\WKDWHYHQWLVSURFHVVHGWKHIUDPHZRUNFDOOVWKHdrawPHWKRGDWWKH
WRSRIWKHYLHZWUHH7KLVWLPHWKHFDOOLVSURSDJDWHGSUHRUGHUHDFKYLHZGUDZLQJLWVHOI
EHIRUHLWFDOOVLWVFKLOGUHQ7KLVPHDQVWKDWOHDIYLHZVDUHGUDZQDIWHUWKHLUSDUHQWV
ZKLFKDUHLQWXUQGUDZQDIWHUWKHLUSDUHQWV9LHZVWKDWDUHORZHULQWKHWUHHDSSHDUWR
EHGUDZQRQWRSRIWKRVHQHDUHUWKHURRWRIWKHWUHH
7KHdrawPHWKRGFDOOVonDrawZKLFKHDFKVXEFODVVRYHUULGHVWRLPSOHPHQWLWVFXVWRP
UHQGHULQJ:KHQ\RXUZLGJHW¦VonDrawPHWKRGLVFDOOHGLWPXVWUHQGHULWVHOIDFFRUGLQJ
WR WKH FXUUHQW DSSOLFDWLRQ VWDWH DQG UHWXUQ ,W WXUQV RXW E\ WKH ZD\ WKDW QHLWKHU
View.drawQRUViewGroup.dispatchDraw UHVSRQVLEOHIRUWKHWUDYHUVDORIWKHYLHZWUHH LV
ILQDO%XWRYHUULGHWKHPDW\RXUSHULO
,QRUGHUWRSUHYHQWH[WUDSDLQWLQJWKH$QGURLG8,IUDPHZRUNPDLQWDLQVVRPHVWDWH
LQIRUPDWLRQDERXWWKHYLHZFDOOHGWKHFOLSUHFWDQJOH$NH\FRQFHSWLQWKHIUDPHZRUN
WKHFOLSUHFWDQJOHLVSDUWRIWKHVWDWHWKDWLVSDVVHGLQFDOOVWRDFRPSRQHQW¦VJUDSKLFDO
UHQGHULQJPHWKRGV,WKDVDORFDWLRQDQGVL]HWKDWFDQEHUHWULHYHGDQGDGMXVWHGWKURXJK
PHWKRGVRQWKHFDQYDV,WDFWVOLNHDVWHQFLOWKURXJKZKLFKDFRPSRQHQWGRHVDOOLWV
GUDZLQJWKHFRPSRQHQWFDQRQO\GUDZRQWKHSRUWLRQVRIWKHFDQYDVYLVLEOHWKURXJK
WKHFOLSUHFWDQJOH%\FRUUHFWO\VHWWLQJWKHVL]HVKDSHDQGORFDWLRQRIWKHFOLSUHFWDQJOH
DSHUWXUHWKHIUDPHZRUNFDQSUHYHQWDFRPSRQHQWIURPGUDZLQJRXWVLGHLWVERXQGDULHV
RUUHGUDZLQJUHJLRQVWKDWDUHDOUHDG\FRUUHFWO\GUDZQ
%HIRUHSURFHHGLQJWRWKHVSHFLILFVRIGUDZLQJOHW¦VDJDLQSXWWKHGLVFXVVLRQLQWKHFRQ
WH[WRI$QGURLG¦VVLQJOHWKUHDGHG09&GHVLJQSDWWHUQ7KHUHDUHWZRHVVHQWLDOUXOHV
‡ 'UDZLQJFRGHVKRXOGEHLQVLGHWKHonDrawPHWKRG<RXUZLGJHWVKRXOGGUDZLWVHOI
FRPSOHWHO\UHIOHFWLQJWKHSURJUDPVWDWHZKHQonDrawLVLQYRNHG
Rolling Your Own Widgets | 217
‡ $ZLGJHWVKRXOGGUDZLWVHOIDVTXLFNO\DVSRVVLEOHZKHQ onDrawLVLQYRNHG7KH
PLGGOH RI WKH FDOO WR onDraw LV QR WLPH WR UXQ D FRPSOH[ GDWDEDVH TXHU\ RU WR
GHWHUPLQHWKHVWDWXVRIVRPHGLVWDQWQHWZRUNHGVHUYLFH$OOWKHVWDWH\RXQHHGWR
GUDZVKRXOGEHFDFKHGDQGUHDG\IRUXVHDWGUDZLQJWLPH/RQJUXQQLQJWDVNV
VKRXOGXVHDVHSDUDWHWKUHDGDQGRQHRIWKHPHFKDQLVPVGHVFULEHGLQ£$GYDQFHG
:LULQJ)RFXVDQG7KUHDGLQJ¤RQSDJH0RGHOVWDWHLQIRUPDWLRQFDFKHGLQ
WKHYLHZLVVRPHWLPHVFDOOHGWKHYLHZPRGHO
7KH$QGURLG8,IUDPHZRUNXVHVIRXUPDLQFODVVHVLQGUDZLQJ,I\RXDUHJRLQJWRLP
SOHPHQWFXVWRPZLGJHWVDQGGR\RXURZQGUDZLQJ\RXZLOOZDQWWREHFRPHYHU\ID
PLOLDUZLWKWKHP
Canvas DVXEFODVVRIandroid.graphics.Canvas
7KHFDQYDVKDVQRFOHDUDQDORJLQUHDOOLIHPDWHULDOV<RXPLJKWWKLQNRILWDVD
FRPSOH[HDVHOWKDWFDQRULHQWEHQGDQGHYHQFUXPSOHWKHSDSHURQZKLFK\RXDUH
GUDZLQJLQLQWHUHVWLQJZD\V,WPDLQWDLQVWKHFOLSUHFWDQJOHWKHVWHQFLOWKURXJK
ZKLFK\RXSDLQW,WFDQDOVRVFDOHGUDZLQJVDVWKH\DUHGUDZQOLNHDSKRWRJUDSKLF
HQODUJHU,WFDQHYHQSHUIRUPRWKHUWUDQVIRUPDWLRQVIRUZKLFKPDWHULDODQDORJVDUH
PRUHGLIILFXOWWRILQGPDSSLQJFRORUVDQGGUDZLQJWH[WDORQJSDWKV
Paint DVXEFODVVRIandroid.graphics.Paint
7KLVLVWKHPHGLXPZLWKZKLFK\RXZLOOGUDZ,WFRQWUROVWKHFRORUWUDQVSDUHQF\
DQGEUXVKVL]HIRUREMHFWVSDLQWHGRQWKHFDQYDV,WDOVRFRQWUROVIRQWVL]HDQG
VW\OHZKHQGUDZLQJWH[W
Bitmap DVXEFODVVRIandroid.graphics.Bitmap
7KLVLVWKHSDSHU\RXDUHGUDZLQJRQ,WKROGVWKHDFWXDOSL[HOVWKDW\RXGUDZ
Drawable OLNHO\DVXEFODVVRIandroid.graphics.drawable.Drawable
7KLVLVWKHWKLQJ\RXZDQWWRGUDZDUHFWDQJOHRULPDJH$OWKRXJKQRWDOOWKHWKLQJV
WKDW\RXGUDZDUHDrawableV WH[WIRULQVWDQFHLVQRW PDQ\HVSHFLDOO\WKHPRUH
FRPSOH[RQHVDUH
([DPSOHDFFRPSOLVKHGLWVGUDZLQJE\XVLQJRQO\WKHCanvasSDVVHGDVDSDUDPHWHU
WRonDraw,QRUGHUWRGRDQ\WKLQJPRUHLQWHUHVWLQJZHZLOOQHHGDWWKHYHU\OHDVWPaint
PaintSURYLGHVFRQWURORYHUWKHFRORUDQGWUDQVSDUHQF\ DOSKD RIWKHJUDSKLFVGUDZQ
ZLWKLW,WDOVRFRQWUROVWKHZLGWKRIWKHEUXVKXVHGIRUGUDZLQJ:KHQXVHGLQFRQ
QHFWLRQ ZLWK WH[W GUDZLQJ PHWKRGV LW FRQWUROV WKH IRQW VL]H DQG VW\OH RI WKH WH[W
Paint KDV PDQ\ PDQ\ RWKHU FDSDELOLWLHV VRPH RI ZKLFK DUH GHVFULEHG LQ
£%OLQJ¤RQSDJH([DPSOHKRZHYHULVHQRXJKWRJHW\RXVWDUWHG,WVHWVWZR
RIWKHPDQ\SDUDPHWHUV PaintFRQWUROV FRORUDQGOLQHZLGWK EHIRUHGUDZLQJDWKLFN
YHUWLFDOOLQHIROORZHGE\DVHULHVRIKRUL]RQWDOOLQHV7KHDOSKDYDOXH ZKLFKSOD\VWKH
VDPHUROHDVWKHIRXUWKYDOXHLQ5*%ZHEFRORUV LVUHGXFHGIRUHDFKJUHHQOLQHWRPDNH
LWPRUHWUDQVSDUHQWWKDQWKHSUHYLRXVRQH([SORUHWKHFODVVGRFXPHQWDWLRQIRURWKHU
XVHIXODWWULEXWHV
218 | Chapter 9:ಗDrawing 2D and 3D Graphics
([DPSOH8VLQJ3DLQW
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.drawLine(33, 0, 33, 100, paint);
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
canvas.drawLine(56, 0, 56, 100, paint);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(5);
for (int y = 30, alpha = 255; alpha > 2; alpha >>= 1, y += 10) {
paint.setAlpha(alpha);
canvas.drawLine(0, y, 100, y, paint);
}
}
7KHJUDSKLFFUHDWHGE\WKHFRGHLQWKHH[DPSOHLVVKRZQLQ)LJXUH
)LJXUH2XWSXWXVLQJ3DLQW
:LWK WKH DGGLWLRQ RI Paint ZH DUH SUHSDUHG WR XQGHUVWDQG PRVW RI WKH RWKHU WRROV
QHFHVVDU\WRGUDZDXVHIXOZLGJHW7KHFRGHLQ([DPSOHIRULQVWDQFHLVWKHZLGJHW
XVHGLQ([DPSOH:KLOHVWLOOQRWYHU\FRPSOH[LWGHPRQVWUDWHVDOOWKHSLHFHVRID
IXOO\IXQFWLRQDOZLGJHW,WKDQGOHVOD\RXWXVHVKLJKOLJKWLQJ ZKHWKHUWKHYLHZKDVWKH
XVHU¦VIRFXV DQGUHIOHFWVWKHVWDWHRIWKHPRGHOWRZKLFKLWLVDWWDFKHG7KHZLGJHW
GUDZVDVHULHVRIGRWVZKRVHLQIRUPDWLRQLVVWRUHGLQDSULYDWHDUUD\(DFKGRWVSHFLILHV
LWVRZQ[DQG\ORFDWLRQDVZHOODVLWVGLDPHWHUDQGFRORU7KH onDrawIXQFWLRQUHVHWV
WKHFRORURILWVPaintIRUHDFKDQGXVHVWKHRWKHUSDUDPHWHUVWRVSHFLI\WKHFLUFOHEHLQJ
GUDZQE\WKHFDQYDV¦VdrawCirclePHWKRG
([DPSOH'RWZLGJHW
package com.oreilly.android.intro.view;
import android.content.Context;
import android.graphics.Canvas;
Rolling Your Own Widgets | 219
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.View;
import com.oreilly.android.intro.model.Dot;
import com.oreilly.android.intro.model.Dots;
public class DotView extends View {
private final Dots dots;
/**
* @param context the rest of the application
* @param dots the dots we draw
*/
public DotView(Context context, Dots dots) {
super(context);
this.dots = dots;
setMinimumWidth(180);
setMinimumHeight(200);
setFocusable(true);
}
/** @see android.view.View#onMeasure(int, int) */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getSuggestedMinimumWidth(),
getSuggestedMinimumHeight());
}
/** @see android.view.View#onDraw(android.graphics.Canvas) */
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setColor(hasFocus() ? Color.BLUE : Color.GRAY);
canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, paint);
paint.setStyle(Style.FILL);
for (Dot dot : dots.getDots()) {
paint.setColor(dot.getColor());
canvas.drawCircle(
dot.getX(),
dot.getY(),
dot.getDiameter(),
paint);
}
}
}
$VZLWKPaintZHKDYHRQO\HQRXJKVSDFHWREHJLQDQH[SORUDWLRQRICanvasPHWKRGV
7KHUHDUHWZRJURXSVRIIXQFWLRQDOLW\KRZHYHUWKDWDUHZRUWKVSHFLDOQRWLFH
220 | Chapter 9:ಗDrawing 2D and 3D Graphics
Download from Wow! eBook <www.wowebook.com>
Drawing text
$PRQJWKHPRVWLPSRUWDQWCanvasPHWKRGVDUHWKRVHXVHGWRGUDZWH[W$OWKRXJKVRPH
CanvasIXQFWLRQDOLW\LVGXSOLFDWHGLQRWKHUSODFHVWH[WUHQGHULQJFDSDELOLWLHVDUHQRW,Q
RUGHUWRSXWWH[WLQ\RXUZLGJHW\RXZLOOKDYHWRXVH Canvas RURIFRXUVHVXEFODVV
VRPHRWKHUZLGJHWWKDWXVHVLW CanvasSURYLGHVVHYHUDOPHWKRGVIRUUHQGHULQJWH[WWKDWJLYH\RXYDULRXVDPRXQWVRI
IOH[LELOLW\RYHUWKHSODFHPHQWRIHDFKFKDUDFWHULQWKHWH[W7KHPHWKRGVFRPHLQSDLUV
RQHWDNLQJDStringDQGWKHRWKHUWDNLQJDchar[]DUUD\,QVRPHFDVHVWKHUHDUHDGGL
WLRQDOFRQYHQLHQFHPHWKRGV)RULQVWDQFHWKHVLPSOHVWZD\WRGUDZWH[WSDVVHVWKH[
DQG\FRRUGLQDWHVZKHUHWKHWH[WVWDUWVDQGPaintWKDWVSHFLILHVLWVIRQWFRORUDQGRWKHU
DWWULEXWHV VHH([DPSOH ([DPSOH$SDLURIWH[WGUDZLQJPHWKRGV
public void drawText(String text, float x, float y, Paint paint)
public void drawText(char[] text, int index, int count, float x,
float y, Paint paint)
:KLOH WKH ILUVW PHWKRG SDVVHV WH[W WKURXJK D VLQJOH String SDUDPHWHU WKH VHFRQG
PHWKRGXVHVWKUHHSDUDPHWHUVDQDUUD\RIcharDQLQGH[LQGLFDWLQJWKHILUVWFKDUDFWHU
LQWKDWDUUD\WREHGUDZQDQGWKHQXPEHURIWRWDOFKDUDFWHUVLQWKHWH[WWREHUHQGHUHG
,I\RXZDQWVRPHWKLQJIDQFLHUWKDQDVLPSOHKRUL]RQWDOWH[W\RXFDQOD\LWRXWDORQJD
JHRPHWULFSDWKRUHYHQSODFHHDFKFKDUDFWHUSUHFLVHO\ZKHUH\RXZDQW([DPSOH
FRQWDLQVDQonDrawPHWKRGWKDWGHPRQVWUDWHVWKHXVHRIHDFKRIWKHWKUHHWH[WUHQGHULQJ
PHWKRGV7KHRXWSXWLVVKRZQLQ)LJXUH
([DPSOH7KUHHZD\VRIGUDZLQJWH[W
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawText("Android", 25, 30, paint);
Path path = new Path();
path.addArc(new RectF(10, 50, 90, 200), 240, 90);
paint.setColor(Color.CYAN);
canvas.drawTextOnPath("Android", path, 0, 0, paint);
float[] pos = new float[] {
20, 80,
29, 83,
36, 80,
46, 83,
52, 80,
62, 83,
68, 80
Rolling Your Own Widgets | 221
};
paint.setColor(Color.GREEN);
canvas.drawPosText("Android", pos, paint);
}
)LJXUH2XWSXWIURPWKUHHZD\VRIGUDZLQJWH[W
$V\RXFDQVHHWKHPRVWHOHPHQWDU\RIWKHSDLUV drawTextVLPSO\VWDUWVWH[WDWWKH
SDVVHGFRRUGLQDWHV:LWKDrawTextOnPathRQWKHRWKHUKDQG\RXFDQGUDZWH[WDORQJ
DQ\Path7KHH[DPSOHSDWKLVMXVWDQDUF,WFRXOGMXVWDVHDVLO\KDYHEHHQDOLQHGUDZLQJ
RU%H]LHUFXUYH
)RUWKRVHRFFDVLRQVRQZKLFKHYHQ DrawTextOnPathLVLQVXIILFLHQW CanvasRIIHUV Draw
PosTextZKLFKOHWV\RXVSHFLI\WKHH[DFWSRVLWLRQRIHDFKFKDUDFWHULQWKHWH[W1RWH
WKDWWKHFKDUDFWHUSRVLWLRQVDUHVSHFLILHGE\DOWHUQDWLQJDUUD\HOHPHQWV[\[\
Matrix transformations
7KHVHFRQGLQWHUHVWLQJJURXSRI CanvasPHWKRGVDUHWKH MatrixWUDQVIRUPDWLRQVDQG
WKHLUUHODWHGFRQYHQLHQFHPHWKRGVrotatescaleDQGskew7KHVHPHWKRGVWUDQVIRUP
ZKDW\RXGUDZLQZD\VWKDWDUHLPPHGLDWHO\UHFRJQL]DEOHWRWKRVHIDPLOLDUZLWK'
JUDSKLFVLQRWKHUHQYLURQPHQWV7KHPHWKRGVDOORZDVLQJOHGUDZLQJWREHUHQGHUHGLQ
ZD\VWKDWFDQPDNHLWDSSHDUDVWKRXJKWKHYLHZHUZHUHPRYLQJZLWKUHVSHFWWRWKH
REMHFWVLQWKHGUDZLQJ
7KHVPDOODSSOLFDWLRQLQ([DPSOHGHPRQVWUDWHVWKHCanvas¦VFRRUGLQDWHWUDQVIRU
PDWLRQFDSDELOLWLHV
([DPSOH8VLQJDWUDQVIRUPDWLRQLQDFDQYDV
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
222 | Chapter 9:ಗDrawing 2D and 3D Graphics
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
public class TranformationalActivity extends Activity {
private interface Transformation {
void transform(Canvas canvas);
String describe();
}
private static class TransformedViewWidget extends View {
private final Transformation transformation;
public TransformedViewWidget(Context context, Transformation xform) {
super(context);
transformation = xform;
setMinimumWidth(160);
setMinimumHeight(105);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getSuggestedMinimumWidth(),
getSuggestedMinimumHeight());
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.save();
transformation.transform(canvas);
paint.setTextSize(12);
paint.setColor(Color.GREEN);
canvas.drawText("Hello", 40, 55, paint);
paint.setTextSize(16);
paint.setColor(Color.RED);
canvas.drawText("Android", 35, 65, paint);
canvas.restore();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
Rolling Your Own Widgets | 223
Rect r = canvas.getClipBounds();
canvas.drawRect(r, paint);
}
paint.setTextSize(10);
paint.setColor(Color.BLUE);
canvas.drawText(transformation.describe(), 5, 100, paint);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.transformed);
LinearLayout v1 = (LinearLayout) findViewById(R.id.v_left);
v1.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "identity"; }
@Override public void transform(Canvas canvas) { }
} ));
v1.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "rotate(-30)"; }
@Override public void transform(Canvas canvas) {
canvas.rotate(-30.0F);
} }));
v1.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "scale(.5,.8)"; }
@Override public void transform(Canvas canvas) {
canvas.scale(0.5F, .8F);
} }));
v1.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "skew(.1,.3)"; }
@Override public void transform(Canvas canvas) {
canvas.skew(0.1F, 0.3F);
} }));
LinearLayout v2 = (LinearLayout) findViewById(R.id.v_right);
v2.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "translate(30,10)"; }
@Override public void transform(Canvas canvas) {
canvas.translate(30.0F, 10.0F);
} }));
v2.addView(new TransformedViewWidget(
this,
new Transformation() {
224 | Chapter 9:ಗDrawing 2D and 3D Graphics
@Override public String describe() {
return "translate(110,-20),rotate(85)";
}
@Override public void transform(Canvas canvas) {
canvas.translate(110.0F, -20.0F);
canvas.rotate(85.0F);
} }));
v2.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() {
return "translate(-50,-20),scale(2,1.2)";
}
@Override public void transform(Canvas canvas) {
canvas.translate(-50.0F, -20.0F);
canvas.scale(2F, 1.2F);
} }));
v2.addView(new TransformedViewWidget(
this,
new Transformation() {
@Override public String describe() { return "complex"; }
@Override public void transform(Canvas canvas) {
canvas.translate(-100.0F, -100.0F);
canvas.scale(2.5F, 2F);
canvas.skew(0.1F, 0.3F);
} }));
}
}
7KHUHVXOWVRIWKLVSURWUDFWHGH[HUFLVHDUHVKRZQLQ)LJXUH
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
7KLVLVWKHGHILQLWLRQRIWKHQHZZLGJHWTransformedViewWidget
*HWV WKH DFWXDO WUDQVIRUPDWLRQ WR SHUIRUP IURP WKH VHFRQG DUJXPHQW RI WKH
FRQVWUXFWRU
7KLVLVWKHonDrawPHWKRGRITransformedViewWidget
3XVKHV WKH FXUUHQW GUDZLQJ VWDWH RQ WKH VWDFN XVLQJ save EHIRUH SHUIRUPLQJ DQ\
WUDQVIRUPDWLRQ
3HUIRUPVWKHWUDQVIRUPDWLRQSDVVHGDVFRQVWUXFWRUDUJXPHQW
5HVWRUHVWKHROGVWDWHVDYHGLQLWHPLQSUHSDUDWLRQIRUGUDZLQJWKHERXQGER[DQG
ODEHO
7KLVLVWKHActivity¦VonCreatePHWKRG
&UHDWHVWKHFRQWDLQHUYLHZIRUWKHOHIWKDQGFROXPQRIZLGJHWV
7KHVHDUHLQVWDQWLDWLRQVRITransformedViewWidgetDGGHGWRWKHOHIWKDQGFROXPQ
&UHDWHV D WUDQVIRUPDWLRQ DV SDUW RI WKH SDUDPHWHU OLVW WR WKH FRQVWUXFWRU RI
TransformedViewWidget
Rolling Your Own Widgets | 225
&UHDWHVWKHFRQWDLQHUYLHZIRUWKHULJKWKDQGFROXPQRIZLGJHWV
7KHVHDUHLQVWDQWLDWLRQVRITransformedViewWidgetDGGHGWRWKHULJKWKDQGFROXPQ
)LJXUH7UDQVIRUPHGYLHZV
7KLVVPDOODSSOLFDWLRQLQWURGXFHVVHYHUDOQHZLGHDV,QWHUPVRIYLHZVDQGZLGJHWVWKH
DSSOLFDWLRQGHILQHVDVLQJOHZLGJHW TransformedViewWidgetRIZKLFKLWFUHDWHVHLJKW
LQVWDQFHV)RUOD\RXWWKHDSSOLFDWLRQFUHDWHVWZRYLHZVQDPHG v1DQG v2UHWULHYLQJ
WKHLU SDUDPHWHUV IURP UHVRXUFHV 7KHQ LW DGGV IRXU LQVWDQFHV RI TransformedView
WidgetWRHDFK LinearLayoutYLHZ7KLVLVDQH[DPSOHRIKRZDSSOLFDWLRQVFRPELQH
UHVRXUFHEDVHGDQGG\QDPLFYLHZV1RWHWKDWWKHFUHDWLRQRIWKHOD\RXWYLHZVDQGWKH
FRQVWUXFWRUVRIWKHQHZZLGJHWVWDNHSODFHZLWKLQWKH$FWLYLW\¦VonCreatePHWKRG
7KLVDSSOLFDWLRQDOVRPDNHVWKHQHZZLGJHWIOH[LEOHWKURXJKDVRSKLVWLFDWHGGLYLVLRQ
RI ODERU EHWZHHQ WKH ZLGJHW DQG WKH SDUHQW YLHZ 6HYHUDO VLPSOH REMHFWV DUH GUDZQ
GLUHFWO\ZLWKLQWKHGHILQLWLRQRITransformedViewWidgetLQLWVonDrawPHWKRG
‡ $ZKLWHEDFNJURXQG
‡ 7KHZRUGHelloLQSRLQWJUHHQW\SH
‡ 7KHZRUGAndroidLQSRLQWUHGW\SH
‡ $EODFNIUDPH
226 | Chapter 9:ಗDrawing 2D and 3D Graphics
‡ $EOXHODEHO
,QWKHPLGGOHRIWKLVWKHonDrawPHWKRGSHUIRUPVDWUDQVIRUPDWLRQWKDWLVVSHFLILHGE\
WKH FDOOHU 7KH DSSOLFDWLRQ GHILQHV LWV RZQ LQWHUIDFH FDOOHG Transformation DQG WKH
FRQVWUXFWRUIRUTransformedViewWidgetDFFHSWVDTransformationDVDSDUDPHWHU:H¦OO
VHHLQDPRPHQWKRZWKHFDOOHUDFWXDOO\FRGHVDWUDQVIRUPDWLRQ
,W¦VLPSRUWDQWILUVWWRVHHKRZ onDrawSUHVHUYHVLWRZQWH[WZKLOHDOORZLQJWKHWUDQV
IRUPDWLRQ,QWKLVH[DPSOHZHZDQWWRPDNHVXUHWKHIUDPHDQGODEHODUHGUDZQODVW
VR WKDW WKH\ DUH GUDZQ RYHU DQ\WKLQJ HOVH GUDZQ E\ WKH ZLGJHW HYHQ LI WKH\ PLJKW
RYHUODS:HGRQRWZDQWWKHWUDQVIRUPDWLRQWRDIIHFWHLWKHUWKHIUDPHRUWKHODEHO
)RUWXQDWHO\ WKH Canvas PDLQWDLQV DQ LQWHUQDO VWDFN RQWR ZKLFK ZH FDQ UHFRUG DQG
UHFRYHUWKHWUDQVODWLRQPDWUL[FOLSUHFWDQJOHDQGDOORWKHUHOHPHQWVRIPXWDEOHVWDWH
LQWKHCanvas7DNLQJDGYDQWDJHRIWKLVVWDFNonDrawFDOOVCanvas.saveWRVDYHLWVVWDWH
EHIRUHWKHWUDQVIRUPDWLRQDQGCanvas.restoreDIWHUZDUGWRUHVWRUHWKHVDYHGVWDWH
7KHUHVWRIWKHDSSOLFDWLRQFRQWUROVWKHWUDQVIRUPDWLRQDSSOLHGWRHDFKRIWKHHLJKW
LQVWDQFHVRITransformedViewWidget(DFKQHZLQVWDQFHRIWKHZLGJHWLVFUHDWHGZLWKLWV
RZQDQRQ\PRXVLQVWDQFHRITransformation7KHLPDJHLQWKHDUHDODEHOHG£LGHQWLW\¤
KDVQRWUDQVODWLRQDSSOLHG7KHRWKHUVHYHQDUHDVDUHODEHOHGZLWKWKHWUDQVIRUPDWLRQV
WKH\GHPRQVWUDWH
7KHEDVHPHWKRGVIRU CanvasWUDQVODWLRQDUH setMatrixDQG concatMatrix7KHVHWZR
PHWKRGVDOORZ\RXWREXLOGDQ\SRVVLEOHWUDQVIRUPDWLRQ7KHgetMatrixPHWKRGDOORZV
\RXWRUHFRYHUDG\QDPLFDOO\FRQVWUXFWHGPDWUL[IRUODWHUXVH7KHPHWKRGVLQWURGXFHG
LQWKHH[DPSOH¢translate rotate scaleDQG skew¢DUHFRQYHQLHQFHPHWKRGVWKDW
FRPSRVHVSHFLILFFRQVWUDLQHGPDWULFHVLQWRWKHFXUUHQWCanvasVWDWH
:KLOHLWPD\QRWEHREYLRXVDWILUVWWKHVHWUDQVIRUPDWLRQIXQFWLRQVFDQEHWUHPHQ
GRXVO\XVHIXO7KH\DOORZ\RXUDSSOLFDWLRQWRDSSHDUWRFKDQJHLWVSRLQWRIYLHZZLWK
UHVSHFWWRD'REMHFW,WGRHVQ¦WWDNHWRRPXFKLPDJLQDWLRQIRULQVWDQFHWRVHHWKH
VFHQHLQWKHVTXDUHODEHOHG£VFDOH ¤DVWKHVDPHDVWKDWVHHQLQWKHVTXDUHODEHOHG
£LGHQWLW\¤EXWYLHZHGIURPIDUWKHUDZD\:LWKDELWPRUHLPDJLQDWLRQWKHLPDJHLQ
WKHER[ODEHOHG£VNHZ ¤FRXOGEHWKHXQWUDQVIRUPHGLPDJHDJDLQEXWWKLVWLPH
YLHZHGIURPDERYHDQGVOLJKWO\WRWKHVLGH6FDOLQJRUWUDQVODWLQJDQREMHFWFDQPDNH
LWDSSHDUWRDXVHUDVWKRXJKWKHREMHFWKDVPRYHG6NHZLQJDQGURWDWLQJFDQPDNHLW
DSSHDUWKDWWKHREMHFWKDVWXUQHG
:KHQ \RX FRQVLGHU WKDW WKHVH WUDQVIRUP IXQFWLRQV DSSO\ WR HYHU\WKLQJ GUDZQ RQ D
FDQYDV¢OLQHVWH[WDQGHYHQLPDJHV¢WKHLULPSRUWDQFHLQDSSOLFDWLRQVEHFRPHVHYHQ
PRUHDSSDUHQW$YLHZWKDWGLVSOD\VWKXPEQDLOVRISKRWRVFRXOGEHLPSOHPHQWHGWULY
LDOO\WKRXJKSHUKDSVQRWRSWLPDOO\DVDYLHZWKDWVFDOHVHYHU\WKLQJLWGLVSOD\VWR
RILWVDFWXDOVL]H$QDSSOLFDWLRQWKDWGLVSOD\VZKDW\RXVHHDV\RXORRNWR\RXUOHIW
ZKLOHGULYLQJGRZQWKHVWUHHWPLJKWEHLPSOHPHQWHGLQSDUWE\VFDOLQJDQGVNHZLQJ
DVPDOOQXPEHURILPDJHV
Rolling Your Own Widgets | 227
Drawables
$ Drawable LV DQ REMHFW WKDW NQRZV KRZ WR UHQGHU LWVHOI RQ D Canvas %HFDXVH D
DrawableKDVFRPSOHWHFRQWUROGXULQJUHQGHULQJHYHQDYHU\FRPSOH[UHQGHULQJSURFHVV
FDQEHHQFDSVXODWHGLQDZD\WKDWPDNHVLWIDLUO\HDV\WRXVH
([DPSOHVDQGVKRZWKHFKDQJHVQHFHVVDU\WRLPSOHPHQWWKHH[DPSOHVKRZQ
LQ)LJXUHXVLQJD Drawable7KHFRGHWKDWGUDZVWKHUHGDQGJUHHQWH[WKDVEHHQ
UHIDFWRUHG LQWR D HelloAndroidTextDrawable FODVV XVHG LQ UHQGHULQJ E\ WKH ZLGJHW¦V
onDrawPHWKRG
([DPSOH8VLQJD7H[W'UDZDEOH
private static class HelloAndroidTextDrawable extends Drawable {
private ColorFilter filter;
private int opacity;
public HelloAndroidTextDrawable() {}
@Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColorFilter(filter);
paint.setAlpha(opacity);
paint.setTextSize(12);
paint.setColor(Color.GREEN);
canvas.drawText("Hello", 40, 55, paint);
paint.setTextSize(16);
paint.setColor(Color.RED);
canvas.drawText("Android", 35, 65, paint);
}
@Override
public int getOpacity() { return PixelFormat.TRANSLUCENT; }
@Override
public void setAlpha(int alpha) { }
@Override
public void setColorFilter(ColorFilter cf) { }
}
8VLQJ WKH QHZ Drawable LPSOHPHQWDWLRQ UHTXLUHV RQO\ D IHZ VPDOO FKDQJHV WR WKH
onDrawPHWKRGIURPRXUH[DPSOH
([DPSOH8VLQJD'UDZDEOHZLGJHW
package com.oreilly.android.intro.widget;
import android.content.Context;
import android.graphics.Canvas;
228 | Chapter 9:ಗDrawing 2D and 3D Graphics
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
/**A widget that renders a drawable with a transformation */
public class TransformedViewWidget extends View {
/** A transformation */
public interface Transformation {
/** @param canvas */
void transform(Canvas canvas);
/** @return text description of the transform. */
String describe();
}
private final Transformation transformation;
private final Drawable drawable;
/**
* Render the passed drawable, transformed.
*
* @param context app context
* @param draw the object to be drawn, in transform
* @param xform the transformation
*/
public TransformedViewWidget(
Context context,
Drawable draw,
Transformation xform)
{
super(context);
drawable = draw;
transformation = xform;
}
setMinimumWidth(160);
setMinimumHeight(135);
/** @see android.view.View#onMeasure(int, int) */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getSuggestedMinimumWidth(),
getSuggestedMinimumHeight());
}
/** @see android.view.View#onDraw(android.graphics.Canvas) */
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.save();
Rolling Your Own Widgets | 229
transformation.transform(canvas);
drawable.draw(canvas);
canvas.restore();
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
Rect r = canvas.getClipBounds();
canvas.drawRect(r, paint);
paint.setTextSize(10);
paint.setColor(Color.BLUE);
canvas.drawText(
transformation.describe(),
5,
getMeasuredHeight() - 5,
paint);
}
}
7KLVFRGHEHJLQVWRGHPRQVWUDWHWKHSRZHURIXVLQJDDrawable7KLVLPSOHPHQWDWLRQ
RI TransformedViewWidgetZLOOWUDQVIRUPDQ\ DrawableQRPDWWHUZKDWLWKDSSHQVWR
GUDZ,WLVQRORQJHUWLHGWRURWDWLQJDQGVFDOLQJRXURULJLQDOKDUGFRGHGWH[W,WFDQEH
UHXVHGWRWUDQVIRUPERWKWKHWH[WIURPWKHSUHYLRXVH[DPSOHDQGDSKRWRFDSWXUHG
IURP WKH FDPHUD DV )LJXUH GHPRQVWUDWHV ,W FRXOG HYHQ EH XVHG WR WUDQVIRUP D
DrawableDQLPDWLRQ
)LJXUH7UDQVIRUPHGYLHZVZLWKSKRWRV
230 | Chapter 9:ಗDrawing 2D and 3D Graphics
DrawableVPDNHFRPSOH[JUDSKLFDOWHFKQLTXHVOLNHSDWFKHVDQGDQLPDWLRQWUDFWDEOH
,QDGGLWLRQVLQFHWKH\ZUDSWKHUHQGHULQJSURFHVVFRPSOHWHO\DrawableVFDQEHQHVWHG
WRGHFRPSRVHFRPSOH[UHQGHULQJLQWRVPDOOUHXVDEOHSLHFHV
&RQVLGHUIRUDPRPHQWKRZZHPLJKWH[WHQGWKHSUHYLRXVH[DPSOHWRPDNHHDFKRI
WKHVL[LPDJHVIDGHWRZKLWHRYHUDSHULRGRIDPLQXWH&HUWDLQO\ZHPLJKWMXVWFKDQJH
WKHFRGHLQ([DPSOHWRGRWKHIDGH$GLIIHUHQW¢DQGYHU\DSSHDOLQJ¢LPSOHPHQ
WDWLRQLQYROYHVZULWLQJRQHQHZDrawable
7KHFRQVWUXFWRURIWKLVQHZ DrawableZKLFKZH¦OOFDOO FaderDrawableZLOOWDNHDVDQ
DUJXPHQWDUHIHUHQFHWRLWVWDUJHWWKHDrawableWKDWLWZLOOIDGHWRZKLWH,QDGGLWLRQLW
PXVWKDYHVRPHQRWLRQRIWLPHSUREDEO\DQLQWHJHU¢OHW¦VFDOOLWt¢WKDWLVLQFUHPHQWHG
E\ D WLPHU :KHQHYHU WKH draw PHWKRG RI FaderDrawable LV FDOOHG LW ILUVW FDOOV WKH
drawPHWKRGRILWVWDUJHW1H[WKRZHYHULWSDLQWVRYHUH[DFWO\WKHVDPHDUHDZLWKWKH
FRORUZKLWHXVLQJWKHYDOXHRI tWRGHWHUPLQHWKHWUDQVSDUHQF\ DOSKDYDOXH RIWKH
SDLQW DVGHPRQVWUDWHGLQ([DPSOH $VWLPHSDVVHV tJHWVODUJHUWKHZKLWHJHWV
LQFUHDVLQJO\RSDTXHDQGWKHWDUJHWDrawableIDGHVWRZKLWH
7KLV K\SRWKHWLFDO FaderDrawable GHPRQVWUDWHV VRPH RI WKH LPSRUWDQW IHDWXUHV RI
DrawableV1RWHILUVWRIDOOWKDWFaderDrawableLVHPLQHQWO\UHXVDEOH,WZLOOIDGHMXVW
DERXWDQ\Drawable$OVRQRWHWKDWVLQFHFaderDrawableH[WHQGVDrawableZHFDQXVH
LWDQ\ZKHUHZHZRXOGKDYHXVHGLWVWDUJHWWKHDrawableWKDWLWIDGHVWRZKLWH$Q\FRGH
WKDWXVHVDDrawableLQLWVUHQGHULQJSURFHVVFDQXVHDFaderDrawableZLWKRXWFKDQJH
2IFRXUVHD FaderDrawableFRXOGLWVHOIEHZUDSSHG,QIDFWLWLVSRVVLEOHWRDFKLHYH
YHU\FRPSOH[HIIHFWVVLPSO\E\EXLOGLQJDFKDLQRI DrawableZUDSSHUV7KH$QGURLG
WRRONLWSURYLGHVDrawableZUDSSHUVWKDWVXSSRUWWKLVVWUDWHJ\LQFOXGLQJClipDrawable
RotateDrawableDQGScaleDrawable
$WWKLVSRLQW\RXPD\EHPHQWDOO\UHGHVLJQLQJ\RXUHQWLUH8,LQWHUPVRI DrawableV
:KLOHWKH\DUHDSRZHUIXOWRROWKH\DUHQRWDSDQDFHD7KHUHDUHVHYHUDOLVVXHVWRNHHS
LQPLQGZKHQFRQVLGHULQJWKHXVHRIDrawableV
<RXPD\ZHOOKDYHQRWLFHGWKDWWKH\VKDUHDORWRIWKHIXQFWLRQDOLW\RIWKH ViewFODVV
ORFDWLRQGLPHQVLRQVYLVLELOLW\DQGVRRQ,W¦VQRWDOZD\VHDV\WRGHFLGHZKHQDView
VKRXOGGUDZGLUHFWO\RQWKHCanvasZKHQLWVKRXOGGHOHJDWHWRDVXEYLHZDQGZKHQLW
VKRXOGGHOHJDWHWRRQHRUPRUH DrawableREMHFWV7KHUHLVHYHQD DrawableContainer
FODVVWKDWDOORZVWKHJURXSLQJRIVHYHUDOFKLOGDrawableVZLWKLQDSDUHQW,WLVSRVVLEOH
WREXLOGWUHHVRI DrawableVWKDWSDUDOOHOWKHWUHHVRI ViewVZH¦YHEHHQXVLQJVRIDU,Q
GHDOLQJZLWKWKH$QGURLG8,IUDPHZRUN\RXMXVWKDYHWRDFFHSWWKDWWKHUHLVPRUHWKDQ
RQHZD\WRVFDOHDFDW
2QHGLIIHUHQFHEHWZHHQWKHWZRFKRLFHVLVWKDW DrawableVGRQRWLPSOHPHQWWKH View
PHDVXUHOD\RXWSURWRFROZKLFK\RX¦OOUHFDOODOORZVDFRQWDLQHUYLHZWRQHJRWLDWHWKH
OD\RXWRILWVFRPSRQHQWVLQUHVSRQVHWRFKDQJLQJYLHZVL]H:KHQDUHQGHUDEOHREMHFW
QHHGVWRDGGUHPRYHRUOD\RXWLQWHUQDOFRPSRQHQWVLW¦VDSUHWW\JRRGLQGLFDWLRQWKDW
LWVKRXOGEHDIXOOIOHGJHGViewLQVWHDGRIDDrawable
Rolling Your Own Widgets | 231
$ VHFRQG LVVXH WR FRQVLGHU LV WKDW EHFDXVH DrawableV FRPSOHWHO\ ZUDS WKH GUDZLQJ
SURFHVV WKH\ DUH QRW GUDZQ OLNH String RU Rect REMHFWV 7KHUH DUH IRU LQVWDQFH QR
CanvasPHWKRGVWKDWZLOOUHQGHUDDrawableDWVSHFLILFFRRUGLQDWHV<RXPD\ILQG\RXU
VHOIGHOLEHUDWLQJRYHUZKHWKHULQRUGHUWRUHQGHUDFHUWDLQLPDJHWZLFHDView.onDraw
PHWKRGVKRXOGXVHWZRGLIIHUHQWLPPXWDEOHDrawableVRUDVLQJOHDrawableWZLFHUH
VHWWLQJLWVFRRUGLQDWHV
3HUKDSVPRVWLPSRUWDQWWKRXJKLVDPRUHJHQHULFSUREOHP7KHUHDVRQWKHLGHDRID
FKDLQRIDrawableVZRUNVLVWKDWWKHDrawableLQWHUIDFHFRQWDLQVQRLQIRUPDWLRQDERXW
WKHLQWHUQDOLPSOHPHQWDWLRQRIWKH Drawable:KHQ\RXUFRGHLVSDVVHGD Drawable
WKHUHLVQRZD\IRULWWRNQRZZKHWKHULWLVVRPHWKLQJWKDWZLOOUHQGHUDVLPSOHLPDJH
RUDFRPSOH[FKDLQRIHIIHFWVWKDWURWDWHVIODVKHVDQGERXQFHV&OHDUO\WKLVFDQEHD
ELJDGYDQWDJH,WFDQDOVREHDSUREOHPWKRXJK
4XLWHDELWRIWKHGUDZLQJSURFHVVLVVWDWHIXO<RXVHWXSPaintDQGWKHQGUDZZLWKLW
<RXVHWXSCanvasFOLSUHJLRQVDQGWUDQVIRUPDWLRQVDQGWKHQGUDZWKURXJKWKHP:KHQ
FRRSHUDWLQJLQDFKDLQDrawableVPXVWEHYHU\FDUHIXOLIWKH\FKDQJHVWDWHWKDWWKRVH
FKDQJHVQHYHUFROOLGH7KHSUREOHPLVWKDWZKHQFRQVWUXFWLQJD DrawableFKDLQWKH
SRVVLELOLW\RIFROOLVLRQFDQQRWE\GHILQLWLRQ WKH\DUHDOOMXVWDrawableV EHH[SOLFLWLQ
WKHREMHFW¦VW\SH$VHHPLQJO\VPDOOFKDQJHPLJKWKDYHDQHIIHFWWKDWLVQRWGHVLUDEOH
DQGLVGLIILFXOWWRGHEXJ
7RLOOXVWUDWHFRQVLGHUWZR DrawableZUDSSHUFODVVHVRQHWKDWLVPHDQWWRVKULQNLWV
FRQWHQWVDQGDQRWKHUWKDWLVPHDQWWRURWDWHWKHPE\GHJUHHV,IHLWKHULVLPSOHPHQ
WHGE\VHWWLQJWKHWUDQVIRUPDWLRQPDWUL[WRDVSHFLILFYDOXHFRPSRVLQJWKHWZRPD\
QRWKDYHWKHGHVLUHGHIIHFW:RUVHLWPLJKWZRUNSHUIHFWO\LI$ZUDSV%EXWQRWLI%
ZUDSV$&DUHIXOGRFXPHQWDWLRQRIKRZDDrawableLVLPSOHPHQWHGLVHVVHQWLDO
Bitmaps
7KHBitmapLVWKHODVWPHPEHURIWKHIRXUHVVHQWLDOVIRUGUDZLQJVRPHWKLQJWRGUDZ D
String RectHWF D PaintZLWKZKLFKWRGUDZD CanvasRQZKLFKWRGUDZDQGWKH
Bitmap WR KROG WKH ELWV 0RVW RI WKH WLPH \RX GRQ¦W KDYH WR GHDO GLUHFWO\ ZLWK D
BitmapEHFDXVHWKHCanvasSURYLGHGDVDQDUJXPHQWWRWKHonDrawPHWKRGDOUHDG\KDV
RQHEHKLQGLW7KHUHDUHFLUFXPVWDQFHVWKRXJKXQGHUZKLFK\RXPD\ZDQWWRXVHD
BitmapGLUHFWO\
$FRPPRQXVHIRUDBitmapLVWRFDFKHDGUDZLQJWKDWPD\EHWLPHFRQVXPLQJWRGUDZ
EXWXQOLNHO\WRFKDQJHIUHTXHQWO\&RQVLGHUIRUH[DPSOHDGUDZLQJSURJUDPWKDWDO
ORZVWKHXVHUWRGUDZLQPXOWLSOHOD\HUV7KHOD\HUVDFWDVWUDQVSDUHQWRYHUOD\VRQD
EDVHLPDJHDQGWKHXVHUWXUQVWKHPRIIDQGRQDWZLOO,WPLJKWEHYHU\H[SHQVLYHWR
DFWXDOO\GUDZHDFKLQGLYLGXDOOD\HUHYHU\WLPH onDrawJHWVFDOOHG,QVWHDGLWPLJKWEH
IDVWHUWRUHQGHUWKHHQWLUHGUDZLQJXSRQILUVWDSSHDUDQFHZLWKDOOYLVLEOHOD\HUVDQG
WKHQUHGUDZWKHVLQJOHOD\HUWKDWQHHGVFKDQJLQJRQO\ZKHQWKHXVHUPDNHVDYLVLEOH
FKDQJHWRLW
232 | Chapter 9:ಗDrawing 2D and 3D Graphics
7KHLPSOHPHQWDWLRQRIVXFKDQDSSOLFDWLRQPLJKWORRNVRPHWKLQJOLNH([DPSOH
([DPSOH%LWPDSFDFKLQJ
private class CachingWidget extends View {
private Bitmap cache;
public CachingWidget(Context context) {
super(context);
setMinimumWidth(200);
setMinimumHeight(200);
}
public void invalidateCache() {
cache = null;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
if (null == cache) {
cache = Bitmap.createBitmap(
getMeasuredWidth(),
getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
drawCachedBitmap(new Canvas(cache));
}
}
canvas.drawBitmap(cache, 0, 0, new Paint());
// ... definition of drawCachedBitmap
}
7KLV ZLGJHW QRUPDOO\ MXVW FRSLHV WKH FDFKHG Bitmap cache WR WKH Canvas SDVVHG WR
onDraw2QO\LIWKHFDFKHLVPDUNHGVWDOHE\FDOOLQJ invalidateCacheZLOO drawCached
BitmapEHFDOOHGWRDFWXDOO\UHQGHUWKHZLGJHW
7KHPRVWFRPPRQZD\WRHQFRXQWHUD BitmapLVDVWKHSURJUDPPDWLFUHSUHVHQWDWLRQ
RIDJUDSKLFVUHVRXUFH Resources.getDrawableUHWXUQVD BitmapDrawableZKHQWKHUH
VRXUFHLVDQLPDJH
&RPELQLQJWKHVHWZRLGHDVFDFKLQJDQLPDJHDQGZUDSSLQJLWLQDDrawableRSHQV\HW
DQRWKHULQWHUHVWLQJZLQGRZ,WPHDQVDQ\WKLQJWKDWFDQEHGUDZQFDQDOVREHSRVW
SURFHVVHG$QDSSOLFDWLRQWKDWXVHGDOOWKHWHFKQLTXHVGHPRQVWUDWHGLQWKLVFKDSWHU
FRXOGDOORZDXVHUWRGUDZIXUQLWXUHLQDURRP FUHDWLQJDELWPDS DQGWKHQWRZDON
DURXQGLW XVLQJWKHPDWUL[WUDQVIRUPV Rolling Your Own Widgets | 233
:LWK +RQH\FRPE WKHUH KDYH EHHQ VXEVWDQWLDO FKDQJHV LQ $QGURLG¦V
UHQGHULQJDUFKLWHFWXUH7KHVHFKDQJHVWDNHDGYDQWDJHRIWKHLQFUHDVLQJ
SRZHURI*38VDQGFUHDWHDZKROHQHZVHWRIUXOHVIRURSWLPL]LQJWKH
ZD\\RXU8,LVGUDZQ&RQVLGHUView.setLayerTypeEHIRUHFUHDWLQJQHZ
ELWPDSV
Bling
7KH$QGURLG8,IUDPHZRUNLVDORWPRUHWKDQMXVWDQLQWHOOLJHQWZHOOSXWWRJHWKHU*8,
WRRONLW:KHQLWWDNHVRIILWVJODVVHVDQGVKDNHVRXWLWVKDLULWFDQEHGRZQULJKWVH[\
7KHWRROVPHQWLRQHGKHUHFHUWDLQO\GRQRWPDNHDQH[KDXVWLYHFDWDORJ7KH\PLJKWJHW
\RXVWDUWHGWKRXJKRQWKHSDWKWRPDNLQJ\RXUDSSOLFDWLRQ)LOWK\5LFK
6HYHUDORIWKHWHFKQLTXHVGLVFXVVHGLQWKLVVHFWLRQDUHFORVHWRWKHHGJHV
RIWKH$QGURLGODQGVFDSH$VVXFKWKH\DUHOHVVZHOOHVWDEOLVKHGWKDQ
WKHFODVVHVZHGLVFXVVHGHDUOLHULQWKHFKDSWHUWKHGRFXPHQWDWLRQLVQRW
DVWKRURXJKVRPHRIWKHIHDWXUHVDUHFOHDUO\LQWUDQVLWLRQDQG\RXPD\
HYHQILQGEXJV,I\RXUXQLQWRSUREOHPVWKH*RRJOH*URXS£$QGURLG
'HYHORSHUV¤LVDQLQYDOXDEOHUHVRXUFH4XHVWLRQVDERXWDSDUWLFXODUDV
SHFWRIWKHWRRONLWKDYHVRPHWLPHVEHHQDQVZHUHGE\WKHYHU\SHUVRQ
UHVSRQVLEOHIRULPSOHPHQWLQJWKDWDVSHFW
%HFDUHIXODERXWFKHFNLQJWKHGDWHVRQVROXWLRQV\RXILQGE\VHDUFKLQJ
WKH:HE6RPHRIWKHVHIHDWXUHVDUHFKDQJLQJUDSLGO\&RGHWKDWZRUNHG
DVUHFHQWO\DVVL[PRQWKVDJRPD\QRWZRUNQRZ$FRUROODU\RIFRXUVH
LVWKDWDQ\DSSOLFDWLRQWKDWJHWVZLGHGLVWULEXWLRQLVOLNHO\WREHUXQRQ
SODWIRUPVWKDWKDYHGLIIHULQJLPSOHPHQWDWLRQVRIWKHIHDWXUHVGLVFXVVHG
KHUH%\XVLQJWKHVHWHFKQLTXHV\RXPD\OLPLWWKHOLIHWLPHRI\RXUDS
SOLFDWLRQDQGWKHQXPEHURIGHYLFHVWKDWLWZLOOVXSSRUW
7KHUHVWRIWKLVVHFWLRQFRQVLGHUVDVLQJOHDSSOLFDWLRQPXFKOLNHWKHRQHXVHGLQ([
DPSOHDFRXSOHRILinearLayoutVWKDWFRQWDLQPXOWLSOHLQVWDQFHVRIDVLQJOHZLGJHW
HDFKGHPRQVWUDWLQJDGLIIHUHQWJUDSKLFVHIIHFW([DPSOHSURYLGHVWKHNH\SDUWVRI
WKHZLGJHWZLWKFRGHGLVFXVVHGSUHYLRXVO\HOLGHGIRUEUHYLW\7KHZLGJHWVLPSO\GUDZV
DIHZJUDSKLFDOREMHFWVDQGGHILQHVDQLQWHUIDFHWKURXJKZKLFKYDULRXVJUDSKLFVHIIHFWV
FDQEHDSSOLHGWRWKHUHQGHULQJ
([DPSOH(IIHFWVZLGJHW
public class EffectsWidget extends View {
/** The effect to apply to the drawing */
public interface PaintEffect { void setEffect(Paint paint); }
// ...
// PaintWidget's widget rendering method
protected void onDraw(Canvas canvas) {
234 | Chapter 9:ಗDrawing 2D and 3D Graphics
Paint paint = new Paint();
paint.setAntiAlias(true);
effect.setEffect(paint);
paint.setColor(Color.DKGRAY);
paint.setStrokeWidth(5);
canvas.drawLine(10, 10, 140, 20, paint);
paint.setTextSize(26);
canvas.drawText("Android", 40, 50, paint);
paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawText(String.valueOf(id), 2.0F, 12.0F, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
canvas.drawRect(canvas.getClipBounds(), paint);
}
}
7KHDSSOLFDWLRQWKDWXVHVWKLVZLGJHW ([DPSOH VKRXOGDOVRIHHOIDPLOLDU,WFUHDWHV
VHYHUDOFRSLHVRIWKH EffectsWidgetHDFKZLWKLWVRZQHIIHFW7KHUHDUHWZRVSHFLDO
ZLGJHWV7KHERWWRPZLGJHWLQWKHOHIWKDQGFROXPQXVHV2SHQ*/DQLPDWLRQ,QWKH
ULJKWFROXPQWKHERWWRPZLGJHWLVHPSW\EXWWKHRQHDERYHLWVKRZVDEXWWRQZLWKDQ
DQLPDWHGEDFNJURXQG
([DPSOH(IIHFWVDSSOLFDWLRQ
private void buildView() {
setContentView(R.layout.main);
LinearLayout view = (LinearLayout) findViewById(R.id.v_left);
view.addView(new EffectsWidget(
this,
1,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) {
paint.setShadowLayer(1, 3, 4, Color.BLUE);
} }));
view.addView(new EffectsWidget(
this,
3,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) {
paint.setShader(
new LinearGradient(
0.0F,
0.0F,
160.0F,
80.0F,
new int[] { Color.BLACK, Color.RED, Color.YELLOW },
null,
Shader.TileMode.REPEAT));
Bling | 235
} }));
view.addView(new EffectsWidget(
this,
5,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) {
paint.setMaskFilter(
new BlurMaskFilter(2, BlurMaskFilter.Blur.NORMAL));
} }));
// Not an EffectsWidget: this is the OpenGL Animation widget.
glWidget = new GLDemoWidget(this);
view.addView(glWidget);
view = (LinearLayout) findViewById(R.id.v_right);
view.addView(new EffectsWidget(
this,
2,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) {
paint.setShadowLayer(3, -8, 7, Color.GREEN);
} }));
view.addView(new EffectsWidget(
this,
4,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) {
paint.setShader(
new LinearGradient(
0.0F,
40.0F,
15.0F,
40.0F,
Color.BLUE,
Color.GREEN,
Shader.TileMode.MIRROR));
} }));
// A widget with an animated background
View w = new EffectsWidget(
this,
6,
new EffectsWidget.PaintEffect() {
@Override public void setEffect(Paint paint) { }
});
view.addView(w);
w.setBackgroundResource(R.drawable.throbber);
}
w.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
((AnimationDrawable) v.getBackground()).start();
} });
236 | Chapter 9:ಗDrawing 2D and 3D Graphics
)LJXUHVKRZVZKDWWKHFRGHORRNVOLNHZKHQUXQ:LGJHWVDQGDUHDQLPDWHG
:LGJHWKDVDEDFNJURXQGWKDWSXOVHVUHGZKHQFOLFNHGDQGWKHJUHHQFKHFNHUERDUG
PRYHVIURPOHIWWRULJKWDFURVVZLGJHW:LGJHWLVXQXVHG
)LJXUH*UDSKLFVHIIHFWV
Shadows, Gradients, and Filters
PathEffect MaskFilter ColorFilter Shader DQG ShadowLayer DUH DOO DWWULEXWHV RI
Paint$Q\WKLQJGUDZQZLWK PaintFDQEHGUDZQXQGHUWKHLQIOXHQFHRIRQHRUPRUH
RIWKHVHWUDQVIRUPDWLRQV7KHWRSILYHZLGJHWVLQ)LJXUHJLYHH[DPSOHVRIVHYHUDORI
WKHVHHIIHFWV
:LGJHWVDQGGHPRQVWUDWHVKDGRZV6KDGRZVDUHFXUUHQWO\FRQWUROOHGE\WKH set
ShadowLayerPHWKRG7KHDUJXPHQWVDEOXUUDGLXVDQG[DQG\GLVSODFHPHQWVFRQWURO
WKHDSSDUHQWGLVWDQFHDQGSRVLWLRQRIWKHOLJKWVRXUFHWKDWFUHDWHVWKHVKDGRZZLWK
UHVSHFWWRWKHVKDGRZHGREMHFW
7KHVHFRQGURZRIZLGJHWVGHPRQVWUDWHVShaderV7KH$QGURLGWRRONLWFRQWDLQVVHYHUDO
SUHEXLOWVKDGHUV:LGJHWVDQGGHPRQVWUDWHRQHRIWKHPWKHLinearGradientVKDGHU
$JUDGLHQWLVDUHJXODUWUDQVLWLRQEHWZHHQFRORUVWKDWFDQEHXVHGIRULQVWDQFHWRJLYH
DSDJHEDFNJURXQGDELWPRUHOLIHZLWKRXWUHVRUWLQJWRH[SHQVLYHELWPDSUHVRXUFHV
$ LinearGradientLVVSHFLILHGZLWKDYHFWRUWKDWGHWHUPLQHVWKHGLUHFWLRQDQGUDWHRI
WKHFRORUWUDQVLWLRQDQDUUD\RIFRORUVWKURXJKZKLFKWRWUDQVLWLRQDQGDPRGH7KH
ILQDODUJXPHQWWKHPRGHGHWHUPLQHVZKDWKDSSHQVZKHQDVLQJOHFRPSOHWHWUDQVLWLRQ
WKURXJKWKHJUDGLHQWLVLQVXIILFLHQWWRFRYHUWKHHQWLUHSDLQWHGREMHFW)RULQVWDQFHLQ
ZLGJHWWKHWUDQVLWLRQLVRQO\SL[HOVORQJZKHUHDVWKHGUDZLQJLVPRUHWKDQ
Bling | 237
Download from Wow! eBook <www.wowebook.com>
SL[HOVZLGH8VLQJWKHPRGH Shader.TileMode.MirrorFDXVHVWKHWUDQVLWLRQWRUHSHDW
DOWHUQDWLQJGLUHFWLRQDFURVVWKHGUDZLQJ,QWKHH[DPSOHWKHJUDGLHQWWUDQVLWLRQVIURP
EOXHWRJUHHQLQSL[HOVWKHQIURPJUHHQWREOXHLQWKHQH[WDQGVRRQDFURVV
WKHFDQYDV
Animation
7KH $QGURLG 8, WRRONLW RIIHUV VHYHUDO GLIIHUHQW DQLPDWLRQ WRROV 7UDQVLWLRQ
DQLPDWLRQV¢ZKLFK WKH *RRJOH GRFXPHQWDWLRQ FDOOV WZHHQHG DQLPDWLRQV¢DUH VXE
FODVVHV RI android.view.animation.Animation RotateAnimation TranslateAnimation
ScaleAnimationDQGVRRQ7KHVHDQLPDWLRQVDUHXVHGDVWUDQVLWLRQVEHWZHHQSDLUVRI
YLHZV $ VHFRQG W\SH RI DQLPDWLRQ VXEFODVVHV RI android.graphics.drawable
.AnimationDrawable.AnimationDrawableFDQEHSXWLQWRWKHEDFNJURXQGRIDQ\ZLGJHW
WRSURYLGHDZLGHYDULHW\RIHIIHFWV)LQDOO\WKHUHLVDIXOORQDQLPDWLRQFODVVRQWRSRI
D SurfaceView WKDW JLYHV \RX FRPSOHWH FRQWURO WR GR \RXU RZQ VHDWRIWKHSDQWV
DQLPDWLRQ
%HFDXVHERWKRIWKHILUVWWZRW\SHVRIDQLPDWLRQWUDQVLWLRQDQGEDFNJURXQGDUHVXS
SRUWHGE\ViewHLWKHUFDQEHXVHGLQQHDUO\DQ\ZLGJHW
Transition animation
$WUDQVLWLRQDQLPDWLRQLVVWDUWHGE\FDOOLQJWKH ViewPHWKRG startAnimationZLWKDQ
LQVWDQFHRIAnimation RURIFRXUVH\RXURZQVXEFODVV 2QFHLQVWDOOHGWKHDQLPDWLRQ
UXQVWRFRPSOHWLRQWUDQVLWLRQDQLPDWLRQVKDYHQRSDXVHVWDWH
7KHKHDUWRIWKHDQLPDWLRQLVLWV applyTransformationPHWKRG7KLVPHWKRGLVFDOOHG
WRSURGXFHVXFFHVVLYHIUDPHVRIWKHDQLPDWLRQ([DPSOHVKRZVWKHLPSOHPHQWD
WLRQRIRQHWUDQVIRUPDWLRQ$V\RXFDQVHHLWGRHVQRWDFWXDOO\JHQHUDWHHQWLUHJUDSKLFDO
IUDPHVIRUWKHDQLPDWLRQ,QVWHDGLWJHQHUDWHVVXFFHVVLYHWUDQVIRUPDWLRQVWREHDSSOLHG
WR D VLQJOH LPDJH EHLQJ DQLPDWHG <RX ZLOO UHFDOO IURP £0DWUL[ WUDQVIRUPD
WLRQV¤RQSDJHWKDWPDWUL[WUDQVIRUPDWLRQVFDQEHXVHGWRPDNHDQREMHFWDSSHDU
WRPRYH7UDQVLWLRQDQLPDWLRQVGHSHQGRQH[DFWO\WKLVWULFN
([DPSOH7UDQVLWLRQDQLPDWLRQ
@Override
protected void applyTransformation(float t, Transformation xf) {
Matrix xform = xf.getMatrix();
float z = ((dir > 0) ? 0.0f : -Z_MAX) - (dir * t * Z_MAX);
camera.save();
camera.rotateZ(t * 360);
camera.translate(0.0F, 0.0F, z);
camera.getMatrix(xform);
camera.restore();
xform.preTranslate(-xCenter, -yCenter);
238 | Chapter 9:ಗDrawing 2D and 3D Graphics
}
xform.postTranslate(xCenter, yCenter);
7KLVSDUWLFXODULPSOHPHQWDWLRQPDNHVLWVWDUJHWDSSHDUWRVSLQLQWKHVFUHHQSODQH WKH
rotatePHWKRGFDOO DQGDWWKHVDPHWLPHWRVKULQNLQWRWKHGLVWDQFH WKH translate
PHWKRGFDOO 7KHPDWUL[WKDWZLOOEHDSSOLHGWRWKHWDUJHWLPDJHLVREWDLQHGIURPWKH
TransformationREMHFWSDVVHGLQWKDWFDOO
7KLVLPSOHPHQWDWLRQXVHV cameraDQLQVWDQFHRIWKHXWLOLW\FODVV Camera7KLV Camera
FODVV¢QRW WR EH FRQIXVHG ZLWK WKH FDPHUD LQ WKH SKRQH¢LV D XWLOLW\ WKDW PDNHV LW
SRVVLEOHWRUHFRUGUHQGHULQJVWDWH,WLVXVHGKHUHWRFRPSRVHWKHURWDWLRQDQGWUDQVOD
WLRQ WUDQVIRUPDWLRQV LQWR D VLQJOH PDWUL[ ZKLFK LV WKHQ VWRUHG DV WKH DQLPDWLRQ
WUDQVIRUPDWLRQ
7KHILUVWSDUDPHWHUWRapplyTransformationQDPHGtLVHIIHFWLYHO\WKHIUDPHQXPEHU
,WLVSDVVHGDVDIORDWLQJSRLQWQXPEHUEHWZHHQDQGDQGPLJKWDOVREHXQGHU
VWRRGDVWKHSHUFHQWRIWKHDQLPDWLRQWKDWLVFRPSOHWH7KLVH[DPSOHXVHVtWRLQFUHDVH
WKHDSSDUHQWGLVWDQFHDORQJWKH]D[LV DOLQHSHUSHQGLFXODUWRWKHSODQHRIWKHVFUHHQ RIWKHLPDJHEHLQJDQLPDWHGDQGWRVHWWKHSURSRUWLRQRIRQHFRPSOHWHURWDWLRQWKURXJK
ZKLFKWKHLPDJHKDVSDVVHG$VtLQFUHDVHVWKHDQLPDWHGLPDJHDSSHDUVWRURWDWHIXU
WKHUDQGIXUWKHUFRXQWHUFORFNZLVHDQGWRPRYHIDUWKHUDQGIDUWKHUDZD\DORQJWKH]
D[LVLQWRWKHGLVWDQFH
7KHpreTranslateDQGpostTranslateRSHUDWLRQVDUHQHFHVVDU\LQRUGHUWRWUDQVODWHWKH
LPDJHDURXQGLWVFHQWHU%\GHIDXOWPDWUL[RSHUDWLRQVWUDQVIRUPWKHLUWDUJHWDURXQG
WKHRULJLQ XSSHUOHIWFRUQHU ,IZHGLGQRWSHUIRUPWKHVHEUDFNHWLQJWUDQVODWLRQVWKH
WDUJHWLPDJHZRXOGDSSHDUWRURWDWHDURXQGLWVXSSHUOHIWFRUQHU preTranslateHIIHF
WLYHO\PRYHVWKHRULJLQWRWKHFHQWHURIWKHDQLPDWLRQWDUJHWIRUWKHWUDQVODWLRQDQG
postTranslateFDXVHVWKHGHIDXOWWREHUHVWRUHGDIWHUWKHWUDQVODWLRQ
,I\RXFRQVLGHUZKDWDWUDQVLWLRQDQLPDWLRQPXVWGR\RX¦OOUHDOL]HWKDWLWLVDFWXDOO\
OLNHO\WRFRPSRVHWZRDQLPDWLRQVWKHSUHYLRXVVFUHHQPXVWEHDQLPDWHGRXWDQGWKH
QH[WRQHDQLPDWHGLQ([DPSOHVXSSRUWVWKLVXVLQJWKHUHPDLQLQJXQH[SODLQHG
YDULDEOHdir,WVYDOXHLVHLWKHURU¡DQGFRQWUROVZKHWKHUWKHDQLPDWHGLPDJHVHHPV
WRVKULQNLQWRWKHGLVWDQFHRUJURZLQWRWKHIRUHJURXQG:HQHHGRQO\ILQGDZD\WR
FRPSRVHDVKULQNLQJDQGDJURZLQJDQLPDWLRQ
7KLVLVGRQHXVLQJWKHIDPLOLDUListenerSDWWHUQ7KHAnimationFODVVGHILQHVDOLVWHQHU
QDPHG Animation.AnimationListener.$Q\LQVWDQFHRI AnimationWKDWKDVDQRQQXOO
OLVWHQHUFDOOVWKDWOLVWHQHURQFHZKHQLWVWDUWVRQFHZKHQLWVWRSVDQGRQFHIRUHDFK
LWHUDWLRQLQEHWZHHQ$OLVWHQHUWKDWQRWLFHVZKHQWKHVKULQNLQJDQLPDWLRQFRPSOHWHV
DQGVSDZQVDQHZJURZLQJDQLPDWLRQZLOOFUHDWHH[DFWO\WKHHIIHFWZHGHVLUH([DP
SOHVKRZVWKHUHVWRIWKHLPSOHPHQWDWLRQRIWKHDQLPDWLRQ
Bling | 239
([DPSOH7UDQVLWLRQDQLPDWLRQFRPSRVLWLRQ
public void runAnimation() {
animateOnce(new AccelerateInterpolator(), this);
}
@Override
public void onAnimationEnd(Animation animation) {
root.post(new Runnable() {
public void run() {
curView.setVisibility(View.GONE);
nextView.setVisibility(View.VISIBLE);
nextView.requestFocus();
new RotationTransitionAnimation(-1, root, nextView, null)
.animateOnce(new DecelerateInterpolator(), null);
} });
}
void animateOnce(
Interpolator interpolator,
Animation.AnimationListener listener)
{
setDuration(700);
setInterpolator(interpolator);
setAnimationListener(listener);
root.startAnimation(this);
}
7KH runAnimation PHWKRG VWDUWV WKH WUDQVLWLRQ 7KH RYHUULGGHQ AnimationListener
PHWKRGonAnimationEndVSDZQVWKHVHFRQGKDOI&DOOHGZKHQWKHWDUJHWLPDJHDSSHDUV
WREHIDULQWKHGLVWDQFHLWKLGHVWKHLPDJHEHLQJDQLPDWHGRXW WKHcurView DQGUHSODFHV
LWZLWKWKHQHZO\YLVLEOHLPDJHnextView,WWKHQFUHDWHVDQHZDQLPDWLRQWKDWUXQQLQJ
LQUHYHUVHVSLQVDQGJURZVWKHQHZLPDJHLQWRWKHIRUHJURXQG
7KH InterpolatorFODVVUHSUHVHQWVDQLIW\DWWHQWLRQWRGHWDLO7KHYDOXHVIRU tSDVVHG
WRapplyTransformationQHHGQRWEHOLQHDUO\GLVWULEXWHGRYHUWLPH,QWKLVLPSOHPHQ
WDWLRQ WKH DQLPDWLRQ DSSHDUV WR VSHHG XS DV LW UHFHGHV DQG WKHQ WR VORZ DJDLQ DV
WKH QHZ LPDJH DGYDQFHV 7KLV LV DFFRPSOLVKHG E\ XVLQJ WKH WZR LQWHUSRODWRUV
AccelerateInterpolator IRU WKH ILUVW KDOI RI WKH DQLPDWLRQ DQG DecelerateInterpola
torIRUWKHVHFRQG:LWKRXWWKHLQWHUSRODWRUWKHGLIIHUHQFHEHWZHHQVXFFHVVLYHYDOXHV
RItSDVVHGWRapplyTransformationZRXOGEHFRQVWDQW7KLVZRXOGPDNHWKHDQLPD
WLRQ DSSHDU WR KDYH D FRQVWDQW VSHHG 7KH AccelerateInterpolator FRQYHUWV WKRVH
HTXDOO\VSDFHGYDOXHVRI tLQWRYDOXHVWKDWDUHFORVHWRJHWKHUDWWKHEHJLQQLQJRIWKH
DQLPDWLRQDQGPXFKIDUWKHUDSDUWWRZDUGWKHHQG7KLVPDNHVWKHDQLPDWLRQDSSHDU
WRVSHHGXSDecelerateInterpolatorKDVH[DFWO\WKHRSSRVLWHHIIHFW$QGURLGDOVRSUR
YLGHVDCycleInterpolatorDQGLinearInterpolatorIRUXVHDVDSSURSULDWH
$QLPDWLRQFRPSRVLWLRQLVDFWXDOO\EXLOWLQWRWKHWRRONLWXVLQJWKH SHUKDSVFRQIXVLQJO\
QDPHG AnimationSetFODVV7KLVFODVVSURYLGHVDFRQYHQLHQWZD\WRVSHFLI\DOLVW¢
IRUWXQDWHO\ QRW D VHW LW LV RUGHUHG DQG PD\ UHIHU WR D JLYHQ DQLPDWLRQ PRUH WKDQ
RQFH¢RIDQLPDWLRQVWREHSOD\HGLQRUGHU,QDGGLWLRQWKHWRRONLWSURYLGHVVHYHUDO
240 | Chapter 9:ಗDrawing 2D and 3D Graphics
VWDQGDUG WUDQVLWLRQV AlphaAnimation RotateAnimation ScaleAnimation DQG
TranslateAnimation&HUWDLQO\WKHUHLVQRQHHGIRUWKHVHWUDQVLWLRQDODQLPDWLRQVWREH
V\PPHWULFDVWKH\DUHLQWKHSUHYLRXVH[DPSOH$QHZLPDJHPLJKWDOSKDIDGHLQDV
WKHROGRQHVKULQNVLQWRDFRUQHURUVOLGHXSIURPWKHERWWRPDVWKHROGRQHIDGHVRXW
7KHSRVVLELOLWLHVDUHHQGOHVV
Background animation
)UDPHE\IUDPHDQLPDWLRQDVLWLVFDOOHGLQWKH*RRJOHGRFXPHQWDWLRQLVFRPSOHWHO\
VWUDLJKWIRUZDUGDVHWRIIUDPHVSOD\HGLQRUGHUDWUHJXODULQWHUYDOV7KLVNLQGRIDQL
PDWLRQLVLPSOHPHQWHGE\VXEFODVVHVRIAnimationDrawable
$VVXEFODVVHVRI Drawable AnimationDrawableREMHFWVFDQEHXVHGLQDQ\FRQWH[WWKDW
DQ\RWKHUDrawableLVXVHG7KHPHFKDQLVPWKDWDQLPDWHVWKHPKRZHYHULVQRWDSDUW
RIWKHDrawableLWVHOI,QRUGHUWRDQLPDWHDQAnimationDrawableUHOLHVRQDQH[WHUQDO
VHUYLFHSURYLGHU¢DQLPSOHPHQWDWLRQRIWKHDrawable.CallbackLQWHUIDFH¢WRDQLPDWH
LW
7KHViewFODVVLPSOHPHQWVWKLVLQWHUIDFHDQGFDQEHXVHGWRDQLPDWHDQAnimationDraw
able8QIRUWXQDWHO\LWZLOOVXSSO\DQLPDWLRQVHUYLFHVRQO\WRWKHRQH DrawableREMHFW
WKDWLVLQVWDOOHGDVLWVEDFNJURXQG
7KHJRRGQHZVKRZHYHULVWKDWWKLVLVSUREDEO\VXIILFLHQW$EDFNJURXQGDQLPDWLRQ
KDVDFFHVVWRWKHHQWLUHZLGJHWFDQYDV(YHU\WKLQJLWGUDZVZLOODSSHDUWREHEHKLQG
DQ\WKLQJGUDZQE\WKHView.onDrawPHWKRGVRLWZRXOGEHKDUGWRXVHLWWRLPSOHPHQW
IXOOIOHGJHGVSULWHV6WLOOZLWKFOHYHUXVHRIWKHDrawableContainerFODVV ZKLFKDOORZV
\RXWRDQLPDWHVHYHUDOGLIIHUHQWDQLPDWLRQVVLPXOWDQHRXVO\ DQGEHFDXVHWKHEDFN
JURXQGFDQEHFKDQJHGDWDQ\WLPHLWLVSRVVLEOHWRDFFRPSOLVKTXLWHDELWZLWKRXW
UHVRUWLQJWRLPSOHPHQWLQJ\RXURZQDQLPDWLRQIUDPHZRUN
$QAnimationDrawableLQDYLHZEDFNJURXQGLVHQWLUHO\VXIILFLHQWWRGRDQ\WKLQJIURP
VD\LQGLFDWLQJWKDWVRPHORQJUXQQLQJDFWLYLW\LVWDNLQJSODFH¢PD\EHZLQJHGSDFNHWV
IO\LQJDFURVVWKHVFUHHQIURPDSKRQHWRDWRZHU¢WRVLPSO\PDNLQJWKHEDFNJURXQG
WRDEXWWRQSXOVH
7KHSXOVLQJEXWWRQH[DPSOHLQZLGJHWLVLOOXVWUDWLYHDQGVXUSULVLQJO\HDV\WRLPSOH
PHQW([DPSOHVDQGVKRZDOO\RXQHHG7KHDQLPDWLRQLVGHILQHGDVDUH
VRXUFHDQGFRGHDSSOLHVLWWRWKHEXWWRQ<RXFDQVHWDDrawableDVDEDFNJURXQGXVLQJ
HLWKHUsetBackgroundDrawableRUsetBackgroundResource
([DPSOH)UDPHE\IUDPHDQLPDWLRQ UHVRXUFH
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/throbber_f0" android:duration="70" />
<item android:drawable="@drawable/throbber_f1" android:duration="70" />
<item android:drawable="@drawable/throbber_f2" android:duration="70" />
<item android:drawable="@drawable/throbber_f3" android:duration="70" />
Bling | 241
<item android:drawable="@drawable/throbber_f4" android:duration="70" />
<item android:drawable="@drawable/throbber_f5" android:duration="70" />
<item android:drawable="@drawable/throbber_f6" android:duration="70" />
</animation-list>
([DPSOH)UDPHE\IUDPHDQLPDWLRQ FRGH
// w is a button that will "throb"
button.setBackgroundResource(R.drawable.throbber);
button.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
AnimationDrawable animation
= (AnimationDrawable) v.getBackground();
if (animation.isRunning()) { animation.stop(); }
else { animation.start(); }
// button action.
} });
7KHUHDUHDFRXSOHJRWFKDVKHUHWKRXJK)LUVWRIDOOWKHUHGRHVQRWDSSHDUWREHDQ\
ZD\WRVWDUWDEDFNJURXQGDQLPDWLRQIURPDQActivity.onCreatePHWKRG((Animation
Drawable) view.getBackground()).start() ZRQ¦W GR LW ,I \RXU DSSOLFDWLRQ¦V EDFN
JURXQGVKRXOGEHDQLPDWHGZKHQHYHULWLVYLVLEOH\RX¦OOKDYHWRXVHWULFNHU\WRVWDUWLW
7KHH[DPSOHLPSOHPHQWDWLRQXVHVDQonClickKDQGOHUWRVWDUWWKHDQLPDWLRQ7KHUHDUH
VXJJHVWLRQV RQ WKH :HE WKDW WKH DQLPDWLRQ FDQ DOVR EH VWDUWHG VXFFHVVIXOO\ IURP D
WKUHDGWKDWSDXVHVEULHIO\EHIRUHFDOOLQJAnimationDrawable.start
$OVRLI\RXKDYHZRUNHGZLWKRWKHU8,IUDPHZRUNVHVSHFLDOO\PRELOH8,IUDPHZRUNV
\RXPD\EHDFFXVWRPHGWRSDLQWLQJWKHYLHZEDFNJURXQGLQWKHILUVWFRXSOHRIOLQHVRI
WKH onDrawPHWKRG RUHTXLYDOHQW ,I\RXGRWKDWKHUH\RXZLOOSDLQWRYHU\RXUDQL
PDWLRQ,WLVLQJHQHUDODJRRGLGHDWRJHWLQWRWKHKDELWRIXVLQJ setBackgroundWR
FRQWUROWKH ViewEDFNJURXQGZKHWKHULWLVDVROLGFRORUDJUDGLHQWDQLPDJHRUDQ
DQLPDWLRQ
6SHFLI\LQJD DrawableAnimationE\UHVRXUFHLVYHU\IOH[LEOH<RXFDQVSHFLI\DOLVWRI
GUDZDEOHUHVRXUFHV¢DQ\LPDJHV\RXOLNH¢WKDWFRPSULVHWKHDQLPDWLRQ,I\RXUDQL
PDWLRQQHHGVWREHG\QDPLFAnimationDrawableLVDVWUDLJKWIRUZDUGUHFLSHIRUFUHDWLQJ
DG\QDPLFGUDZDEOHWKDWFDQEHDQLPDWHGLQWKHEDFNJURXQGRIDView
Surface view animation
)XOORQDQLPDWLRQUHTXLUHVDSurfaceView7KHSurfaceViewSURYLGHVDQRGHLQWKHYLHZ
WUHH¢DQGWKHUHIRUHVSDFHRQWKHGLVSOD\¢RQZKLFKDQ\SURFHVVDWDOOFDQGUDZ$IWHU
\RXOD\RXWDQGVL]HWKHSurfaceViewQRGHLWUHFHLYHVFOLFNVDQGXSGDWHVMXVWOLNHDQ\
RWKHUZLGJHW,QVWHDGRIGUDZLQJKRZHYHULWVLPSO\UHVHUYHVVSDFHRQWKHVFUHHQSUH
YHQWLQJRWKHUZLGJHWVIURPDIIHFWLQJDQ\RIWKHSL[HOVZLWKLQLWVIUDPH
'UDZLQJRQD SurfaceViewUHTXLUHVLPSOHPHQWLQJWKH SurfaceHolder.CallbackLQWHU
IDFH7KHWZRPHWKRGVsurfaceCreatedDQGsurfaceDestroyedLQIRUPWKHLPSOHPHQWRU
242 | Chapter 9:ಗDrawing 2D and 3D Graphics
WKDWWKHGUDZLQJVXUIDFHLVDYDLODEOHIRUGUDZLQJDQGWKDWLWKDVEHFRPHXQDYDLODEOH
UHVSHFWLYHO\ 7KH DUJXPHQW WR ERWK FDOOV LV DQ LQVWDQFH RI \HW D WKLUG FODVV Surface
Holder,QWKHLQWHUYDOEHWZHHQWKHVHWZRFDOOVDGUDZLQJURXWLQHFDQFDOOWKHSurface
ViewPHWKRGVlockCanvasDQGunlockCanvasAndPostWRHGLWWKHSL[HOVWKHUH
,IWKLVVHHPVFRPSOH[HYHQDORQJVLGHVRPHRIWKHHODERUDWHDQLPDWLRQGLVFXVVHGSUH
YLRXVO\¢ZHOOLWLV$VXVXDOFRQFXUUHQF\LQFUHDVHVWKHOLNHOLKRRGRIQDVW\KDUGWR
ILQGEXJV7KHFOLHQWRID SurfaceViewPXVWEHVXUHQRWRQO\WKDWDFFHVVWRDQ\VWDWH
VKDUHG DFURVV WKUHDGV LV SURSHUO\ V\QFKURQL]HG EXW DOVR WKDW LW QHYHU WRXFKHV WKH
SurfaceView Surface RU Canvas H[FHSW LQ WKH LQWHUYDO EHWZHHQ WKH FDOOV WR surface
CreatedDQGsurfaceDestroyed7KHWRRONLWFRXOGFOHDUO\EHQHILWIURPDPRUHFRPSOHWH
IUDPHZRUNVXSSRUWIRUSurfaceViewDQLPDWLRQ
,I \RX DUH FRQVLGHULQJ SurfaceView DQLPDWLRQ \RX DUH SUREDEO\ DOVR FRQVLGHULQJ
2SHQ*/JUDSKLFV$VZH¦OOVHHDQH[WHQVLRQLVDYDLODEOHIRU2SHQ*/DQLPDWLRQRQD
SurfaceView,WZLOOWXUQXSLQDVRPHZKDWRXWRIWKHZD\SODFHWKRXJK
OpenGL Graphics
7KH$QGURLGSODWIRUPVXSSRUWV2SHQ*/JUDSKLFVLQURXJKO\WKHVDPHZD\WKDWDVLON
KDWVXSSRUWVUDEELWV:KLOHWKLVLVFHUWDLQO\DPRQJWKHPRVWH[FLWLQJWHFKQRORJLHVLQ
$QGURLGLWLVGHILQLWHO\DWWKHHGJHRIWKHPDS,WDOVRDSSHDUVWKDWMXVWEHIRUHWKHILQDO
EHWDUHOHDVHWKHLQWHUIDFHXQGHUZHQWPDMRUFKDQJHV0XFKRIWKHFRGHDQGPDQ\RI
WKHVXJJHVWLRQVIRXQGRQWKH:HEDUHREVROHWHDQGQRORQJHUZRUN
7KH$3,9BUUHOHDVHLVDQLPSOHPHQWDWLRQRI2SHQ*/(6DQGPXFKRI(6,W
LVHVVHQWLDOO\DGRPDLQVSHFLILFODQJXDJHHPEHGGHGLQ-DYD6RPHRQHZKRKDVEHHQ
GRLQJJDPLQJ8,VIRUDZKLOHLVOLNHO\WREHPXFKPRUHFRPIRUWDEOHGHYHORSLQJ$QGURLG
2SHQ*/SURJUDPVWKDQD-DYDSURJUDPPHUHYHQD-DYD8,H[SHUW
%HIRUHGLVFXVVLQJWKH2SHQ*/JUDSKLFVOLEUDU\LWVHOIZHVKRXOGWDNHDPLQXWHWRFRQ
VLGHU H[DFWO\ KRZ SL[HOV GUDZQ ZLWK 2SHQ*/ DSSHDU RQ WKH GLVSOD\ 7KXV IDU WKLV
FKDSWHUKDVGLVFXVVHGWKHLQWULFDWHViewIUDPHZRUNWKDW$QGURLGXVHVWRRUJDQL]HDQG
UHSUHVHQWREMHFWVRQWKHVFUHHQ2SHQ*/LVDODQJXDJHLQZKLFKDQDSSOLFDWLRQGHVFULEHV
DQHQWLUHVFHQHWKDWZLOOEHUHQGHUHGE\DQHQJLQHWKDWLVQRWRQO\RXWVLGHWKH-90EXW
SUREDEO\UXQQLQJRQDQRWKHUSURFHVVRUDOWRJHWKHU WKH*UDSKLFV3URFHVVLQJ8QLWRU
*38 &RRUGLQDWLQJWKHWZRSURFHVVRUV¦YLHZVRIWKHVFUHHQLVWULFN\
7KHSurfaceViewGLVFXVVHGHDUOLHULVQHDUO\VXIILFLHQW,WVSXUSRVHLVWRFUHDWHDVXUIDFH
RQZKLFKDWKUHDGRWKHUWKDQWKH8,JUDSKLFVWKUHDGFDQGUDZ7KHWRROZH¦GOLNHLVDQ
H[WHQVLRQRISurfaceViewWKDWKDVDELWPRUHVXSSRUWIRUFRQFXUUHQF\FRPELQHGZLWK
VXSSRUWIRU2SHQ*/
,WWXUQVRXWWKDWWKHUHLVH[DFWO\VXFKDWRRO$OOWKHGHPRDSSOLFDWLRQVLQWKH$QGURLG
6'. GLVWULEXWLRQ WKDW GR 2SHQ*/ DQLPDWLRQ GHSHQG RQ WKH XWLOLW\ FODVV GLSurface
View6LQFHWKHGHPRDSSOLFDWLRQVZULWWHQE\WKHFUHDWRUVRI$QGURLGXVHWKLVFODVV
FRQVLGHULQJLWIRU\RXUDSSOLFDWLRQVVHHPVDGYLVDEOH
Bling | 243
GLSurfaceViewGHILQHVDQLQWHUIDFH GLSurfaceView.RendererZKLFKGUDPDWLFDOO\VLP
SOLILHVWKHRWKHUZLVHRYHUZKHOPLQJFRPSOH[LW\RIXVLQJ2SHQ*/DQG GLSurfaceView
GLSurfaceViewFDOOVWKHgetConfigSpecUHQGHULQJPHWKRGWRJHWLWV2SHQ*/FRQILJXUD
WLRQLQIRUPDWLRQ7ZRRWKHUPHWKRGVsizeChangedDQGsurfaceCreatedDUHFDOOHGE\
WKH GLSurfaceViewWRLQIRUPWKHUHQGHUHUWKDWLWVVL]HKDVFKDQJHGRUWKDWLWVKRXOG
SUHSDUHWRGUDZUHVSHFWLYHO\)LQDOO\drawFrameWKHKHDUWRIWKHLQWHUIDFHLVFDOOHGWR
UHQGHUDQHZ2SHQ*/IUDPH
([DPSOHVKRZVWKHLPSRUWDQWPHWKRGVIURPWKHLPSOHPHQWDWLRQRIDQ2SHQ*/
UHQGHUHU
([DPSOH)UDPHE\IUDPHDQLPDWLRQZLWK2SHQ*/
// ... some state set up in the constructor
@Override
public void surfaceCreated(GL10 gl) {
// set up the surface
gl.glDisable(GL10.GL_DITHER);
gl.glHint(
GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(0.4f, 0.2f, 0.2f, 0.5f);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
// fetch the checker-board
initImage(gl);
}
@Override
public void drawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// apply the checker-board to the shape
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glTexEnvx(
GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_MODULATE);
gl.glTexParameterx(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
244 | Chapter 9:ಗDrawing 2D and 3D Graphics
GL10.GL_REPEAT);
gl.glTexParameterx(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
// animation
int t = (int) (SystemClock.uptimeMillis() % (10 * 1000L));
gl.glTranslatef(6.0f - (0.0013f * t), 0, 0);
}
// draw
gl.glFrontFace(GL10.GL_CCW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuf);
gl.glDrawElements(
GL10.GL_TRIANGLE_STRIP,
5,
GL10.GL_UNSIGNED_SHORT, indexBuf);
private void initImage(GL10 gl) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_NEAREST);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(
GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
InputStream in
= context.getResources().openRawResource(R.drawable.cb);
Bitmap image;
try { image = BitmapFactory.decodeStream(in); }
finally {
try { in.close(); } catch(IOException e) { }
}
Bling | 245
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, image, 0);
image.recycle();
}
7KHPHWKRGsurfaceCreatedSUHSDUHVWKHVFHQH,WVHWVVHYHUDO2SHQ*/DWWULEXWHVWKDW
QHHGWREHLQLWLDOL]HGRQO\ZKHQWKHZLGJHWJHWVDQHZGUDZLQJVXUIDFH,QDGGLWLRQLW
FDOOVinitImageZKLFKUHDGVLQDELWPDSUHVRXUFHDQGVWRUHVLWDVD'WH[WXUH:KHQ
ILQDOO\drawFrameLVFDOOHGHYHU\WKLQJLVUHDG\IRUGUDZLQJ7KHWH[WXUHLVDSSOLHGWRD
SODQHZKRVHYHUWLFHVZHUHVHWXSLQvertexBufE\WKHFRQVWUXFWRUWKHDQLPDWLRQSKDVH
LVFKRVHQDQGWKHVFHQHLVUHGUDZQ
,WDSSHDUVWKDWZLWKWKH+RQH\FRPEUHOHDVH2SHQ*/KDVEHHQIXOO\
LQWHJUDWHG LQWR $QGURLG JUDSKLFV $FFRUGLQJ WR WKH GRFXPHQWDWLRQ
+RQH\FRPEQRWRQO\VXSSRUWV2SHQ*/EXWDOVRXVHVLWDVWKHEDVLV
IRUUHQGHULQJViewREMHFWV
246 | Chapter 9:ಗDrawing 2D and 3D Graphics
CHAPTER 10
Handling and Persisting Data
7RDFFRPSOLVKPDQ\RIWKHDFWLYLWLHVRIIHUHGE\PRGHUQPRELOHSKRQHVVXFKDVWUDFN
LQJFRQWDFWVHYHQWVDQGWDVNVDPRELOHRSHUDWLQJV\VWHPDQGLWVDSSOLFDWLRQVPXVWEH
DGHSWDWVWRULQJDQGNHHSLQJWUDFNRIODUJHTXDQWLWLHVRIGDWD7KLVGDWDLVXVXDOO\VWUXF
WXUHGLQURZVDQGFROXPQVOLNHDVSUHDGVKHHWRUDYHU\VLPSOHGDWDEDVH%H\RQGD
WUDGLWLRQDO DSSOLFDWLRQ¦V UHTXLUHPHQWV IRU VWRULQJ GDWD WKH $QGURLG DSSOLFDWLRQ OLIH
F\FOHGHPDQGVUDSLGDQGFRQVLVWHQWSHUVLVWHQFHRIGDWDIRULWWRVXUYLYHWKHYRODWLOLW\RI
WKHPRELOHHQYLURQPHQWZKHUHGHYLFHVFDQVXGGHQO\ORVHSRZHURUWKH$QGURLGRSHU
DWLQJV\VWHPFDQDUELWUDULO\GHFLGHWRUHPRYH\RXUDSSOLFDWLRQIURPPHPRU\
$QGURLGSURYLGHVWKHOLJKWZHLJKWEXWSRZHUIXO64/LWHUHODWLRQDOGDWDEDVHHQJLQHIRU
SHUVLVWLQJGDWD)XUWKHUPRUHDVGHVFULEHGLQ&KDSWHUWKHFRQWHQWSURYLGHUIHDWXUH
OHWVDSSOLFDWLRQVH[SRVHWKHLUGDWDWRRWKHUDSSOLFDWLRQV
,QWKLVFKDSWHUZHSURYLGHDVLPSOH64/WXWRULDOVRWKDW\RXFDQOHDUQWRZRUNZLWK
$QGURLG64/LWHSHUVLVWHQFH:HDOVRZDON\RXWKURXJKDQLQWHUHVWLQJDSSOLFDWLRQ¢
0-$QGURLG¢WKDWSURYLGHVDUHDOZRUOGORRNDWKRZWRPDQLSXODWHDGDWDEDVHLQ$Q
GURLG/DWHULQ&KDSWHUZH¦OOUHIHUHQFHWKHVDPHH[DPSOHWRGHPRQVWUDWHWKHXVH
RIWKHPDSSLQJ$3,LQ$QGURLG&KDSWHUZLOOVKRZ\RXKRZWRLPSOHPHQWDFRQWHQW
SURYLGHU
Relational Database Overview
$UHODWLRQDOGDWDEDVHSURYLGHVDQHIILFLHQWVWUXFWXUHGDQGJHQHULFV\VWHPIRUPDQDJLQJ
SHUVLVWHQWLQIRUPDWLRQ:LWKDGDWDEDVHDSSOLFDWLRQVXVHVWUXFWXUHGTXHULHVWRPRGLI\
LQIRUPDWLRQLQSHUVLVWHQWWZRGLPHQVLRQDOPDWULFHVFDOOHGWDEOHV RULQWKHRULJLQDOWKH
RUHWLFDOSDSHUVUHODWLRQV 'HYHORSHUVZULWHTXHULHVLQDKLJKOHYHOODQJXDJHFDOOHGWKH
6WDQGDUG4XHU\/DQJXDJHRUPRUHFRPPRQO\64/64/LVWKHFRPPRQODQJXDJHIRU
UHODWLRQDOGDWDEDVHPDQDJHPHQWV\VWHPV 5'%06V WKDWKDYHEHHQDSRSXODUWRROIRU
GDWDPDQDJHPHQWVLQFHWKHODWHV64/EHFDPHDQLQGXVWU\ZLGHVWDQGDUGZKHQ
LWZDVDGRSWHGE\1,67LQDQG,62LQ,WLVXVHGIRUHYHU\WKLQJIURPWHUDE\WH
2UDFOHDQG64/6HUYHULQVWDOODWLRQVWRDVZHVKDOOVHHVWRULQJHPDLORQ\RXUSKRQH
247
'DWDEDVHWDEOHVDUHDQDWXUDOILWIRUGDWDWKDWLQFOXGHVPDQ\LQVWDQFHVRIWKHVDPHNLQG
RIWKLQJ¢DW\SLFDORFFXUUHQFHLQVRIWZDUHGHYHORSPHQW)RUH[DPSOHDFRQWDFWOLVWKDV
PDQ\FRQWDFWVDOORIZKLFKSRWHQWLDOO\KDYHWKHVDPHW\SHRILQIRUPDWLRQ LHDGGUHVV
SKRQHQXPEHUHWF (DFK£URZ¤RIGDWDLQDWDEOHVWRUHVLQIRUPDWLRQDERXWDGLIIHUHQW
SHUVRQZKLOHHDFK£FROXPQ¤VWRUHVDVSHFLILFDWWULEXWHRIHDFKSHUVRQQDPHVLQRQH
FROXPQDGGUHVVLQDQRWKHUFROXPQDQGKRPHSKRQHQXPEHULQDWKLUG:KHQVRPH
RQHLVUHODWHGWRPXOWLSOHWKLQJV VXFKDVPXOWLSOHDGGUHVVHV UHODWLRQDOGDWDEDVHVKDYH
ZD\VRIKDQGOLQJWKDWWRREXWZHZRQ WJRLQWRVXFKGHWDLOLQWKLVFKDSWHU
SQLite
$QGURLGXVHVWKH64/LWHGDWDEDVHHQJLQHDVHOIFRQWDLQHGWUDQVDFWLRQDOGDWDEDVHHQ
JLQH WKDW UHTXLUHV QR VHSDUDWH VHUYHU SURFHVV 0DQ\ DSSOLFDWLRQV DQG HQYLURQPHQWV
EH\RQG$QGURLGPDNHXVHRILWDQGDODUJHRSHQVRXUFHFRPPXQLW\DFWLYHO\GHYHORSV
64/LWH,QFRQWUDVWWRGHVNWRSRULHQWHGRUHQWHUSULVHGDWDEDVHVZKLFKSURYLGHDSOH
WKRUDRIIHDWXUHVUHODWHGWRIDXOWWROHUDQFHDQGFRQFXUUHQWDFFHVVWRGDWD64/LWHDJ
JUHVVLYHO\VWULSVRXWIHDWXUHVWKDWDUHQRWDEVROXWHO\QHFHVVDU\LQRUGHUWRDFKLHYHDVPDOO
IRRWSULQW)RUH[DPSOHPDQ\GDWDEDVHV\VWHPVXVHVWDWLFW\SLQJEXW64/LWHGRHVQRW
VWRUHGDWDEDVHW\SHLQIRUPDWLRQ,QVWHDGLWSXVKHVWKHUHVSRQVLELOLW\RINHHSLQJW\SH
LQIRUPDWLRQLQWRKLJKOHYHOODQJXDJHVVXFKDV-DYDWKDWPDSGDWDEDVHVWUXFWXUHVLQWR
KLJKOHYHOW\SHV
64/LWHLVQRWD*RRJOHSURMHFWDOWKRXJK*RRJOHKDVFRQWULEXWHGWRLW64/LWHKDVDQ
LQWHUQDWLRQDOWHDPRIVRIWZDUHGHYHORSHUVZKRDUHGHGLFDWHGWRHQKDQFLQJWKHVRIW
ZDUH¦VFDSDELOLWLHVDQGUHOLDELOLW\5HOLDELOLW\LVDNH\IHDWXUHRI64/LWH0RUHWKDQKDOI
RIWKHFRGHLQWKHSURMHFWLVGHYRWHGWRWHVWLQJWKHOLEUDU\7KHOLEUDU\LVGHVLJQHGWR
KDQGOHPDQ\NLQGVRIV\VWHPIDLOXUHVVXFKDVORZPHPRU\GLVNHUURUVDQGSRZHU
IDLOXUHV7KHGDWDEDVHVKRXOGQHYHUEHOHIWLQDQXQUHFRYHUDEOHVWDWHDVWKLVZRXOGEH
DVKRZVWRSSHURQDPRELOHSKRQHZKHUHFULWLFDOGDWDLVRIWHQVWRUHGLQDGDWDEDVH
)RUWXQDWHO\WKH64/LWHGDWDEDVHLVQRWVXVFHSWLEOHWRHDV\FRUUXSWLRQ¢LILWZHUHDQ
LQRSSRUWXQHEDWWHU\IDLOXUHFRXOGWXUQDPRELOHSKRQHLQWRDQH[SHQVLYHSDSHUZHLJKW
7KH64/LWHSURMHFWSURYLGHVFRPSUHKHQVLYHDQGGHWDLOHGGRFXPHQWDWLRQDWKWWSZZZ
VTOLWHRUJGRFVKWPO
The SQL Language
:ULWLQJ$QGURLGDSSOLFDWLRQVXVXDOO\UHTXLUHVDEDVLFDELOLW\WRSURJUDPLQWKH64/
ODQJXDJHDOWKRXJKKLJKHUOHYHOFODVVHVDUHSURYLGHGIRUWKHPRVWFRPPRQGDWDUHODWHG
DFWLYLWLHV7KLVFKDSWHUSURYLGHVDEHJLQQHU¦VLQWURGXFWLRQWR64/LWH$OWKRXJKWKLVLV
QRWDERRNDERXW64/ZHZLOOSURYLGH\RXZLWKHQRXJKGHWDLODERXW$QGURLGRULHQWHG
64/WROHW\RXLPSOHPHQWGDWDSHUVLVWHQFHLQDZLGHYDULHW\RI$QGURLGDSSOLFDWLRQV
)RU PRUH FRPSUHKHQVLYH LQIRUPDWLRQ SHUWDLQLQJ WR WKH 64/LWH ODQJXDJH VHH KWWS
ZZZVTOLWHRUJODQJKWPO :H¦OO XVH VLPSOH 64/ FRPPDQGV WR H[SODLQ WKH 64/LWH
248 | Chapter 10:ಗHandling and Persisting Data
ODQJXDJHDQGDORQJWKHZD\ZH¦OOGHPRQVWUDWHKRZWRXVHWKH sqlite3FRPPDQGWR
VHHWKHHIIHFWVWKRVHTXHULHVKDYHRQWKHWDEOHVWKH\PRGLI\<RXPD\DOVRILQGWKH
:6FKRROVWXWRULDOXVHIXOKWWSZZZZVFKRROVFRPVTOVTOBLQWURDVS
:LWK64/LWHWKHGDWDEDVHLVDVLPSOHILOHLQWKH$QGURLGILOHV\VWHPZKLFKFRXOGUHVLGH
LQIODVKRUH[WHUQDOFDUGPHPRU\EXW\RXZLOOILQGWKDWPRVWDSSOLFDWLRQV¦GDWDEDVHV
UHVLGHLQDGLUHFWRU\FDOOHGGDWDGDWDcom.example.yourAppPackageGDWDEDVHV<RXFDQ
LVVXHWKH lsFRPPDQGLQWKHDGEVKHOOWROLVWWKHGDWDEDVHVWKDW$QGURLGKDVFUHDWHG
IRU\RXLQWKDWGLUHFWRU\
7KHGDWDEDVHWDNHVFDUHRISHUVLVWHQFH¢WKDWLVLWXSGDWHVWKH64/LWHILOHLQWKHZD\
VSHFLILHGE\HDFK64/VWDWHPHQWLVVXHGE\DQDSSOLFDWLRQ,QWKHIROORZLQJWH[WZH
GHVFULEH64/LWHFRPPDQGVDVWKH\DUHXVHGLQVLGHWKHsqlite3FRPPDQGOLQHXWLOLW\
/DWHUZHZLOOVKRZZD\VWRDFKLHYHWKHVDPHHIIHFWVXVLQJWKH$QGURLG$3,$OWKRXJK
FRPPDQGOLQH64/ZLOOQRWEHSDUWRIWKHDSSOLFDWLRQ\RXVKLSLWFDQFHUWDLQO\KHOSWR
GHEXJDSSOLFDWLRQVDV\RX¦UHGHYHORSLQJWKHP<RXZLOOILQGWKDWZULWLQJGDWDEDVHFRGH
LQ$QGURLGLVXVXDOO\DQLWHUDWLYHSURFHVVRIZULWLQJ-DYDFRGHWRPDQLSXODWHWDEOHVDQG
WKHQSHHNLQJDWFUHDWHGGDWDXVLQJWKHFRPPDQGOLQH
SQL Data Definition Commands
6WDWHPHQWVLQWKH64/ODQJXDJHIDOOLQWRWZRGLVWLQFWFDWHJRULHVWKRVHXVHGWRFUHDWH
DQGPRGLI\WDEOHV¢WKHORFDWLRQVZKHUHGDWDLVVWRUHG¢DQGWKRVHXVHGWRFUHDWHUHDG
XSGDWHDQGGHOHWHWKHGDWDLQWKRVHWDEOHV,QWKLVVHFWLRQZH¦OOORRNDWWKHIRUPHUWKH
GDWDGHILQLWLRQFRPPDQGV
CREATE TABLE
'HYHORSHUVVWDUWZRUNLQJZLWK64/E\FUHDWLQJDWDEOHWRVWRUHGDWD7KH CREATE
TABLEFRPPDQGFUHDWHVDQHZWDEOHLQDQ64/LWHGDWDEDVH,WVSHFLILHVDQDPH
ZKLFKPXVWEHXQLTXHDPRQJWKHWDEOHVLQWKHGDWDEDVHDQGYDULRXVFROXPQVWR
KROGWKHGDWD(DFKFROXPQKDVDXQLTXHQDPHZLWKLQWKHWDEOHDQGDW\SH WKH
W\SHVDUHGHILQHGE\64/VXFKDVDGDWHRUWH[WVWULQJ 7KHFROXPQPD\DOVRVSHFLI\
RWKHUDWWULEXWHVVXFKDVZKHWKHUYDOXHVKDYHWREHXQLTXHZKHWKHUWKHUHLVDGH
IDXOWYDOXHZKHQDURZLVLQVHUWHGZLWKRXWVSHFLI\LQJDYDOXHDQGZKHWKHUNULLLV
DOORZHGLQWKHFROXPQ
$WDEOHLVVLPLODUWRDVSUHDGVKHHW5HWXUQLQJWRWKHH[DPSOHRIDFRQWDFWGDWDEDVH
HDFKURZLQWKHWDEOHFRQWDLQVWKHLQIRUPDWLRQIRURQHFRQWDFW7KHFROXPQVLQWKH
WDEOHDUHWKHYDULRXVELWVRILQIRUPDWLRQ\RXFROOHFWDERXWHDFKLQGLYLGXDOFRQWDFW
ILUVWQDPHODVWQDPHELUWKGD\DQGVRRQ:HSURYLGHVHYHUDOH[DPSOHVLQWKLV
FKDSWHUWKDWZLOOKHOS\RXWREHJLQXVLQJRXUMREGDWDEDVH
7KHWDEOHVFUHDWHGE\64/CREATE TABLEVWDWHPHQWVDQGWKHDWWULE
XWHVWKH\FRQWDLQDUHFDOOHGDGDWDEDVHVFKHPD
The SQL Language | 249
DROP TABLE
7KLVUHPRYHVDWDEOHDGGHGZLWKWKHCREATE TABLEVWDWHPHQW,WWDNHVWKHQDPHRI
WKHWDEOHWREHGHOHWHG2QFRPSOHWLRQDQ\GDWDWKDWZDVVWRUHGLQWKHWDEOHPD\
QRWEHUHWULHYHG
+HUH LV VRPH 64/ FRGH WKDW ZLOO FUHDWH DQG WKHQ GHOHWH D VLPSOH WDEOH IRU VWRULQJ
FRQWDFWV
CREATE TABLE contacts (
first_name TEXT,
last_name TEXT,
phone_number TEXT,
height_in_meters REAL);
DROP TABLE contacts;
:KHQHQWHULQJFRPPDQGVWKURXJKVTOLWH\RXPXVWWHUPLQDWHHDFKFRPPDQGZLWKD
VHPLFRORQ
<RXPD\FKDQJHWKHGDWDEDVHVFKHPDDIWHU\RXFUHDWHWDEOHV ZKLFK\RXPD\ZDQWWR
GRWRDGGDFROXPQRUFKDQJHWKHGHIDXOWYDOXHRIDFROXPQ E\HQWHULQJWKH ALTER
TABLEFRPPDQG
SQLite types
<RXPXVWVSHFLI\DW\SHIRUHDFKFROXPQWKDW\RXFUHDWHLQDOOWDEOHVWKDW\RXGHILQH
DVGLVFXVVHGLQ£64/'DWD'HILQLWLRQ&RPPDQGV¤RQSDJH64/LWHVXSSRUWVWKH
IROORZLQJGDWDW\SHV
TEXT
$ WH[W VWULQJ VWRUHG XVLQJ WKH GDWDEDVH HQFRGLQJ 87) 87)%( RU
87)/( <RXZLOOILQGWKDWWKHTEXTW\SHLVWKHPRVWFRPPRQ
REAL
$IORDWLQJSRLQWYDOXHVWRUHGDVDQE\WH,(((IORDWLQJSRLQWQXPEHU
BLOB
$UELWUDU\ELQDU\GDWDVWRUHGH[DFWO\DVLILWZDVLQSXW<RXFDQXVHWKH BLOBGDWD
W\SH WR VWRUH DQ\ NLQG RI YDULDEOHOHQJWK GDWD VXFK DV DQ H[HFXWDEOH ILOH RU D
GRZQORDGHGLPDJH*HQHUDOO\EOREVFDQDGGDODUJHSHUIRUPDQFHRYHUKHDGWRD
PRELOH GDWDEDVH DQG \RX VKRXOG XVXDOO\ DYRLG XVLQJ WKHP ,Q &KDSWHU ZH
SUHVHQWDQDOWHUQDWHVFKHPHWRVWRUHLPDJHVGRZQORDGHGIURPWKH,QWHUQHW
INTEGER
$VLJQHGLQWHJHUVWRUHGLQRUE\WHVGHSHQGLQJRQWKHPDJQLWXGHRI
WKHYDOXH
6SHFLILFLQIRUPDWLRQUHJDUGLQJ64/LWHW\SHVLVDYDLODEOHDWKWWSZZZVTOLWHRUJGDWD
W\SHKWPO
250 | Chapter 10:ಗHandling and Persisting Data
Database constraints
'DWDEDVHFRQVWUDLQWVPDUNDFROXPQZLWKSDUWLFXODUDWWULEXWHV6RPHFRQVWUDLQWVHQ
IRUFHGDWDRULHQWHGOLPLWDWLRQVVXFKDVUHTXLULQJDOOYDOXHVLQDFROXPQWREHXQLTXH
HJDFROXPQFRQWDLQLQJ6RFLDO6HFXULW\QXPEHUV 2WKHUFRQVWUDLQWVH[KLELWPRUH
IXQFWLRQDOXVHV5HODWLRQDOFRQVWUDLQWVPRIMARY KEYDQGFOREIGN KEYIRUPWKHEDVLVRI
LQWHUWDEOHUHODWLRQVKLSV
0RVWWDEOHVVKRXOGKDYHDSDUWLFXODUFROXPQWKDWXQLTXHO\LGHQWLILHVHDFKJLYHQURZ
'HVLJQDWHGLQ64/DVDPRIMARY KEYWKLVFROXPQWHQGVWREHXVHGRQO\DVDQLGHQWLILHU
IRUHDFKURZDQG XQOLNHD6RFLDO6HFXULW\QXPEHU KDVQRPHDQLQJWRWKHUHVWRIWKH
ZRUOG7KXV\RXGRQRWQHHGWRVSHFLI\YDOXHVIRUWKHFROXPQ,QVWHDG\RXFDQOHW
64/LWH DVVLJQ LQFUHPHQWLQJ LQWHJHU YDOXHV DV QHZ URZV DUH DGGHG 2WKHU GDWDEDVHV
W\SLFDOO\UHTXLUH\RXWRVSHFLDOO\PDUNWKHFROXPQDVDXWRLQFUHPHQWLQJWRDFKLHYHWKLV
UHVXOW64/LWHDOVRRIIHUVDQH[SOLFLWAUTOINCREMENTFRQVWUDLQWEXWDXWRLQFUHPHQWVSUL
PDU\NH\VE\GHIDXOW7KHLQFUHPHQWLQJYDOXHVLQWKHFROXPQWDNHRQDUROHVLPLODUWR
DQRSDTXHREMHFWSRLQWHULQDKLJKOHYHOODQJXDJHVXFKDV-DYDRU&RWKHUGDWDEDVH
WDEOHVDQGFRGHLQDKLJKOHYHOODQJXDJHFDQXVHWKHFROXPQWRUHIHUHQFHWKDWSDUWLFXODU
URZ
:KHQGDWDEDVHURZVKDYHDXQLTXHSULPDU\NH\LWLVSRVVLEOHWRVWDUWWKLQNLQJDERXW
GHSHQGHQFLHVEHWZHHQWDEOHV)RUH[DPSOHDWDEOHXVHGDVDQHPSOR\HHGDWDEDVHFRXOG
GHILQHDQLQWHJHUFROXPQFDOOHGemployer_idWKDWZRXOGFRQWDLQWKHSULPDU\NH\YDOXHV
RIURZVLQDGLIIHUHQWWDEOHFDOOHGemployers,I\RXSHUIRUPDTXHU\DQGVHOHFWRQHRU
PRUHURZVIURPWKH employersWDEOH\RXFDQXVHJUDEWKHLU,'VDQGWRORRNXSHP
SOR\HHVLQDQ employeesWDEOHWKURXJKWKHWDEOH V employer_idFROXPQ7KLVDOORZVD
SURJUDPWRILQGWKHHPSOR\HHVRIDJLYHQHPSOR\HU7KHWZRWDEOHV VWULSSHGGRZQWR
DIHZFROXPQVUHOHYDQWWRWKLVH[DPSOH PLJKWORRNOLNHWKLV
CREATE TABLE employers (
_id INTEGER PRIMARY KEY,
company_name TEXT);
CREATE TABLE employees (
name TEXT,
annual_salary REAL NOT NULL CHECK (annual_salary > 0),
employer_id REFERENCES employers(_id));
7KHLGHDRIDWDEOHUHIHUULQJWRDQRWKHUWDEOH¦VSULPDU\NH\KDVIRUPDOVXSSRUWLQ64/
DVWKHFOREIGN KEYFROXPQFRQVWUDLQWZKLFKHQIRUFHVWKHYDOLGLW\RIFURVVWDEOHUHIHU
HQFHV7KLVFRQVWUDLQWWHOOVWKHGDWDEDVHWKDWLQWHJHUVLQDFROXPQZLWKDIRUHLJQNH\
FRQVWUDLQWPXVWUHIHUWRYDOLGSULPDU\NH\VRIGDWDEDVHURZVLQDQRWKHUWDEOH7KXVLI
\RXLQVHUWDURZLQWRWKHemployeesWDEOHZLWKDQemployer_idIRUDURZWKDWGRHVQRW
H[LVWLQWKHemployersWDEOHPDQ\IODYRUVRI64/ZLOOUDLVHDFRQVWUDLQWYLRODWLRQ7KLV
PD\KHOS\RXWRDYRLGRUSKDQHGUHIHUHQFHVDOVRNQRZQDVHQIRUFHPHQWRIIRUHLJQNH\V
+RZHYHUWKHIRUHLJQNH\FRQVWUDLQWLQ64/LWHLVRSWLRQDODQGLVWXUQHGRIILQ$QGURLG
$VRI$QGURLG\RXFDQQRWUHO\RQDIRUHLJQNH\FRQVWUDLQWWRFDWFKLQFRUUHFWIRUHLJQ
The SQL Language | 251
NH\UHIHUHQFHVVR\RXZLOOQHHGWRWDNHFDUHZKHQFUHDWLQJGDWDEDVHVFKHPDVWKDWXVH
IRUHLJQNH\V
7KHUHDUHVHYHUDORWKHUFRQVWUDLQWVZLWKOHVVIDUUHDFKLQJHIIHFWV
UNIQUE
)RUFHVWKHYDOXHRIWKHJLYHQFROXPQWREHGLIIHUHQWIURPWKHYDOXHVLQWKDWFROXPQ
LQDOOH[LVWLQJURZVZKHQHYHUDURZLVLQVHUWHGRUXSGDWHG$Q\LQVHUWRUXSGDWH
RSHUDWLRQWKDWDWWHPSWVWRLQVHUWDGXSOLFDWHYDOXHZLOOUHVXOWLQDQ64/LWHFRQ
VWUDLQWYLRODWLRQ
NOT NULL
5HTXLUHVDYDOXHLQWKHFROXPQNULLFDQQRWEHDVVLJQHG1RWHWKDWDSULPDU\NH\
LVERWKUNIQUEDQGNOT NULL
CHECK
7DNHVD%RROHDQYDOXHGH[SUHVVLRQDQGUHTXLUHVWKDWWKHH[SUHVVLRQUHWXUQWUXHIRU
DQ\YDOXHLQVHUWHGLQWKHFROXPQ$QH[DPSOHLVWKHCHECK (annual_salary > 0),
DWWULEXWHVKRZQHDUOLHULQWKHemployeesWDEOH
SQL Data Manipulation Commands
2QFH\RXKDYHGHILQHGWDEOHVXVLQJGDWDGHILQLWLRQFRPPDQGV\RXFDQWKHQLQVHUW\RXU
GDWDDQGTXHU\WKHGDWDEDVH7KHIROORZLQJGDWDPDQLSXODWLRQFRPPDQGVDUHWKHPRVW
FRPPRQO\XVHG64/VWDWHPHQWV
SELECT
7KLVVWDWHPHQWSURYLGHVWKHPDLQWRROIRUTXHU\LQJWKHGDWDEDVH7KHUHVXOWRIWKLV
VWDWHPHQWLV]HURRUPRUHURZVRIGDWDZKHUHHDFKURZKDVDIL[HGQXPEHURI
FROXPQV<RXFDQWKLQNRIWKHSELECTVWDWHPHQWDVSURGXFLQJDQHZWDEOHZLWKRQO\
WKHURZVDQGFROXPQVWKDW\RXFKRRVHLQWKHVWDWHPHQW7KH SELECTVWDWHPHQWLV
WKHPRVWFRPSOLFDWHGFRPPDQGLQWKH64/ODQJXDJHDQGVXSSRUWVDEURDGQXP
EHURIZD\VWREXLOGUHODWLRQVKLSVEHWZHHQGDWDDFURVVRQHRUPRUHGDWDEDVHWDEOHV
&ODXVHVIRU64/¦VSELECTFRPPDQGZKLFKDUHDOOVXSSRUWHGE\WKH$QGURLG$3,
LQFOXGHWKHIROORZLQJ
‡ FROMZKLFKVSHFLILHVWKHWDEOHVIURPZKLFKGDWDZLOOEHSXOOHGWRIXOILOOWKHTXHU\
‡ WHEREZKLFKVSHFLILHVFRQGLWLRQVWKDWVHOHFWHGURZVLQWKHWDEOHVPXVWPDWFKWR
EHUHWXUQHGE\WKHTXHU\
‡ GROUP BYZKLFKRUGHUVUHVXOWVLQFOXVWHUVDFFRUGLQJWRFROXPQQDPH
‡ HAVINGZKLFKIXUWKHUOLPLWVUHVXOWVE\HYDOXDWLQJJURXSVDJDLQVWH[SUHVVLRQV
<RXPLJKWUHPRYHJURXSVIURP\RXUTXHU\WKDWGRQRWKDYHDPLQLPXPQXPEHU
RIHOHPHQWV
‡ ORDER BYZKLFKVHWVWKHVRUWRUGHURITXHU\UHVXOWVE\VSHFLI\LQJDFROXPQQDPH
WKDW ZLOO GHILQH WKH VRUW DQG D IXQFWLRQ HJ ASC IRU DVFHQGLQJ DSC IRU GH
VFHQGLQJ WKDWZLOOVRUWWKHURZVE\HOHPHQWVLQWKHVSHFLILHGFROXPQ
252 | Chapter 10:ಗHandling and Persisting Data
‡ LIMITZKLFKOLPLWVWKHQXPEHURIURZVLQDTXHU\WRWKHVSHFLILHGYDOXH HJ
ILYHURZV +HUHDUHDIHZH[DPSOHVRISELECTVWDWHPHQWV
SELECT * FROM contacts;
SELECT first_name, height_in_meters
FROM contacts
WHERE last_name = "Smith";
SELECT employees.name, employers.name
FROM employees, employers
WHERE employee.employer_id = employer._id
ORDER BY employer.company_name ASC;
7KHILUVWVWDWHPHQWUHWULHYHVDOOWKHURZVLQWKH contactsWDEOHEHFDXVHQR WHERE
FODXVHILOWHUVUHVXOWV$OOFROXPQV LQGLFDWHGE\WKHDVWHULVN* RIWKHURZVDUHUH
WXUQHG7KHVHFRQGVWDWHPHQWJHWVWKHQDPHVDQGKHLJKWVRIWKHPHPEHUVRIWKH
6PLWKIDPLO\7KHODVWVWDWHPHQWSULQWVDOLVWRIHPSOR\HHVDQGWKHLUHPSOR\HUV
VRUWHGE\FRPSDQ\QDPH
)RUPRUHLQIRUPDWLRQVHHKWWSZZZVTOLWHRUJODQJBVHOHFWKWPO
INSERT
7KLVVWDWHPHQWDGGVDQHZGDWDURZWRDVSHFLILHGGDWDEDVHWDEOHDORQJZLWKDVHW
RI VSHFLILHG YDOXHV RI WKH SURSHU 64/LWH W\SH IRU HDFK FROXPQ HJ IRU DQ
integer 7KHLQVHUWPD\VSHFLI\DOLVWRIFROXPQVDIIHFWHGE\WKHLQVHUWZKLFKPD\
EHOHVVWKDQWKHQXPEHURIFROXPQVLQWKHWDEOH,I\RXGRQ¦WVSHFLI\YDOXHVIRUDOO
FROXPQV 64/LWH ZLOO ILOO LQ D GHIDXOW YDOXH IRU HDFK XQVSHFLILHG FROXPQ LI \RX
GHILQHGRQHIRUWKDWFROXPQLQ\RXUCREATE TABLEVWDWHPHQW,I\RXGRQ¦WSURYLGH
DGHIDXOW64/LWHXVHVDGHIDXOWRINULL
+HUHDUHDIHZH[DPSOHVRIINSERTVWDWHPHQWV
INSERT INTO contacts(first_name)
VALUES("Thomas");
INSERT INTO employers VALUES(1, "Acme Balloons");
INSERT INTO employees VALUES("Wile E. Coyote", 100000.000, 1);
7KHILUVWDGGVDQHZURZWRWKHFRQWDFWVIRUVRPHRQHZKRVHILUVWQDPHLV7KRPDV
DQGZKRVHODVWQDPHSKRQHQXPEHUDQGKHLJKWDUHXQNQRZQ NULL 7KHVHFRQG
DGGV$FPH%DOORRQVDVDQHZHPSOR\HUDQGWKHWKLUGDGGV:LOH(&R\RWHDVDQ
HPSOR\HHWKHUH
)RUPRUHLQIRUPDWLRQVHHKWWSZZZVTOLWHRUJODQJBLQVHUWKWPO
UPDATE
7KLVVWDWHPHQWPRGLILHVVRPHURZVLQDJLYHQWDEOHZLWKQHZYDOXHV(DFKDVVLJQ
PHQWVSHFLILHVDWDEOHQDPHDQGDJLYHQIXQFWLRQWKDWVKRXOGSURYLGHDQHZYDOXH
IRUWKHFROXPQ/LNH SELECT\RXFDQVSHFLI\D WHEREFODXVHWKDWZLOOLGHQWLI\WKH
URZVWKDWVKRXOGEHXSGDWHGGXULQJDQLQYRFDWLRQRIWKH UPDATEFRPPDQG/LNH
The SQL Language | 253
INSERT\RXFDQDOVRVSHFLI\DOLVWRIFROXPQVWREHXSGDWHGGXULQJFRPPDQGH[
HFXWLRQ7KHOLVWRIFROXPQVZRUNVLQWKHVDPHPDQQHUDVLWGRHVZLWKINSERT7KH
WHEREFODXVHLVFULWLFDOLILWPDWFKHVQRURZVWKH UPDATEFRPPDQGZLOOKDYHQR
HIIHFWEXWLIWKHFODXVHLVRPLWWHGWKHVWDWHPHQWZLOODIIHFWHYHU\URZLQWKHWDEOH
+HUHDUHDIHZH[DPSOHVRIUPDATEVWDWHPHQWV
UPDATE contacts
SET height_in_meters = 10, last_name = "Jones"
UPDATE employees
SET annual_salary = 200000.00
WHERE employer_id = (
SELECT _id
FROM employers
WHERE company_name = "Acme Balloons");
7KHILUVWFODLPVWKDWDOO\RXUIULHQGVDUHJLDQWVZLWKWKHODVWQDPH-RQHV7KHVHFRQG
LVDPRUHFRPSOH[TXHU\,WJLYHVDVXEVWDQWLDOUDLVHWRDOOWKHHPSOR\HHVRI$FPH
%DOORRQV
)RUPRUHLQIRUPDWLRQVHHKWWSZZZVTOLWHRUJODQJBXSGDWHKWPO
Additional Database Concepts
<RXQRZNQRZHQRXJKVLPSOH64/WREHDEOHWRVWDUWZRUNLQJZLWKGDWDEDVHVLQ$Q
GURLG$VWKHDSSOLFDWLRQV\RXZULWHJURZLQVRSKLVWLFDWLRQ\RXDUHOLNHO\WRPDNHXVH
RIWKHIROORZLQJ64/FRQVWUXFWVWKDWZHZRQ¦WFRYHULQGHWDLOLQWKLVERRN
,QQHUMRLQ
$Q LQQHU MRLQ VHOHFWV GDWD DFURVV WZR RU PRUH WDEOHV ZKHUH GDWD LV UHODWHG E\ D
IRUHLJQNH\7KLVW\SHRITXHU\LVXVHIXOIRUDVVHPEOLQJREMHFWVWKDWQHHGWREH
GLVWULEXWHG DFURVV RQH RU PRUH WDEOHV 7KH HPSOR\HHHPSOR\HU H[DPSOH HDUOLHU
GHPRQVWUDWHGDQLQQHUMRLQ$VZH¦YHQRWHGVLQFH$QGURLGGRHVQRWHQIRUFHIRUHLJQ
NH\V\RXFDQJHWLQWRWURXEOHKHUHLIDNH\IRUDMRLQGRHVQRWH[LVWDVDYDOLGFURVV
WDEOHUHIHUHQFH¢WKDWLVDIRUHLJQNH\FROXPQDFWXDOO\SRLQWVWRDSULPDU\NH\RI
DURZLQDQRWKHUWDEOHWKDWDFWXDOO\H[LVWV
&RPSRXQGTXHU\
64/LWHVXSSRUWVFRPSOH[GDWDEDVHPDQLSXODWLRQVWKURXJKFRPELQDWLRQVRIVWDWH
PHQWV2QHRIWKHXSGDWHH[DPSOHVVKRZQHDUOLHUZDVDFRPSRXQGTXHU\ZLWKD
SELECTHPEHGGHGLQDQUPDATE
7ULJJHUV
$GDWDEDVHWULJJHUDOORZVDGHYHORSHUWRZULWH64/VWDWHPHQWVWKDWZLOOUHFHLYHD
FDOOEDFNZKHQSDUWLFXODUGDWDEDVHFRQGLWLRQVRFFXU
)RUGHWDLOHGLQIRUPDWLRQRQWKHVHWRSLFVZHVXJJHVW\RXFRQVXOWDERRNRQ64/VXFK
DV/HDUQLQJ64/E\$ODQ%HDXOLHXRU64/3RFNHW*XLGHE\-RQDWKDQ*HQQLFNERWK
SXEOLVKHGE\2¦5HLOO\
254 | Chapter 10:ಗHandling and Persisting Data
Database Transactions
'DWDEDVHWUDQVDFWLRQVPDNHVHTXHQFHVRI64/VWDWHPHQWVDWRPLFHLWKHUDOOVWDWHPHQWV
VXFFHHGRUQRQHRIWKHPKDYHDQ\HIIHFWRQWKHGDWDEDVH7KLVFDQEHLPSRUWDQWIRU
LQVWDQFHLI\RXUDSSHQFRXQWHUVDQXQIRUWXQDWHRFFXUUHQFHVXFKDVDV\VWHPFUDVK$
WUDQVDFWLRQZLOOJXDUDQWHHWKDWLIWKHGHYLFHIDLOVSDUWZD\WKURXJKDJLYHQVHTXHQFHRI
RSHUDWLRQVQRQHRIWKHRSHUDWLRQVZLOODIIHFWWKHGDWDEDVH,QGDWDEDVHMDUJRQ64/LWH
WUDQVDFWLRQVVXSSRUWWKHZLGHO\UHFLWHG$&,'WUDQVDFWLRQSURSHUWLHVKWWSHQZLNLSH
GLDRUJZLNL$&,'
:LWK64/LWHHYHU\GDWDEDVHRSHUDWLRQWKDWPRGLILHVDGDWDEDVHUXQVLQLWVRZQGDWD
EDVHWUDQVDFWLRQZKLFKPHDQVDGHYHORSHUFDQEHDVVXUHGWKDWDOOYDOXHVRIDQLQVHUW
ZLOOEHZULWWHQLIWKHVWDWHPHQWVXFFHHGVDWDOO<RXFDQDOVRH[SOLFLWO\VWDUWDQGHQGD
WUDQVDFWLRQVRWKDWLWHQFRPSDVVHVPXOWLSOHVWDWHPHQWV)RUDJLYHQWUDQVDFWLRQ64/LWH
GRHVQRWPRGLI\WKHGDWDEDVHXQWLODOOVWDWHPHQWVLQWKHWUDQVDFWLRQKDYHFRPSOHWHG
VXFFHVVIXOO\
*LYHQWKHYRODWLOLW\RIWKH$QGURLGPRELOHHQYLURQPHQWZHUHFRPPHQGWKDWLQDGGLWLRQ
WRPHHWLQJWKHQHHGVIRUFRQVLVWHQF\LQ\RXUDSS\RXDOVRPDNHOLEHUDOXVHRIWUDQV
DFWLRQVWRVXSSRUWIDXOWWROHUDQFHLQ\RXUDSSOLFDWLRQ
Example Database Manipulation Using sqlite3
1RZWKDW\RXXQGHUVWDQGWKHEDVLFVRI64/DVLWSHUWDLQVWR64/LWHOHW¦VKDYHDORRN
DWDVLPSOHGDWDEDVHIRUVWRULQJYLGHRPHWDGDWDXVLQJWKHVTOLWHFRPPDQGOLQHWRRO
DQGWKH$QGURLGGHEXJVKHOOZKLFK\RXFDQVWDUWE\XVLQJWKH adbFRPPDQG8VLQJ
WKHFRPPDQGOLQHZLOODOORZXVWRYLHZGDWDEDVHFKDQJHVULJKWDZD\DQGZLOOSURYLGH
VRPHVLPSOHH[DPSOHVRIKRZWRZRUNZLWKWKLVXVHIXOGDWDEDVHGHEXJJLQJWRRO64/LWH
KDVPRUHLQIRUPDWLRQRQVTOLWHDWKWWSZZZVTOLWHRUJVTOLWHKWPO1RWHWKDWLWLVOLNHO\
HDVLHVWDWILUVWWRUXQWKLVH[DPSOHXVLQJWKH$QGURLGHPXODWRUVLQFH\RXZLOOQHHGURRW
DFFHVVLQRUGHUWRUXQLWRQDGHYLFH
:H¦OOJHWWKHH[DPSOHVWDUWHGE\LQLWLDOL]LQJWKHGDWDEDVH
$ adb shell
# cd /data/data/
# mkdir com.oreilly.demo.pa.ch10.sql
# cd com.oreilly.demo.pa.ch10.sql
# mkdir databases
# cd databases
#
# sqlite3 simple_video.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
The SQL Language | 255
1RWHWKDWGHYHORSHUVVKRXOGQRWFUHDWHWKHVHGLUHFWRULHVE\KDQGDVZH
KDYHGRQHLQWKLVH[DPSOHVLQFH$QGURLGZLOOFUHDWHWKHPGXULQJLQ
VWDOODWLRQRIDQDSSOLFDWLRQ'LUHFWRU\FUHDWLRQLVPHUHO\XVHIXOIRUWKLV
SDUWLFXODUH[DPSOHEHFDXVHZHGRQRW\HWKDYHDQDSSOLFDWLRQLQZKLFK
WKHGLUHFWRULHVZRXOGKDYHEHHQDXWRPDWLFDOO\FUHDWHG
7KHVTOLWHFRPPDQGOLQHDFFHSWVWZRNLQGVRIFRPPDQGVOHJDO64/DQGVLQJOHZRUG
FRPPDQGVWKDWEHJLQZLWKDSHULRG <RXFDQVHHWKHILUVW DQGSUREDEO\PRVWLP
SRUWDQW RIWKHVHLQWKHLQWURGXFWLRQPHVVDJH.help7U\LWRXWMXVWWRJHWDQLGHDRI
WKHRSWLRQVDYDLODEOHWR\RX
sqlite> .help
.bail ON|OFF
.databases
.dump ?TABLE? ...
.echo ON|OFF
.exit
.explain ON|OFF
.header(s) ON|OFF
.help
.import FILE TABLE
.indices TABLE
.load FILE ?ENTRY?
.mode MODE ?TABLE?
.nullvalue STRING
.output FILENAME
.output stdout
.prompt MAIN CONTINUE
.quit
.read FILENAME
.schema ?TABLE?
.separator STRING
.show
.tables ?PATTERN?
.timeout MS
.timer ON|OFF
.width NUM NUM ...
Stop after hitting an error. Default OFF
List names and files of attached databases
Dump the database in a SQL text format
Turn command echo on or off
Exit this program
Turn output mode suitable for EXPLAIN on or off.
Turn display of headers on or off
Show this message
Import data from FILE into TABLE
Show names of all indices on TABLE
Load an extension library
Set output mode where MODE is one of:
csv
Comma-separated values
column
Left-aligned columns. (See .width)
html
HTML <table> code
insert
SQL insert statements for TABLE
line
One value per line
list
Values delimited by .separator string
tabs
Tab-separated values
tcl
TCL list elements
Print STRING in place of NULL values
Send output to FILENAME
Send output to the screen
Replace the standard prompts
Exit this program
Execute SQL in FILENAME
Show the CREATE statements
Change separator used by output mode and .import
Show the current values for various settings
List names of tables matching a LIKE pattern
Try opening locked tables for MS milliseconds
Turn the CPU timer measurement on or off
Set column widths for "column" mode
7KHUH¦VDQRWKHULPSRUWDQWFRPPDQGLQWKLVOLVW.exit5HPHPEHULW,W¦VKRZ\RXJHW
RXWRIKHUH$OWHUQDWLYHO\\RXFDQTXLWZLWKWKH&WUO'NH\VWURNH
$QRWKHULPSRUWDQWWKLQJWRUHPHPEHULVWKDWHYHU\64/FRPPDQGQHHGVWREHWHUPL
QDWHGZLWKDVHPLFRORQ,I\RXVHHVRPHWKLQJOLNHWKLV
256 | Chapter 10:ಗHandling and Persisting Data
sqlite> select * from video
...>
LWMXVWPHDQV64/LWHWKLQNV\RX¦YHVWDUWHGWRHQWHU64/DQGLWLVZDLWLQJIRUWKH ;DW
WKHHQG1RWHWKDWWKH.FRPPDQGVGRQRWQHHGWREHWHUPLQDWHGE\DVHPLFRORQ
:H¦YHXVHGlsDVDQH[DPSOHRIDFRPPDQGDXVHUPLJKWKDYHDEVHQW
PLQGHGO\W\SHGLIKHIRUJRWKHZDVXVLQJVTOLWH lsLVQRWDFWXDOO\D
VTOLWHFRPPDQGLI\RXW\SH ;DIWHU lsVTOLWHZLOOFRPSODLQZLWKDQ
HUURUDQGWKHQ\RXFDQHQWHUFRUUHFWGRWFRPPDQGVRUVTOVWDWHPHQWV
0RVWRIWKH£GRW¤FRPPDQGVDUHQ¦WYHU\LQWHUHVWLQJDWWKLVSRLQWEHFDXVHWKLVGDWDEDVH
LVVWLOOHPSW\6ROHW¦VDGGVRPHGDWD
sqlite> create table video (
...> _id integer primary key,
...> title text,
...> description text,
...> url text);
7KHVHOLQHVFUHDWHDQHZWDEOHFDOOHGvideo7KHW\SHVRIWKHFROXPQVDUHintegerDQG
text7KHWDEOHFRQWDLQVDSULPDU\NH\FDOOHG _id7KLVSDUWLFXODUFROXPQQDPHLVQRW
FKRVHQDFFLGHQWDOO\$QGURLGUHTXLUHVWKHXVHRIWKLVH[DFWQDPHLQRUGHUIRUWKHWDEOH
WRZRUNZLWKLWVFXUVRUV\VWHP
:HFDQVHHWKHQHZO\FUHDWHGWDEOHVXVLQJWKH£GRW¤FRPPDQG.table
sqlite> .table
video
sqlite>
1H[WZH¦OOJRWKURXJKDIHZGLIIHUHQWTXHULHVWKDWLOOXVWUDWHWKH64/FRQFHSWVZHLQ
WURGXFHGHDUOLHUDQGWKDWDQDSSOLFDWLRQEDVHGRQWKHVHWDEOHV)LUVWOHW¦VLQVHUWVRPH
GDWDLQWRRXUQHZWDEOHVVRWKDWRXUTXHULHVUHWXUQVRPHH[DPSOHUHVXOWV
INSERT INTO video (_id, title, url)
VALUES(1, "Epic Fail Car", "http://www.youtube.com/watch?v=01ynapTnYVkeGE");
INSERT INTO video (_id, title, url)
VALUES(2, "Epic Fail Bicycle", "http://www.youtube.com/watch?v=7n7apTnYVkeGE");
INSERT INTO video (_id, title, url)
VALUES(3, "Epic Fail Wagon", "http://www.youtube.com/watch?v=m0iGn2c47LA");
INSERT INTO video (_id, title, url)
VALUES(4, "Epic Fail Sidewalk", "http://www.youtube.com/watch?v=m0iGn2cNcNo");
INSERT INTO video (_id, title, url)
VALUES(5, "Epic Fail Motorcycle",
"http://www.youtube.com/watch?v=7n7apBB8qkeGE");
%HFDUHIXOWREDODQFH\RXUTXRWHV,I\RXHQWHUDVLQJOHTXRWHVTOLWHZLOOSURPSW\RX
IRUHYHUXQWLOLWJHWVWKHPDWFK
,QWKLVH[DPSOHZHGLGQRWHQWHUYDOXHVIRUDOOWKHFROXPQVLQWKHWDEOH7KHFRQWHQWV
RIWKHSDUHQWKHVHVDIWHUWKH INTOSKUDVHLQWKHVWDWHPHQWOLVWWKHFROXPQVLQWRZKLFK
The SQL Language | 257
Download from Wow! eBook <www.wowebook.com>
WKHVWDWHPHQWZLOOSXWGDWD7KHSDUHQWKHVHVDIWHUWKHVALUESSKUDVHFRQWDLQWKHYDOXHV
WKHPVHOYHVLQWKHVDPHRUGHU
1RZVXSSRVH\RXZDQWWRILQGWKHQDPHVRIDOOWKHYLGHRVWKDWKDYHWKHZRUGIUDJPHQW
F\FOHLQWKHP8VHDSELECTTXHU\
sqlite> SELECT title FROM video WHERE title LIKE "%cycle%";
Epic Fail Bicycle
Epic Fail Motorcycle
6TOLWHSULQWVWKHURZVRQHWRDOLQH,QWKHH[DPSOHZHFDSLWDOL]HG64/UHVHUYHGZRUGV
WRKHOSNHHSV\QWD[FOHDU,WLVQRWQHFHVVDU\WRGRVR7KH\FDQEHXSSHUFDVHORZHUFDVH
RUPL[HGFDVH
7KHH[DPSOHDOVRVKRZVWKHUXGLPHQWDU\SDWWHUQPDWFKLQJDYDLODEOHLQ64/7KHNH\
ZRUGLIKEFRPELQHGZLWKWKHZLOGFDUGSHUFHQWVLJQFKDUDFWHU % DOORZV\RXWRPDWFK
SDUWVRIVWULQJV
6XSSRVHQRZWKDWZH¦GOLNHDOOWKHYLGHRVZLWKWKHLU85/VVRUWHGLQUHYHUVHDOSKD
EHWLFDORUGHUE\WLWOH
sqlite> SELECT title, url FROM video ORDER BY title DESC;
Epic Fail Wagon|http://www.youtube.com/watch?v=m0iGn2c47LA
Epic Fail Sidewalk|http://www.youtube.com/watch?v=m0iGn2cNcNo
Epic Fail Motorcycle|http://www.youtube.com/watch?v=7n7apBB8qkeGE
Epic Fail Car|http://www.youtube.com/watch?v=01ynapTnYVkeGE
Epic Fail Bicycle|http://www.youtube.com/watch?v=7n7apTnYVkeGE
<RXFDQVHHWKDWVTOLWHXVHVWKHSLSHFKDUDFWHU _ WRVHSDUDWHWKHYDOXHVLQGLIIHUHQW
FROXPQV
:HGLGQ¦WDGGGHVFULSWLRQVIRURXUYLGHRV/HW¦VDGGMXVWRQHQRZ
sqlite> UPDATE video SET description="Crash!" WHERE title LIKE "%Car";
sqlite> UPDATE video SET description="Trip!" WHERE title LIKE '%Sidewalk%';
sqlite> SELECT title, description FROM video WHERE NOT description IS NULL;
Epic Fail Car|Crash!
Epic Fail Sidewalk|Trip!
)LQDOO\OHW¦VGHOHWHDUHFRUGXVLQJLWV,'
sqlite> DELETE FROM video WHERE _id = 1;
sqlite> SELECT _id, description FROM videos;
2|Epic Fail Bicycle
3|Epic Fail Wagon
4|Epic Fail Sidewalk
5|Epic Fail Motorcycle
SQL and the Database-Centric Data Model for Android
Applications
1RZWKDW\RXKDYHVRPHEDVLF64/SURJUDPPLQJNQRZOHGJHZHFDQVWDUWWKLQNLQJ
DERXW KRZ WR SXW LW WR XVH LQ DQ $QGURLG DSSOLFDWLRQ 2XU JRDO LV WR FUHDWH UREXVW
258 | Chapter 10:ಗHandling and Persisting Data
DSSOLFDWLRQVEDVHGRQWKHSRSXODU0RGHO9LHZ&RQWUROOHU 09& SDWWHUQWKDWXQGHU
OLHVZHOOZULWWHQ8,SURJUDPVVSHFLILFDOO\LQDZD\WKDWZRUNVZHOOIRU$QGURLG:LNL
SHGLDKDVEDFNJURXQGLQIRUPDWLRQRQ09&DWKWWSHQZLNLSHGLDRUJZLNL0RGHOBYLHZ
BFRQWUROOHU
2QHIXQGDPHQWDOGLIIHUHQFHEHWZHHQPRELOHSKRQHDSSVDQGGHVNWRSDSSVLVKRZWKH\
KDQGOH SHUVLVWHQFH 7UDGLWLRQDO GHVNWRSEDVHG DSSOLFDWLRQV¢ZRUG SURFHVVRUV WH[W
HGLWRUVGUDZLQJSURJUDPVSUHVHQWDWLRQSURJUDPVDQGVRRQ¢RIWHQXVHDGRFXPHQW
FHQWULFIRUPRIWKH09&SDWWHUQ7KH\RSHQDGRFXPHQWUHDGLWLQWRPHPRU\DQG
WXUQLWLQWRREMHFWVLQPHPRU\WKDWIRUPWKHGDWDPRGHO6XFKSURJUDPVZLOOPDNHYLHZV
IRUWKHGDWDPRGHOSURFHVVXVHULQSXWWKURXJKWKHLUFRQWUROOHUDQGWKHQPRGLI\WKH
GDWDPRGHO )LJXUH 7KHNH\FRQVHTXHQFHRIWKLVGHVLJQLVWKDW\RXH[SOLFLWO\RSHQ
DQGVDYHGRFXPHQWVLQRUGHUWRPDNHWKHGDWDPRGHOSHUVLVWEHWZHHQSURJUDPLQYR
FDWLRQV :H¦YH VHHQ KRZ XVHU LQWHUIDFH FRPSRQHQWV ZRUN LQ $QGURLG 1H[W ZH¦OO
H[SORUHWKH$QGURLG$3,VIRUGDWDEDVHPDQLSXODWLRQZKLFKZLOOSUHSDUH\RXWRLP
SOHPHQWDQDSSOLFDWLRQGDWDPRGHOWKDWZRUNVLQDQHZZD\
)LJXUH'RFXPHQWFHQWULFDSSOLFDWLRQVZKLFKLPSOHPHQWDGDWDPRGHOZLWKLQPHPRU\REMHFWV
5REXVWXVHRI$QGURLGFRPELQHVGDWDPRGHOVDQGXVHULQWHUIDFHHOHPHQWVLQDGLIIHUHQW
PDQQHU$SSVUXQRQPRELOHGHYLFHVZLWKOLPLWHGPHPRU\ZKLFKFDQUXQRXWRIEDWWHU\
SRZHU DW XQSUHGLFWDEOH DQG SRVVLEO\ LQRSSRUWXQH WLPHV 6PDOO PRELOH GHYLFHV DOVR
SODFHDSUHPLXPRQUHGXFLQJWKHLQWHUDFWLYHEXUGHQRQWKHXVHUUHPLQGLQJDXVHUKH
RXJKWWRVDYHDGRFXPHQWZKHQKHLVWU\LQJWRDQVZHUDSKRQHFDOOLVQRWDJRRGXVHU
H[SHULHQFH7KHZKROHFRQFHSWRIDGRFXPHQWLVDEVHQWLQ$QGURLG7KHXVHUVKRXOG
DOZD\VKDYHWKHULJKWGDWDDWKDQGDQGEHFRQILGHQWKHUGDWDLVVDIH
7RPDNHLWHDV\WRVWRUHDQGXVHDSSOLFDWLRQGDWDLQFUHPHQWDOO\LWHPE\LWHPDQG
DOZD\VKDYHLWLQSHUVLVWHQWPHPRU\ZLWKRXWH[SOLFLWO\VDYLQJWKHZKROHGDWDPRGHO
$QGURLGSURYLGHVVXSSRUWLQLWVGDWDEDVHYLHZDQGDFWLYLW\FODVVHVIRUGDWDEDVHFHQWULF
GDWD )LJXUH :H¦OOH[SODLQKRZWRXVH$QGURLGGDWDEDVHFODVVHVWRLPSOHPHQW
WKLVNLQGRIPRGHO
The Android Database Classes
7KLVVHFWLRQLQWURGXFHVWKH-DYDFODVVHVWKDWJLYH\RXDFFHVVWRWKH64/LWHIXQFWLRQV
GHVFULEHGHDUOLHULQWKHFKDSWHUZLWKWKHGDWDFHQWULFPRGHOZHMXVWGHVFULEHGLQPLQG
The Android Database Classes | 259
)LJXUH$QGURLGVXSSRUWIRUDGDWDPRGHOWKDWPRVWO\UHVLGHVLQDGDWDEDVH
SQLiteDatabase
$QGURLG¦V -DYD LQWHUIDFH WR LWV UHODWLRQDO GDWDEDVH 64/LWH ,W VXSSRUWV DQ 64/
LPSOHPHQWDWLRQULFKHQRXJKIRUDQ\WKLQJ\RX¦UHOLNHO\WRQHHGLQDPRELOHDSSOL
FDWLRQLQFOXGLQJDFXUVRUIDFLOLW\
Cursor
$FRQWDLQHUIRUWKHUHVXOWVRIDGDWDEDVHTXHU\WKDWVXSSRUWVDQ09&VW\OHREVHU
YDWLRQV\VWHP&XUVRUVDUHVLPLODUWR-'%&UHVXOWVHWVDQGDUHWKHUHWXUQYDOXHRI
DGDWDEDVHTXHU\LQ$QGURLG$FXUVRUFDQUHSUHVHQWPDQ\REMHFWVZLWKRXWUHTXLU
LQJDQLQVWDQFHIRUHDFKRQH:LWKDFXUVRU\RXFDQPRYHWRWKHVWDUWRITXHU\
UHVXOWVDQGDFFHVVHDFKURZRQHDWDWLPHDVQHHGHG7RDFFHVVFXUVRUGDWD\RXFDOO
PHWKRGVQDPHGDVCursor.getAs*(int columnNumber) HJgetAsString 7KHYDO
XHV WKH FXUVRU ZLOO UHWXUQ GHSHQG RQ WKH FXUUHQW FXUVRU LQGH[ ZKLFK \RX FDQ
LQFUHPHQW E\ FDOOLQJ Cursor.moveToNext RU GHFUHPHQW E\ FDOOLQJ Cursor.moveTo
PreviousDVQHHGHG<RXFDQWKLQNRIWKHFXUUHQWLQGH[RIWKHFXUVRUDVDSRLQWHU
WRDUHVXOWREMHFW
&XUVRUVDUHDWWKHKHDUWRIWKHEDVLVIRU$QGURLG09&ZKLFKZHZLOOFRYHULQGHWDLO
LQ&KDSWHU
SQLiteOpenHelper
3URYLGHVDOLIHF\FOHIUDPHZRUNIRUFUHDWLQJDQGXSJUDGLQJ\RXUDSSOLFDWLRQGDWD
EDVH,W¦VTXLWHKHOSIXOWRXVHWKLVFODVVWRDVVLVWZLWKWKHFULWLFDOWDVNRIWUDQVLWLRQLQJ
WKHGDWDIURPRQHYHUVLRQRIDQDSSOLFDWLRQWRDSRVVLEOHQHZVHWRIGDWDEDVHWDEOHV
LQDQHZYHUVLRQRIDQDSSOLFDWLRQ
SQLiteQueryBuilder
3URYLGHVDKLJKOHYHODEVWUDFWLRQIRUFUHDWLQJ64/LWHTXHULHVIRUXVHLQ$QGURLG
DSSOLFDWLRQV8VLQJWKLVFODVVFDQVLPSOLI\WKHWDVNRIZULWLQJDTXHU\VLQFHLWVDYHV
\RXIURPKDYLQJWRILGGOHZLWK64/V\QWD[\RXUVHOI
Database Design for Android Applications
,QWKHQH[WVHFWLRQZH¦OOH[DPLQHVRPHFRGHIURP&KDSWHUWKDWGHDOVZLWKSHUVLVWHQW
VWRUDJHRIYLGHRUHODWHGPHWDGDWDLQIRUPDWLRQWLWOHGHVFULSWLRQDQGYLGHR85/7KLV
FRGHUHVLGHVLQVLGHDQ$QGURLGFRQWHQWSURYLGHUZKLFKZHIHHOLVDQDSSURSULDWHORFD
260 | Chapter 10:ಗHandling and Persisting Data
WLRQIRUGDWDEDVHFRGH:LWKRXWH[SODLQLQJPXFKDERXWFRQWHQWSURYLGHUVZH¦OOGLVFXVV
KRZWRZULWHDGDWDEDVHIRURQH&KDSWHUH[SODLQVLQGHWDLOKRZWRZULWHDFRQWHQW
SURYLGHU7KHIROORZLQJFRGHZLOOKHOSXVLOOXVWUDWHKRZWRFUHDWHDQGXVHDQ64/LWH
GDWDEDVHLQ$QGURLG7KLVDSSOLFDWLRQZLOOXVHURXJKO\WKHVDPHGDWDEDVHWKDWZHMXVW
H[DPLQHGXVLQJWKH sqlite3FRPPDQGOLQHWRRO7KLVWLPHWKRXJKZH¦OOEHZULWLQJ
FRGHWKDWXVHVWKH$QGURLG$3,WRPDQLSXODWHWKHGDWD
Basic Structure of the SimpleVideoDbHelper Class
,Q RXU H[DPSOH WKH 6LPSOH)LQFK9LGHR&RQWHQW3URYLGHUMDYD ILOH HQFDSVXODWHV DOO WKH
64/ORJLFQHFHVVDU\WRZRUNZLWKWKHVLPSOHBYLGHRGDWDEDVHLQ$QGURLG$SSOLFDWLRQV
WKDWQHHGDFFHVVWRWKHSHUVLVWHQWGDWDLQWKLVGDWDEDVHLQWHUDFWZLWKWKHSURYLGHUDQG
WKHFXUVRUVLWVXSSOLHVDVZH¦OOH[SODLQLQ&KDSWHU&OLHQWVDUHFRPSOHWHO\LQVXODWHG
IURPWKHGHWDLOVRIKRZWKHGDWDLVDFWXDOO\VWRUHG7KLVLVJRRGSURJUDPPLQJSUDFWLFH
DQGVKRXOGEHHPXODWHGLQDOO\RXU$QGURLGDSSOLFDWLRQVWKDWXVHGDWDEDVHV
)RUQRZVLQFHZHDUHIRFXVLQJRQKRZWRXVHGDWDEDVHVLQ$QGURLGLW¦VVXIILFLHQWWR
NQRZWKDWSimpleVideoDbHelperLVWKHPRGHORIWKHGDWDEDVHLQWKHSURYLGHUHYHU\WKLQJ
VSHFLILFWRWKHLPSOHPHQWDWLRQRIWKHGDWDEDVH¢LWVQDPHWKHQDPHVRILWVFROXPQV
WKHGHILQLWLRQVRILWVWDEOHV¢WDNHVHIIHFWLQWKLVFODVV)RUDODUJHFRPSOH[GDWDEDVHRI
FRXUVH WKH KHOSHU FODVV PD\ EH PXFK PRUH FRPSOH[ DQG EH FRPSRVHG RI VHYHUDO
FRPSRQHQWV
SimpleVideoDbHelperLQKHULWVIURPWKHDEVWUDFW SQLiteOpenHelperFODVVDQGWKHUHIRUH
PXVWRYHUULGHWKHonCreateDQGonUpgradePHWKRGV7KHonCreatePHWKRGLVDXWRPDW
LFDOO\FDOOHGZKHQWKHDSSOLFDWLRQVWDUWVIRUWKHILUVWWLPH,WVMRELVWRFUHDWHWKHGDWDEDVH
:KHQQHZYHUVLRQVRIWKHDSSOLFDWLRQVKLSLWPD\EHQHFHVVDU\WRXSGDWHWKHGDWDEDVH
SHUKDSVDGGLQJWDEOHVDGGLQJFROXPQVRUHYHQFKDQJLQJWKHVFKHPDHQWLUHO\:KHQ
WKLVLVQHFHVVDU\WKHWDVNIDOOVWRWKHonUpgradePHWKRGZKLFKLVFDOOHGZKHQHYHUWKH
DATABASE_VERSIONLQWKHFDOOWRWKHFRQVWUXFWRULVGLIIHUHQWIURPWKHRQHVWRUHGZLWKWKH
GDWDEDVH:KHQ\RXVKLSDQHZYHUVLRQRIDGDWDEDVH\RXPXVWLQFUHPHQWWKHYHUVLRQ
QXPEHU
public static final String VIDEO_TABLE_NAME = "video";
public static final String DATABASE_NAME = SIMPLE_VIDEO + ".db";
private static int DATABASE_VERSION = 2;
public static final int ID_COLUMN = 0;
public static final int TITLE_COLUMN = 1;
public static final int DESCRIPTION_COLUMN = 2;
public static final int TIMESTAMP_COLUMN = 3;
public static final int QUERY_TEXT_COLUMN = 4;
public static final int MEDIA_ID_COLUMN = 5;
private static class SimpleVideoDbHelper extends SQLiteOpenHelper {
private SimpleVideoDbHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory)
{
Database Design for Android Applications | 261
}
super(context, name, factory, DATABASE_VERSION);
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
createTable(sqLiteDatabase);
}
private void createTable(SQLiteDatabase sqLiteDatabase) {
String qs = "CREATE TABLE " + VIDEO_TABLE_NAME + " (" +
FinchVideo.SimpleVideos._ID +
" INTEGER PRIMARY KEY AUTOINCREMENT, " +
FinchVideo.SimpleVideos.TITLE_NAME + " TEXT, " +
FinchVideo.SimpleVideos.DESCRIPTION_NAME + " TEXT, " +
FinchVideo.SimpleVideos.URI_NAME + " TEXT);";
sqLiteDatabase.execSQL(qs);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase,
int oldv, int newv)
{
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " +
VIDEO_TABLE_NAME + ";");
createTable(sqLiteDatabase);
}
}
7KHJHQHUDOHOHPHQWVDVVRFLDWHGZLWKSimpleVideoDbHelperFRGHDUH
&RQVWDQWV
7KHSimpleVideoDbHelperFODVVGHILQHVWZRLPSRUWDQWFRQVWDQWV
DATABASE_NAME
7KLV KROGV WKH ILOHQDPH RI WKH GDWDEDVH VLPSOHBYLGHRGE LQ WKLV FDVH
7KLVQDPHVWKHDFWXDO64/LWHGDWDEDVHILOH5HFDOOWKDWZHPHQWLRQHGWKLVILOH
UHVLGHVLQWKHIROORZLQJSDWKDQGWKDW$QGURLGZLOOWDNHFDUHWRFUHDWHWKH
GDWDEDVHILOHIRU\RXGDWDGDWDFRPRUHLOO\GHPRSDILQFKYLGHRGDWDEDVHVVLP
SOHBYLGHRGE
DATABASE_VERSION
7KLVGHILQHVWKHGDWDEDVHYHUVLRQZKLFK\RXFKRRVHDUELWUDULO\DQGLQFUHPHQW
ZKHQHYHU\RXFKDQJHWKHGDWDEDVHVFKHPD,IWKHYHUVLRQRIWKHGDWDEDVHRQ
WKH PDFKLQH LV OHVV WKDQ DATABASE_VERSION WKH V\VWHP UXQV \RXU onUpgrade
PHWKRGWRXSJUDGHWKHGDWDEDVHWRWKHFXUUHQWOHYHO
VIDEO_TABLE_NAME
7KLVLVWKHQDPHRIWKHRQO\WDEOHLQRXUVLPSOHGDWDEDVH
*_NAME
7KHVHDUHWKHQDPHVRIWKHFROXPQVLQWKHGDWDEDVH$VPHQWLRQHGHDUOLHULW
LVHVVHQWLDOWRGHILQHDFROXPQQDPHG_idDQGXVHLWDVWKHSULPDU\NH\IRUDQ\
WDEOHWKDW\RXZLOODFFHVVWKURXJKDFXUVRU
262 | Chapter 10:ಗHandling and Persisting Data
&RQVWUXFWRU
7KHFRQVWUXFWRUIRUWKHGDWDEDVHLQWKLVSURYLGHU SimpleVideoDbHelperXVHVWKH
superIXQFWLRQWRFDOOLWVSDUHQW¦VFRQVWUXFWRU7KHSDUHQWGRHVPRVWRIWKHZRUN
RIFUHDWLQJWKHGDWDEDVHREMHFW
onCreate
:KHQDQ$QGURLGDSSOLFDWLRQDWWHPSWVWRUHDGRUZULWHGDWDWRDGDWDEDVHWKDW
GRHVQRWH[LVWWKHIUDPHZRUNH[HFXWHVWKHonCreatePHWKRG7KHonCreatePHWKRG
LQWKH YouTubeDbHelperFODVVVKRZVRQHZD\WRFUHDWHWKHGDWDEDVH,ILQLWLDOL]LQJ
WKHGDWDEDVHUHTXLUHGDVXEVWDQWLDODPRXQWRI64/FRGHLWPLJKWEHSUHIHUDEOHWR
NHHSWKHFRGHLQWKHVWULQJV[POUHVRXUFHILOH7KLVPLJKWPDNHWKH-DYDFRGHPXFK
PRUHUHDGDEOH%XWLWDOVRIRUFHVDGHYHORSHUPRGLI\LQJWKHFRGHWRORRNLQWZR
VHSDUDWHILOHVWRVHHZKDW¦VUHDOO\JRLQJRQ2IFRXUVHLIDSURJUDPKDVDVLPSOH
GDWDEDVH LW PLJKW EH HDVLHU WR MXVW ZULWH WKH 64/ LQ -DYD DV ZH KDYH GRQH LQ
SimpleVideoDbHelperRULI\RXXVHDTXHU\EXLOGHUWKHUHPD\EHQR64/DWDOO
,I\RXLQWHQGWRORDG\RXU64/IURPD StringUHVRXUFH\RXPXVW
WDNHFDUHRIDFKDQJHWRWKHVWULQJPHQWLRQHGRQO\EULHIO\LQWKH
$QGURLG GRFXPHQWDWLRQ HVFDSH DOO VLQJOH TXRWHV DQG GRXEOH
TXRWHVZLWKDEDFNVODVK FKDQJLQJ "WR \"DQG 'WR \' ZLWKLQD
UHVRXUFHVWULQJRUHQFORVHWKHHQWLUHVWULQJLQHLWKHUVLQJOHRUGRXEOH
TXRWHV<RXVKRXOGDOVRWXUQRIIIRUPDWWLQJLQWKHVWULQJXVLQJWKH
formatted="false"DWWULEXWH)RUH[DPSOH
<string name="sql_query" formatted="false">
SELECT * FROM videos WHERE name LIKE \"%cycle%\"
</string>
7KH onCreatePHWKRGGRHVQ¦WDFWXDOO\KDYHWRFUHDWHWKHGDWDEDVH,WLVSDVVHGD
EUDQGQHZ HPSW\ GDWDEDVH DQG PXVW FRPSOHWHO\ LQLWLDOL]H LW ,Q SimpleVideoDb
HelperWKLVLVDVLPSOHWDVNDQGLVDFFRPSOLVKHGZLWKWKHFDOOWRcreateVideosTable
onUpdate
7KHonUpdatePHWKRGIRUSimpleVideoContentProviderLVYHU\VLPSOHLWGHOHWHVWKH
GDWDEDVH:KHQWKHSURYLGHUWULHVWRXVHLWODWHU$QGURLGZLOOFDOOWKH onCreate
PHWKRGEHFDXVHLWGRHVQRWH[LVW:KLOHVXFKDFUXGHDSSURDFKPLJKWEHDFFHSWDEOH
LQWKLVH[WUHPHO\VLPSOHFDVHDSURYLGHULQWHQGHGRQO\DVDFDFKHIRUQHWZRUNGDWD
LWZRXOGFHUWDLQO\QRWEHDFFHSWDEOHIRUVD\DGDWDEDVHRIFRQWDFWV<RXUFXVWRPHUV
ZRQ¦WEHYHU\KDSS\LIWKH\KDYHWRUHNH\WKHLULQIRUPDWLRQHDFKWLPHWKH\XSJUDGH
VRIWZDUHYHUVLRQV6RRXU onUpdatePHWKRGZRQ¦WZRUNYHU\ZHOOLQUHDOOLIH,Q
JHQHUDOWKHonUpdatePHWKRGZLOOKDYHWRUHFRJQL]HDOOSUHYLRXVYHUVLRQVRIGDWD
EDVHVXVHGE\DQDSSOLFDWLRQDQGKDYHDGDWDVDIHVWUDWHJ\IRUFRQYHUWLQJWKRVH
GDWDEDVHVWRWKHPRVWUHFHQWIRUPDW$ODUJHUDSSOLFDWLRQZRXOGKDYHVHYHUDOXS
JUDGHVFULSWVRQHIRUHDFKYHUVLRQWKDWPLJKWEHRXWLQWKHZLOG7KHDSSOLFDWLRQ
ZRXOGWKHQH[HFXWHHDFKXSJUDGHVFULSWLQWXUQXQWLOWKHGDWDEDVHZDVFRPSOHWHO\
XSWRGDWH
Database Design for Android Applications | 263
createVideosTable
:HFUHDWHGWKLVIXQFWLRQWRHQFDSVXODWHWKH64/FRGHWKDWFUHDWHVRXUWDEOH
Using the Database API: MJAndroid
,QWKLVVHFWLRQZHSUHVHQWDPRUHDGYDQFHGH[DPSOHDSSOLFDWLRQFDOOHG0-$QGURLG
WKDWGHPRQVWUDWHVWKHXVHRIDVPDOOGDWDEDVHIRUDK\SRWKHWLFDOMREVHDUFKLQJDSSOL
FDWLRQ ,Q WKLV FKDSWHU ZH H[SORUH WKH GDWD SHUVLVWHQFH DVSHFWV RI WKLV SURJUDP ,Q
&KDSWHUZHWDNHDORRNDWKRZWKHDSSOLFDWLRQLQWHJUDWHVPDSSLQJIHDWXUHVWRVKRZ
MRETXHU\UHVXOWVRQDPDS)LUVWZH¦OOH[SODLQWKHDSSOLFDWLRQLQDELWPRUHGHWDLO
Android and Social Networking
2QHRIWKHJUHDWSURPLVHVRI$QGURLGPRELOHSKRQHVLVWKHLUDELOLW\WRUXQDSSOLFDWLRQV
WKDWHQKDQFHRSSRUWXQLWLHVIRUVRFLDOQHWZRUNLQJDPRQJXVHUV7KLVSURPLVHHFKRHV
WKHUHDOLW\RIWKH,QWHUQHW¢WKHILUVWJHQHUDWLRQRI,QWHUQHWDSSOLFDWLRQVZHUHDERXWXVHU
DFFHVVWRLQIRUPDWLRQDQGPDQ\RIWKRVHDSSOLFDWLRQVKDYHEHHQYHU\SRSXODU7KH
VHFRQGZDYHRI,QWHUQHWDSSOLFDWLRQVZHUHDERXWFRQQHFWLQJXVHUVWRRQHDQRWKHU$S
SOLFDWLRQVVXFKDV)DFHERRN<RX7XEHDQGPDQ\RWKHUVHQKDQFHRXUDELOLW\WRFRQQHFW
ZLWKSHRSOHRIVLPLODULQWHUHVWVDQGDOORZWKHDSSOLFDWLRQXVHUVWRSURYLGHVRPHRUDOO
RIWKHFRQWHQWWKDWPDNHVWKHDSSOLFDWLRQZKDWLWLV$QGURLGKDVWKHSRWHQWLDOWRWDNH
WKDWFRQFHSWDQGDGGDQHZGLPHQVLRQ¢PRELOLW\,W¦VH[SHFWHGWKDWDZKROHQHZJHQ
HUDWLRQRIDSSOLFDWLRQVZLOOEHEXLOWIRUXVHUVRIPRELOHGHYLFHVVRFLDOQHWZRUNLQJDS
SOLFDWLRQVWKDWDUHHDV\WRXVHZKLOHZDONLQJGRZQWKHVWUHHWDSSOLFDWLRQVWKDWDUHDZDUH
RIWKHXVHU¦VORFDWLRQDSSOLFDWLRQVWKDWDOORZWKHHDV\VKDULQJRIFRQWHQWULFKLQIRU
PDWLRQOLNHSLFWXUHVDQGYLGHRVHWF0-$QGURLGSURYLGHVDFRQFUHWHH[DPSOHRIKRZ
$QGURLGFDQDGGUHVVWKLVJURZLQJQLFKH
,QWKHFDVHRIWKH0-$QGURLG0LFUR-REVDSSOLFDWLRQWKHXVHULVWU\LQJWRORFDWHDWHP
SRUDU\MRELQKHUJHRJUDSKLFYLFLQLW\ZKHUHVKHFDQZRUNIRUDIHZKRXUVWRHDUQVRPH
H[WUDPRQH\7KHSUHPLVHLVWKDWHPSOR\HUVORRNLQJIRUWHPSRUDU\KHOSKDYHHQWHUHG
DYDLODEOHMREVGHVFULSWLRQVKRXUVDQGRIIHUHGZDJHVLQDZHEEDVHGGDWDEDVHWKDWLV
DFFHVVLEOHIURP$QGURLGPRELOHSKRQHV3HRSOHORRNLQJIRUDIHZKRXUV¦ZRUNFDQXVH
WKH0LFUR-REVDSSOLFDWLRQWRDFFHVVWKDWGDWDEDVHORRNIRUMREVLQWKHLULPPHGLDWHDUHD
FRPPXQLFDWHZLWKIULHQGVDERXWSRWHQWLDOHPSOR\HUVDQGSRWHQWLDOMREVDQGFDOOWKH
HPSOR\HUGLUHFWO\LIWKH\DUHLQWHUHVWHGLQWKHSRVLWLRQ)RURXUSXUSRVHVKHUHZHZRQ¦W
FUHDWHDQRQOLQHVHUYLFHZH¦OOMXVWKDYHVRPHFDQQHGGDWDRQWKHSKRQH7KHDSSOLFDWLRQ
KDVDQXPEHURIIHDWXUHVWKDWH[WHQGWKDWFHQWUDOLGHDLQZD\VWKDWDUHXQLTXHWRPRELOH
KDQGVHWV
0DSSLQJ
7KH$QGURLGPRELOHSKRQHHQYLURQPHQWSURYLGHVVXSSRUWIRUG\QDPLFLQWHUDFWLYH
PDSVDQGZH¦UHJRLQJWRWDNHIXOODGYDQWDJHRILWVFDSDELOLWLHV,Q£7KH0DS9LHZ
DQG0DS$FWLYLW\¤RQSDJH\RX¦OOVHHWKDWZLWKYHU\OLWWOHFRGHZH¦OOEHDEOH
264 | Chapter 10:ಗHandling and Persisting Data
WRVKRZG\QDPLFPDSVRIRXUORFDOQHLJKERUKRRGJHWWLQJORFDWLRQXSGDWHVIURP
WKHLQWHUQDO*36WRDXWRPDWLFDOO\VFUROOWKHPDSDVZHPRYH:H¦OOEHDEOHWRVFUROO
WKHPDSLQWZRGLUHFWLRQV]RRPLQDQGRXWDQGHYHQVZLWFKWRVDWHOOLWHYLHZV
)LQGLQJIULHQGVDQGHYHQWV
$JDLQLQ&KDSWHUZH¦OOVHHDJUDSKLFRYHUOD\RQWKHPDSWKDWZLOOVKRZXVZKHUH
MREVDUHORFDWHGLQWKHDUHDDQGZLOODOORZXVWRJHWPRUHLQIRUPDWLRQDERXWDMRE
E\MXVWWRXFKLQJLWVV\PERORQWKHPDS:HZLOODFFHVV$QGURLG¦VFRQWDFWPDQDJHU
DSSOLFDWLRQWRJHWDGGUHVVLQIRUPDWLRQIRURXUIULHQGV WHOHSKRQHQXPEHUVLQVWDQW
PHVVDJLQJDGGUHVVHVHWF DQGWKH0LFUR-REVGDWDEDVHWRJHWPRUHLQIRUPDWLRQ
DERXWSRVWHGMREV
,QVWDQWPHVVDJLQJ
:KHQZHILQGIULHQGVZHZDQWWRFKDWZLWKZHZLOOEHDEOHWRFRQWDFWWKHPYLD
LQVWDQWPHVVDJHVE\WUDGLQJ606PHVVDJHVZLWKRXUIULHQGV¦PRELOHSKRQHV
7DONLQJZLWKIULHQGVRUHPSOR\HUV
,I,0LQJLVWRRVORZRUFXPEHUVRPHZH¦OOEHDEOHWRHDVLO\SODFHDFHOOXODUFDOOWR
RXUIULHQGVRUFDOOWKHHPSOR\HURIIHULQJDMRE
%URZVLQJWKH:HE
0RVWHPSOR\HUVKDYHDQDVVRFLDWHGZHEVLWHWKDWSURYLGHVPRUHGHWDLOHGLQIRUPD
WLRQ:H¦OOEHDEOHWRVHOHFWDQHPSOR\HURIIDOLVWRURIIWKHPDSDQGTXLFNO\]HUR
LQRQWKHLUZHEVLWHWRILQGRXWIRUH[DPSOHZKDWWKHSODFHORRNVOLNH
7KLVLVDIXQDSSOLFDWLRQWKDWFRXOGHDVLO\EHGHYHORSHGIXUWKHULQWRDIXOOEORZQVHUYLFH
EXWRXULQWHQWLQWKLVERRNLVWRVKRZ\RXMXVWKRZHDV\LWLVWRGHYHORSDQGFRPELQH
WKHVHSRZHUIXOFDSDELOLWLHVLQ\RXURZQDSSOLFDWLRQ/LNHDOOWKHFRGHLQWKLVERRNWKH
FRPSOHWHFRGHLVDYDLODEOHIRUGRZQORDG$OWKRXJKLW¦VQRWDEVROXWHO\UHTXLUHGLQRUGHU
WRXQGHUVWDQGWKHPDWHULDOLQWKHERRN\RXDUHVWURQJO\HQFRXUDJHGWRGRZQORDGWKH
VRXUFHWR\RXURZQFRPSXWHU7KDWZD\\RX¦OOKDYHLWUHDGLO\DYDLODEOHIRUUHIHUHQFH
DQGLWZLOOEHHDV\WRFXWVHFWLRQVRIFRGHDQGSDVWHWKHPLQWR\RXURZQDSSOLFDWLRQV
DV\RXPRYHRQ)RUQRZZH¦OOXVHWKH0-$QGURLGH[DPSOHWRSURYLGHD£FORVHWRUHDO
ZRUOG¤H[DPSOHWRGLJLQWRWKH$QGURLGGDWDEDVH$3,
)LJXUHVKRZVWKHVFUHHQGLVSOD\HGE\0-$QGURLGZKHQ\RXILUVWUXQLW,W¦VDPDS
RI\RXUORFDODUHDRYHUODLGZLWKDIHZEXWWRQVDQGSLQV
The Source Folder (src)
7KHSDFNDJHQDPHIRU0-$QGURLGLVcom.microjobsinc.mjandroid(FOLSVHOD\VRXWWKH
HTXLYDOHQWGLUHFWRU\VWUXFWXUHMXVWDVLWZRXOGIRUDQ\-DYDSURMHFWDQGVKRZV\RXWKH
ZKROHWKLQJZKHQ\RXRSHQWKHVUFIROGHUV,QDGGLWLRQWRWKHVHSDFNDJHIROGHUVWKHUH
LVDIROGHUQDPHGIRUWKHSDFNDJHWKDWFRQWDLQVDOOWKH-DYDILOHVIRUWKHSURMHFW7KHVH
LQFOXGHWKHIROORZLQJILOHV
Using the Database API: MJAndroid | 265
)LJXUH0-$QGURLGRSHQLQJVFUHHQVKRW
0LFUR-REVMDYD
7KHPDLQVRXUFHILOHIRUWKHDSSOLFDWLRQ¢WKHDFWLYLW\WKDWVWDUWVILUVWGLVSOD\VWKH
PDSWKDWLVWKHFHQWHUSLHFHRIWKHDSSOLFDWLRQDQGFDOOVRWKHUDFWLYLWLHVRUVHUYLFHV
DVQHFHVVDU\WRLPSOHPHQWGLIIHUHQWIHDWXUHVLQWKHXVHULQWHUIDFH
0LFUR-REV'DWDEDVHMDYD
$GDWDEDVHKHOSHUWKDWSURYLGHVHDV\DFFHVVWRWKHORFDO0-$QGURLGGDWDEDVH7KLV
LVZKHUHDOOWKHHPSOR\HUXVHUDQGMRELQIRUPDWLRQLVVWRUHGXVLQJ64/LWH
$GG-REMDYDDQG(GLW-REMDYD
3DUWRIWKHGDWDEDVHSRUWLRQRI0-$QGURLG7KH\SURYLGHVFUHHQVWKDWWKHXVHUFDQ
XVHWRDGGRUHGLWMREHQWULHVLQWKHGDWDEDVH
0LFUR-REV'HWDLOMDYD
7KH Activity WKDW GLVSOD\V DOO WKH GHWDLO LQIRUPDWLRQ DERXW D SDUWLFXODU MRE
RSSRUWXQLW\
0LFUR-REV(PS'HWDLOMDYD
7KH ActivityWKDWGLVSOD\VLQIRUPDWLRQDERXWDQHPSOR\HULQFOXGLQJQDPHDG
GUHVVUHSXWDWLRQHPDLODGGUHVVSKRQHQXPEHUDQGVRIRUWK
266 | Chapter 10:ಗHandling and Persisting Data
0LFUR-REV/LVWMDYD
7KH ActivityWKDWGLVSOD\VDOLVWRIMREV DVRSSRVHGWRWKHPDSYLHZLQ0LFUR
-REVMDYD ,WVKRZVDVLPSOHOLVWRIHPSOR\HUVDQGMREVDQGDOORZVWKHXVHUWRVRUW
WKHOLVWE\HLWKHUILHOGDVZHOODVWRFDOOXSVSHFLILFVDERXWWKHMRERUHPSOR\HUE\
WRXFKLQJWKHQDPHRQWKHOLVW
Loading and Starting the Application
5XQQLQJ0-$QGURLGIURPWKH6'.LVFRPSOLFDWHGE\WKHIDFWWKDWWKHDSSOLFDWLRQXVHV
DMapView$QGURLGUHTXLUHVDVSHFLDO0DSV$3,NH\ZKHQHYHU\RXXVHDMapViewDQG
WKHNH\LVWLHGWR\RXUSDUWLFXODUGHYHORSPHQWPDFKLQH:HOHDUQHGLQ£$SSOLFDWLRQ
6LJQLQJ¤RQSDJHDERXWWKHUHTXLUHPHQWVIRUVLJQLQJDQGVWDUWLQJ\RXUDSSOLFDWLRQ
DQGVLQFHWKLVDSSOLFDWLRQUHOLHVRQWKHPDSV$3,\RXZLOOQHHGWRKDYHVHWXS\RXU$3,
NH\IRUWKHH[DPSOHWRZRUNSURSHUO\7RVWDUW0-$QGURLGMXVWRSHQDQGUXQWKHHFOLSVH
SURMHFWIRUWKLVFKDSWHUDV\RXKDYHGRQHIRURWKHUFKDSWHUV
Database Queries and Reading Data from the Database
7KHUHDUHPDQ\ZD\VWRUHDGGDWDIURPDQ64/GDWDEDVHEXWWKH\DOOFRPHGRZQWRD
EDVLFVHTXHQFHRIRSHUDWLRQV
&UHDWHD64/VWDWHPHQWWKDWGHVFULEHVWKHGDWD\RXQHHGWRUHWULHYH
([HFXWHWKDWVWDWHPHQWDJDLQVWWKHGDWDEDVH
0DSWKHUHVXOWDQW64/GDWDLQWRGDWDVWUXFWXUHVWKDWWKHODQJXDJH\RX¦UHZRUNLQJ
LQFDQXQGHUVWDQG
7KLVSURFHVVFDQEHYHU\FRPSOH[LQWKHFDVHRIREMHFWUHODWLRQDOPDSSLQJVRIWZDUHRU
UHODWLYHO\VLPSOHEXWODERULQWHQVLYHZKHQZULWLQJWKHTXHULHVGLUHFWO\LQWR\RXUDSSOL
FDWLRQ 2EMHFW UHODWLRQDO PDSSLQJ 250 DW KWWSHQZLNLSHGLDRUJZLNL2EMHFWBUHOD
WLRQDOBPDSSLQJ WRROVVKLHOG\RXUFRGHIURPWKHFRPSOH[LWLHVRIGDWDEDVHSURJUDPPLQJ
DQGREMHFWPDSSLQJE\PRYLQJWKDWFRPSOH[LW\RXWRI\RXULPPHGLDWHILHOGRIYLVLRQ
<RXU FRGH PD\ EH PRUH UREXVW LQ WKH IDFH RI GDWDEDVH FKDQJHV EXW DW WKH FRVW RI
FRPSOH[250VHWXSDQGPDLQWHQDQFH&XUUHQWO\LW¦VQRWW\SLFDOWRXVHDQ250LQDQ
$QGURLGDSSOLFDWLRQ
7KHVLPSOHDSSURDFKRIZULWLQJTXHULHVGLUHFWO\LQWR\RXUDSSOLFDWLRQZRUNVZHOORQO\
IRUYHU\VPDOOSURMHFWVWKDWZLOOQRWFKDQJHPXFKRYHUWLPH$SSOLFDWLRQVGLUHFWO\FRQ
WDLQLQJGDWDEDVHFRGHKDYHVRPHDGGHGULVNRIIUDJLOLW\EHFDXVHZKHQWKHGDWDEDVH
VFKHPDFKDQJHVDQ\FRGHWKDWUHIHUHQFHVWKHVFKHPDPXVWEHH[DPLQHGDQGSRWHQWLDOO\
UHZULWWHQ
$FRPPRQPLGGOHJURXQGDSSURDFKLVWRVHTXHVWHUDOOWKHGDWDEDVHORJLFLQWRDVHWRI
REMHFWVZKRVHVROHSXUSRVHLVWRWUDQVODWHDSSOLFDWLRQUHTXHVWVLQWRGDWDEDVHUHTXHVWV
DQGGHOLYHUWKHUHVXOWVEDFNWRWKHDSSOLFDWLRQ7KLVLVWKHDSSURDFKZHKDYHWDNHQZLWK
WKH0-$QGURLGDSSOLFDWLRQDOOWKHGDWDEDVHFRGHLVFRQWDLQHGLQWKHVLQJOHFODVVMicro
Using the Database API: MJAndroid | 267
JobsDatabase ZKLFK DOVR H[WHQGV SQLiteOpenHelper %XW ZLWK SimpleFinchVideoCon
tentProviderWKHGDWDEDVHLVVLPSOHHQRXJKWKDWZHGRQ¦WERWKHUWRXVHH[WHUQDOVWULQJV
:KHQ QRW XVHG ZLWK D FRQWHQW SURYLGHU $QGURLG JLYHV XV WKH DELOLW\ WR FXVWRPL]H
FXUVRUVDQGZHXVHWKDWDELOLW\WRIXUWKHUUHGXFHFRGHGHSHQGHQFLHVE\KLGLQJDOOWKH
LQIRUPDWLRQDERXWHDFKVSHFLILFGDWDEDVHRSHUDWLRQLQVLGHDFXVWRPFXUVRU7KHLQWHU
IDFHWRWKHFDOOHULQWKHgetJobsPHWKRGRIMicroJobsDatabaseDSSHDUVILUVWLQWKHFRGH
WKDWIROORZV7KHPHWKRG¦VMRELVWRUHWXUQD JobsCursorILOOHGZLWKMREVIURPWKHGD
WDEDVH 7KH XVHU FDQ FKRRVH WKURXJK WKH VLQJOH SDUDPHWHU SDVVHG WR WKH getJobs
PHWKRG WRVRUWMREVE\HLWKHUWKHtitleFROXPQRUWKHemployer_nameFROXPQ
public class MicroJobsDatabase extends SQLiteOpenHelper {
...
/** Return a sorted JobsCursor
* @param sortBy the sort criteria
*/
public JobsCursor getJobs(JobsCursor.SortBy sortBy) {
String sql = JobsCursor.QUERY + sortBy.toString();
SQLiteDatabase d = getReadableDatabase();
JobsCursor c = (JobsCursor) d.rawQueryWithFactory(
new JobsCursor.Factory(),
sql,
null,
null);
c.moveToFirst();
return c;
}
...
public static class JobsCursor extends SQLiteCursor{
public static enum SortBy{
title,
employer_name
}
private static final String QUERY =
"SELECT jobs._id, title, employer_name, latitude, longitude, status "+
"FROM jobs, employers "+
"WHERE jobs.employer_id = employers._id "+
"ORDER BY ";
private JobsCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
String editTable, SQLiteQuery query) {
super(db, driver, editTable, query);
}
private static class Factory implements SQLiteDatabase.CursorFactory{
@Override
public Cursor newCursor(SQLiteDatabase db,
SQLiteCursorDriver driver, String editTable,
SQLiteQuery query) {
return new JobsCursor(db, driver, editTable, query);
}
}
public long getColJobsId(){
return getLong(getColumnIndexOrThrow("jobs._id"));
}
public String getColTitle(){
268 | Chapter 10:ಗHandling and Persisting Data
}
return getString(getColumnIndexOrThrow("title"));
}
public String getColEmployerName(){
return getString(getColumnIndexOrThrow("employer_name"));
}
public long getColLatitude(){
return getLong(getColumnIndexOrThrow("latitude"));
}
public long getColLongitude(){
return getLong(getColumnIndexOrThrow("longitude"));
}
public long getColStatus(){
return getLong(getColumnIndexOrThrow("status"));
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
)XQFWLRQ WKDW IDVKLRQV D TXHU\ EDVHG RQ WKH XVHU¦V UHTXHVWHG VRUW FROXPQ WKH
sortBySDUDPHWHU DQGUHWXUQVUHVXOWVDVDFXUVRU
&UHDWHVWKHTXHU\VWULQJ0RVWRIWKHVWULQJLVVWDWLF WKHQUERYYDULDEOH EXWWKLVOLQH
WDFNVRQWKHVRUWFROXPQ(YHQWKRXJK QUERYLVSULYDWHLWLVVWLOODYDLODEOHWRWKH
HQFORVLQJFODVV7KLVLVEHFDXVHWKH getJobsPHWKRGDQGWKH JobsCursorFODVVDUH
ERWK ZLWKLQ WKH MicroJobsDatabase FODVV ZKLFK PDNHV JobsCursor¦V SULYDWH GDWD
PHPEHUVDYDLODEOHWRWKHgetJobsPHWKRG
7RJHWWKHWH[WIRUWKHVRUWFROXPQZHMXVWUXQtoStringRQWKHHQXPHUDWHGSDUDP
HWHUSDVVHGE\WKHFDOOHU:HFRXOGKDYHGHILQHGDQDVVRFLDWLYHDUUD\ZKLFKZRXOG
JLYHXVPRUHIOH[LELOLW\LQQDPLQJYDULDEOHVEXWWKLVVROXWLRQLVVLPSOHU$GGLWLRQDOO\
WKHQDPHVRIWKHFROXPQVSRSXSTXLWHQLFHO\XVLQJ\RXU,'(¦VDXWRFRPSOHWLRQ
5HWULHYHVDKDQGOHWRWKHGDWDEDVH
&UHDWHV WKH JobsCursor FXUVRU XVLQJ WKH SQLiteDatabase REMHFW¦V rawQueryWith
FactoryPHWKRG7KLVPHWKRGOHWVXVSDVVDIDFWRU\PHWKRGWKDW$QGURLGZLOOXVH
WR FUHDWH WKH H[DFW W\SH RI FXUVRU ZH QHHG ,I ZH KDG XVHG WKH VLPSOHU rawQuery
PHWKRG ZH ZRXOG JHW EDFN D JHQHULF Cursor ODFNLQJ WKH VSHFLDO IHDWXUHV RI
JobsCursor
$VDFRQYHQLHQFHWRWKHFDOOHUPRYHVWRWKHILUVWURZLQWKHUHVXOW7KLVZD\WKH
FXUVRULVUHWXUQHGUHDG\WRXVH$FRPPRQPLVWDNHLVWRIRUJHWWKHmoveToFirstFDOO
DQGWKHQSXOO\RXUKDLURXWWU\LQJWRILJXUHRXWZK\WKH CursorREMHFWLVWKURZLQJ
H[FHSWLRQV
7KHFXUVRULVWKHUHWXUQYDOXH
&ODVVWKDWFUHDWHVWKHFXUVRUUHWXUQHGE\getJobs
6LPSOH ZD\ WR SURYLGH DOWHUQDWH VRUW FULWHULD VWRUH WKH QDPHV RI FROXPQV LQ DQ
enum7KLVW\SHLVXVHGLQLWHP
Using the Database API: MJAndroid | 269
&RQVWUXFWRUIRUWKHFXVWRPL]HGFXUVRU7KHILQDODUJXPHQWLVWKHTXHU\SDVVHGE\
WKHFDOOHU
)DFWRU\FODVVWRFUHDWHWKHFXUVRUHPEHGGHGLQWKHJobsCursorFODVV
&UHDWHVWKHFXUVRUIURPWKHTXHU\SDVVHGE\WKHFDOOHU
5HWXUQVWKHFXUVRUWRWKHHQFORVLQJJobsCursorFODVV
&RQYHQLHQFHIXQFWLRQVWKDWH[WUDFWSDUWLFXODUFROXPQVIURPWKHURZXQGHUWKHFXU
VRU )RU LQVWDQFH getColTitle UHWXUQV WKH YDOXH RI WKH title FROXPQ LQ WKH URZ
FXUUHQWO\UHIHUHQFHGE\WKHFXUVRU7KLVVHSDUDWHVWKHGDWDEDVHLPSOHPHQWDWLRQIURP
WKHFDOOLQJFRGHDQGPDNHVWKDWFRGHHDVLHUWRUHDG
:KLOHVXEFODVVLQJDFXUVRULVDQLFHWULFNIRUXVLQJDGDWDEDVHZLWKLQD
VLQJOHDSSOLFDWLRQLWZRQ¦WZRUNZLWKWKHFRQWHQWSURYLGHU$3,VLQFH
$QGURLGGRHVQRWKDYHDZD\IRUFXUVRUVXEFODVVHVWREHVKDUHGDFURVV
SURFHVVHV$GGLWLRQDOO\WKH0-$QGURLGDSSOLFDWLRQLVDFRQWULYHGH[
DPSOHWRGHPRQVWUDWHXVLQJDGDWDEDVHZHSUHVHQWDQDSSOLFDWLRQZLWK
DPRUHUREXVWDUFKLWHFWXUHWKDW\RXPLJKWVHHLQDSURGXFWLRQDSSOLFD
WLRQLQ&KDSWHU
$VDPSOHXVHRIWKHGDWDEDVHIROORZV7KHFRGHJHWVDFXUVRUVRUWHGE\WLWOHWKURXJK
DFDOOWRgetJobs,WWKHQLWHUDWHVWKURXJKWKHMREV
MicroJobsDatabase db = new MicroJobsDatabase(this);
JobsCursor cursor = db.getJobs(JobsCursor.SortBy.title);
for (int rowNum = 0; rowNum < cursor.getCount(); rowNum++) {
cursor.moveToPosition(rowNum);
doSomethingWith(cursor.getColTitle());
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
&UHDWHVDMicroJobsDatabaseREMHFW7KHDUJXPHQWthisUHSUHVHQWVWKHFRQWH[WDV
GLVFXVVHGSUHYLRXVO\
&UHDWHVWKHJobsCursorFXUVRUUHIHUULQJWRWKHSortByHQXPHUDWLRQGLVFXVVHGHDUOLHU
8VHVJHQHULFCursorPHWKRGVWRLWHUDWHWKURXJKWKHFXUVRU
6WLOO ZLWKLQ WKH ORRS LQYRNHV RQH RI WKH FXVWRP DFFHVVRU PHWKRGV SURYLGHG E\
JobsCursorWR£GRVRPHWKLQJ¤FKRVHQE\WKHXVHUZLWKWKHYDOXHRIHDFKURZ¦VWLWOH
FROXPQ
Using the query method
:KLOHLW¦VKHOSIXOIRUDSSOLFDWLRQVWKDWH[HFXWHQRQWULYLDOGDWDEDVHRSHUDWLRQVWRLVRODWH
WKHLU64/VWDWHPHQWVDVVKRZQSUHYLRXVO\LW¦VDOVRFRQYHQLHQWIRUDSSOLFDWLRQVZLWK
VLPSOHGDWDEDVHRSHUDWLRQVVXFKDVRXU SimpleFinchVideoContentProviderWRPDNH
270 | Chapter 10:ಗHandling and Persisting Data
XVH RI WKH PHWKRG SQLiteDatabase.query DV VKRZQ LQ WKH IROORZLQJ videoUHODWHG
H[DPSOH
videoCursor = mDb.query(VIDEO_TABLE_NAME, projection,
where, whereArgs,
null, null, sortOrder);
$VZLWKSQLiteDatabase.rawQueryWithFactoryVKRZQSUHYLRXVO\WKHUHWXUQYDOXHRIWKH
queryPHWKRGLVDCursorREMHFW+HUHZHDVVLJQWKLVFXUVRUWRWKHSUHYLRXVO\GHILQHG
videoCursorYDULDEOH
7KH query PHWKRG UXQV D SELECT RQ D JLYHQ WDEOH QDPH LQ WKLV FDVH WKH FRQVWDQW
VIDEO_TABLE_NAME7KHPHWKRGWDNHVWZRSDUDPHWHUV)LUVWDSURMHFWLRQWKDWQDPHV
WKHFROXPQVWKDWVKRXOGRQO\VKRZXSLQWKHTXHU\¢RWKHUFROXPQYDOXHVZLOOQRWVKRZ
XSLQWKHFXUVRUUHVXOWV0DQ\DSSOLFDWLRQVZRUNMXVWILQHSDVVLQJnullIRUWKHSURMHF
WLRQZKLFKZLOOFDXVHDOOFROXPQYDOXHVWRVKRZXSLQWKHUHVXOWDQWFXUVRU1H[WWKH
whereDUJXPHQWFRQWDLQVD64/ whereFODXVHZLWKRXWWKH WHERENH\ZRUG7KH where
DUJXPHQWFDQDOVRFRQWDLQDQXPEHURI'?'VWULQJVWKDWZLOOEHUHSODFHGZLWKWKHYDOXHV
RIwhereArgs:H¦OOGLVFXVVLQPRUHGHWDLOKRZWKHVHWZRYDOXHVELQGWRJHWKHUZKHQZH
GLVFXVVWKHexecSQLPHWKRG
Modifying the Database
$QGURLGCursorVDUHJUHDWZKHQ\RXZDQWWRUHDGGDWDIURPWKHGDWDEDVHEXWWKHFODVV
android.database.CursorGRHVQRWSURYLGHPHWKRGVIRUFUHDWLQJXSGDWLQJRUGHOHWLQJ
GDWD7KHSQLiteDatabaseFODVVSURYLGHVWZREDVLF$3,VWKDW\RXFDQXVHIRUERWKUHDG
LQJDQGZULWLQJ
‡ $VHWRIIRXUPHWKRGVFDOOHGVLPSO\insertqueryupdateDQGdelete
‡ $PRUHJHQHUDOexecSQLPHWKRGWKDWWDNHVDQ\VLQJOH64/VWDWHPHQWWKDWGRHVQRW
UHWXUQGDWDDQGUXQVLWDJDLQVWWKHGDWDEDVH
:HUHFRPPHQGXVLQJWKHILUVWVHWRIFDOOVZKHQ\RXURSHUDWLRQVILWLWVFDSDELOLWLHV:H¦OO
VKRZ\RXERWKZD\VWRXVHWKH0-$QGURLGRSHUDWLRQV
Inserting data into the database
7KH 64/ INSERT VWDWHPHQW LV XVHG ZKHQHYHU \RX ZDQW WR LQVHUW GDWD LQWR DQ 64/
GDWDEDVH 7KH INSERT VWDWHPHQW PDSV WR WKH £FUHDWH¤ RSHUDWLRQ RI WKH &58'
PHWKRGRORJ\
,QWKH0-$QGURLGDSSOLFDWLRQWKHXVHUFDQDGGMREVWRWKHOLVWE\FOLFNLQJRQWKH$GG
-REPHQXLWHPZKHQORRNLQJDWWKH-REVOLVW7KHXVHUFDQWKHQILOORXWDIRUPWRLQSXW
WKHHPSOR\HUMREWLWOHDQGGHVFULSWLRQ$IWHUWKHXVHUFOLFNVRQWKH$GG-REEXWWRQRQ
WKHIRUPWKHIROORZLQJOLQHRIFRGHLVH[HFXWHG
db.addJob(employer.id, txtTitle.getText().toString(),
txtDescription.getText().toString());
Using the Database API: MJAndroid | 271
7KLVFRGHFDOOVWKHaddJobIXQFWLRQSDVVLQJLQWKHHPSOR\HU,'WKHMREWLWOHDQGWKH
MREGHVFULSWLRQ7KHaddJobIXQFWLRQGRHVWKHDFWXDOZRUNRIZULWLQJWKHMRERXWWRWKH
GDWDEDVH
Using the insert method. 7KHIROORZLQJH[DPSOHGHPRQVWUDWHVXVHRIWKHinsertPHWKRG
/**
* Add a new job to the database. The job will have a status of open.
* @param employer_id
The employer offering the job
* @param title
The job title
* @param description
The job description
*/
public void addJob(long employer_id, String title, String description) {
ContentValues map = new ContentValues();
map.put("employer_id", employer_id);
map.put("title", title);
map.put("description", description);
try{
getWritableDatabase().insert("jobs", null, map);
} catch (SQLException e) {
Log.e("Error writing new job", e.toString());
}
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
7KH ContentValuesREMHFWLVDPDSRIFROXPQQDPHVWRFROXPQYDOXHV,QWHUQDOO\
LW¦VLPSOHPHQWHGDVD HashMap<String,Object>+RZHYHUXQOLNHDVLPSOH HashMap
ContentValuesLVVWURQJO\W\SHG<RXFDQVSHFLI\WKHGDWDW\SHRIHDFKYDOXHVWRUHG
LQD ContentValuesFRQWDLQHU:KHQ\RXSXOOYDOXHVEDFNRXW ContentValuesZLOO
DXWRPDWLFDOO\FRQYHUWYDOXHVWRWKHUHTXHVWHGW\SHLISRVVLEOH
7KHVHFRQGSDUDPHWHUWRWKH insertPHWKRGLV nullColumnHack,W¦VXVHGRQO\DVD
GHIDXOWYDOXHZKHQWKHWKLUGSDUDPHWHUWKHPDSLVnullDQGWKHUHIRUHWKHURZZRXOG
RWKHUZLVHEHFRPSOHWHO\HPSW\
Using the execSQL method. 7KLVVROXWLRQZRUNVDWDORZHUOHYHOWKDQWKHinsertVROXWLRQ,W
FUHDWHV64/DQGSDVVHVLWWRWKHOLEUDU\WRH[HFXWH$OWKRXJK\RXFRXOGKDUGFRGHHYHU\
VWDWHPHQWLQFOXGLQJWKHGDWDSDVVHGE\WKHXVHUWKLVVHFWLRQVKRZVDSUHIHUDEOHPHWKRG
WKDWHPSOR\VELQGSDUDPHWHUV
$ELQGSDUDPHWHULVDTXHVWLRQPDUNWKDWKROGVDSODFHLQDQ64/VWDWHPHQWXVXDOO\
IRUDSDUDPDWHUSDVVHGE\WKHXVHUVXFKDVDYDOXHLQDWHEREFODXVH$IWHUFUHDWLQJDQ
64/VWDWHPHQWZLWKELQGSDUDPHWHUV\RXFDQUHXVHLWUHSHDWHGO\VHWWLQJWKHDFWXDO
YDOXHRIWKHELQGSDUDPHWHUVEHIRUHH[HFXWLQJLWHDFKWLPH
/**
* Add a new job to the database. The job will have a status of open.
* @param employer_id
The employer offering the job
* @param title
The job title
* @param description
The job description
*/
public void addJob(long employer_id, String title, String description){
272 | Chapter 10:ಗHandling and Persisting Data
}
String sql =
"INSERT INTO jobs " +
"(_id, employer_id, title, description, start_time, end_time, status) " +
"VALUES " +
"(NULL, ?,
?,
?,
0,
0,
3)";
Object[] bindArgs = new Object[]{employer_id, title, description};
try{
getWritableDatabase().execSQL(sql, bindArgs);
} catch (SQLException e) {
Log.e("Error writing new job", e.toString());
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
%XLOGVDQ64/TXHU\WHPSODWHQDPHG sqlWKDWFRQWDLQVELQGDEOHSDUDPHWHUVWKDW
ZLOOEHILOOHGLQZLWKXVHUGDWD7KHELQGDEOHSDUDPHWHUVDUHPDUNHGE\TXHVWLRQ
PDUNVLQWKHVWULQJ1H[WZHEXLOGDQREMHFWDUUD\QDPHG bindArgsWKDWFRQWDLQV
RQHREMHFWSHUHOHPHQWLQRXU64/WHPSODWH7KHUHDUHWKUHHTXHVWLRQPDUNVLQWKH
WHPSODWHVRWKHUHPXVWEHWKUHHHOHPHQWVLQWKHREMHFWDUUD\
([HFXWHVWKH64/FRPPDQGE\SDVVLQJWKH64/WHPSODWHVWULQJDQGWKHELQGDUJX
PHQWVWRexecSQL
8VLQJDQ64/WHPSODWHDQGELQGDUJXPHQWVLVPXFKSUHIHUUHGRYHUEXLOGLQJXSWKH
64/VWDWHPHQWFRPSOHWHZLWKSDUDPHWHUVLQWRDStringRUStringBuilder%\XVLQJD
WHPSODWHZLWKSDUDPHWHUV\RXSURWHFW\RXUDSSOLFDWLRQIURP64/LQMHFWLRQDWWDFNV
7KHVHDWWDFNVRFFXUZKHQDPDOLFLRXVXVHUHQWHUVLQIRUPDWLRQLQWRDIRUPWKDWLVGH
OLEHUDWHO\PHDQWWRPRGLI\WKHGDWDEDVHLQDZD\WKDWZDVQRWLQWHQGHGE\WKHGHYHORSHU
,QWUXGHUVQRUPDOO\GRWKLVE\HQGLQJWKHFXUUHQW64/FRPPDQGSUHPDWXUHO\XVLQJ
64/V\QWD[FKDUDFWHUVDQGWKHQDGGLQJQHZ64/FRPPDQGVGLUHFWO\LQWKHIRUPILHOG
7KHWHPSODWHSOXVSDUDPHWHUVDSSURDFKDOVRSURWHFWV\RXIURPPRUHUXQRIWKHPLOO
HUURUVVXFKDVLQYDOLGFKDUDFWHUVLQWKHSDUDPHWHUV,WDOVROHDGVWRFOHDQHUFRGHDVLW
DYRLGVORQJVHTXHQFHVRIPDQXDOO\DSSHQGHGVWULQJVE\DXWRPDWLFDOO\UHSODFLQJTXHV
WLRQPDUNV
Updating data already in the database
7KH0LFUR-REVDSSOLFDWLRQHQDEOHVWKHXVHUWRHGLWDMREE\FOLFNLQJRQWKHMRELQWKH
-REVOLVWDQGFKRRVLQJWKH(GLW-REPHQXLWHP7KHXVHUFDQWKHQPRGLI\WKHVWULQJV
IRUHPSOR\HUMREWLWOHDQGGHVFULSWLRQLQWKHeditJobIRUP$IWHUWKHXVHUFOLFNVRQWKH
8SGDWHEXWWRQRQWKHIRUPWKHIROORZLQJOLQHRIFRGHLVH[HFXWHG
db.editJob((long)job_id, employer.id, txtTitle.getText().toString(),
txtDescription.getText().toString());
7KLVFRGHFDOOVWKHeditJobPHWKRGSDVVLQJWKHMRE,'DQGWKHWKUHHLWHPVWKHXVHUFDQ
FKDQJHHPSOR\HU,'MREWLWOHDQGMREGHVFULSWLRQ7KHeditJobPHWKRGGRHVWKHDFWXDO
ZRUNRIPRGLI\LQJWKHMRELQWKHGDWDEDVH
Using the update method. 7KHIROORZLQJH[DPSOHGHPRQVWUDWHVXVHRIWKHupdatePHWKRG
Using the Database API: MJAndroid | 273
/**
* Update a job in the database.
* @param job_id
The job id of the existing job
* @param employer_id
The employer offering the job
* @param title
The job title
* @param description
The job description
*/
public void editJob(long job_id, long employer_id, String title, String description)
{
ContentValues map = new ContentValues();
map.put("employer_id", employer_id);
map.put("title", title);
map.put("description", description);
String[] whereArgs = new String[]{Long.toString(job_id)};
try{
getWritableDatabase().update("jobs", map, "_id=?", whereArgs);
} catch (SQLException e) {
Log.e("Error writing new job", e.toString());
}
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
7KHILUVWSDUDPHWHUWRupdateLVWKHQDPHRIWKHWDEOHWRPDQLSXODWH7KHVHFRQGLV
WKHPDSRIFROXPQQDPHVWRQHZYDOXHV7KHWKLUGLVDVPDOOVQLSSHWRI64/,QWKLV
FDVH LW¦V DQ 64/ WHPSODWH ZLWK RQH SDUDPHWHU 7KH SDUDPHWHU LV PDUNHG ZLWK D
TXHVWLRQPDUNDQGLVILOOHGRXWZLWKWKHFRQWHQWVRIWKHIRXUWKDUJXPHQW
Using the execSQL method. 7KH IROORZLQJ H[DPSOH GHPRQVWUDWHV XVH RI WKH execSQL
PHWKRG
/**
* Update a job in the database.
* @param job_id
The job id of the existing job
* @param employer_id
The employer offering the job
* @param title
The job title
* @param description
The job description
*/
public void editJob(long job_id, long employer_id, String title, String description)
{
String sql =
"UPDATE jobs " +
"SET employer_id = ?, "+
" title = ?, "+
" description = ? "+
"WHERE _id = ? ";
Object[] bindArgs = new Object[]{employer_id, title, description, job_id};
try{
getWritableDatabase().execSQL(sql, bindArgs);
} catch (SQLException e) {
Log.e("Error writing new job", e.toString());
}
}
274 | Chapter 10:ಗHandling and Persisting Data
)RUWKLVH[DPSOHDSSOLFDWLRQZHVKRZWKHVLPSOHVWSRVVLEOHIXQFWLRQ7KLVPDNHVLW
HDV\WRXQGHUVWDQGLQDERRNEXWLVQRWHQRXJKIRUDUHDODSSOLFDWLRQ,QDUHDODSSOL
FDWLRQ\RXZRXOGZDQWWRFKHFNLQSXWVWULQJVIRULQYDOLGFKDUDFWHUVYHULI\WKDWWKHMRE
H[LVWVEHIRUHWU\LQJWRXSGDWHLWYHULI\WKDWWKHemployer_idYDOXHLVYDOLGEHIRUHXVLQJ
LWGRDEHWWHUMRERIFDWFKLQJHUURUVDQGVRRQ<RXZRXOGDOVRSUREDEO\DXWKHQWLFDWH
WKHXVHUIRUDQ\DSSOLFDWLRQWKDWLVVKDUHGE\PXOWLSOHSHRSOH
Deleting data in the database
7KH0LFUR-REVDSSOLFDWLRQHQDEOHVWKHXVHUWRGHOHWHDMREDVZHOODVFUHDWHDQGFKDQJH
LW)URPWKHPDLQDSSOLFDWLRQLQWHUIDFHWKHXVHUFOLFNVRQWKH/LVW-REVEXWWRQWRJHWD
OLVWRIMREVDQGWKHQFOLFNVRQDSDUWLFXODUMREWRVHHWKHMREGHWDLO$WWKLVOHYHOWKHXVHU
FDQFOLFNRQWKH£'HOHWHWKLVMRE¤PHQXLWHPWRGHOHWHWKHMRE7KHDSSOLFDWLRQDVNVWKH
XVHUZKHWKHUKHUHDOO\ZDQWVWRGHOHWHWKHMRE:KHQWKHXVHUKLWVWKH'HOHWHEXWWRQLQ
UHVSRQVHWKHIROORZLQJOLQHRIFRGHLQWKH0LFUR-REV'HWDLOMDYDILOHLVH[HFXWHG
db.deleteJob(job_id);
7KLVFRGHFDOOVWKHdeleteJobPHWKRGRIWKHMicroJobsDatabaseFODVVSDVVLQJLWWKHMRE
,'WRGHOHWH7KHFRGHLVVLPLODUWRWKHIXQFWLRQVZH¦YHDOUHDG\VHHQDQGODFNVWKHVDPH
UHDOZRUOGIHDWXUHV
Using the delete method. 7KHIROORZLQJH[DPSOHGHPRQVWUDWHVXVHRIWKHdeletePHWKRG
/**
* Delete a job from the database.
* @param job_id
The job id of the job to delete
*/
public void deleteJob(long job_id) {
String[] whereArgs = new String[]{Long.toString(job_id)};
try{
getWritableDatabase().delete("jobs", "_id=?", whereArgs);
} catch (SQLException e) {
Log.e("Error deleteing job", e.toString());
}
}
Using the execSQL method. 7KH IROORZLQJ H[DPSOH GHPRQVWUDWHV XVH RI WKH execSQL
PHWKRG
/**
* Delete a job from the database.
* @param job_id
The job id of the job to delete
*/
public void deleteJob(long job_id) {
String sql = String.format(
"DELETE FROM jobs " +
"WHERE _id = '%d' ",
job_id);
try{
getWritableDatabase().execSQL(sql);
} catch (SQLException e) {
Log.e("Error deleteing job", e.toString());
Using the Database API: MJAndroid | 275
}
}
276 | Chapter 10:ಗHandling and Persisting Data
PART III
A Skeleton Application
for Android
7KHILUVWWZRSDUWVRIWKLVERRNGHVFULEHDQDSSURDFKWRNH\DUFKLWHFWXUDOLVVXHVLQ
$QGURLGDSSOLFDWLRQV7KHVNHOHWRQDSSOLFDWLRQVGHVFULEHGLQ3DUW,,,HPERG\WKLVDS
SURDFK<RXFDQXVHWKHFRGHDVDVWDUWLQJSRLQWIRU\RXURZQDSSOLFDWLRQV
CHAPTER 11
A Framework for a
Well-Behaved Application
,QWKLVFKDSWHUDQGWKHQH[WZHLQWURGXFHIUDPHZRUNRU£VNHOHWRQ¤DSSOLFDWLRQVWKDW
H[HPSOLI\PDQ\RIWKHGHVLJQDQGLPSOHPHQWDWLRQDSSURDFKHVSUHVHQWHGLQWKLVERRN
HVSHFLDOO\LQ&KDSWHUZKHUHZHLQWURGXFHGWKHFRPSRQHQWVRIDQDSSOLFDWLRQ
7KHIUDPHZRUNDSSOLFDWLRQLQWKLVFKDSWHUFDQEHXVHGDVDVWDUWLQJSRLQWIRU\RXURZQ
DSSOLFDWLRQV:HUHFRPPHQGWKLVDSSURDFKWRFUHDWLQJDSSOLFDWLRQVRYHUVWDUWLQJIURP
VFUDWFK RU IURP VPDOOHU H[DPSOHV WKDW GR QRW LPSOHPHQW DOO WKH DVSHFWV RI WKH
ActivityREMHFWDQGSURFHVVOLIHF\FOH
7KH DSSURDFK ZH WDNH LQ WKLV FKDSWHU HQDEOHV \RX WR YLVXDOL]H DQG XQGHUVWDQG WKH
FRPSRQHQWOLIHF\FOHEHIRUH\RXNQRZ\RXQHHGLW5HWURILWWLQJOLIHF\FOHKDQGOLQJWR
DQDSSOLFDWLRQWKDWZDVZULWWHQZLWKRXWXQGHUVWDQGLQJOLIHF\FOHVRUZLWKWKHH[SHFW
DWLRQWKDWOLIHF\FOHKDQGOLQJZRQ¦WEHQHHGHGLVRQHRIWKHHDVLHVWZD\VWRFUHDWHDQ
$QGURLGDSSOLFDWLRQWKDWIDLOVXQH[SHFWHGO\LQZD\VWKDWDUHKDUGWRUHSURGXFHFRQ
VLVWHQWO\DQGWKDWKDVSHUVLVWHQWEXJVWKDWFDQUHPDLQXQGLVFRYHUHGDFURVVPXOWLSOH
DWWHPSWVWRHUDGLFDWHWKHP,QRWKHUZRUGVLW¦VEHVWWROHDUQWKLVEHIRUHLWELWHV\RXLQ
WKHDVV
:KLOHWKLVFKDSWHULVQ¦WDERXWXVHULQWHUIDFHV\RXVKRXOGNHHSLQPLQGWKDWWKH$QGURLG
XVHULQWHUIDFHFODVVHVZHUHGHVLJQHGZLWKERWKWKHFRQVWUDLQWVRIWKH$QGURLGDUFKLWHF
WXUHDQGWKHFDSDELOLWLHVRIWKH$QGURLGV\VWHPLQPLQG,PSOHPHQWDWLRQVRIXVHULQ
WHUIDFHDQGOLIHF\FOHKDQGOLQJJRKDQGLQKDQG&RUUHFWO\KDQGOLQJWKHOLIHF\FOHVRIDQ
DSSOLFDWLRQWKHSURFHVVWKDWFRQWDLQVWKHDSSOLFDWLRQWKHActivityREMHFWVWKDWFRQWDLQ
WKH 8, RI WKH DSSOLFDWLRQ DQG WKH Fragment REMHFWV WKDW PLJKW EH FRQWDLQHG LQ DQ
ActivityLQVWDQFHDUHNH\WRDJRRGXVHUH[SHULHQFH
7R JHW WKH DSSOLFDWLRQ IUDPHZRUN FRGH DV \RX UHDG LW KHUH \RX FDQ GRZQORDG DQ
DUFKLYH IURP WKH ([DPSOHV OLQN RQ WKH ERRN¦V ZHEVLWH KWWSRUHLOO\FRPFDWDORJ
ZKLFKPD\LQFOXGHPRUHIHDWXUHVDQGFRUUHFWLRQVRIHUUDWD
279
Visualizing Life Cycles
(DUOLHULQWKLVERRNDQGLQWKH$QGURLGGHYHORSHUGRFXPHQWDWLRQ\RXVDZDVSHFWVRI
FRPSRQHQWOLIHF\FOHVGLDJUDPPHGDQGUHDGDERXWKRZOLIHF\FOHVZRUN7KHSUREOHP
ZLWKWKHVHGHVFULSWLRQVLVWKDWFRPSRQHQWOLIHF\FOHVDUHG\QDPLFDQGDVWDWHGLDJUDP
LVDVWDWLFSLFWXUH0RUHRYHUFRPSRQHQWDQGSURFHVVOLIHF\FOHWUDQVLWLRQVDUHGULYHQ
E\PHPRU\PDQDJHPHQWZKHQ\RXUXQRXWWKLQJVVWDUWWRKDSSHQLQFRPSRQHQWOLIH
F\FOHVWRUHFRYHUPHPRU\0HPRU\DOORFDWLRQJDUEDJHFROOHFWLRQDQGWKHZD\$QGURLG
HQDEOHVPHPRU\UHFRYHU\WRVSDQSURFHVVHVDUHLQKHUHQWO\QRWDVGHWHUPLQLVWLFDVUXQ
QLQJDEORFNRIFRGHDQGDUHFRQILJXUDWLRQGHSHQGHQW+HUHE\LQVWUXPHQWLQJDQG
UXQQLQJFRGHZHZLOOVHHDSSOLFDWLRQOLIHF\FOHVDVWKH\KDSSHQDQGHQDEOH\RXWR
H[SHULPHQWZLWKWKHPLQDUXQQLQJSURJUDP
Visualizing the Activity Life Cycle
:HZLOOPDNHWKH ActivityFRPSRQHQWOLIHF\FOHPRUHYLVLEOHWR\RXE\UXQQLQJDQ
LQVWUXPHQWHGSURJUDPDQGREVHUYLQJWKHEHKDYLRURIWKH ActivityOLIHF\FOHPHWKRGV
XVLQJWKH/RJ&DWYLHZLQ(FOLSVH7KHIROORZLQJFRGHLVDOLVWLQJRIWKHActivityVXEFODVV
ZLWK WKH OLIH F\FOH PHWKRGV LPSOHPHQWHG DQG ORJJLQJ FDOOV LQ HDFK PHWKRG 7KH
FDOORXWVLQWKHFRGHUHIHUWRDPHWKRGE\PHWKRGH[SODQDWLRQRIOLIHF\FOHKDQGOLQJLQ
£/LIHF\FOHPHWKRGVRIWKH$FWLYLW\FODVV¤RQSDJH7DNHDORRNDWWKLVOLVWLQJWR
VHHZKDWNLQGRILQIRUPDWLRQZLOOEHORJJHG
package com.oreilly.demo.pa.ch10.finchlifecycle;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class FinchLifecycle extends Activity {
// Make strings for logging
private final String TAG = this.getClass().getSimpleName();
private final String RESTORE = ", can restore state";
// The string "fortytwo" is used as an example of state
private final String state = "fortytwo";
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.main);
String answer = null;
// savedState could be null
if (null != savedState) {
answer = savedState.getString("answer");
}
Log.i(TAG, "onCreate"
280 | Chapter 11:ಗA Framework for a Well-Behaved Application
Download from Wow! eBook <www.wowebook.com>
}
+ (null == savedState ? "" : (RESTORE + " " + answer)));
@Override
protected void onRestart() {
super.onRestart();
// Notification that the activity will be started
Log.i(TAG, "onRestart");
}
@Override
protected void onStart() {
}
super.onStart();
// Notification that the activity is starting
Log.i(TAG, "onStart");
@Override
protected void onResume() {
}
super.onResume();
// Notification that the activity will interact with the user
Log.i(TAG, "onResume");
protected void onPause() {
}
super.onPause();
// Notification that the activity will stop interacting with the user
Log.i(TAG, "onPause" + (isFinishing() ? " Finishing" : ""));
@Override
protected void onStop() {
}
super.onStop();
// Notification that the activity is no longer visible
Log.i(TAG, "onStop");
@Override
protected void onDestroy() {
}
super.onDestroy();
// Notification that the activity will be destroyed
Log.i(TAG,
"onDestroy "
// Log which, if any, configuration changed
+ Integer.toString(getChangingConfigurations(), 16));
// ////////////////////////////////////////////////////////////////////////////
// Called during the life cycle, when instance state should be saved/restored
// ////////////////////////////////////////////////////////////////////////////
Visualizing Life Cycles | 281
@Override
protected void onSaveInstanceState(Bundle outState) {
// Save instance-specific state
outState.putString("answer", state);
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState");
}
@Override
public Object onRetainNonConfigurationInstance() {
Log.i(TAG, "onRetainNonConfigurationInstance");
return new Integer(getTaskId());
}
@Override
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
// Restore state; we know savedState is not null
String answer = null != savedState ? savedState.getString("answer") : "";
Object oldTaskObject = getLastNonConfigurationInstance();
if (null != oldTaskObject) {
int oldtask = ((Integer) oldTaskObject).intValue();
int currentTask = getTaskId();
// Task should not change across a configuration change
assert oldtask == currentTask;
}
Log.i(TAG, "onRestoreInstanceState"
+ (null == savedState ? "" : RESTORE) + " " + answer);
}
// ////////////////////////////////////////////////////////////////////////////
// These are the minor life cycle methods, you probably won't need these
// ////////////////////////////////////////////////////////////////////////////
@Override
protected void onPostCreate(Bundle savedState) {
super.onPostCreate(savedState);
String answer = null;
// savedState could be null
if (null != savedState) {
answer = savedState.getString("answer");
}
Log.i(TAG, "onPostCreate"
+ (null == savedState ? "" : (RESTORE + " " + answer)));
}
@Override
protected void onPostResume() {
super.onPostResume();
282 | Chapter 11:ಗA Framework for a Well-Behaved Application
}
Log.i(TAG, "onPostResume");
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
Log.i(TAG, "onUserLeaveHint");
}
}
:KHQ\RXDUHUHDG\WRUXQWKHDSSOLFDWLRQILUVWVKRZWKH/RJ&DWYLHZE\VHOHFWLQJ
:LQGRZൺ6KRZ9LHZൺ2WKHUšDQGH[SDQGLQJWKH$QGURLGIROGHULQWKH6KRZ9LHZ
GLDORJ7KHQVHOHFW/RJ&DWDVVKRZQLQ)LJXUH
)LJXUH6HOHFWLQJWKH/RJ&DWYLHZIURPWKHOLVWVKRZQ
1RZUXQWKHDSSOLFDWLRQLQDQHPXODWRURURQDSK\VLFDOGHYLFH6LQFHWKHH[DPSOHLQ
WKLVFKDSWHUKDVEHHQEXLOWZLWKERWKWKH)UDJPHQW$3,LQ$QGURLG$3,OHYHOFRU
UHVSRQGLQJWR$QGURLGYHUVLRQ£+RQH\FRPE¤DQGWKHYHUVLRQRIWKH)UDJPHQW
FODVVLQWKH$QGURLG&RPSDWLELOLW\3DFNDJH\RXFDQXVHHLWKHUFRGHEDVHWRUXQWKH
H[DPSOH
Visualizing Life Cycles | 283
<RXZLOOVWDUWWRVHHORJJLQJLQIRUPDWLRQLQWKH/RJ&DWYLHZLQ(FOLSVH7RVHHRQO\WKH
ORJJLQJLQIRUPDWLRQIURPWKHFRGHLQWKHSUHYLRXVOLVWLQJ\RXFDQILOWHUWKHORJJLQJ
LQIRUPDWLRQ&OLFNWKHJUHHQSOXVVLJQLQWKHWRROEDURIWKHORJJLQJZLQGRZWREULQJXS
DGLDORJIRUGHILQLQJDORJJLQJILOWHUDVVKRZQLQ)LJXUH
,Q WKLV FDVH \RX ZLOO ZDQW WR ILOWHU WKH ORJ EDVHG RQ WKH WDJ ZH XVH LQ WKH Finch
LifecycleFODVVZKLFKKDSSHQVWREHWKHQDPHRIWKHFODVV£)LQFK/LIHF\FOH¤:HQDPH
WKHILOWHU£DFWLYLW\OLIHF\FOH¤DVVKRZQLQ)LJXUH
)LJXUH0DNLQJDILOWHUWKDWZLOOVKRZRQO\ORJGDWDWDJJLQJZLWK£)LQFK/LIHF\FOH¤
1RZZKHQ\RXUXQWKHSURJUDP\RXZLOOVHHRQO\WKHORJJLQJRXWSXWIRUWKHDFWLYLW\
OLIHF\FOHPHWKRGVLQWKHWDEODEHOHG£DFWLYLW\OLIHF\FOH¤LQWKH/RJ&DWYLHZDVVKRZQ
LQ)LJXUH,I\RXZDQWWRVHHDOOWKHORJJLQJLQIRUPDWLRQWKH/RJWDEZLOOVKRZDQ
XQILOWHUHGORJ
:KHQ\RXUXQWKHSURJUDP\RXZLOOVHHLI\RXXVHDQHPXODWRUUXQQLQJ$QGURLG
VRPHWKLQJOLNHWKHVFUHHQVKRWLQ)LJXUH
:HXVH$QGURLGKHUHEHFDXVHWKLVFKDSWHULQFOXGHVFRYHUDJHRIOLIHF\FOHVDQGWKH
FragmentFODVV
,I\RXZDQWWRUXQWKHH[DPSOHRQDGHYLFHRUHPXODWRUWKDWSUHGDWHV
$QGURLG\RXFDQXVHWKH£EDFNSRUWHG¤YHUVLRQRIWKHH[DPSOHWKDW
PDNHVXVHRIWKH$QGURLG&RPSDWLELOLW\3DFNDJHZKLFKHQDEOHVWKHXVH
RIFragmentDQGRWKHU$QGURLG$3,OHYHOFODVVHVLQ$QGURLGYHUVLRQV
EDFNWR$3,OHYHOFRUUHVSRQGLQJWR$QGURLG
284 | Chapter 11:ಗA Framework for a Well-Behaved Application
)LJXUH7KHH[DPSOHFRGHRIWKLVFKDSWHUUXQQLQJLQDQ$QGURLGHPXODWRU
7KHILUVWWKLQJ\RXZLOOVHHLQWKH£DFWLYLW\OLIHF\FOH¤WDERIWKH/RJ&DWYLHZLVWKHVHW
RIORJPHVVDJHVLQ)LJXUH
,QRUGHUWRJHQHUDWHLQWHUHVWLQJORJJLQJLQIRUPDWLRQ\RXFDQVWDUWRWKHUDSSOLFDWLRQV
DQGJREDFNDQGIRUWKXVLQJWKHDSSOLFDWLRQVZLWFKHURUWKH/DXQFKHUWRUHWXUQWRWKH
)LQFKDSSOLFDWLRQ6WDUWHQRXJKRWKHUDSSOLFDWLRQVDQGRQUHWXUQLQJWRWKH)LQFKDS
SOLFDWLRQ\RXZLOOVHHWKDWWKHSURFHVV,'RU3,'KDVFKDQJHGEXWWKHDSSOLFDWLRQ
DSSHDUVWREHLQWKHVDPHVWDWHDV\RXOHIWLW7KLVLVEHFDXVHVWDWHZDVUHVWRUHGIRUWKLV
DFWLYLW\DQGDOORWKHUFRPSRQHQWVRIWKHDSSOLFDWLRQIURPWKHVDYHGVWDWH7KHORJ
LQIRUPDWLRQVKRZQLQWKHVFUHHQVKRWLQ)LJXUHVKRZVMXVWVXFKDWUDQVLWLRQ
,I\RXILQGWKHUHLVQRRXWSXWLQWKH/RJ&DWYLHZVZLWFKWRWKH''06
SHUVSHFWLYH XVLQJWKH:LQGRZPHQX DQGFOLFNRQWKHGHYLFHRUHP
XODWRU\RXDUHXVLQJLQWKH'HYLFHVYLHZ
Visualizing Life Cycles | 285
)LJXUH/RJJLQJRXWSXWVKRZLQJDQHZSURFHVVDQGDFWLYLW\VWDWHEHLQJUHVWRUHG
%\VWDUWLQJRWKHUDSSOLFDWLRQVWKDWQHHGPHPRU\\RXKDYHWULJJHUHGVRPHRIWKHVWUDW
HJLHV$QGURLGXVHVWRUHFRYHUPHPRU\2IFRXUVHVLQFH$QGURLGDSSOLFDWLRQVUXQLQD
YLUWXDOPDFKLQHVLPLODUWRD-DYDYLUWXDOPDFKLQHWKHILUVWWKLQJWKDWKDSSHQVLVJDUEDJH
FROOHFWLRQZKHUHWKHPHPRU\WDNHQXSE\XQXVHGXQUHIHUHQFHGLQVWDQFHVRIREMHFWV
LVUHFRYHUHG$QGURLGDGGVDQRWKHUVWUDWHJ\WRJDUEDJHFROOHFWLRQDFWLYLW\FRPSRQHQWV
WKDWDUHQRWYLVLEOHWRWKHXVHUFDQKDYHWKHLUVWDWHVDYHGDQGWKHQWKH\DUH£GHVWUR\HG¤
ZKLFKUHDOO\MXVWPHDQVWKHV\VWHPGHOHWHVLWVUHIHUHQFHVWRWKRVHFRPSRQHQWVDQGWKH\
FDQWKHQEHJDUEDJHFROOHFWHG$QGURLGKDV\HWDQRWKHUVWUDWHJ\IRUPHPRU\UHFRYHU\
E\WHOOLQJDOOWKHFRPSRQHQWVLQDQDSSOLFDWLRQWRVDYHWKHLUVWDWHZKROHSURFHVVHVFDQ
EHGHOHWHGDQGWKHLUPHPRU\UHFRYHUHG7KLVLVKRZ$QGURLGHQDEOHVDIRUPRI£JDUEDJH
FROOHFWLRQ¤WKDWVSDQVPXOWLSOHSURFHVVHV
286 | Chapter 11:ಗA Framework for a Well-Behaved Application
)LJXUH/RJJLQJRXWSXWVKRZLQJDQHZSURFHVVDQGDFWLYLW\VWDWHEHLQJUHVWRUHG
Memory recovery and life cycles
7KHOLIHRIDQ$QGURLGDFWLYLW\VHHPVSHULORXVDQGIOHHWLQJ$QDFWLYLW\¦VSURFHVVFDQEH
NLOOHGRUWKHActivityREMHFWGHVWUR\HGVHHPLQJO\DWWKHV\VWHP¦VZKLP2QWRSRIWKDW
\RXGRQ¦WHYHQJHWDJXDUDQWHHWKDWDOO\RXUOLIHF\FOHPHWKRGRYHUULGHVZLOOJHWFDOOHG
ZKHQWKHSURFHVVLVNLOOHG
$JRRGEDVLVIRUXQGHUVWDQGLQJOLIHF\FOHVLQ$QGURLGLVWRIRFXVRQZKDWKDSSHQVZKHQ
DQActivityLQVWDQFHLVGHVWUR\HGDQGZKHQDSURFHVVLVNLOOHG
'HVWUR\LQJDQDFWLYLW\
$QDFWLYLW\LVGHVWUR\HGDQGWKHonDestroyPHWKRGLVFDOOHGZKHQ$QGURLGZDQWV
WRGLVFDUGWKLVLQVWDQFHRIWKH ActivityFODVV£'LVFDUG¤PHDQVWKDWWKH$QGURLG
V\VWHPZLOOVHWLWVUHIHUHQFHVWRWKHActivityLQVWDQFHWRQXOO$QGWKDWPHDQVWKDW
Visualizing Life Cycles | 287
XQOHVV\RXUFRGHLVKROGLQJDUHIHUHQFHWRWKLVActivityWKHActivityZLOOE\DQG
E\JHWJDUEDJHFROOHFWHG7KHZRUGGHVWUR\LVFRQIXVLQJWRVRPH¢LWLPSOLHVDF
WLYHO\ZLSLQJRXWVRPHWKLQJ
$IWHUWKH onDestroyPHWKRGLVFDOOHG\RXFDQEHVXUHWKDWWKLVLQVWDQFHRI\RXU
VXEFODVVRIActivityZLOOQRWEHXVHGDJDLQ%XWWKLVGRHVQRWQHFHVVDULO\PHDQWKDW
\RXUDSSOLFDWLRQRUWKHSURFHVVLWLVUXQQLQJLQLVJRLQJWRVWRSUXQQLQJ,QIDFW
DQHZLQVWDQFHRIWKHVDPHActivityVXEFODVVFRXOGEHLQVWDQWLDWHGDQGFDOOHG)RU
H[DPSOHWKLVKDSSHQVDOPRVWLPPHGLDWHO\DIWHUDFRQILJXUDWLRQFKDQJH FKDQJLQJ
WKHVFUHHQRULHQWDWLRQIRUH[DPSOH FDXVHVWKHSUHYLRXVO\XVHGActivityREMHFWWR
EHGHVWUR\HGVRWKDWUHVRXUFHORDGLQJFDQVWDUWDIUHVKIRUWKHQHZFRQILJXUDWLRQ
.LOOLQJDSURFHVV
:KHQDQ$QGURLGV\VWHPVWDUWVUXQQLQJRXWRIPHPRU\LWILQGVSURFHVVHVWRNLOO
7\SLFDOO\$QGURLGDSSOLFDWLRQVUXQLQVHSDUDWHSURFHVVHVVRJDUEDJHFROOHFWLRQLQ
RQHSURFHVVFDQ¦WUHDFKDOOWKHPHPRU\LQDQ$QGURLGV\VWHP7KDWPHDQVWKDWLQ
ORZPHPRU\FRQGLWLRQV$QGURLGILQGVSURFHVVHVWKDWGRQRWKDYHFRPSRQHQWV
WKDWDUHLQXVHDQGNLOOVWKHP,QH[WUHPLV$QGURLGZLOODOVRNLOOSURFHVVHVWKDWGR
KDYHFRPSRQHQWVWKDWDUHEHLQJXVHG)RUVLPSOHDSSOLFDWLRQVWKHLUSURFHVVEH
FRPHVDFDQGLGDWHIRUEHLQJNLOOHGDIWHU onPauseKDVEHHQFDOOHG7KDWLVDOOWKH
RWKHUActivityOLIHF\FOHPHWKRGVWKDWFDQEHFDOOHGDIWHUonPauseKDYHQRJXDUDQWHH
WKH\ZLOOEHFDOOHGLIWKH$QGURLGV\VWHPQHHGVWRDFTXLUHVRPHIUHHPHPRU\E\
NLOOLQJDSURFHVV
,QERWKRIWKHVHFDVHV\RXUDSSOLFDWLRQLVOLNHO\WRQHHGWRVDYHVRPHVWDWHWKDWH[LVWV
WHPSRUDULO\LQWKHXVHULQWHUIDFHRIDQDSSOLFDWLRQYDULRXVLQSXWVWKHXVHUHQWHUHGWKDW
KDYHQRW\HWEHHQSURFHVVHGWKHVWDWHRIVRPHYLVXDOLQGLFDWRUWKDWLVQRWSDUWRIWKH
GDWDPRGHODQGVRRQ7KLVLVZK\HDFKFRPSRQHQWRI\RXUDSSOLFDWLRQDQGHVSHFLDOO\
HDFKDFWLYLW\ZLOOQHHGWRRYHUULGHVRPHOLIHF\FOHPHWKRGV
Life cycle methods of the Activity class
1RZWKDWZHNQRZZKHQDQGZK\WKHOLIHF\FOHPHWKRGVDUHFDOOHGLQJHQHUDOOHW¦VORRN
DWWKHLQGLYLGXDOPHWKRGVLQWKHSUHYLRXVSURJUDPOLVWLQJDQGVHHZKDWWKH\GR
7KHonCreatePHWKRGLVFDOOHGDIWHUDQ ActivityLQVWDQFHKDVEHHQFUHDWHG7KLVLV
ZKHUHPRVWDSSOLFDWLRQVSHUIRUPPRVWRIWKHLULQLWLDOL]DWLRQUHDGLQJLQWKHOD\RXWV
DQGFUHDWLQJViewLQVWDQFHVELQGLQJWRGDWDDQGVRRQ1RWHWKDWLIWKLV Activity
LQVWDQFHKDVQRWEHHQGHVWUR\HGQRUWKHSURFHVVNLOOHGWKLVLVQRWFDOOHGDJDLQ,WLV
FDOOHGRQO\LIDQHZLQVWDQFHRIDQ ActivityFODVVLVFUHDWHG7KHDUJXPHQWWRWKLV
PHWKRGLVDBundleREMHFWWKDWFRQWDLQVVDYHGDSSOLFDWLRQVWDWH,IWKHUHLVQRVDYHG
VWDWHWKHYDOXHRIWKLVDUJXPHQWLVnull
7KH onRestart PHWKRG LV FDOOHG RQO\ LI DQ DFWLYLW\ KDV EHHQ VWRSSHG £6WRSSHG¤
PHDQVWKHDFWLYLW\LVQRWLQWKHIRUHJURXQGLQWHUDFWLQJZLWKWKHXVHU7KLVPHWKRG
LVFDOOHGEHIRUHWKHonStartPHWKRG
288 | Chapter 11:ಗA Framework for a Well-Behaved Application
7KHonStartPHWKRGLVFDOOHGZKHQWKHActivityREMHFWDQGLWVYLHZVEHFRPHYLVLEOH
WRWKHXVHU
7KH onResumePHWKRGLVFDOOHGZKHQWKH ActivityREMHFWDQGLWVYLHZVEHFRPHLQ
WHUDFWLYHZLWKWKHXVHU
7KHonPausePHWKRGLVFDOOHGZKHQDGLIIHUHQWActivityLQVWDQFHLVJRLQJWREHYLVLEOH
DQGWKHFXUUHQWActivityKDVVWRSSHGLQWHUDFWLQJZLWKWKHXVHU
7KHonStopPHWKRGLVFDOOHGZKHQDQDFWLYLW\LVQRORQJHUYLVLEOHWRRULQWHUDFWLQJ
ZLWKWKHXVHU
7KHonDestroyPHWKRGLVFDOOHGZKHQDQActivityLQVWDQFHLVJRLQJWREHGHVWUR\HG¢
QRORQJHUXVHG%HIRUHWKLVPHWKRGLVFDOOHGWKHDFWLYLW\KDVDOUHDG\VWRSSHGLQWHU
DFWLQJZLWKWKHXVHUDQGLVQRORQJHUYLVLEOHRQWKHVFUHHQ,IWKLVPHWKRGLVEHLQJ
FDOOHGDVWKHUHVXOWRIDFDOOWRfinishDFDOOWRisFinishingZLOOUHWXUQtrue
Saving and restoring instance state
0HPRU\UHFRYHU\DQGWKHFRPSRQHQWOLIHF\FOHLVZK\\RXUActivityVXEFODVVHVQHHG
WRVDYHVWDWH+HUHLVKRZDQGZKHQWKH\VKRXOGGRLW
7KHBundleFODVVH[LVWVWRKROGVHULDOL]HGGDWDLQWKHIRUPRINH\YDOXHSDLUV7KHGDWD
FDQEHSULPLWLYHW\SHVRULWFDQEHDQ\W\SHWKDWLPSOHPHQWVWKHParcelableLQWHUIDFH
VHH£3DUFHODEOH¤RQSDJH <RXFDQILQGRXWPRUHDERXW BundleRQWKH$QGURLG
'HYHORSHUV VLWH DW KWWSGHYHORSHUDQGURLGFRPUHIHUHQFHDQGURLGRV%XQGOHKWPO ,Q
VDYLQJActivityLQVWDQFHVWDWH\RXZLOOXVHWKH£SXW¤PHWKRGVRIWKHBundleFODVV
,QWKHFDOOWR onCreateDQGLQWKHFDOOWR onRestoreInstanceStateD BundleREMHFWLV
SDVVHGWRWKHPHWKRG,WFRQWDLQVGDWDWKDWDSUHYLRXVLQVWDQFHRIWKHVDPH Activity
FODVVSXWWKHUHLQRUGHUWRVWRUHLWDFURVVLQVWDQWLDWLRQV7KDWLVLIDQActivityLQVWDQFH
KDVVWDWHDSDUWIURPZKDWLVSHUVLVWHGLQDGDWDPRGHOLWFDQEHVDYHGDQGUHVWRUHG
DFURVVPXOWLSOHLQVWDQFHVRIWKDWActivityFODVV7RWKHXVHULWORRNVOLNHVKHKDVSLFNHG
XSULJKWZKHUHVKHOHIWRIIEXWVKHPD\EHORRNLQJDWDQHQWLUHO\QHZLQVWDQFHRIDQ
ActivityFODVVSRVVLEO\LQDQHQWLUHO\QHZSURFHVV
<RXPD\KDYHQRWLFHGWKDWWKH onPauseOLIHF\FOHPHWKRGGRHVQRWSURYLGHD Bundle
REMHFWIRUVWRULQJVWDWH6RZKHQLVVWDWHVWRUHG"7KHUHDUHVHSDUDWHPHWKRGVLQWKH
ActivityFODVVIRUVDYLQJVWDWHDQGIRUEHLQJQRWLILHGWKDWVWDWHLVEHLQJUHVWRUHG
7KLV LV ZKHUH DQ DSSOLFDWLRQ JHWV D FKDQFH WR VDYH LQVWDQFH VWDWH ,QVWDQFH VWDWH
VKRXOGEHVWDWHWKDWLVQRWSHUVLVWHGZLWKDQDSSOLFDWLRQ¦VGDWDPRGHOVXFKDVWKH
VWDWH RI DQ LQGLFDWRU RU RWKHU VWDWH WKDW LV RQO\ SDUW RI WKH Activity REMHFW 7KLV
PHWKRG KDV DQ LPSOHPHQWDWLRQ LQ WKH SDUHQW FODVV LW FDOOV WKH onSaveInstance
StatePHWKRGRIHDFKViewREMHFWLQWKLVLQVWDQFHRIActivityZKLFKKDVWKHUHVXOW
RIVDYLQJWKHVWDWHRIWKHVHViewREMHFWVDQGWKLVLVRIWHQWKHRQO\VWDWH\RXQHHGWR
VWRUHWKLVZD\'DWDWKDW\RXUVXEFODVVQHHGVWRVWRUHLVVDYHGXVLQJWKH£SXW¤PHWK
RGVRIWKHBundleFODVV
Visualizing Life Cycles | 289
The onRestoreInstanceStatePHWKRGLVFDOOHGZKHQWKHUHLVLQVWDQFHVWDWHWREHUH
VWRUHG,IWKLVPHWKRGLVFDOOHGLWLVFDOOHGDIWHU onStartDQGEHIRUH onPostCreate
ZKLFKLVDPLQRUOLIHF\FOHPHWKRGGHVFULEHGLQ£0LQRUOLIHF\FOHPHWKRGVRIWKH
$FWLYLW\FODVV¤RQSDJH
Configuration changes and the activity life cycle
3UHYLRXVO\ZHFRYHUHGKRZ\RXFDQSURYRNHWKH$QGURLGV\VWHPLQWRNLOOLQJWKHSURF
HVVWKDW\RXUDFWLYLW\DQGHYHU\RWKHUFRPSRQHQWRI\RXUDSSOLFDWLRQLVUXQQLQJLQE\
ODXQFKLQJHQRXJKDSSOLFDWLRQVWKDWVRPHSURFHVVHVDUHNLOOHG7KHORJV\RXZRXOGVHH
DQGWKHRQHLQWKHVFUHHQVKRWLQ)LJXUHVKRZWKDWWKHSURFHVV,'FKDQJHVDQG
WKDWDQHZLQVWDQFHRIWKHActivityVXEFODVVWKDWGHILQHVKRZWKLVDSSOLFDWLRQLQWHUDFWV
ZLWKWKHXVHULVFUHDWHG7KLVQHZLQVWDQFHUHORDGVDOOWKHUHVRXUFHVIRUWKLVDFWLYLW\
DQGLIWKHUHZHUHDQ\DSSOLFDWLRQGDWDWREHORDGHGWKDWZRXOGEHORDGHGDQHZWRR
7KHQHWHIIHFWLVWKDWWKHXVHUSURFHHGVDVWKRXJKQRWKLQJKDVKDSSHQHGWKHQHZLQ
VWDQFHORRNVOLNHWKHROGRQHEHFDXVHLWKDVWKHVDPHVWDWH
7KHUH LV DQRWKHU ZD\ WR IRUFH $QGURLG WR XVH D QHZ Activity LQVWDQFH FKDQJH WKH
FRQILJXUDWLRQRIWKHV\VWHP7KHPRVWFRPPRQFRQILJXUDWLRQFKDQJHDSSOLFDWLRQVHQ
FRXQWHULVDFKDQJHLQVFUHHQRULHQWDWLRQ%XWWKHUHDUHPDQ\GLPHQVLRQVWRZKDWFRXQWV
DVDQHZFRQILJXUDWLRQFKDQJHVLQZKHWKHUDKDUGNH\ERDUGLVDFFHVVLEOHRUQRWFKDQJHV
LQORFDOHFKDQJHVLQIRQWVL]HDQGPRUH7KHFRPPRQIDFWRULQDOOFKDQJHVWRFRQILJ
XUDWLRQLVWKDWWKH\FDQUHTXLUHUHVRXUFHVWREHUHORDGHGXVXDOO\EHFDXVHWKH\QHHG
OD\RXWVWREHUHFDOFXODWHG
7KHHDVLHVWZD\WRPDNHVXUHHYHU\UHVRXUFHXVHGLQDQDFWLYLW\LVORDGHGDQHZLQOLJKW
RIWKHQHZFRQILJXUDWLRQLVIRUWKHFXUUHQWLQVWDQFHRIWKHDFWLYLW\WREHGLVFDUGHGDQG
DQHZLQVWDQFHFUHDWHGVRWKDWLWUHORDGVDOOUHVRXUFHV7RFDXVHWKLVWRRFFXUZKLOH
UXQQLQJWKHDSSOLFDWLRQLQDQHPXODWRUSUHVVWKHNH\RQWKHQXPHULFNH\SDG7KLV
FKDQJHVWKHVFUHHQRULHQWDWLRQLQWKHHPXODWRU,QWKHORJ\RXZLOOVHHVRPHWKLQJOLNH
ZKDW LV LQ WKH VFUHHQVKRW LQ )LJXUH <RX ZLOO VHH LQ WKH ORJ WKDW WKH onDestroy
PHWKRGLVFDOOHGVLQFHWKHActivityLQVWDQFHLVGLVFDUGHGDVSDUWRIFKDQJLQJFRQILJX
UDWLRQVQRWZKHQWKHV\VWHPUXQQLQJORZRQPHPRU\NLOOVWKHSURFHVV<RXZLOODOVR
QRWLFHWKDWDFURVVQHZLQVWDQFHVRIWKHActivityREMHFWWKHSURFHVV,'VWD\VWKHVDPH¢
WKHV\VWHPKDVQRQHHGWRUHFRYHUWKHPHPRU\WKHDSSOLFDWLRQLVXVLQJ
7KLVDSSURDFKPD\VHHPSURIOLJDWHDQHZLQVWDQFHRIWKH Activity":KDWIRU":K\
FDQ¦W,SUHVHUYHWKLVLQVWDQFH",VQ¦WWKDWJRLQJWREHVORZ",QPRVWFDVHVKRZHYHUWKH
UHVRXUFHV ORDGHG E\ DQ DFWLYLW\ ZKHQ LW VWDUWV FRQVWLWXWH PRVW RI WKH VWDWH RI WKDW
ActivityLQVWDQFH,QPDQ\FDVHVWKHODUJHVWDPRXQWRIFRPSXWDWLRQWKDWWDNHVSODFH
LQDQDFWLYLW\KDSSHQVZKHQLWUHDGVWKH;0/ILOHDQGFDOFXODWHVOD\RXWV$QGLQPRVW
FDVHVDFRQILJXUDWLRQFKDQJHVXFKDVVFUHHQRULHQWDWLRQRUORFDOHFKDQJHUHTXLUHVQHDUO\
HYHU\UHVRXUFHWRKDYHLWVOD\RXWUHFDOFXODWHG6RWXUQLQJDFRQILJXUDWLRQFKDQJHLQWR
ZKDWDPRXQWVWRDUHVWDUWRIDQDFWLYLW\LVLQHYLWDEOHDVLVWKHDPRXQWRISURFHVVLQJ
WKDWJRHVLQWRWKDWUHVWDUW
290 | Chapter 11:ಗA Framework for a Well-Behaved Application
)LJXUH7KH3,'UHPDLQLQJXQFKDQJHGZKHQWKHRQ'HVWUR\PHWKRGLVFDOOHG
.HHSLQPLQGWKDWWKHRQO\WKLQJJRLQJRQZKHQ$QGURLG£GHVWUR\V¤DQDFWLYLW\LVWKDW
WKHUHIHUHQFHWRWKHDFWLYLW\LVGLVFDUGHGHYHQWXDOO\WREHJDUEDJHFROOHFWHG(YHU\WLPH
WKHXVHUPRYHVIURPRQHDFWLYLW\WRDQHZDFWLYLW\DOOWKHFRPSXWDWLRQWKDWJRHVLQWR
FUHDWLQJWKDWQHZDFWLYLW\LVSHUIRUPHG'RLQJWKHVDPHZKHQDFRQILJXUDWLRQFKDQJH
RFFXUVLVQRWDQH[WUDRUGLQDU\DPRXQWRIZRUNIRUWKHV\VWHP
Minor life cycle methods of the Activity class
6HYHUDODGGLWLRQDOPHWKRGVRWKHUWKDQWKHPDLQOLIHF\FOHPHWKRGVXVHGLQWKH$QGURLG
GRFXPHQWDWLRQWRGHVFULEHWKHDFWLYLW\OLIHF\FOHDUHDOVRFDOOHGDVDQDFWLYLW\PRYHV
WKURXJKLWVOLIHF\FOH
7KHonPostCreatePHWKRGLVFDOOHGDIWHUonRestoreInstanceStateLVFDOOHG,WPD\EH
XVHIXOLI\RXUDSSOLFDWLRQUHTXLUHVWKDWVWDWHEHUHVWRUHGLQWZRVWDJHV,WLVSDVVHGD
BundleREMHFWFRQWDLQLQJLQVWDQFHVWDWH
7KHonPostResumePHWKRGLVFDOOHGDIWHUonResumeZKHQWKHActivityLQVWDQFHVKRXOG
EHYLVLEOHDQGLVLQWHUDFWLQJZLWKWKHXVHU
7KHonUserLeaveHintPHWKRGLVFDOOHGLIDQDFWLYLW\LVJRLQJWRVWRSEHLQJYLVLEOHDQG
LQWHUDFWLQJZLWKWKHXVHUGXHWRWKHXVHU¦VDFWLRQV¢IRUH[DPSOHSUHVVLQJWKHEDFN
RUKRPHKDUGNH\V7KLVLVDFRQYHQLHQWSODFHWRFOHDUDOHUWVDQGGLDORJV
Visualizing Life Cycles | 291
<RXFDQVHHLQWKHSURJUDPOLVWLQJLQ)LJXUHWKDWZHKDYHLPSOHPHQWHGRYHUULGHV
RIWKHVHPHWKRGVLQRUGHUWRORJZKHQWKH\DUHFDOOHG7KHVHPHWKRGVH[LVWIRUFDVHV
ZKHUHIRUH[DPSOH\RXQHHGDQDGGLWLRQDOVWDJHIRUUHVWRULQJLQVWDQFHVWDWH
+RZHYHULI\RXUHDOO\QHHGWRSUHVHUYHVRPHGDWDDFURVVFRQILJXUDWLRQFKDQJHVDQG
LWLVQ¦WSDUWRIWKHVWDWHWKDWJHWVVWRUHGLQWKHBundleREMHFWEHWZHHQLQVWDQFHVDQGLW
LVQ¦WSDUWRIWKHGDWDPRGHOWKDWZRXOGJHWVDYHG\RXFDQXVHWKH onRetainNonConfi
gurationInstancePHWKRGWR£VWDVK¤DUHIHUHQFHWRDQREMHFW7KLVUHIHUHQFHFDQWKHQ
EHUHTXHVWHGE\DQHZ ActivityLQVWDQFHXVLQJWKH getLastNonConfigurationInstance
PHWKRG
7KHonRetainNonConfigurationInstancePHWKRGLVFDOOHGDIWHUonStopZKLFKPHDQV
WKHUH LV QR JXDUDQWHH LW ZLOO EH FDOOHG QRU HYHQ LI LW LV FDOOHG WKDW WKH UHIHUHQFH
UHWXUQHGZLOOEHSUHVHUYHGDQGSURYLGHGWRWKHVXEVHTXHQW ActivityLQVWDQFH7KH
getLastNonConfigurationInstance()PHWKRGFDQEHFDOOHGLQWKHonCreatePHWKRG
RUVXEVHTXHQWO\ZKHQUHVWRULQJDFWLYLW\VWDWH
7RLOOXVWUDWHWKHXVHRIWKHVHPHWKRGVZHUHWXUQDQREMHFWFRQWDLQLQJWKHWDVN,'RI
WKH DFWLYLW\ ZKHQ onRetainNonConfigurationInstance LV FDOOHG DQG ZKHQ onRestore
InstanceState(Bundle)LVFDOOHGZHFKHFNLWWRVHHWKDWWKHWDVN,'KDVQRWFKDQJHG
7KLVFRQILUPVWKDWHYHQLIWKHLQVWDQFHRIWKHFRPSRQHQWRUHYHQRIWKHZKROHSURFHVV
LVGLIIHUHQWWRWKHXVHULW¦VWKHVDPHWDVN
7KHPRVWFRPPRQO\FLWHGXVHFDVHIRUXVLQJWKHVHPHWKRGVLVWRVWRUHWKHUHVXOWVRID
ZHETXHU\\RXFRXOGUHGRWKHTXHU\EXWWKHODWHQF\RIDTXHU\WRDZHEVHUYHUPLJKW
EHDIHZVHFRQGV6RZKLOHWKHGDWDFDQEHUHFUHDWHGLIWKHV\VWHPFDQQRWSUHVHUYHLW
IRUWKHQHZActivityREMHFWLQVWDQFHWRUHWULHYHWKHUHLVDVLJQLILFDQWXSVLGHWRFDFKLQJ
LW+RZHYHULQWKLVERRNZHVKRZ\RXLQ&KDSWHUKRZWRLQWHUSRVHDORFDOGDWDEDVH
DVDFDFKHLQ5(67IXODSSOLFDWLRQVUHGXFLQJWKHQHHGIRUWKLVNLQGRIRSWLPL]DWLRQ
Visualizing the Fragment Life Cycle
,I\RXDUHGHYHORSLQJIRU$QGURLG£+RQH\FRPE¤$3,OHYHORUODWHUWKH)UDJPHQW
$3,LVDYDLODEOH,IKRZHYHU\RXSUHIHUWRGHYHORSIRUDSUH+RQH\FRPEYHUVLRQRI
$QGURLGDQGZRXOGOLNHWRXVHFragmentREMHFWVLQ\RXUXVHULQWHUIDFH\RXFDQXVHWKH
$QGURLG&RPSDWLELOLW\3DFNDJHDVGHVFULEHGLQ&KDSWHU7KHH[DPSOHFRGHIRUWKLV
FKDSWHULVSURYLGHGLQWZRIRUPVRQHWKDWLVVHWXSWRZRUNZLWK$3,OHYHODVWKH
WDUJHW$3,DQGRQHWKDWFDQEHWDUJHWHGWR$3,OHYHOVDVORZDV$3,OHYHOFRUUHVSRQGLQJ
WR$QGURLG<RXZLOOILQGWKHIROORZLQJFragmentFRGHLGHQWLFDOH[FHSWIRUWKHSDFN
DJH GHFODUDWLRQ IRU WKH Fragment FODVV DQG \RX ZLOO ILQG LW EHKDYHV LGHQWLFDOO\ ZLWK
UHVSHFWWRWKHFragmentOLIHF\FOH
7KLVFRGHOLNHWKHActivityFODVVSUHVHQWHGHDUOLHULQVWUXPHQWVWKHOLIHF\FOHFDOOEDFNV
VRWKDWWKH\FDQEHREVHUYHGDVWKHSURJUDPUXQV
292 | Chapter 11:ಗA Framework for a Well-Behaved Application
package com.oreilly.demo.pa.ch10.finchlifecycle;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TestFragment extends Fragment {
// get a label for our log entries
private final String TAG = this.getClass().getSimpleName();
public TestFragment() {
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.i(TAG, "onAttach");
}
@Override
public void onCreate(Bundle saved) {
super.onCreate(saved);
if (null != saved) {
// Restore state here
}
Log.i(TAG, "onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle saved) {
View v = inflater.inflate(R.layout.fragment_content, container, false);
Log.i(TAG, "onCreateView");
return v;
}
@Override
public void onActivityCreated(Bundle saved) {
super.onActivityCreated(saved);
Log.i(TAG, "onActivityCreated");
}
@Override
public void onStart() {
super.onStart();
Log.i(TAG, "onStart");
}
@Override
Visualizing the Fragment Life Cycle | 293
public void onResume() {
super.onResume();
Log.i(TAG, "onResume");
}
@Override
public void onPause() {
super.onPause();
Log.i(TAG, "onPause");
}
@Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop");
}
// ////////////////////////////////////////////////////////////////////////////
// Called during the life cycle, when instance state should be saved/restored
// ////////////////////////////////////////////////////////////////////////////
@Override
public void onSaveInstanceState(Bundle toSave) {
super.onSaveInstanceState(toSave);
Log.i(TAG, "onSaveinstanceState");
}
}
$V\RXGLGZLWKWKH/RJ&DWILOWHUIRUILQGLQJWKHORJHQWULHVWKDWVKRZ$FWLYLW\FRPSR
QHQWFDOOEDFNV\RXZLOOVHWXSDILOWHUIRUFragmentFDOOEDFNV
,I\RXUHSHDWWKHVWHSV\RXWRRN¢VWDUWLQJRWKHUDSSOLFDWLRQVXQWLO\RXVHHLQWKH/RJ&DW
ZLQGRZWKDWWKHFragmentOLIHF\FOHPHWKRGVDUHEHLQJFDOOHG¢\RXZLOOVHHWKDWHDFK
Fragment LQVWDQFH LQ DQ Activity LQVWDQFH EHKDYHV OLNH WKH HQFORVLQJ Activity ZLWK
UHVSHFWWRWKHViewsLWFRQWDLQV6LPLODUOLIHF\FOHWUDQVLWLRQVDQGVWDWHVDUHFDOOHG
/HW¦VWDNHDORRNDWHDFKPHWKRGWKDWJHWVFDOOHGQRZWKDWZHNQRZZKHQWKH\DUH
FDOOHG
7KH onAttach PHWKRG LV FDOOHG ZKHQ WKH Fragment LQVWDQFH LV DVVRFLDWHG ZLWK DQ
ActivityLQVWDQFH7KLVGRHVQRWPHDQWKHActivityLVIXOO\LQLWLDOL]HG
7KH onCreatePHWKRGLVFDOOHGZKHQWKH FragmentLQVWDQFHLVEHLQJFUHDWHGRUUH
FUHDWHG,ILWLVEHLQJUHFUHDWHGDIWHUWKHFragmentRUWKHFRQWDLQLQJActivityFRP
SRQHQWKDVEHHQGHVWUR\HGWKHEXQGOHDUJXPHQWZLOOEHQRQQXOOLIDQ\VWDWHKDG
EHHQVDYHG
7KH onCreateViewPHWKRGLVFDOOHGZKHQWKH FragmentLQVWDQFHVKRXOGFUHDWHWKH
ViewREMHFWKLHUDUFK\LWFRQWDLQV FragmentKDVDQXQXVXDOUROHLQDQ ActivityLW
EHKDYHVVRPHZKDWOLNHDViewGroupEXWLWLVQ¦WSDUWRIWKHViewFODVVKLHUDUFK\<RX
FDQWKLQNRILWDVHQDEOLQJWKHActivityWRFRQWDLQPXOWLSOHVHWVRIViewLQVWDQFHV,Q
RXUH[DPSOHZHORDGDQH[WUHPHO\VLPSOHOD\RXWFRQWDLQLQJDTextView
294 | Chapter 11:ಗA Framework for a Well-Behaved Application
7KH onActivityCreated PHWKRG LV FDOOHG ZKHQ WKH Activity FRQWDLQLQJ WKH
Fragment LQVWDQFH KDV EHHQ FUHDWHG DQG WKH View REMHFWV FRQWDLQHG E\ WKH Frag
mentKDYHEHHQFUHDWHG$WWKLVSRLQWLWLVVDIHWRVHDUFKIRUViewREMHFWVE\WKHLU,'
IRUH[DPSOH
7KHonStartPHWKRGLVFDOOHGZKHQWKHFragmentEHFRPHVYLVLEOHLQDYHU\VLPLODU
ZD\WRWKHActivityPHWKRGonStart
7KHonResumePHWKRGLVFDOOHGZKHQWKHFragmentEHFRPHVYLVLEOHDQGLVUXQQLQJ
7KH onPause PHWKRG DOVR LV FDOOHG XQGHU WKH VDPH FRQGLWLRQV DV DQ Activity
LQVWDQFH¦V onPause PHWKRG ZKHQ WKH Fragment LV DERXW WR EH WDNHQ RXW RI WKH
IRUHJURXQG
7KHonStopPHWKRGLVFDOOHGZKHQWKHFragmentLVDERXWWRVWRSUXQQLQJ
7KHonSaveInstanceStatePHWKRGLVFDOOHGZKHQLWLVQHFHVVDU\WRVDYHLQVWDQFHVWDWH
VRWKDWLIWKHLQVWDQFHLVGHVWUR\HG UHDOO\MXVWGHUHIHUHQFHG DQ\FODVVVSHFLILFVWDWH
WKDWQHHGVWREHVWRUHGFDQEHVWRUHGLQWKHBundleREMHFWSDVVHGWRWKLVFDOO
)UDJPHQWREMHFWVDUHQRWFRPSRQHQWV<RXFDQWKLQNRIWKHPDVDZD\RIEUHDNLQJXS
DQ ActivityREMHFWLQWRPXOWLSOHREMHFWVFRQWDLQHGZLWKLQDQ ActivityHDFKZLWKLWV
RZQViewKLHUDUFK\WKDWEHKDYHVOLNHLWLVLQVLGHDQActivity
The Activity Class and Well-Behaved Applications
8QGHUVWDQGLQJ DSSOLFDWLRQ OLIH F\FOHV LV NH\ WR LPSOHPHQWLQJ ZHOOEHKDYHG DSSOLFD
WLRQVDQGLWLVDOVRNH\WRXQGHUVWDQGLQJPLVEHKDYLQJDSSOLFDWLRQV/DJJLQJSHUIRUP
DQFH H[FHVVLYH UHVRXUFH XVH DQG XQH[SHFWHG XVHU LQWHUIDFH EHKDYLRU FDQ RIWHQ EH
GLDJQRVHGE\REVHUYLQJWKHDSSOLFDWLRQ¦VOLIHF\FOH/LIHF\FOHLVGLIILFXOWWRXQGHUVWDQG
MXVWE\ORRNLQJDWFRGHRUWKHGRFXPHQWDWLRQSDJHIRUWKH ActivityFODVV7RHQDEOH
\RXWRREVHUYHOLIHF\FOHDVLWLVKDSSHQLQJZHZLOOSXWORJJLQJFDOOVLQWRRXULPSOH
PHQWDWLRQVRI$QGURLGOLIHF\FOHPHWKRGVUXQWKHSURJUDPVDQGREVHUYHKRZOLIHF\FOH
ZRUNVLQDUXQQLQJSURJUDP,QXVLQJWKLVIUDPHZRUN\RXFDQOHDYHWKHVHORJJLQJFDOOV
LQ\RXUDSSOLFDWLRQ¦VFRGHDV\RXGHYHORSLWEHFDXVHDSSOLFDWLRQVRIWHQFRPHWRQHHG
ORJJLQJLQWKHVHPHWKRGVWRGLDJQRVHSUREOHPV
0RVW RI WKH PHWKRGV FDOOHG RQ FKDQJHV LQ OLIH F\FOH DUH LPSOHPHQWHG RQ D SHU
FRPSRQHQWEDVLVDQGVRPHRQDSHUSURFHVVEDVLV(DFKW\SHRIFRPSRQHQW¢Serv
ice BroadcastReceiver ContentProvider DQG Activity¢KDV LWV RZQ OLIH F\FOH /LIH
F\FOHVRIFRPSRQHQWVRWKHUWKDQ ActivityDUHFRYHUHGLQ&KDSWHU0RVWOLIHF\FOHV
DUHVLPSOHUWKDQWKHActivityOLIHF\FOH7KLVLVEHFDXVHWKHActivityFODVVLQWHUDFWVZLWK
WKHXVHUDQGZKHQDQActivityLVQRORQJHUDYLVLEOHSDUWRIWKHXVHULQWHUIDFHLWLVOLNHO\
WKDWWKHPHPRU\RFFXSLHGE\UHVRXUFHVDVVRFLDWHGZLWKWKDW ActivityLQVWDQFHFRXOG
EHVFDYHQJHGLIQHHGHG0DQDJLQJPHPRU\RFFXSLHGE\UHVRXUFHVUHODWHGWRFRPSR
QHQWVLVRQHRIWKHSULQFLSDOSXUSRVHVRIFRPSRQHQWOLIHF\FOHV
The Activity Class and Well-Behaved Applications | 295
The Activity Life Cycle and the User Experience
,QIDFWLI\RXUDSSOLFDWLRQLVZHOOGHVLJQHGIRUWKHPRELOHHQYLURQPHQWLQJHQHUDOLW
ZLOOQHHGOHVVFRGHLQDSSOLFDWLRQOLIHF\FOHPDQDJHPHQW
‡ ,IWKHGDWDXVHGE\DQDFWLYLW\LVDOZD\VXSWRGDWHDQGLQDGDWDEDVH\RXZLOOQRW
KDYHWRH[SOLFLWO\VWRUHLWLQWKHFRGHLQDQDSSOLFDWLRQOLIHF\FOHPHWKRG
‡ ,I\RXUXVHULQWHUIDFHKDVPLQLPDOVWDWH\RXZRQ¦WKDYHWRVDYHPXFKLIDQ\VWDWH
LQDQDFWLYLW\OLIHF\FOHPHWKRG
7KHVHVHHPOLNHVWULQJHQWFRQVWUDLQWVEXWLQPRELOHDQGRWKHUDSSOLDQFHOLNHGHYLFHV
WKH\DUHQRW7KHEDWWHU\RQDPRELOHSKRQHFDQGLHDWDQ\WLPHDQGWKHOHVVDQDSSOL
FDWLRQ¦VGDWDPRGHODQGVWDWHDUHKHOGLQPHPRU\WKHOHVVWKHXVHUZLOOORVHZKHQWKH
GHYLFHVKXWVRIIXQH[SHFWHGO\$PRELOHXVHUPD\EHLQWHUUXSWHGE\DSKRQHFDOODQG
WKHXVHUZLOOQHYHUJHWDFKDQFHWRUHWXUQWRDQDSSOLFDWLRQWRSHUIRUPRSHUDWLRQVWKDW
VDYHGDWD0RELOHDSSOLFDWLRQVDUHQRWLQWHQGHGWRZRUNOLNHW\SLFDOLQWHUDFWLYHDSSOL
FDWLRQVRQSHUVRQDOFRPSXWHUVZLWKGRFXPHQWVRQILOHV\VWHPVWKDWEHFRPHLQPHPRU\
GDWDPRGHOVWREHH[SOLFLWO\VDYHGRUHOVHWKHGDWDLVORVW
,QWKLVFKDSWHUDQGWKHQH[W\RXZLOOVHHWKDWDSSOLFDWLRQOLIHF\FOHWKHGDWDPRGHODQG
RWKHUDVSHFWVRIDSSOLFDWLRQDUFKLWHFWXUHDQGWKHXVHUH[SHULHQFHDUHDOOLQWHUWZLQHG
DQGWKDWWKHSDWKRIOHDVWUHVLVWDQFHDQGOHDVWLPSOHPHQWDWLRQLQOLIHF\FOHPHWKRGV
OHDGVWRDSSOLFDWLRQLPSOHPHQWDWLRQVWKDWDUHUREXVWDUHHDV\WRXVHDUHJRRGFLWL]HQV
RIWKH$QGURLGHQYLURQPHQWDQGSHUIRUPZHOO,I\RXWUHDWDEDWWHU\IDLOXUHWKHVDPH
DVWKHXVHUQRORQJHUXVLQJDQDFWLYLW\RUWKHVDPHDVWKHV\VWHPNLOOLQJDQDFWLYLW\WR
FODZEDFNPHPRU\DQGRWKHUV\VWHPUHVRXUFHV\RXZLOOVLPSOLI\\RXULPSOHPHQWDWLRQ
DQGXQEXUGHQWKHXVHU([SOLFLWDFWLRQVVXFKDV£VDYH¤DQG£TXLW¤VKRXOGEHDYRLGHG
LQWKHPRELOHXVHUH[SHULHQFHDQGLQWKHLPSOHPHQWDWLRQRIZHOOEHKDYHGDSSOLFDWLRQV
Life Cycle Methods of the Application Class
7KHOLIHF\FOHPHWKRGVRIWKH ApplicationFODVVDUHDQGVKRXOGEHLQIUHTXHQWO\XVHG
LQVLPSOHDSSOLFDWLRQV$QGWKH\VKRXOGEHXVHGZLWKUHVWUDLQWHYHQLQFRPSOH[DSSOL
FDWLRQV,VLVHDV\WREORDWApplicationFODVVRYHUULGHVZLWKGDWDWKDWKDQJVDURXQGLQ
PHPRU\DFURVVPXOWLSOHDFWLYLWLHV7KLVGHIHDWV$QGURLG¦VDELOLW\WRPDQDJHUHVRXUFHV
RQDSHUFRPSRQHQWEDVLV)RUH[DPSOHLI\RXPRYHWKHUHIHUHQFHWRVRPHGDWDIURP
DQActivityREMHFWWRWKHApplicationREMHFWDOO\RXKDYHGRQHLVH[WHQGWKHV\VWHP¦V
FKDVHIRUUHVRXUFHVLQDORZPHPRU\VLWXDWLRQWRWKHDSSOLFDWLRQOLIHF\FOHDQG\RX
PXVWPDQDJHWKLVGDWDVHSDUDWHO\IURPWKHDFWLYLW\OLIHF\FOH
+HUHZHLPSOHPHQWWKHOLIHF\FOHPHWKRGVRIWKHApplicationFODVVWRVKRZWKHLUSODFH
LQ WKH $QGURLG DSSOLFDWLRQ OLIH F\FOH DQG EHFDXVH ORJJLQJ LQIRUPDWLRQ IURP WKHVH
PHWKRGVPD\EHXVHIXO
package com.finchframework.finch;
296 | Chapter 11:ಗA Framework for a Well-Behaved Application
import android.app.Application;
import android.content.res.Configuration;
import android.util.Log;
/**
* @author zigurd
*
*
This the framework's Application subclass. This illustrates what
*
you may need to do in an Application subclass.
*
*
To get this class instantiated, you must refer to it in the
*
application tag of the manifest.
*/
public class FinchApplication extends Application {
private final String TAG = this.getClass().getSimpleName();
@Override
public void onCreate() {
// First, call the parent class
super.onCreate();
// This is a good place to put code that must manage global data across
// multiple activities, but it's better to keep most things in a
// database, rather than in memory
Log.i(TAG, "onCreate");
}
@Override
public void onTerminate() {
Log.i(TAG, "onTerminate");
}
@Override
public void onLowMemory() {
// In-memory caches should be thrown overboard here
Log.i(TAG, "onLowMemory");
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.i(TAG, "onConfigurationChanged");
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, newConfig.toString());
}
}
}
(DUOLHU ZH PHQWLRQHG WKDW PDQ\ DSSOLFDWLRQV FDQ GR ZLWKRXW VXEFODVVLQJ
Application %HFDXVH RI WKLV WKH 1HZ $QGURLG 3URMHFW :L]DUG GRHV QRW FUHDWH DQ
ApplicationVXEFODVVQRUGRHVLWDGGDUHIHUHQFHWRLWLQWKHPDQLIHVW/LNHWKHLQLWLDO
REMHFWWKDWJHWVVWDUWHGZKHQDQLQWHUDFWLYHDSSOLFDWLRQVWDUWVWKHApplicationVXEFODVV
Life Cycle Methods of the Application Class | 297
Download from Wow! eBook <www.wowebook.com>
\RXFUHDWHJHWVLQVWDQWLDWHGE\WKH$QGURLGV\VWHPDVSDUWRIODXQFKLQJDQDSSOLFDWLRQ
,QPXFKWKHVDPHZD\DV$QGURLGKDQGOHV ActivityVXEFODVVHVLWNQRZVZKLFKFODVV
WRPDNHDQLQVWDQFHRIDQGXVHVWKH android:nameSURSHUW\RIWKH applicationWDJLQ
WKHPDQLIHVW7KHHDVLHVWZD\WRJHWWKLVULJKWLVE\XVLQJWKH$SSOLFDWLRQWDERIWKH
PDQLIHVWHGLWRU7KHILUVWILHOGRQWKDWHGLWLQJWDELVODEHOHG1DPH VHH)LJXUH &OLFNLQJWKH%URZVHEXWWRQQH[WWRWKDWILHOGVKRZVWKHApplicationVXEFODVVHVLQ\RXU
DSSOLFDWLRQ
)LJXUH7KH1DPHILHOGRQWKH$SSOLFDWLRQWDERIWKHPDQLIHVWHGLWRUZKHUH\RXHQWHUWKHQDPH
RIWKH$SSOLFDWLRQVXEFODVV\RXKDYHGHILQHG
$VZLWKWKHActivityFODVV¦VOLIHF\FOHPHWKRGVLWLVPRVWUHYHDOLQJWRNQRZZKHQOLIH
F\FOHPHWKRGVJHWFDOOHG<RXFDQRIFRXUVHILQGWKLVRXWE\GHEXJJLQJDQDSSOLFDWLRQ
298 | Chapter 11:ಗA Framework for a Well-Behaved Application
DQGVHWWLQJEUHDNSRLQWVLQHDFKPHWKRGEXWRIWHQWKHPRVWLQIRUPDWLYHLQIRUPDWLRQLV
IRXQGE\ORRNLQJDWORQJUXQQLQJDSSOLFDWLRQV¦EHKDYLRUDQGILOWHULQJDORJE\WKHWDJV
XVHGLQWKHActivityDQGApplicationVXEFODVVHVWRJHWDQLGHDRIZKHQOLIHF\FOHPHWK
RGVKDYHEHHQFDOOHG
7ZR RI WKH PRVW LQWHUHVWLQJ FDOOEDFNV WR WUDFN LQ WKH Application FODVV DUH onLowMe
moryDQGonTerminateZKLFKZLOOWHOO\RXZKHQREYLRXVO\HQRXJKWKHV\VWHPWKLQNV
LWLVLQDORZPHPRU\FRQGLWLRQDQGZKHQ\RXUDSSOLFDWLRQWHUPLQDWHV7KHVHFRQG
VLWXDWLRQ LV XVXDOO\ QRW REYLRXV EHFDXVH PRVW $QGURLG DSSOLFDWLRQV GR QRW QHHG WR
H[SOLFLWO\H[LWVLQFH$QGURLG¦VPHPRU\PDQDJHPHQWLQFRQFHUWZLWKFRPSRQHQWOLIH
F\FOHVLVHQRXJKWRVZHHSRXWXQXVHGFRGHLILWZDVFRUUHFWO\LPSOHPHQWHGZLWKUHVSHFW
WROLIHF\FOHDQGPHPRU\PDQDJHPHQW
A Flowing and Intuitive User Experience Across Activities
$IWHUWKHEDVLFVRIWKHOLIHF\FOHRIDQDFWLYLW\QDYLJDWLRQDQGIORZIURPRQHDFWLYLW\WR
DQRWKHULVWKHQH[WPRVWIXQGDPHQWDODVSHFWRIWKHDUFKLWHFWXUHRI$QGURLGDSSOLFD
WLRQVDQGLWJRHVKDQGLQKDQGZLWKOLIHF\FOH,QDPRELOHGHYLFHZLWKDVPDOOVFUHHQ
DQLQWXLWLYHIORZDPRQJPXOWLSOHVFUHHQVLVNH\WRPD[LPL]LQJWKHYLVXDOLQIRUPDWLRQ
WKHXVHUFDQDFFHVVDQGXVH:KHQDSSOLFDWLRQVDUHFRUUHFWO\LPSOHPHQWHGDQGPD[L
PDOO\FRRSHUDWLYHDXVHUPD\QDYLJDWHDPRQJVHYHUDODFWLYLWLHVHDFKRIZKLFKLVLP
SOHPHQWHGLQDVHSDUDWHDSSOLFDWLRQDQGWKLQNKHKDVXVHGRQO\RQHDSSOLFDWLRQ
Multitasking in a Small-Screen Environment
.HHSLQJWUDFNRIPXOWLSOHWDVNV¢PXOWLSOHSURJUDPVGRFXPHQWVDQGVRIRUWK¢LQD
SHUVRQDOFRPSXWHU¦VXVHULQWHUIDFHLVVRPHWKLQJVRFRPPRQSODFHWKDW\RXPD\QRW
WKLQNPXFKDERXWKRZLWLVDFFRPSOLVKHG0XOWLSOHGRFXPHQWVRYHUODSSLQJZLQGRZV
DQGDPRXVHSRLQWHUDUHDOOLQJUHGLHQWVRIDXVHULQWHUIDFHSDUDGLJPFDOOHGWKH£GHVNWRS
PHWDSKRU¤<RXUSHUVRQDOFRPSXWHUVFUHHQLVDPHWDSKRUIRUDUHDOGHVNZLWKRYHU
ODSSLQJGRFXPHQWVRQLW0RYHDGRFXPHQWWRWKHWRSE\VHOHFWLQJLWZLWKWKHSRLQWHU
DQGLWEHFRPHVWKHGRFXPHQW\RXDUHZRUNLQJRQ
2QDVPDOOVFUHHQWKHHQWLUHVFUHHQLVGHYRWHGWRDVLQJOHWDVNDQGWKHFRQFHSWRID
WDVN DQG WDVN VZLWFKLQJ LV LQKHUHQWO\ OHVV YLVXDO ,Q PRELOH XVHU LQWHUIDFHV D EDFN
VWDFN¢DVWDFNRIDFWLYLWLHV\RXFDQJREDFNWR¢LVRIWHQDFHQWUDOFRQFHSW,Q$QGURLG
WKHEDFNVWDFNLVFDOOHGWKH£DFWLYLW\VWDFN¤
Tasks and Applications
,IDQDFWLYLW\LVWKHEDVLFXQLWRI$QGURLGXVHULQWHUDFWLRQD£WDVN¤LVWKHQH[WODUJHU
JURXSLQJ,Q$QGURLGWKHZRUGWDVNGRHVQRWGHQRWHDQH[HFXWDEOHREMHFWVXFKDVD
SURFHVVRUDSSOLFDWLRQLQVWHDGLWUHIHUVWRDVLQJOHDFWLYLW\VWDFNZLWKSRWHQWLDOO\PXO
WLSOHDFWLYLWLHVIURPPXOWLSOHDSSOLFDWLRQVLQLW7KRVHDFWLYLWLHVFDQEHLPSOHPHQWHGLQ
A Flowing and Intuitive User Experience Across Activities | 299
PXOWLSOHVHSDUDWHDSSOLFDWLRQVDVVKRZQLQ)LJXUHLQ&KDSWHU$VWKHXVHULQWHUDFWV
ZLWKWKHV\VWHPVRPHWLPHVRQHDFWLYLW\ZLOOE\ZD\RIDQIntentREMHFWDVNWKHV\VWHP
WRILQGDQDFWLYLW\WKDWPDWFKHVWKHLQWHQW¦VVSHFLILFDWLRQV,IWKDWDFWLYLW\LVLQDQRWKHU
DSSOLFDWLRQLWXVXDOO\EHFRPHVSDUWRIWKHWDVNWKHXVHUEHJDQZKHQVKHODXQFKHGDQ
DSSOLFDWLRQIURPWKH/DXQFKHURU+RPHVFUHHQVKRUWFXW
:KHQWKHXVHUODXQFKHVZKDWVKHWKLQNVRIDVDQDSSOLFDWLRQVKHDOVRVWDUWVWKH£URRW
DFWLYLW\¤RIDWDVN7KLVEHFRPHVFRQFUHWHWRWKHXVHUWKURXJK$QGURLG¦VPHWKRGVRI
WDVNVZLWFKLQJDIWHUDQDSSOLFDWLRQKDVEHHQODXQFKHGSUHVVLQJDQDSSOLFDWLRQLFRQLQ
WKH+RPHDFWLYLW\RUWKH5HFHQW7DVNVVZLWFKHUWKDWSRSVXSZKHQ\RXORQJSUHVVWKH
+RPHEXWWRQUHWXUQVWRDQDOUHDG\VWDUWHGWDVN LQPRVWFDVHV 7DVNVDUHQRWSURFHVVHV,QIDFWWKHSURFHVVIRUWKHFXUUHQWDFWLYLW\RIDWDVNPD\KDYH
EHHQNLOOHGEXWLWZLOOEHUHVWDUWHGDQGDQHZLQVWDQFHRIWKHActivityREMHFWLQVWDQ
WLDWHGDQGLWVVWDWHUHVWRUHGZKHQWKHXVHUVZLWFKHVWRWKDWWDVN7KHXVHUGRHVQ¦WKDYH
WR FRQFHUQ KHUVHOI ZLWK KRZ PHPRU\ LV PDQDJHG 7KH $QGURLG V\VWHP ZLOO UHVWRUH
SURFHVVHVDQGDFWLYLWLHVLQDWDVNDVWKHXVHUQHHGVWKHP
$QGURLGSURYLGHVGHYHORSHUVZLWKULFKFRQWURORYHUWKHEHKDYLRURIWDVNV8VHGFRU
UHFWO\\RXUFRQWURORYHUWDVNEHKDYLRUZLOOUHLQIRUFHWKH$QGURLGFRQFHSWRIWDVNVDQG
PDNHWKHXVHUIHHODVWKRXJKWKHEDFNEXWWRQDOZD\VGRHVZKDWVKHH[SHFWV,ILW¦VXVHG
LQFRUUHFWO\RULQSRRUWDVWHWKHXVHUPD\ILQGKHUVHOIDVNLQJ£+RZGLG,JHWKHUH"¤
Specifying Launch and Task Behavior
7DVNVDUHQRWUHSUHVHQWHGE\DFODVVLQWKH$QGURLG$3,VDQG\RXZRQ¦WEHFRQWUROOLQJ
WDVNREMHFWVZLWKPHWKRGFDOOV7DVNEHKDYLRULVVHWE\SDUDPHWHUVLQDQDSSOLFDWLRQ¦V
PDQLIHVW7DVNEHKDYLRUFDQDOVREHPRGLILHGDVSDUWRIFUHDWLQJDQGXVLQJDQLQWHQW
$V\RXZLOOVHHIURPWKHH[SODQDWLRQRIKRZWDVNEHKDYLRULVFRQWUROOHGDFWLYLW\OLIH
F\FOHDQGWDVNEHKDYLRUDUHLQWHUWZLQHG
Launch mode
$QDFWLYLW\¦VODXQFKPRGHLVDQDWWULEXWHVHWLQWKH activityWDJLQDQDSSOLFDWLRQ¦V
PDQLIHVW7KLVDWWULEXWHDIIHFWVWDVNEHKDYLRUDQGLQGLUHFWO\OLIHF\FOH
7KHandroid:launchModeDWWULEXWHKDVIRXUYDOLGYDOXHVZKLFKDUHPXWXDOO\H[FOXVLYH
"standard"
7KH"standard"ODXQFKPRGHLVWKHGHIDXOW:LWKWKLVYDOXHRIWKHandroid:launch
ModeDWWULEXWHDQDFWLYLW\FDQEHODXQFKHGPXOWLSOHWLPHVZLWKPXOWLSOHLQVWDQFHV
RIWKLV ActivityFODVVH[LVWLQJDWWKHVDPHWLPH7KHVHLQVWDQFHVPD\EHORQJWR
PXOWLSOHWDVNVXVXDOO\WKHWDVNWKDWRZQVWKHFRPSRQHQWWKDWFDOOHG startActiv
ity()WRFDXVHWKHDFWLYLW\WREHODXQFKHG7KHGLDJUDPLQ)LJXUHVKRZVPXO
WLSOHLQVWDQFHVRIDQDFWLYLW\DWWKHWRSRIDWDVN
300 | Chapter 11:ಗA Framework for a Well-Behaved Application
)LJXUH7KHVWDQGDUGODXQFKPRGHZKLFKFUHDWHVDQHZDFWLYLW\
"singleTop"
7KH"singleTop"ODXQFKPRGHGLIIHUVIURP"standard"LQWKDWLIDQLQVWDQFHRIDQ
DFWLYLW\ZLWKWKLVYDOXHRIWKHandroid:launchModeDWWULEXWHDOUHDG\H[LVWVDQGLVLQ
WKHWDVNWKDWZRXOGRZQWKHDFWLYLW\WREHODXQFKHGDQGLVDWWKHWRSRIWKHDFWLYLW\
VWDFNWKHH[LVWLQJDFWLYLW\JHWVWKH IntentREMHFWYLDWKH onNewIntent()PHWKRG
UDWKHUWKDQDQHZDFWLYLW\EHLQJVWDUWHG7KHGLDJUDPLQ)LJXUHVKRZVDVLQJOH
LQVWDQFHRID"singleTop"DFWLYLW\DWWKHWRSRIDWDVN
)LJXUH7KHVLQJOH7RSODXQFKPRGHZKLFKFDXVHVWKHLQWHQWWREHSURFHVVHGE\WKHWRSDFWLYLW\
LILWPDWFKHVWKHLQWHQW
"singleTask"
7KH"singleTask"ODXQFKPRGHVSHFLILHVWKDWWKHDFWLYLW\WREHODXQFKHGLVWKHURRW
RIDQHZWDVNXQOHVVDQLQVWDQFHRIWKLVDFWLYLW\DOUHDG\H[LVWVLQZKLFKFDVHWKH
EHKDYLRULVOLNH"singleTop"DQGWKHIntentREMHFWDVVRFLDWHGZLWKODXQFKLQJWKLV
DFWLYLW\LVSURFHVVHGWKURXJKDFDOOWRonNewIntent()
"singleInstance"
7KH"singleInstance"ODXQFKPRGHVSHFLILHVWKDWWKHDFWLYLW\WREHODXQFKHGLVWKH
URRWRIDQHZWDVNDQGLWVSHFLILHVWKDWDQ\DFWLYLW\ODXQFKHGE\WKLVDFWLYLW\LVDOVR
LQDQHZWDVNHQVXULQJWKDWWKLVDFWLYLW\LVWKHRQHDQGRQO\DFWLYLW\LQLWVWDVN
Task affinity
7KH android:taskAffinity DWWULEXWH FDQ EH VHW WR EH WKH VDPH DV WKH YDOXH RI DQ
android:nameDWWULEXWHRIDQDFWLYLW\,ILWLVQRWVHWWKHGHIDXOWYDOXHLVWKHQDPHRIWKH
SDFNDJHVSHFLILHGLQWKH<manifest>WDJ
A Flowing and Intuitive User Experience Across Activities | 301
7DVNDIILQLW\LVXVHGWRSXWDQDFWLYLW\LQDVSHFLILFWDVN7KDWLVLI\RXGRQRWZDQWWKH
GHIDXOWEHKDYLRULQ$QGURLGZKHUHQHZDFWLYLWLHVEHFRPHSDUWRIWKHWDVNWKDWVWDUWHG
WKRVHDFWLYLWLHVWDVNDIILQLW\HQDEOHV\RXWRRYHUULGHWKDWEHKDYLRUDQGVSHFLI\WKHGH
VLUHGWDVNZKLFKXVXDOO\LVDWDVNDVVRFLDWHGZLWKWKHDSSOLFDWLRQWKDWLPSOHPHQWVWKLV
DFWLYLW\
Other activity attributes affecting task behavior
2WKHUDWWULEXWHVWKDWPRGLI\WDVNEHKDYLRULQFOXGHWKHandroid:noHistoryDWWULEXWH,I
WKLVDWWULEXWHLVVHWWRtrueWKHDFWLYLW\LVQRWSODFHGRQWKHDFWLYLW\VWDFNZKHQWKHXVHU
QDYLJDWHVDZD\IURPLW7KLVLVXVHIXOIRUDFWLYLWLHVVXFKDVORJLQVFUHHQVWKDWVKRXOG
QRWEHUHYLVLWHGH[FHSWZKHQDXWKHQWLFDWLRQLVDFWXDOO\UHTXLUHG
7KHandroid:processDWWULEXWHFDQEHVHWWRWKHQDPHRIDSURFHVVLQZKLFKWKHDFWLYLW\
VKRXOGUXQLQVWHDGRIWKHSURFHVVFUHDWHGIRUWKHILUVWFRPSRQHQWWRUXQLQDQDSSOL
FDWLRQ7KLVDWWULEXWHLVQRWDEOHPDLQO\EHFDXVHLWGRHVQRWDIIHFWWDVNEHKDYLRUHYHQ
WKRXJKWKHDFWLYLW\LVUXQQLQJLQDGLIIHUHQWSURFHVVLWLVJURXSHGLQWRDWDVNDVWKRXJK
LWUDQLQWKHVDPHSURFHVVIURPZKLFKLWZDVODXQFKHG
7KHandroid:finishOnTaskLaunchDWWULEXWHFDXVHVDQ\RWKHULQVWDQFHRIWKLVDFWLYLW\WR
EHILQLVKHGZKHQDQHZLQVWDQFHLVODXQFKHG8VLQJWKLVDWWULEXWHHQVXUHVWKDWWKHVH
NLQGVRIDFWLYLWLHVDUHQHYHUVWDFNHGDQGDSSHDURQO\RQFHDPRQJDOODFWLYLWLHVLQDOO
WDVNV
7KH android:alwaysRetainTaskStateDWWULEXWHWHOOVWKH$QGURLGV\VWHPLILWLVVHWWR
trueWKDWWKHVWDFNRIDFWLYLWLHVDERYHDURRWDFWLYLW\VKRXOGQHYHUEHFOHDUHG%\GHIDXOW
WKHV\VWHPFDQFOHDUWKHDFWLYLW\VWDFNDERYHDURRWDFWLYLW\DIWHUDQLQWHUYDOLQZKLFK
WKHWDVNKDVQRWEHHQXVHG
Modifying task behavior with intent flags
0RVWWDVNEHKDYLRULVGHWHUPLQHGE\DWWULEXWHVLQWKHactivityWDJRIWKHPDQLIHVW7KH
H[FHSWLRQWRWKLVLVLQDVHWRIIODJVWKDWFDQEHVHWLQDQIntentREMHFW
7KHUHLVDVXUSULVLQJO\ODUJHQXPEHURIZD\VWRPRGLI\WDVNEHKDYLRULQLQWHQWIODJV
6RPHDUHREYLRXVO\XVHIXOEXWVRPHDUHMXVWSHUSOH[LQJLQDQDUHDRIIXQFWLRQDOLW\WKDW
LVSHUSOH[LQJHQRXJKDVLWLV
FLAG_ACTIVITY_BROUGHT_TO_FRONT
7KLVIODJ LV XVHG E\WKH V\VWHP WR LPSOHPHQW WKH EHKDYLRUWREHXVHGZKHQDQ
ActivityKDVWKHsingleTaskRUsingleInstanceODXQFKPRGHDWWULEXWHVSHFLILHG
FLAG_ACTIVITY_CLEAR_TASK
7KLVIODJLQGLFDWHVWKHWDVNVWREHFOHDUHGEHIRUHWKHQHZDFWLYLW\VWDUWV7KLVPHDQV
WKHQHZDFWLYLW\LVWKHQHZURRWDFWLYLW\RIWKHWDVN
FLAG_ACTIVITY_CLEAR_TOP
7KLVIODJKDVWKHHIIHFWRISXWWLQJWKHDFWLYLW\WKHIntentREMHFWPDWFKHVRQWRSRI
WKHDFWLYLW\VWDFNLILWLVLQWKHDFWLYLW\VWDFNRIWKHFXUUHQWWDVNE\ILQLVKLQJDOO
302 | Chapter 11:ಗA Framework for a Well-Behaved Application
DFWLYLWLHVRQWRSRIWKHRQHWKHIntentREMHFWPDWFKHV7KHDFWLYLW\WKDWHQGVXSDW
WKHWRSRIWKHDFWLYLW\VWDFNLVLWVHOIILQLVKHGDQGUHFUHDWHGXQOHVVLWLVFDSDEOHRI
UHFHLYLQJDQHZLQWHQWYLDWKHonNewIntent()PHWKRG
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
7KLVIODJLQGLFDWHVWKDWWKHDFWLYLW\EHLQJODXQFKHGLVWKHDFWLYLW\WKDWVKRXOGEHRQ
WRSRIWKHDFWLYLW\VWDFNLIWKHWDVNLVUHVHW£5HVHW¤PHDQVWKHWRSRIWKHDFWLYLW\
VWDFNLVFOHDUHG7KLVLVGRQHDIWHUVRPHWLPHKDVSDVVHG
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
7KHDFWLYLW\VWDUWHGZLWKWKLVIODJLVQRWVDYHGRQWKHDFWLYLW\VWDFN
FLAG_ACTIVITY_FORWARD_RESULT
7KLVIODJPHDQVWKHQHZDFWLYLW\FDQSURYLGHDUHVXOWWRWKHDFWLYLW\WKDWODXQFKHG
WKHFXUUHQWDFWLYLW\,QRWKHUZRUGV£+HUH\RXDQVZHUWKLV¤
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
7KLVIODJPHDQVWKHQHZDFWLYLW\ZDVODXQFKHGIURPWKH£UHFHQWV¤PHQXWRUHSODFH
DQLQVWDQFHWKDWKDGEHHQGHVWUR\HG
FLAG_ACTIVITY_MULTIPLE_TASK
7KLVIODJPHDQVWKHQHZDFWLYLW\FDQEHWKHURRWRIPXOWLSOHWDVNVDQGLIXVHGZLWK
FLAG_ACTIVITY_NEW_TASKLQIDFWFUHDWHVPXOWLSOHWDVNV7KLVFDQEHFRQIXVLQJWR
WKHXVHUVLQFHWKH$QGURLGV\VWHPGRHVQRWSURYLGHWKHXVHUZLWKDZD\WRGLVWLQ
JXLVKDPRQJPXOWLSOHWDVNVZLWKWKHVDPHURRWDFWLYLW\
FLAG_ACTIVITY_NEW_TASK
7KLVIODJPHDQVWKHQHZDFWLYLW\LVWKHURRWRIDQHZWDVNXQOHVV FLAG_ACTIVITY_
MULTIPLE_TASKLVDOVRVHWLQZKLFKFDVHPXOWLSOHWDVNVZLWKWKHVDPHURRWDFWLYLW\
DUHFUHDWHGDQGWKHDIRUHPHQWLRQHGFDXWLRQVDSSO\
FLAG_ACTIVITY_NO_ANIMATION
7KLVIODJVXSSUHVVHVWUDQVLWLRQDQLPDWLRQ
FLAG_ACTIVITY_NO_HISTORY
7KHQHZDFWLYLW\LVQRWRQWKHEDFNVWDFN,WLVWKHVDPHDVWKHnoHistoryDWWULEXWH
FLAG_ACTIVITY_NO_USER_ACTION
7KLVIODJVXSSUHVVHVWKHonUserLeaveHintFDOOEDFNIRUWKHFXUUHQWDFWLYLW\$VVXP
LQJWKLVFDOOEDFNLVXVHGWRFOHDUDOHUWVWKHDOHUWVZLOOVWD\XS7KLVLVXVHIXOIRU
DFWLYLW\WUDQVLWLRQVWKHXVHUGLGQRWLQLWLDWHVXFKDVGLVSOD\LQJDQLQFRPLQJFDOORU
PHVVDJH
FLAG_ACTIVITY_PREVIOUS_IS_TOP
7KLVIODJPHDQVWKHQHZDFWLYLW\ZLOOQRWEHWUHDWHGDVWKHWRSRIWKHDFWLYLW\VWDFN
DQGWKHSUHYLRXVWRSDFWLYLW\ZLOOEHWUHDWHGDVWKHWRSIRUWKHSXUSRVHVRIGHFLGLQJ
ZKHWKHUWKHLQWHQWVKRXOGEHGHOLYHUHGWRWKHWRSDFWLYLW\RUZKHWKHUDQHZDFWLYLW\
VKRXOGEHFUHDWHG7KHUHLVQRNQRZQXVHFDVHIRUWKLVIODJ
FLAG_ACTIVITY_REORDER_TO_FRONT
,IWKHDFWLYLW\LVDOUHDG\UXQQLQJLWZLOOEHUDLVHGWRWKHWRSRIWKHDFWLYLW\VWDFNDQG
PDGHYLVLEOH
A Flowing and Intuitive User Experience Across Activities | 303
6RPHRIWKHVHIODJVKDYHEHHQDGGHGVLQFH$3,OHYHODQGDUHLJQRUHGLQHDUOLHU$3,V
6RPHRIWKHVHIODJVKDYHWKHHIIHFWRIRYHUULGLQJWDVNEHKDYLRUVHWLQWKHPDQLIHVW6RPH
IODJVDIIHFWRWKHUEHKDYLRUVXFKDVWUDQVLWLRQDQLPDWLRQV$QGLQVRPHFDVHVDIODJLQ
DQIntentREMHFWLVWKHRQO\ZD\WRPRGLI\WDVNEHKDYLRU
8VHDOORIWKHVHZLWKFDXWLRQ8QH[SHFWHGWDVNEHKDYLRUFDQGHVWUR\WKHXVHU¦VVHQVHRI
SODFHLQWKH$QGURLG8,
304 | Chapter 11:ಗA Framework for a Well-Behaved Application
CHAPTER 12
Using Content Providers
:KHQ$QGURLGDSSOLFDWLRQVVKDUHGDWDWKH\UHO\RQWKHFRQWHQWSURYLGHU$3,WRH[SRVH
GDWDZLWKLQWKHLUGDWDEDVH)RUH[DPSOHWKH$QGURLGFRQWDFWFRQWHQWSURYLGHUDOORZV
DQXQOLPLWHGQXPEHURIDSSOLFDWLRQVWRUHXVHFRQWDFWSHUVLVWHQFHRQWKH$QGURLGSODW
IRUP%\VLPSO\LQYRNLQJWKLVFRQWHQWSURYLGHUDQDSSOLFDWLRQFDQLQWHJUDWHDFFHVVWR
DXVHU¦VFRQWDFWVVWRUHGORFDOO\DQGV\QFKURQL]HGZLWKWKH*RRJOHFORXG$SSOLFDWLRQV
FDQUHDGDQGZULWHGDWDLQFRQWHQWSURYLGHUVZLWKRXWKDYLQJWRSURYLGHWKHLURZQGD
WDEDVHPDQLSXODWLRQFRGH,QWKLVZD\FRQWHQWSURYLGHUVSURYLGHDSRZHUIXOIHDWXUH
WKDW DOORZV GHYHORSHUV WR HDVLO\ FUHDWH DSSOLFDWLRQV ZLWK VRSKLVWLFDWHG GDWD
PDQDJHPHQW¢LQPDQ\FDVHVDSSOLFDWLRQVZLOOHQGXSZULWLQJYHU\OLWWOHGDWDSHUVLV
WHQFHFRGHRIWKHLURZQ
7KHFRQWHQWSURYLGHU$3,HQDEOHVFOLHQWDSSOLFDWLRQVWRTXHU\WKH26IRUUHOHYDQWGDWD
XVLQJD8QLIRUP5HVRXUFH,GHQWLILHU 85, VLPLODUWRWKHZD\DEURZVHUUHTXHVWVLQ
IRUPDWLRQ IURP WKH ,QWHUQHW )RU D JLYHQ 85, TXHU\ D FOLHQW GRHV QRW NQRZ ZKLFK
DSSOLFDWLRQZLOOSURYLGHWKHGDWDLWVLPSO\SUHVHQWVWKH26ZLWKD85,DQGOHDYHVLWWR
WKHSODWIRUPWRVWDUWWKHDSSURSULDWHDSSOLFDWLRQWRSURYLGHWKHUHVXOW7KHSODWIRUP
DOVRSURYLGHVDSHUPLVVLRQWKDWDOORZVFOLHQWVWROLPLWDFFHVVWRFRQWHQWSURYLGHUGDWD
7KHFRQWHQWSURYLGHU$3,HQDEOHVIXOOFUHDWHUHDGXSGDWHDQGGHOHWHDFFHVVWRVKDUHG
FRQWHQW7KLVPHDQVDSSOLFDWLRQVFDQXVH85,RULHQWHGUHTXHVWVWR
‡ &UHDWHQHZUHFRUGV
‡ 5HWULHYHRQHDOORUDOLPLWHGVHWRIUHFRUGV
‡ 8SGDWHUHFRUGV
‡ 'HOHWHUHFRUGV
7KLVFKDSWHUVKRZV\RXKRZWRZULWH\RXURZQFRQWHQWSURYLGHUE\H[DPLQLQJWKH
LQQHUZRUNLQJVRIDQH[DPSOHFRQWHQWSURYLGHUSimpleFinchVideoContentProviderLQ
FOXGHGZLWKLQWKH)LQFKVRXUFHWUHH$OOILOHUHIHUHQFHVDUHFRQWDLQHGLQWKHVRXUFHGL
UHFWRU\IRUWKLVFKDSWHU7KXVZKHQWKH$QGURLG0DQLIHVW[POILOHLVUHIHUHQFHGLQWKLV
VHFWLRQWKH )LQFK9LGHR $QGURLG0DQLIHVW[POILOHLVDVVXPHG:H¦OOXVHWKLVFRGHWR
GHVFULEHKRZWRFUHDWHDFRQWHQWSURYLGHUE\LPSOHPHQWLQJHDFKPHWKRGUHTXLUHGE\
305
WKHPDLQFRQWHQWSURYLGHU$3,WKHFODVVContentProvider:HZLOODOVRH[SODLQKRZWR
LQWHJUDWHD64/LWHGDWDEDVHLQWRWKDWFRQWHQWSURYLGHU:H¦OOGHVFULEHKRZWRLPSOH
PHQWWKHEDVLFIXQFWLRQRIDFRQWHQWSURYLGHUZKLFKLVWRSURYLGHDPDSSLQJEHWZHHQ
85,VWKDWUHIHUHQFHGDWDDQGGDWDEDVHURZV<RXZLOOVHHKRZDFRQWHQWSURYLGHUHQ
FDSVXODWHVGDWDSHUVLVWHQFHIXQFWLRQVDQGHQDEOHV\RXUDSSOLFDWLRQWRVKDUHGDWDDFURVV
SURFHVVHVZKHQ\RXGHFODUH\RXUSURYLGHULQ$QGURLG0DQLIHVW[PO:HZLOOVKRZ\RX
KRZWRKRRNFRQWHQWSURYLGHUGDWDLQWR$QGURLG8,FRPSRQHQWVWKXVFRPSOHWLQJWKH
09&DUFKLWHFWXUHWKDWZHKDYHOHGXSWRVRIDULQWKLVERRN)LQDOO\ZHZLOOEXLOGD
GDWDYLHZLQJDFWLYLW\WKDWDXWRPDWLFDOO\UHIUHVKHVLWVGLVSOD\LQUHVSRQVHWRFKDQJHVLQ
GDWD
7KURXJKRXWWKLVFKDSWHUZHPDNHWKHDVVXPSWLRQWKDWORFDOFRQWHQW
SURYLGHU VWRUDJH XVHV D 64/LWH GDWDEDVH *LYHQ WKH FRQWHQW SURYLGHU
query insert updateDQG delete$3,PHWKRGVLW¦VDFWXDOO\DELWRID
VWUHWFK WR WKLQN DERXW PDSSLQJ LW WR DQ\WKLQJ HOVH HYHQ WKRXJK LQ
WKHRU\WKH$3,FDQVWRUHDQGUHWULHYHGDWDXVLQJDQ\EDFNHQGVXFKDV
DIODWILOHWKDWFRXOGVXSSRUWWKHUHTXLUHGRSHUDWLRQV
:HIROORZWKLVLQWURGXFWLRQLQWKHQH[WFKDSWHUE\VKRZLQJ\RXKRZWRH[WHQGDQG
HQKDQFHWKHYHU\FRQFHSWRIDFRQWHQWSURYLGHU,QWKHSURFHVV\RXZLOOOHDUQWROHYHUDJH
WKHFRQWHQWSURYLGHU$3,WRHQDEOHLQWHJUDWLRQRI5(67IXOQHWZRUNVHUYLFHVLQWR$Q
GURLG7KLVVLPSOHDUFKLWHFWXUHZLOOSUHYHQWPDQ\FRPPRQPRELOHSURJUDPPLQJHU
URUVHYHQWKRXJKLWRQO\UHOLHVRQEDVLF$QGURLGFRPSRQHQWV<RXZLOOVHHWKDWWKLV
DSSURDFKOHDGVORJLFDOO\LQWRDPRELOHDSSOLFDWLRQDUFKLWHFWXUHWKDWDGGVVLJQLILFDQW
UREXVWQHVVDQGSHUIRUPDQFHLPSURYHPHQWVWR$QGURLGDSSOLFDWLRQV
:HZLOOZDONWKURXJKDYLGHROLVWLQJDSSOLFDWLRQWKDWSURYLGHVDVLPSOLILHGLOOXVWUDWLRQ
RIWKLVDUFKLWHFWXUH7KLVDSSOLFDWLRQZLOOIROORZWKHVXJJHVWHGDSSURDFKE\ORDGLQJ
SDUVLQJDQGFDFKLQJ<RX7XEHYLGHRFRQWHQWHQWULHVIURPWKH5(67IXOZHEVHUYLFHDW
KWWSJGDWD\RXWXEHFRP:H¦OOVLPSO\EHXVLQJgDataDVDQH[DPSOHRID5(67IXOVHUY
LFHWKDWZHFDQLQWHJUDWHLQWRDQ$QGURLGFRQWHQWSURYLGHU7KHDSSOLFDWLRQ8,ZLOOXVH
FRQWHQWSURYLGHUVWRG\QDPLFDOO\GLVSOD\YLGHRHQWULHVDVWKH\DUHORDGHGDQGSDUVHG
IURPWKHQHWZRUN<RXZLOOEHDEOHWRDSSO\WKLVDSSURDFKWRLQWHJUDWHWKHODUJHQXPEHU
RIZHEVHUYLFHVDYDLODEOHRQWKH,QWHUQHWLQWR\RXU$QGURLGEDVHGDSSOLFDWLRQ,QFL
GHQWDOO\WKHgData85,SURYLGHVDSUHWW\QHDWGHPRIURP*RRJOHDQGZRUWKFKHFNLQJ
RXWLQLWVRZQULJKW
Understanding Content Providers
&RQWHQWSURYLGHUVHQFDSVXODWHGDWDPDQDJHPHQWVRWKDWRWKHUSDUWVRIDQDSSOLFDWLRQ
VXFKDVWKHYLHZDQGFRQWUROOHUGRQRWQHHGWRSDUWLFLSDWHLQSHUVLVWLQJDSSOLFDWLRQ
GDWD6D\LQJWKLVLQDGLIIHUHQWZD\FRQWHQWSURYLGHUVSHUVLVWDSSOLFDWLRQGDWDEHFDXVH
WKHYLHZDQGFRQWUROOHUVKRXOGQRWKDQGOHLW6SHFLDOL]HGVRIWZDUHOD\HUVWKDWGRQRW
306 | Chapter 12:ಗUsing Content Providers
DWWHPSWWRSHUIRUPWDVNVRIRWKHUOD\HUVDUHWKHKDOOPDUNRIZHOOFUDIWHGFRGH%XJVDQG
XQQHHGHGFRPSOH[LW\DULVHZKHQVRIWZDUHOD\HUVSHUIRUPWDVNVWKDWDUHEH\RQGWKHLU
VFRSH7KXVD8,VKRXOGFRQVLVWRQO\RIZHOOODLGRXW8,FRPSRQHQWVILQHWXQHGWR
FROOHFWHYHQWVIURPWKHLUHQGXVHU$ZHOOZULWWHQDSSOLFDWLRQFRQWUROOHUZLOOFRQWDLQ
RQO\WKHGRPDLQORJLFRIWKHPRELOHDSSOLFDWLRQ$QGLQFRQQHFWLRQZLWKWKLVFKDSWHU
VLPSOLILFDWLRQVDULVHZKHQERWKW\SHVRIFRGHFDQRXWVRXUFHGDWDSHUVLVWHQFHWRDORJLFDO
WKLUGSDUW\FRQWHQWSURYLGHUV5HFDOOLQJWKHGLVFXVVLRQIURP£64/DQGWKH'DWDEDVH
&HQWULF'DWD0RGHOIRU$QGURLG$SSOLFDWLRQV¤RQSDJHFRQWHQWSURYLGHUVDUHZHOO
VXLWHGWRLPSOHPHQWLQJWKHQRQGRFXPHQWFHQWULFGDWDPRGHO
:LWKWKHDVVLVWDQFHRIDFRQWHQWSURYLGHUDSSOLFDWLRQVGRQRWQHHGWRRSHQWKHLURZQ
64/LWHWDEOHVVLQFHWKDWGHWDLOZLOOWDNHSODFHEHKLQGWKHFRQWHQWSURYLGHULQWHUIDFHLQ
WDEOHVRZQHGE\WKHFRQWHQWSURYLGHU,QWKHSDVWWRVKDUHGDWDPRELOHDSSOLFDWLRQV
PLJKWKDYHKDGWRVWRUHLWLQILOHVLQWKHORFDOILOHV\VWHPZLWKDQDSSOLFDWLRQGHILQHG
FRQILJXUDWLRQIRUPDW,QVWHDGZLWK$QGURLGDSSOLFDWLRQVFDQRIWHQUHO\VROHO\RQFRQ
WHQWSURYLGHUVWRUDJH
%HIRUHGLJJLQJLQWRWKHSimpleFinchVideoContentProviderZH¦OOSURYLGHDQRYHUYLHZRI
WKHVLPSOHILQFKYLGHRDSSOLFDWLRQDQGSURYLGHEDFNJURXQGRQFRQWHQWSURYLGHULP
SOHPHQWDWLRQWDVNV
Implementing a Content Provider
7RWDNHDGYDQWDJHRIWKLVGHVLJQVWUXFWXUH\RXZLOOQHHGWRZULWH\RXURZQFRQWHQW
SURYLGHUZKLFKLQYROYHVFRPSOHWLQJWKHIROORZLQJWDVNV
‡ &UHDWHDFRQWHQWSURYLGHUSXEOLF$3,IRUFOLHQWFRQVXPSWLRQE\
¢ 'HILQLQJWKHCONTENT_URIIRU\RXUFRQWHQWSURYLGHU
¢ &UHDWLQJFROXPQQDPHVIRUFRPPXQLFDWLRQZLWKFOLHQWV
¢ 'HFODULQJSXEOLFVWDWLFStringREMHFWVWKDWFOLHQWVXVHWRVSHFLI\FROXPQV
¢ 'HILQLQJ0,0(W\SHVIRUDQ\QHZGDWDW\SHV
‡ ,PSOHPHQW\RXUFRQWHQWSURYLGHU7KLVUHTXLUHVWKHIROORZLQJ
¢ ([WHQGLQJWKHPDLQFRQWHQWSURYLGHU$3,WKHContentProviderFODVVWRFUHDWH
DFXVWRPFRQWHQWSURYLGHULPSOHPHQWDWLRQ
¢ 6HWWLQJXSDSURYLGHU85,
¢ &UHDWLQJD64/LWHGDWDEDVHDQGDVVRFLDWHGFXUVRUVWRVWRUHFRQWHQWSURYLGHUGDWD
¢ 8VLQJFXUVRUVWRPDNHGDWDDYDLODEOHWRFOLHQWVZKLOHVXSSRUWLQJG\QDPLFGDWD
XSGDWHV
¢ 'HILQLQJWKHSURFHVVE\ZKLFKELQDU\GDWDLVUHWXUQHGWRWKHFOLHQW
¢ ,PSOHPHQWLQJWKHEDVLF query insert updateDQG deleteGDWDPHWKRGVRID
CursorWRUHWXUQWRWKHFOLHQW
‡ 8SGDWHWKH$QGURLG0DQLIHVW[POILOHWRGHFODUH\RXU<provider>
Understanding Content Providers | 307
:KHQZHKDYHILQLVKHGGLVFXVVLQJWKHLPSOHPHQWDWLRQRIDEDVLFFRQWHQWSURYLGHUZH
ZLOOGHVFULEHWDVNVUHODWHGWRXVLQJFRQWHQWSURYLGHUVWRGHYHORSWKHPRUHDGYDQFHG
QHWZRUNDUFKLWHFWXUHWKDWZHKDYHPHQWLRQHG
Browsing Video with Finch
7KH)LQFKYLGHRYLHZHUHQDEOHVXVHUVWROLVWYLGHRUHODWHGPHWDGDWD:HKDYHLQFOXGHG
WZR YHUVLRQV RI D YLGHR OLVWLQJ DSSOLFDWLRQ DQG WZR YHUVLRQV RI XQGHUO\LQJ FRQWHQW
SURYLGHUV7KHILUVWYHUVLRQSUHVHQWHGLQWKLVFKDSWHULVDVLPSOHYLGHROLVWLQJDSSOL
FDWLRQWKDWXVHV SimpleFinchVideoContentProviderZKLFKLVGHVLJQHGWRWHDFK\RXWR
LPSOHPHQW\RXUILUVWFRQWHQWSURYLGHU$VHFRQGYHUVLRQRIWKHDSSSUHVHQWHGLQWKH
QH[WFKDSWHUXVHVDVOLJKWO\PRUHFRPSOH[FRQWHQWSURYLGHUWKDWDGGVWKHDELOLW\WRSXOO
FRQWHQWIURPWKHRQOLQH<RX7XEHYLGHRVHDUFKVHUYLFH7KLVVHFRQGYHUVLRQRIWKHDSS
KDVWKHDELOLW\WRFDFKHUHVXOWVDQGWKHDELOLW\WRVKRZYLGHRWKXPEQDLOV
1RZZHZLOOH[SORUHWKHILUVWDSSLQGHWDLO7KLVVLPSOHDSSOLFDWLRQKDVRQHDFWLYLW\
SimpleFinchVideoActivityZKLFKDOORZVDXVHUWRFUHDWHDQGOLVWKLVRZQYLGHRPHWD
GDWD HJYLGHRWLWOHGHVFULSWLRQ85,DQG,' DVVKRZQLQ)LJXUH
)LJXUH$QDFWLYLW\IRURXUVLPSOHYLGHRSURYLGHUWKDWOHWVXVHUVHQWHUWKHLURZQYLGHR£PHWDGDWD¤
7RXVHWKLVDSSOLFDWLRQVLPSO\HQWHUDSSURSULDWHGDWDIRUD£YLGHR¤HQWU\DQGWKHQ
SUHVVWKH,QVHUWEXWWRQ7KHOLVWXQGHUQHDWKWKHWH[WILHOGVXVHV$QGURLG09&WRDX
WRPDWLFDOO\UHIUHVKLWVYLHZRIGDWD
308 | Chapter 12:ಗUsing Content Providers
The simple video database
7R VWRUH WKH GDWD \RX HQWHU LQWR WKLV DSSOLFDWLRQ WKH SimpleFinchVideoContentPro
viderFODVVFUHDWHVLWVGDWDEDVHZLWKWKHIROORZLQJ64/VWDWHPHQW
CREATE TABLE video (_id INTEGER PRIMARY KEY, title TEXT, decription TEXT, uri TEXT);
7KH _idFROXPQLVUHTXLUHGIRUXVHZLWKWKH$QGURLGFXUVRUV\VWHP,WSURYLGHVWKH
XQLTXHLGHQWLW\RIDURZLQDFXUVRUDVZHOODVWKHLGHQWLW\RIDQREMHFWLQWKHGDWDEDVH
$VVXFK\RXQHHGWRGHILQHWKLVFROXPQZLWKWKH64/DWWULEXWHVINTEGER PRIMARY KEY
AUTOINCREMENTWRPDNHFHUWDLQLWVYDOXHLVXQLTXH
7KHtitleDQGdescriptionFROXPQVVWRUHYLGHRWLWOHDQGGHVFULSWLRQGDWDUHVSHFWLYHO\
7KH uriFROXPQFRQWDLQVDPHGLD85,WKDWFRXOGEHXVHGWRSOD\DYLGHRHQWU\LQDQ
DFWXDOZRUNLQJYHUVLRQRIWKLVDSSOLFDWLRQ
Structure of the simple version of the code
7KLVVHFWLRQEULHIO\H[DPLQHVUHOHYDQWILOHVZLWKLQWKHVLPSOH)LQFKYLGHRDSSOLFDWLRQ
$QGURLG0DQLIHVW[PO
:H¦YHFUHDWHGDPDQLIHVWIRUDVLPSOHYLGHRFRQWHQWSURYLGHUDSSOLFDWLRQWKDWZLOO
FRQWDLQDUHIHUHQFHWRRXUDFWLYLW\SimpleFinchVideoActivityDVZHOODVRXUFRQWHQW
SURYLGHUSimpleFinchVideoContentProvider
)LQFK9LGHR VUFFRPRUHLOO\GHPRSDILQFKYLGHR)LQFK9LGHRMDYD
7KH FinchVideo FODVV FRQWDLQV WKH AUTHORITY DWWULEXWH GLVFXVVHG ODWHU DQG WKH
SimpleVideoFODVVWKDWGHILQHVWKHQDPHVRIWKHFRQWHQWSURYLGHUFROXPQV1HLWKHU
WKHFinchVideoFODVVQRUWKHSimpleVideoFODVVFRQWDLQVDQ\H[HFXWDEOHFRGH
)LQFK9LGHR VUFFRPRUHLOO\GHPRSDILQFKYLGHRSURYLGHU6LPSOH)LQFK9LGHR&RQWHQW
3URYLGHUMDYD
7KHSimpleFinchVideoContentProviderFODVVLVWKHFRQWHQWSURYLGHUIRUWKHVLPSOH
YLGHRGDWDEDVH,WKDQGOHV85,UHTXHVWVDVDSSURSULDWHIRUWKHVLPSOHYLGHRDSSOL
FDWLRQ7KLVILOHLVWKHVXEMHFWRIWKHILUVWKDOIRIWKLVFKDSWHU
)LQFK9LGHR VUFFRPRUHLOO\GHPRSDILQFKYLGHR6LPSOH)LQFK9LGHR$FWLYLW\MDYD
7KHSimpleFinchVideoActivityFODVVLVDQDFWLYLW\WKDWDOORZVWKHXVHUWRYLHZDOLVW
RIYLGHRV
Defining a Provider Public API
7KRXJKZHVDZLQ&KDSWHUKRZFOLHQWVXVHFRQWHQWSURYLGHUVZHSURYLGHPRUHLQ
IRUPDWLRQKHUHIRUFRQWHQWSURYLGHUDXWKRUVWRIXOO\LPSOHPHQWWKHSURYLGHUSXEOLF$3,
)RUFOLHQWVWRXVH\RXUFRQWHQWSURYLGHU\RXZLOOQHHGWRFUHDWHDSXEOLF$3,FODVVWKDW
FRQWDLQVDVHWRIFRQVWDQWVWKDWFOLHQWVXVHWRDFFHVVFROXPQILHOGVRI CursorREMHFWV
UHWXUQHGE\\RXUSURYLGHU¦VTXHU\PHWKRG7KLVFODVVZLOODOVRGHILQHWKHFRQWHQWSUR
YLGHU DXWKRULW\ 85, WKDW SURYLGHV WKH IRXQGDWLRQ RI WKH ZKROH SURYLGHU 85,
Defining a Provider Public API | 309
FRPPXQLFDWLRQVFKHPH2XUFODVVFinchVideo.SimpleVideosSURYLGHVWKH$3,WRRXU
SimpleFinchVideo
)LUVWZH¦OOH[SODLQWKHFODVVLQSLHFHVSURYLGLQJEDFNJURXQGRQLWVILHOGVDQGWKHQZH¦OO
VKRZDIXOOOLVWLQJ
Defining the CONTENT_URI
)RUDFOLHQWDSSOLFDWLRQWRTXHU\FRQWHQWSURYLGHUGDWDLWQHHGVWRSDVVD85,WKDW
LGHQWLILHVUHOHYDQWGDWDWRRQHRIWKH$QGURLGFRQWHQWUHVROYHU¦VGDWDDFFHVVPHWKRGV
7KHVH PHWKRGV query insert update DQG delete PLUURU WKH PHWKRGV IRXQG RQ D
FRQWHQW UHVROYHU WKDW ZH GHILQH LQ £:ULWLQJ DQG ,QWHJUDWLQJ D &RQWHQW 3UR
YLGHU¤RQSDJH2QUHFHLYLQJVXFKDQLQYRFDWLRQWKHFRQWHQWUHVROYHUZLOOXVHDQ
DXWKRULW\VWULQJWRPDWFKWKHLQFRPLQJ85,ZLWKWKHCONTENT_URIRIHDFKFRQWHQWSUR
YLGHULWNQRZVDERXWWRILQGWKHULJKWSURYLGHUIRUWKHFOLHQW7KXVWKH CONTENT_URI
GHILQHVWKHW\SHRI85,V\RXUFRQWHQWSURYLGHUFDQSURFHVV
$CONTENT_URIFRQVLVWVRIWKHVHSDUWV
content://
$SUHIL[WKDWWHOOVWKH$QGURLG)UDPHZRUNWKDWLWPXVWILQGDFRQWHQWSURYLGHUWR
UHVROYHWKH85,
7KHDXWKRULW\
7KLV VWULQJ XQLTXHO\ LGHQWLILHV WKH FRQWHQW SURYLGHU DQG FRQVLVWV RI XS WR WZR
VHFWLRQVWKHRUJDQL]DWLRQDOVHFWLRQDQGWKHSURYLGHULGHQWLILHUVHFWLRQ7KHRUJDQ
L]DWLRQDOVHFWLRQXQLTXHO\LGHQWLILHVWKHRUJDQL]DWLRQWKDWFUHDWHGWKHFRQWHQWSUR
YLGHU7KHSURYLGHULGHQWLILHUVHFWLRQLGHQWLILHVDSDUWLFXODUFRQWHQWSURYLGHUWKDW
WKHRUJDQL]DWLRQFUHDWHG)RUFRQWHQWSURYLGHUVWKDWDUHEXLOWLQWR$QGURLGWKH
RUJDQL]DWLRQDOVHFWLRQLVRPLWWHG)RULQVWDQFHWKHEXLOWLQ£PHGLD¤DXWKRULW\WKDW
UHWXUQVRQHRUPRUHLPDJHVGRHVQRWKDYHWKHRUJDQL]DWLRQDOVHFWLRQRIWKHDX
WKRULW\+RZHYHUDQ\FRQWHQWSURYLGHUVWKDWDUHFUHDWHGE\GHYHORSHUVRXWVLGHRI
*RRJOH¦V $QGURLG WHDP PXVW GHILQH ERWK VHFWLRQV RI WKH FRQWHQW SURYLGHU
7KXV WKH VLPSOH )LQFK YLGHR H[DPSOH DSSOLFDWLRQ¦V DXWKRULW\ LV
com.oreilly.demo.pa.finchvideo.SimpleFinchVideo7KHRUJDQL]DWLRQDOVHFWLRQLV
com.oreilly.demo.pa.finchvideo DQG WKH SURYLGHU LGHQWLILHU VHFWLRQ LV
SimpleFinchVideo7KH*RRJOHGRFXPHQWDWLRQVXJJHVWVWKDWWKHEHVWVROXWLRQIRU
SLFNLQJWKHDXWKRULW\VHFWLRQRI\RXUCONTENT_URILVWRXVHWKHIXOO\TXDOLILHGFODVV
QDPHRIWKHFODVVLPSOHPHQWLQJWKHFRQWHQWSURYLGHU
7KHDXWKRULW\VHFWLRQXQLTXHO\LGHQWLILHVWKHSDUWLFXODUFRQWHQWSURYLGHUWKDW$Q
GURLGZLOOFDOOWRUHVSRQGWRTXHULHVWKDWLWKDQGOHV
7KHSDWK
7KHFRQWHQWSURYLGHUFDQLQWHUSUHWWKHUHVWRIWKH85,KRZHYHULWZDQWVEXWLWPXVW
DGKHUHWRVRPHUHTXLUHPHQWV
310 | Chapter 12:ಗUsing Content Providers
‡ ,IWKHFRQWHQWSURYLGHUFDQUHWXUQPXOWLSOHGDWDW\SHVWKH85,PXVWEHFRQ
VWUXFWHGVRWKDWVRPHSDUWRIWKHSDWKVSHFLILHVWKHW\SHRIGDWDWRUHWXUQ
)RULQVWDQFHWKHEXLOWLQ£FRQWDFWV¤FRQWHQWSURYLGHUSURYLGHVPDQ\GLIIHUHQW
W\SHVRIGDWDSHRSOHSKRQHVFRQWDFWPHWKRGVDQGVRRQ7KHFRQWDFWVFRQWHQW
SURYLGHUXVHVVWULQJVLQWKH85,WRGLIIHUHQWLDWHZKLFKW\SHRIGDWDWKHXVHULV
UHTXHVWLQJ7KXVWRUHTXHVWDVSHFLILFSHUVRQWKH85,ZLOOEHVRPHWKLQJOLNH
WKLV
content://contacts/people/1
7RUHTXHVWDVSHFLILFSKRQHQXPEHUWKH85,FRXOGEHVRPHWKLQJOLNHWKLV
content://contacts/people/1/phone/3
,QWKHILUVWFDVHWKH0,0(GDWDW\SHUHWXUQHGZLOOEHvnd.android.cursor.item/
personZKHUHDVLQWKHVHFRQGFDVHLWZLOOEHvnd.android.cursor.item/phone
‡ 7KHFRQWHQWSURYLGHUPXVWEHFDSDEOHRIUHWXUQLQJHLWKHURQHLWHPRUDVHWRI
LWHPLGHQWLILHUV7KHFRQWHQWSURYLGHUZLOOUHWXUQDVLQJOHLWHPZKHQDQLWHP
LGHQWLILHUDSSHDUVLQWKHILQDOSRUWLRQRIWKH85,/RRNLQJEDFNDWRXUSUHYLRXV
H[DPSOHWKH85,FRQWHQWFRQWDFWVSHRSOHSKRQHUHWXUQHGDVLQJOHSKRQH
QXPEHURIW\SH vnd.android.cursor.item/phone,IWKH85,KDGLQVWHDGEHHQ
FRQWHQWFRQWDFWVSHRSOHSKRQHWKHDSSOLFDWLRQZRXOGLQVWHDGUHWXUQDOLVWRI
DOOWKHSKRQHQXPEHUVIRUWKHSHUVRQKDYLQJWKHSHUVRQLGHQWLILHUQXPEHU
DQG WKH 0,0( W\SH RI WKH GDWD UHWXUQHG ZRXOG EH vnd.android.cursor.dir/
phone
$VPHQWLRQHGHDUOLHUFRQWHQWSURYLGHUVFDQLQWHUSUHWWKHSDWKSRUWLRQVRIWKH85,V
WRVXLWWKHLUQHHGV7KLVPHDQVWKHSDWKSRUWLRQFDQXVHLWHPVLQWKHSDWKWRILOWHU
GDWDWRUHWXUQWRWKHFDOOHU)RULQVWDQFHWKHEXLOWLQ£PHGLD¤FRQWHQWSURYLGHUFDQ
UHWXUQHLWKHULQWHUQDORUH[WHUQDOGDWDGHSHQGLQJRQZKHWKHUWKH85,FRQWDLQVWKH
ZRUGLQWHUQDORUH[WHUQDOLQWKHSDWK
7KHIXOOCONTENT_URIIRUWKHVLPSOH)LQFKYLGHRLVFRQWHQWFRPRUHLOO\GHPRSDILQFK
YLGHR6LPSOH)LQFK9LGHRYLGHR
7KH CONTENT_URIPXVWEHRIW\SH public static final Uri,WLVGHILQHGLQWKH Finch
VideoFODVVRIRXUVLPSOHYLGHRDSSOLFDWLRQ,QRXUSXEOLF$3,FODVVZHVWDUWE\H[WHQGLQJ
WKHFODVVBaseColumnsDQGWKHQGHILQHDVWULQJQDPHGAUTHORITY
public final class FinchVideo.SimpleVideos extends BaseColumns {
public static final String SIMPLE_AUTHORITY =
"com.oreilly.demo.pa.finchvideo.FinchVideo";
7KHQZHGHILQHWKHCONTENT_URILWVHOI
public static final class FinchVideo.SimpleVideos implements BaseColumns {
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/video");
3XWPRUHVLPSO\GHILQLQJWKLV85,MXVWLQYROYHVSLFNLQJDQDXWKRULW\VWULQJWKDWVKRXOG
XVHD-DYDSDFNDJHXVHGE\\RXUDSSOLFDWLRQDVWKHRUJDQL]DWLRQDOLGHQWLILHU¢DSXEOLF
Defining a Provider Public API | 311
$3,SDFNDJHLVOLNHO\DEHWWHUFDQGLGDWHKHUHWKDQDQLPSOHPHQWDWLRQSDFNDJHDVZH
GLVFXVVHGLQ£-DYD3DFNDJHV¤RQSDJH7KHFRQWHQWSURYLGHULGHQWLILHULVMXVWWKH
QDPH RI \RXU FRQWHQW SURYLGHU FODVV 7KH SURYLGHU 85, IRU RXU VLPSOH )LQFK YLGHR
SURYLGHUORRNVDVIROORZV
"content://" + FinchVideo.FinchVideoContentProvider.SIMPLE_AUTHORITY + "/" +
FinchVideo.SimpleVideos.VIDEO
Creating the Column Names
&RQWHQWSURYLGHUVH[FKDQJHGDWDZLWKWKHLUFOLHQWVLQPXFKWKHVDPHZD\D64/GD
WDEDVHH[FKDQJHVGDWDZLWKGDWDEDVHDSSOLFDWLRQVXVLQJFXUVRUVIXOORIURZVDQGFRO
XPQVRIGDWD$FRQWHQWSURYLGHUPXVWGHILQHWKHFROXPQQDPHVLWVXSSRUWVMXVWDV
GDWDEDVHDSSOLFDWLRQVPXVWGHILQHWKHFROXPQVWKH\VXSSRUW:KHQWKHFRQWHQWSUR
YLGHUXVHVD64/LWHGDWDEDVHDVLWVGDWDVWRUHWKHREYLRXVVROXWLRQLVWRJLYHWKHFRQWHQW
SURYLGHUFROXPQVZLWKWKHVDPHQDPHDVWKHGDWDEDVHFROXPQVDQGWKDW¦VMXVWZKDW
SimpleFinchVideoContentProviderGRHV%HFDXVHRIWKLVQRPDSSLQJLVQHFHVVDU\EH
WZHHQ WKH SimpleFinchVideoContentProvider FROXPQV DQG WKH XQGHUO\LQJ GDWDEDVH
FROXPQV
1RWDOODSSOLFDWLRQVPDNHDOORIWKHLUGDWDDYDLODEOHWRFRQWHQWSURYLGHU
FOLHQWVDQGVRPHPRUHFRPSOH[DSSOLFDWLRQVPD\ZDQWWRPDNHGHULY
DWLYHYLHZVDYDLODEOHWRFRQWHQWSURYLGHUFOLHQWV7KHSURMHFWLRQPDS
GHVFULEHG LQ £7KH 6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU &ODVV DQG ,Q
VWDQFH9DULDEOHV¤RQSDJHLVDYDLODEOHWRKDQGOHWKHVHFRPSOH[LWLHV
Declaring Column Specification Strings
7KH SimpleFinchVideoProvider FROXPQV DUH GHILQHG LQ WKH FinchVideo.SimpleVideos
FODVVGLVFXVVHGLQWKLVVHFWLRQ(YHU\FRQWHQWSURYLGHUPXVWGHILQHDQ _idFROXPQWR
KROGWKHUHFRUGQXPEHURIHDFKURZ7KHYDOXHRIHDFK_idPXVWEHXQLTXHZLWKLQWKH
FRQWHQWSURYLGHULWLVWKHQXPEHUWKDWDFOLHQWZLOODSSHQGWRWKHFRQWHQWSURYLGHU¦V
YQGDQGURLGFXUVRULWHP85,ZKHQDWWHPSWLQJWRTXHU\IRUDVLQJOHUHFRUG
:KHQ WKH FRQWHQW SURYLGHU LV EDFNHG E\ D 64/LWH GDWDEDVH DV LV WKH FDVH IRU
SimpleFinchVideoProvider WKH _id VKRXOG KDYH WKH W\SH INTEGER PRIMARY KEY AUTO
INCREMENT7KLVZD\WKHURZVZLOOKDYHDXQLTXH_idQXPEHUDQG_idQXPEHUVZLOOQRW
EHUHXVHGHYHQZKHQURZVDUHGHOHWHG7KLVKHOSVVXSSRUWUHIHUHQWLDOLQWHJULW\E\HQ
VXULQJWKDWHDFKQHZURZKDVDQ _idWKDWKDVQHYHUEHHQXVHGEHIRUH,IURZ _idVDUH
UHXVHGWKHUHLVDFKDQFHWKDWFDFKHG85,VFRXOGSRLQWWRWKHZURQJGDWD
+HUHLVDFRPSOHWHSURJUDPOLVWLQJRIWKHVLPSOH)LQFKYLGHRSURYLGHU$3,WKHFODVV
FinchVideo.SimpleVideos1RWHWKDWZHKDYHRQO\LQFOXGHGFRQVWDQWVWKDWVHUYHWKH
SXUSRVHVZHKDYHRXWOLQHG:HWDNHFDUHQRWWRGHILQHFRQWHQWSURYLGHULPSOHPHQWDWLRQ
FRQVWDQWVKHUHVLQFHWKH\ZLOOQRWEHXVHIXOWRDFOLHQWDQGPLJKWWLHFOLHQWVWRXVLQJD
SDUWLFXODULPSOHPHQWDWLRQRIDFRQWHQWSURYLGHU:HVWULYHWRDFKLHYHJRRGVRIWZDUH
312 | Chapter 12:ಗUsing Content Providers
GHVLJQDQGHQVXUHWKDWRXUVRIWZDUHOD\HUVUHPDLQVHSDUDEOHZKHUHFOLHQWVVKRXOGQRW
KDYHGLUHFWFRPSLODWLRQGHSHQGHQFLHVRQFRQWHQWSURYLGHULPSOHPHQWDWLRQFODVVHV7KH
FRPSOHWHOLVWLQJRIWKHSXEOLF$3,RIWKHILQFKYLGHRSURYLGHU$3,IROORZV
/**
* Simple Videos columns
*/
public class FinchVideo {
public static final class SimpleVideos implements BaseColumns {
// This class cannot be instantiated
private SimpleVideos() {}
// uri references all videos
public static final Uri VIDEOS_URI = Uri.parse("content://" +
SIMPLE_AUTHORITY + "/" + SimpleVideos.VIDEO);
/**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = VIDEOS_URI;
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of notes.
*/
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/vnd.finch.video";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* video.
*/
public static final String CONTENT_VIDEO_TYPE =
"vnd.android.cursor.item/vnd.finch.video";
/**
* The video itself
* <P>Type: TEXT</P>
*/
public static final String VIDEO = "video";
/**
* Column name for the title of the video
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
* Column name for the description of the video.
*/
public static final String DESCRIPTION = "description";
/**
* Column name for the media uri
*/
Defining a Provider Public API | 313
public static final String URI = "uri";
}
/**
* Unique identifier for an element of media
*/
public static final String MEDIA_ID = "media_id";
...
// The API for FinchVideo.Videos is also defined in this class.
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
:H XVH WKH VIDEOS_URI WR GHILQH WKH YDOXH IRU RXU CONTENT_URI 7KH YLGHRV 85,
FRQWDLQVWKDWFRQWHQW85,DVGHVFULEHG
7KLVLVWKH0,0(W\SHRIWKHYLGHRHQWULHVWKDWRXUSURYLGHUZLOOVWRUH,Q£,PSOH
PHQWLQJWKHJHW7\SH0HWKRG¤RQSDJHZHH[SODLQKRZRXUFRQWHQWSURYLGHU
XVHVWKLVW\SH
7KHVHDUHWKHQDPHVRIWKHFROXPQVWKDWFOLHQWVFDQXVHWRDFFHVVYDOXHVLQ Cursor
REMHFWVWKDWRXUSURYLGHUFUHDWHV
Writing and Integrating a Content Provider
1RZWKDWZH¦YHH[DPLQHGWKHJHQHUDOVWUXFWXUHRIWKHVLPSOHYLGHROLVWDSSOLFDWLRQDQG
SURYLGHGDZD\IRUFOLHQWVWRDFFHVVRXUFRQWHQWSURYLGHULW¦VWLPHWRORRNDWKRZWKH
DSSOLFDWLRQERWKLPSOHPHQWVDQGFRQVXPHVWKHSimpleFinchVideoContentProvider
Common Content Provider Tasks
,QWKHIROORZLQJVHFWLRQVZHSURYLGHDKLJKOHYHOJXLGHWRWDVNVDVVRFLDWHGZLWKZULWLQJ
DFRQWHQWSURYLGHU:HWKHQSURYLGHDQLQWURGXFWLRQWR$QGURLG09&DQGILQLVKZLWK
DQH[SODQDWLRQRIWKHSimpleFinchVideoContentProviderFRGH
Extending ContentProvider
$SSOLFDWLRQVH[WHQGWKHContentProviderFODVVWRKDQGOH85,VWKDWUHIHUWRDSDUWLFXODU
W\SHRIGDWDVXFKDV006PHVVDJHVSLFWXUHVYLGHRVDQGVRIRUWK)RUH[DPSOHIRU
D FRQWHQW SURYLGHU FODVV WKDW KDQGOHG YLGHRV WKH ContentProvider.insert PHWKRG
ZRXOGLQVHUWGDWDWKDWGHVFULEHGDYLGHRLQWRD64/LWHWDEOHZLWKFROXPQVDSSURSULDWH
IRUWKDWLQIRUPDWLRQVXFKDVDWLWOHGHVFULSWLRQDQGVLPLODULQIRUPDWLRQ
6WDUWZULWLQJ\RXUFRQWHQWSURYLGHUE\LPSOHPHQWLQJWKHIROORZLQJWZRPHWKRGV
314 | Chapter 12:ಗUsing Content Providers
onCreate
7KLVPHWKRGSURYLGHVDKRRNWRDOORZ\RXUFRQWHQWSURYLGHUWRLQLWLDOL]HLWVHOI$Q\
FRGH\RXZDQWWRUXQMXVWRQFHVXFKDVPDNLQJDGDWDEDVHFRQQHFWLRQVKRXOG
UHVLGHLQWKLVPHWKRG
String getType(Uri uri)
7KLVPHWKRGJLYHQD85,UHWXUQVWKH0,0(W\SHRIWKHGDWDWKDWWKLVFRQWHQW
SURYLGHUSURYLGHVDWWKHJLYHQ85,7KH85,FRPHVIURPWKHFOLHQWDSSOLFDWLRQ
LQWHUHVWHGLQDFFHVVLQJWKHGDWD
<RX¦OO FRQWLQXH WR LPSOHPHQW E\ RYHUULGLQJ WKH PDLQ FRQWHQW SURYLGHU GDWD DFFHVV
PHWKRGV
insert(Uri uri, ContentValues values)
7KLVPHWKRGLVFDOOHGZKHQWKHFOLHQWFRGHQHHGVWRLQVHUWGDWDLQWRWKHGDWDEDVH
\RXUFRQWHQWSURYLGHULVVHUYLQJ1RUPDOO\WKHLPSOHPHQWDWLRQIRUWKLVPHWKRG
ZLOOHLWKHUGLUHFWO\RULQGLUHFWO\UHVXOWLQDGDWDEDVHLQVHUWRSHUDWLRQ
Cursor
query(Uri
uri,
String[]
String[] selectionArgs, String sortOrder)
projection,
String
selection,
7KLVPHWKRGLVFDOOHGZKHQHYHUDFOLHQWZLVKHVWRUHDGGDWDIURPWKHFRQWHQWSUR
YLGHU¦VGDWDEDVH1RUPDOO\KHUH\RXUHWULHYHGDWDXVLQJDQ64/SELECTVWDWHPHQW
DQGUHWXUQDFXUVRUFRQWDLQLQJWKHUHTXHVWHGGDWD'HYHORSHUVFDOOWKLVPHWKRG
LQGLUHFWO\XVLQJActivity¦VmanagedQueryPHWKRGRUFDOOstartManagingQueryRQWKH
UHWXUQ YDOXHV IURP WKLV PHWKRG ,I \RXU DFWLYLW\ IDLOV WR £PDQDJH¤ WKH UHWXUQHG
FXUVRURUIDLOVWRFORVHWKHFXUVRU\RXUDSSOLFDWLRQZLOOFRQWDLQDVHULRXVPHPRU\
OHDNWKDWZLOOUHVXOWLQSRRUSHUIRUPDQFHDQGOLNHO\FUDVKHV
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
7KLV PHWKRG LV FDOOHG ZKHQ D FOLHQW ZLVKHV WR XSGDWH RQH RU PRUH URZV LQ WKH
FRQWHQWSURYLGHU¦VGDWDEDVH,WWUDQVODWHVWRDQ64/UPDATEVWDWHPHQW
delete(Uri uri, String selection, String[] selectionArgs)
7KLVPHWKRGLVFDOOHGZKHQDFOLHQWZLVKHVWRGHOHWHRQHRUPRUHURZVLQWKHFRQWHQW
SURYLGHU¦VGDWDEDVH,WWUDQVODWHVWRDQ64/DELETEVWDWHPHQW
7KHVHIRXUPHWKRGVHDFKSHUIRUPDQDFWLRQRQGDWDUHIHUHQFHGE\DJLYHQ85,SDUDP
HWHU$W\SLFDOLPSOHPHQWDWLRQRIHDFKRIWKHVHPHWKRGVVWDUWVZLWKPDWFKLQJWKHLQ
FRPLQJ85,DUJXPHQWWRDSDUWLFXODUW\SHRIGDWD)RUH[DPSOHDFRQWHQWSURYLGHU
LPSOHPHQWDWLRQQHHGVWRILJXUHRXWZKHWKHUDJLYHQ85,UHIHUVWRDVSHFLILFYLGHRRU
WRDJURXSRIYLGHRV$IWHUDSURYLGHUPDWFKHVWKH85ODSSURSULDWH64/RSHUDWLRQV
IROORZ(DFKPHWKRGWKHQUHWXUQVDYDOXHWKDWHLWKHUFRQWDLQVUHIHUHQFHGGDWDGHVFULEHV
DIIHFWHGGDWDRUUHIHUVWRWKHQXPEHURIHOHPHQWVWKDWZHUHDIIHFWHGE\WKHRSHUDWLRQ
)RUH[DPSOHDTXHU\IRUDVSHFLILFYLGHRZRXOGUHWXUQDFXUVRUWKDWFRQWDLQHGDVLQJOH
YLGHRHOHPHQWLIWKHJLYHQ85,UHIHUHQFHGDVLQJOHHOHPHQWSUHVHQWLQDORFDOWDEOH
0DWFKLQJ85,VWRWDEOHGDWDLVDQLQWHJUDOSDUWRIWKHMRERIDFRQWHQWSURYLGHU:KLOH
\RXPLJKWQRWWKLQNLWZRXOGEHWKDWKDUGWRSDUVHDFRQWHQWSURYLGHU85,\RXUVHOI
Writing and Integrating a Content Provider | 315
$QGURLGSURYLGHVDQLFHXWLOLW\IRUGRLQJWKDWMREIRU\RXZKLFKLVFRQYHQLHQWEXWPRUH
LPSRUWDQWO\KHOSVGHYHORSHUVWRVWDQGDUGL]HRQWKHIRUPDWRISURYLGHU85,VWKDWZH
KDYHGLVFXVVHG7KHURIMatcherFODVVVXSSRUWVPDSSLQJIURP85,VFRQWDLQLQJDXWKRU
LW\SDWKDQG,'VWULQJVWRDSSOLFDWLRQGHILQHGFRQVWDQWVXVDEOHZLWKcaseVWDWHPHQWV
WKDWKDQGOHSDUWLFXODUVXEW\SHVRI85,V)URPWKHUHWKHSURYLGHUFDQGHFLGHZKDW64/
RSHUDWLRQVWRXVHWRPDQDJHDFWXDOWDEOHURZV$W\SLFDOFRQWHQWSURYLGHUZLOOFUHDWHD
VWDWLF LQVWDQFH RI URIMatcher DQG SRSXODWH LW XVLQJ D VWDWLF LQLWLDOL]HU WKDW FDOOV URI
Matcher.addURIWRHVWDEOLVKWKHILUVWOHYHOPDSSLQJXVHGODWHULQFRQWHQWSURYLGHUGDWD
PHWKRGV2XUVLPSOHYLGHRFRQWHQWSURYLGHUGRHVWKLVLQ£7KH6LPSOH)LQFK9LGHR&RQ
WHQW3URYLGHU&ODVVDQG,QVWDQFH9DULDEOHV¤RQSDJH
File Management and Binary Data
&RQWHQWSURYLGHUVRIWHQQHHGWRPDQDJHODUJHFKXQNVRIELQDU\GDWDVXFKDVDELWPDS
RUPXVLFFOLS6WRUDJHRIODUJHGDWDILOHVVKRXOGLQIOXHQFHWKHGHVLJQRIDQDSSOLFDWLRQ
DQGZLOOOLNHO\KDYHVLJQLILFDQWSHUIRUPDQFHLPSOLFDWLRQV$FRQWHQWSURYLGHUFDQVHUYH
ILOHVWKURXJKFRQWHQWSURYLGHU85,VLQDZD\WKDWHQFDSVXODWHVWKHORFDWLRQRIDFWXDO
SK\VLFDOILOHVVRWKDWFOLHQWVFDQEHDJQRVWLFDERXWWKDWLQIRUPDWLRQ&OLHQWVXVHFRQWHQW
SURYLGHU85,VWRDFFHVVILOHVZLWKRXWNQRZLQJZKHUHWKHILOHVDFWXDOO\UHVLGH7KLVOD\HU
RILQGLUHFWLRQHQDEOHVDFRQWHQWSURYLGHUWRPDQDJHWKHVHILOHVLQDZD\WKDWPDNHVWKH
PRVWVHQVHIRUWKHFRQWHQWSURYLGHUGDWDZLWKRXWKDYLQJWKDWLQIRUPDWLRQOHDNLQWRWKH
FOLHQW¢ZKLFKFRXOGHQGXSFDXVLQJFRGHFKDQJHVLQDFOLHQWLIWKHFRQWHQWSURYLGHU
QHHGHGWRPDNHDFKDQJHLQWKHZD\WKHSK\VLFDOILOHVDUHVWRUHG*HQHUDOO\LW¦VPXFK
HDVLHUWRFKDQJHMXVWWKHSURYLGHUWKDQDOORILWVSRWHQWLDOFOLHQWV&OLHQWVVKRXOGQRW
QHHGWRNQRZWKDWDVHWRISURYLGHUPHGLDILOHVPLJKWUHVLGHLQIODVKPHPRU\RQWKH
6'FDUGRUHQWLUHO\RQWKHQHWZRUNVRORQJDVWKHSURYLGHUPDNHVWKHILOHVDFFHVVLEOH
IURPDVHWRIFRQWHQWSURYLGHU85,VWKDWWKHFOLHQWXQGHUVWDQGV7KHFOLHQWZLOOMXVWXVH
WKHPHWKRGContentResolver.openInputStreamIRUDJLYHQ85,DQGWKHQUHDGGDWDIURP
WKHUHVXOWDQWVWUHDP
$GGLWLRQDOO\ZKHQVKDULQJODUJHDPRXQWVRIGDWDEHWZHHQDSSOLFDWLRQVVLQFHDQ$Q
GURLGDSSOLFDWLRQVKRXOGQRWUHDGRUZULWHILOHVWKDWDQRWKHUDSSOLFDWLRQKDVFUHDWHGD
FRQWHQWSURYLGHUPXVWEHXVHGWRDFFHVVWKHUHOHYDQWE\WHV7KHUHIRUHZKHQWKHILUVW
FRQWHQW SURYLGHU UHWXUQV D SRLQWHU WR D ILOH WKDW SRLQWHU PXVW EH LQ WKH IRUP RI D
content://85,LQVWHDGRID8QL[ILOHQDPH7KHXVHRIDcontent://85,FDXVHVWKHILOH
WREHRSHQHGDQGUHDGXQGHUWKHSHUPLVVLRQVRIWKHFRQWHQWSURYLGHUWKDWRZQVWKHILOH
QRWWKHFOLHQWDSSOLFDWLRQ ZKLFKVKRXOGQRWKDYHDFFHVVULJKWVWRWKHILOH ,W¦VDOVRLPSRUWDQWWRFRQVLGHUWKDWILOHV\VWHP,2LVPXFKIDVWHUDQGPRUHYHUVDWLOH
WKDQGHDOLQJZLWK64/LWHEOREVDQGLW¦VEHWWHUWRXVHWKH8QL[ILOHV\VWHPWRGLUHFWO\
VWRUHELQDU\GDWD$GGLWLRQDOO\WKHUH¦VQRDGYDQWDJHWRSXWWLQJELQDU\GDWDLQDGDWD
EDVHVLQFH\RXFDQ¦WVHDUFKRQLW
7RLPSOHPHQWWKLVDSSURDFKLQ\RXUDSSWKH$QGURLG6'.GRFXPHQWDWLRQVXJJHVWV
RQHVWUDWHJ\ZKHUHDFRQWHQWSURYLGHUSHUVLVWVGDWDWRDILOHDQGVWRUHVDcontent://85,
316 | Chapter 12:ಗUsing Content Providers
LQWKHGDWDEDVHWKDWSRLQWVWRWKHILOHDVVKRZQLQ)LJXUH&OLHQWDSSOLFDWLRQVZLOO
SDVVWKH85,LQWKLVILHOGWR ContentProvider.openStreamWRUHWULHYHWKHE\WHVWUHDP
IURPWKHILOHLWVSHFLILHV
)LJXUH$QGURLG09&¦VW\SLFDOXVHRIFXUVRUVDQGFRQWHQWSURYLGHUV
,QGHWDLOWRLPSOHPHQWWKHILOHDSSURDFKLQVWHDGRIFUHDWLQJDK\SRWKHWLFDOXVHUWDEOH
OLNHWKLV
CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password
TEXT, picture BLOB );
WKHGRFXPHQWDWLRQVXJJHVWVWZRWDEOHVWKDWORRNOLNHWKLV
CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password
TEXT, picture TEXT );
CREATE TABLE userPicture ( _id INTEGER PRIMARY KEY AUTOINCREMENT,
_data TEXT );
7KHpictureFROXPQRIWKHuserWDEOHZLOOVWRUHDcontent://85,WKDWSRLQWVWRDURZ
LQWKHuserPictureWDEOH7KH_dataFROXPQRIWKHuserPictureWDEOHZLOOSRLQWWRDUHDO
ILOHRQWKH$QGURLGILOHV\VWHP
,IWKHSDWKWRWKHILOHZHUHVWRUHGGLUHFWO\LQWKHuserWDEOHFOLHQWVZRXOGJHWDSDWKEXW
EHXQDEOHWRRSHQWKHILOHEHFDXVHLW¦VRZQHGE\WKHDSSOLFDWLRQVHUYLQJXSWKHFRQWHQW
SURYLGHUDQGWKHFOLHQWVGRQ¦WKDYHSHUPLVVLRQWRUHDGLW,QWKHVROXWLRQVKRZQKHUH
KRZHYHUDFFHVVLVFRQWUROOHGE\DContentResolverFODVVZH¦OOH[DPLQHODWHU
7KHContentResolverFODVVORRNVIRUDFROXPQQDPHG_dataZKHQSURFHVVLQJUHTXHVWV
,IWKHILOHVSHFLILHGLQWKDWFROXPQLVIRXQGWKHSURYLGHU¦V openOutputStreamPHWKRG
RSHQVWKHILOHDQGUHWXUQVDjava.io.OutputStreamWRWKHFOLHQW7KLVLVWKHVDPHREMHFW
WKDW ZRXOG EH UHWXUQHG LI WKH FOLHQW ZHUH DEOH WR RSHQ WKH ILOH GLUHFWO\ 7KH
ContentResolver FODVV LV SDUW RI WKH VDPH DSSOLFDWLRQ DV WKH FRQWHQW SURYLGHU DQG
WKHUHIRUHLVDEOHWRRSHQWKHILOHZKHQWKHFOLHQWFDQQRW
/DWHU LQ WKLV FKDSWHU ZH ZLOO GHPRQVWUDWH D FRQWHQW SURYLGHU WKDW XVHV WKH FRQWHQW
SURYLGHUILOHPDQDJHPHQWIDFLOLW\WRVWRUHWKXPEQDLOLPDJHV
File Management and Binary Data | 317
Android MVC and Content Observation
,W¦VLPSRUWDQWWRUHODWHDELJJHUSLFWXUHRIKRZ09&ZRUNVZLWKFRQWHQWSURYLGHUVLQ
$QGURLG$GGLWLRQDOO\DPRUHGHWDLOHGGLVFXVVLRQRI09&LQ$QGURLGZLOOOHDGXVLQWR
£$£1HWZRUN09&¤¤RQSDJH
,QRUGHUWRXQGHUVWDQGWKHSRZHURIWKHFRQWHQWSURYLGHUIUDPHZRUNZHQHHGWRGLVFXVV
KRZFXUVRUXSGDWHHYHQWVGULYHG\QDPLFXSGDWHVRI$QGURLG8,V:HWKLQNLWZLOOKHOS
WRKLJKOLJKWWKHRIWHQRYHUORRNHGFRPPXQLFDWLRQVSDWKZD\VLQWKHWUDGLWLRQDO09&
SURJUDPPLQJSDWWHUQZKHUHWKHIROORZLQJRFFXUVWKH9LHZGHOLYHUVXVHULQSXWHYHQWV
WRWKH&RQWUROOHUWKH&RQWUROOHUPDNHVPRGLILFDWLRQVWRWKH0RGHODQGWKH0RGHO
VHQGVXSGDWHHYHQWVWRWKH9LHZDQGWRDQ\RWKHUREVHUYHUWKDWUHJLVWHUVLQWHUHVWLQWKH
0RGHOWKH9LHZUHQGHUVWKHFRQWHQWVRIWKH0RGHOXVXDOO\ZLWKRXWGLUHFWO\HQJDJLQJ
LQDSSOLFDWLRQORJLFDQGLGHDOO\MXVWVLPSO\LWHUDWHVRYHUWKHGDWDLQWKH0RGHO
,Q$QGURLGWKH09&SDWWHUQZRUNVDVVKRZQLQ)LJXUHZKHUHH[SOLFLWO\
‡ 7KH 0RGHO FRQVLVWV RI D FRQWHQW SURYLGHU DQG WKH FXUVRUV LW UHWXUQV IURP LWV
queryPHWKRGDVZHOODVWKHGDWDLWKROGVLQLWV64/LWHWDEOHV
‡ &RQWHQW SURYLGHUV VKRXOG EH ZULWWHQ WR VHQG QRWLILFDWLRQ HYHQWV ZKHQHYHU WKH\
FKDQJHGDWDE\FDOOLQJContentResolver.notifyChange6LQFHWKHSURYLGHUKDVVROH
DFFHVVWRPRGLI\WKHGDWDLWZLOODOZD\VNQRZZKHQGDWDFKDQJHV
‡ 1RWLILFDWLRQVDUHGHOLYHUHGWRD8,FRPSRQHQWRIWHQD ListViewWKURXJKREVHU
YDWLRQRICursorREMHFWVWKDWDUHERXQGWRFRQWHQWSURYLGHU85,V&XUVRUXSGDWH
PHVVDJHVILUHIURPWKH0RGHOWRWKH9LHZLQUHVSRQVHWRWKHSURYLGHU¦VLQYRFDWLRQ
RI notifyChange7KH9LHZDQG&RQWUROOHUFRUUHVSRQGWR$QGURLGDFWLYLWLHVDQG
WKHLUYLHZVDQGWRWKHFODVVHVWKDWOLVWHQWRWKHHYHQWVWKH\JHQHUDWH6SHFLILFDOO\
WKH V\VWHP GHOLYHUV ContentObserver.onChange PHVVDJHV WR LQVWDQFHV RI
ContentObserverUHJLVWHUHGXVLQJ Cursor.registerContentObserver7KH$QGURLG
FODVVHV DXWRPDWLFDOO\ UHJLVWHU IRU FXUVRU FKDQJHV ZKHQHYHU D GHYHORSHU FDOOV D
PHWKRGVXFKDV ListView.setAdapter(ListAdapter)7KHOLVWYLHZKDVDQLQWHUQDO
FRQWHQWREVHUYHUDQGWKHOLVWDGDSWHUZLOOUHJLVWHUZLWKWKHCursorREMHFW
7RWKLQNDERXWKRZWKLVQRWLILFDWLRQZRUNVLQSUDFWLFHVXSSRVHDQDFWLYLW\ZHUHWRFDOO
ContentResolver.delete $V ZH¦OO VHH VKRUWO\ WKH FRUUHVSRQGLQJ FRQWHQW SURYLGHU
ZRXOGILUVWGHOHWHDURZIURPLWVGDWDEDVHDQGWKHQQRWLI\WKHFRQWHQWUHVROYHU85,
FRUUHVSRQGLQJWRWKDWURZ$Q\OLVWHQLQJFXUVRUVHPEHGGHGLQDQ\YLHZZLOOEHQRWLILHG
VLPSO\WKDWGDWDKDVFKDQJHGWKHYLHZVZLOOLQWXUQJHWWKHXSGDWHHYHQWDQGWKHQ
UHSDLQWWKHPVHOYHVWRUHIOHFWWKHQHZVWDWH7KHYLHZVSDLQWZKDWHYHUVWDWHUHVLGHVLQ
WKHLUGLVSOD\DUHDLIWKDWKDSSHQHGWRLQFOXGHWKHGHOHWHGHOHPHQWLWZLOOGLVDSSHDU
IURPWKH8,7KHCursorREMHFWVDFWDVDSUR[\REMHFWEHWZHHQFXUVRUFRQVXPHUVDQG
WKHFRQWHQWSURYLGHUV\VWHP(YHQWVIORZIURPWKHSURYLGHUWKURXJKWKHFXUVRUDQG
LQWRWKH9LHZV\VWHP7KHGHJUHHRIDXWRPDWLRQLQWKLVFKDLQRIHYHQWVUHVXOWVLQVLJ
QLILFDQWFRQYHQLHQFHIRUGHYHORSHUVZKRQHHGWRSHUIRUPRQO\WKHPLQLPXPDPRXQW
RIZRUNWRSXWLWLQWRDFWLRQ$GGLWLRQDOO\SURJUDPVGRQ¦WKDYHWRH[SOLFLWO\SROOWR
318 | Chapter 12:ಗUsing Content Providers
)LJXUH7\SLFDOXVHRIFXUVRUVDQGFRQWHQWSURYLGHUVLQWKH$QGURLG09&
NHHSWKHLUUHQGHULQJRIWKHPRGHOXSWRGDWHVLQFHWKHPRGHOWHOOVWKHYLHZZKHQVWDWH
FKDQJHV
A Complete Content Provider: The
SimpleFinchVideoContentProvider Code
1RZ WKDW \RX XQGHUVWDQG WKH LPSRUWDQW WDVNV DVVRFLDWHG ZLWK ZULWLQJ D FRQWHQW
SURYLGHU DQG $QGURLG 09&¢WKH FRPPXQLFDWLRQ V\VWHP IRU $QGURLG FRQWHQW
SURYLGHUV¢OHW¦VVHHKRZWREXLOG\RXURZQFRQWHQWSURYLGHU7KH SimpleFinchVideo
ContentProviderFODVVH[WHQGVContentProviderDVVKRZQKHUH
public class SimpleFinchVideoContentProvider extends ContentProvider {
The SimpleFinchVideoContentProvider Class and Instance Variables
$VXVXDOLW¦VEHVWWRXQGHUVWDQGWKHPDMRUFODVVDQGLQVWDQFHYDULDEOHVXVHGE\DPHWKRG
EHIRUHH[DPLQLQJKRZWKHPHWKRGZRUNV7KHPHPEHUYDULDEOHVZHQHHGWRXQGHUVWDQG
IRUSimpleFinchVideoContentProviderDUH
private static final String DATABASE_NAME = "simple_video.db";
private static final int DATABASE_VERSION = 2;
private static final String VIDEO_TABLE_NAME = "video";
private DatabaseHelper mOpenHelper;
DATABASE_NAME
7KH QDPH RI WKH GDWDEDVH ILOH RQ WKH GHYLFH )RU WKH VLPSOH )LQFK YLGHR WKH
IXOO SDWK WR WKH ILOH LV GDWDGDWDFRPRUHLOO\GHPRSDILQFKYLGHRGDWDEDVHVVLP
SOHBYLGHRGE
A Complete Content Provider: The SimpleFinchVideoContentProvider Code | 319
Download from Wow! eBook <www.wowebook.com>
DATABASE_VERSION
7KHYHUVLRQRIWKHGDWDEDVHWKDWLVFRPSDWLEOHZLWKWKLVFRGH,IWKLVQXPEHULV
KLJKHUWKDQWKHGDWDEDVHYHUVLRQRIWKHGDWDEDVHLWVHOIWKHDSSOLFDWLRQFDOOVWKH
DatabaseHelper.onUpdatePHWKRG
VIDEO_TABLE_NAME
7KHQDPHRIWKHYLGHRWDEOHZLWKLQWKHsimple_videoGDWDEDVH
mOpenHelper
7KHGDWDEDVHKHOSHULQVWDQFHYDULDEOHWKDWLVLQLWLDOL]HGGXULQJonCreate,WSURYLGHV
DFFHVVWRWKHGDWDEDVHIRUWKHinsert queryupdateDQGdeletePHWKRGV
sUriMatcher
$VWDWLFLQLWLDOL]DWLRQEORFNWKDWSHUIRUPVLQLWLDOL]DWLRQVRIVWDWLFYDULDEOHVWKDWFDQ¦W
EHSHUIRUPHGDVVLPSOHRQHOLQHUV)RUH[DPSOHRXUVLPSOHYLGHRFRQWHQWSURYLGHU
EHJLQVE\HVWDEOLVKLQJDFRQWHQWSURYLGHU85,PDSSLQJLQDVWDWLFLQLWLDOL]DWLRQRI
DUriMatcherDVIROORZV
private static UriMatcher sUriMatcher;
private static final int VIDEOS = 1;
private static final int VIDEO_ID = 2;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY, FinchVideo.SimpleVideos.VIDEO_NAME, VIDEOS);
// use of the hash character indicates matching of an id
sUriMatcher.addURI(AUTHORITY,
FinchVideo.SimpleVideos.VIDEO_NAME + "/#", VIDEO_ID);
...
// more initialization to follow
7KH UriMatcherFODVVSURYLGHVWKHEDVLVRIWKHFRQYHQLHQFHXWLOLWLHVWKDW$QGURLG
SURYLGHVIRUPDSSLQJFRQWHQWSURYLGHU85,V7RXVHDQLQVWDQFHRILW\RXSRSXODWH
LWZLWKPDSSLQJVIURPD85,VWULQJVXFKDV£YLGHRV¤WRDFRQVWDQWILHOG2XUPDS
SLQJV ZRUN DV IROORZV WKH DSSOLFDWLRQ ILUVW SURYLGHV DQ DUJXPHQW Uri
Matcher.NO_MATCHWRWKHFRQVWUXFWRURIWKHSURYLGHUUriMatcherWRGHILQHWKHYDOXH
WKDWLQGLFDWHVZKHQD85,GRHVQRWPDWFKDQ\85,7KHDSSOLFDWLRQWKHQDGGV
PDSSLQJVIRUPXOWLSOHYLGHRVWRVIDEOSDQGWKHQDPDSSLQJIRUDVSHFLILFYLGHRWR
VIDEO_ID :LWK DOO SURYLGHU 85,V PDSSHG WR DQ LQWHJHU YDOXH WKH SURYLGHU FDQ
SHUIRUPDVZLWFKRSHUDWLRQWRMXPSWRWKHDSSURSULDWHKDQGOLQJFRGHIRUPXOWLSOH
DQGVLQJOHYLGHRV
7KLV PDSSLQJ FDXVHV D 85, VXFK DV content://com.oreilly.demo.pa.finch
video.SimpleFinchVideo/videoWRPDSWRWKHFRQVWDQWVIDEOSPHDQLQJDOOYLGHRV
$85,IRUDVLQJOHYLGHRVXFKDV content://oreilly.demo.pa.finchvideo.Simple
FinchVideo/video/7ZLOOPDSWRWKHFRQVWDQWVIDEO_IDIRUDVLQJOHYLGHR7KHKDVK
PDUNDWWKHHQGRIWKH85,PDWFKHUELQGLQJLVDZLOGFDUGIRUD85,HQGLQJZLWK
DQ\LQWHJHUQXPEHU
320 | Chapter 12:ಗUsing Content Providers
sVideosProjectionMap
7KHSURMHFWLRQPDSXVHGE\WKHTXHU\PHWKRG7KLV HashMapPDSVWKHFRQWHQW
SURYLGHU¦VFROXPQQDPHVWRGDWDEDVHFROXPQQDPHV$SURMHFWLRQPDSLVQRWUH
TXLUHGEXWZKHQXVHGLWPXVWOLVWDOOFROXPQQDPHVWKDWPLJKWEHUHWXUQHGE\WKH
TXHU\,Q SimpleFinchVideoContentProviderWKHFRQWHQWSURYLGHUFROXPQQDPHV
DQGWKHGDWDEDVHFROXPQQDPHVDUHLGHQWLFDOVRWKHsVideosProjectionMapLVQRW
UHTXLUHG%XWZHSURYLGHLWDVDQH[DPSOHIRUDSSOLFDWLRQVWKDWPLJKWQHHGLW,Q
WKHIROORZLQJFRGHZHFUHDWHRXUH[DPSOHSURMHFWLRQPDSSLQJ
// example projection map, not actually used in this application
sVideosProjectionMap = new HashMap<String, String>();
sVideosProjectionMap.put(FinchVideo.Videos._ID,
FinchVideo.Videos._ID);
sVideosProjectionMap.put(FinchVideo.Videos.TITLE,
FinchVideo.Videos.TITLE);
sVideosProjectionMap.put(FinchVideo.Videos.VIDEO,
FinchVideo.Videos.VIDEO);
sVideosProjectionMap.put(FinchVideo.Videos.DESCRIPTION,
FinchVideo.Videos.DESCRIPTION);
Implementing the onCreate Method
'XULQJLQLWLDOL]DWLRQRIWKHVLPSOH)LQFKYLGHRFRQWHQWSURYLGHUZHFUHDWHWKHYLGHR¦V
64/LWHGDWDVWRUHDVIROORZV
private static class DatabaseHelper extends SQLiteOpenHelper {
public void onCreate(SQLiteDatabase sqLiteDatabase) {
createTable(sqLiteDatabase);
}
// create table method may also be called from onUpgrade
private void createTable(SQLiteDatabase sqLiteDatabase) {
String qs = "CREATE TABLE " + VIDEO_TABLE_NAME + " (" +
FinchVideo.SimpleVideos._ID + " INTEGER PRIMARY KEY, " +
FinchVideo.SimpleVideos.TITLE_NAME + " TEXT, " +
FinchVideo.SimpleVideos.DESCRIPTION_NAME + " TEXT, " +
FinchVideo.SimpleVideos.URI_NAME + " TEXT);";
sqLiteDatabase.execSQL(qs);
}
}
:KHQFUHDWLQJ64/LWHWDEOHVWRVXSSRUWFRQWHQWSURYLGHURSHUDWLRQVGHYHORSHUVDUH
UHTXLUHGWRSURYLGHDILHOGZLWKDSULPDU\NH\FDOOHG _id:KLOHLW¦VQRWLPPHGLDWHO\
FOHDUWKDWWKLVILHOGLVUHTXLUHGXQOHVV\RXUHDGWKH$QGURLGGHYHORSHUGRFVLQGHWDLO
WKH $QGURLG FRQWHQW PDQDJHPHQW V\VWHP DFWXDOO\ GRHV HQIRUFH WKH SUHVHQFH RI WKH
_idILHOGLQWKHFXUVRUVWKDWDUHUHWXUQHGE\WKHTXHU\PHWKRG _idLVXVHGLQTXHU\
PDWFKLQJZLWKWKH#VSHFLDOFKDUDFWHULQFRQWHQWSURYLGHU85/V)RUH[DPSOHD85/
VXFKDVFRQWHQWFRQWDFWVSHRSOHZRXOGPDSWRDGDWDURZLQDcontactsWDEOHZLWK
_id7KHUHTXLUHPHQWLVUHDOO\MXVWWRXVHDVSHFLILFQDPHIRUDWDEOHSULPDU\NH\
A Complete Content Provider: The SimpleFinchVideoContentProvider Code | 321
Implementing the getType Method
1H[WZHLPSOHPHQWWKHgetTypePHWKRGWRGHWHUPLQH0,0(W\SHVRIDUELWUDU\85,V
SDVVHGIURPWKHFOLHQW$V\RXFDQVHHLQWKHIROORZLQJFRGHZHSURYLGH85,PDWFKLQJ
IRUVIDEOSDQGVIDEO_IDWR0,0(W\SHVZHGHILQHGLQRXUSXEOLF$3,
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case VIDEOS:
return FinchVideo.SimpleVideos.CONTENT_TYPE;
case VIDEO_ID:
return FinchVideo.SimpleVideos.CONTENT_VIDEO_TYPE;
default:
throw new IllegalArgumentException("Unknown video type: " + uri);
}
}
Implementing the Provider API
$ FRQWHQW SURYLGHU LPSOHPHQWDWLRQ PXVW RYHUULGH WKH GDWD PHWKRGV RI WKH
ContentProviderEDVHFODVV insert query updateDQG delete)RUWKHVLPSOHYLGHR
DSSOLFDWLRQWKHVHPHWKRGVDUHGHILQHGE\WKHSimpleFinchVideoContentProviderFODVV
The query method
$IWHUPDWFKLQJWKHLQFRPLQJ85,RXUFRQWHQWSURYLGHUqueryPHWKRGSHUIRUPVDFRU
UHVSRQGLQJVHOHFWRQDUHDGDEOHGDWDEDVHE\GHOHJDWLQJWRSQLiteDatabase.queryDQG
WKHQUHWXUQVWKHUHVXOWVLQWKHIRUPRIDGDWDEDVHCursorREMHFW7KHFXUVRUZLOOFRQWDLQ
DOOGDWDEDVHURZVGHVFULEHGE\WKH85,DUJXPHQW$IWHUZH¦YHPDGHWKHTXHU\WKH
$QGURLGFRQWHQWSURYLGHUPHFKDQLVPDXWRPDWLFDOO\VXSSRUWVWKHXVHRIFXUVRULQVWDQ
FHVDFURVVSURFHVVHVZKLFKSHUPLWVRXUSURYLGHU queryPHWKRGWRVLPSO\UHWXUQWKH
FXUVRU DV D QRUPDO UHWXUQ YDOXH WR PDNH LW DYDLODEOH WR FOLHQWV WKDW PLJKW UHVLGH LQ
DQRWKHUSURFHVV
7KH query PHWKRG DOVR VXSSRUWV WKH SDUDPHWHUV uri projection selection
selectionArgsDQGsortOrderZKLFKDUHXVHGLQWKHVDPHPDQQHUDVWKHDUJXPHQWVWR
SQLiteDatabase.queryWKDWZHVDZLQ&KDSWHU-XVWDVZLWKDQ\64/SELECTSDUDP
HWHUVWRWKHqueryPHWKRGHQDEOHRXUSURYLGHUFOLHQWVWRVHOHFWRQO\VSHFLILFYLGHRVWKDW
PDWFKWKHTXHU\SDUDPHWHUV,QDGGLWLRQWRSDVVLQJD85,DFOLHQWFDOOLQJWKHVLPSOH
YLGHRFRQWHQWSURYLGHUFRXOGDOVRSDVVDQDGGLWLRQDOwhereFODXVHZLWKwhereDUJXPHQWV
)RUH[DPSOHWKHVHDUJXPHQWVZRXOGHQDEOHDGHYHORSHUWRTXHU\IRUYLGHRVIURPD
SDUWLFXODUDXWKRU
322 | Chapter 12:ಗUsing Content Providers
$V ZH¦YH VHHQ 09& LQ $QGURLG UHOLHV RQ FXUVRUV DQG WKH GDWD WKH\
FRQWDLQDVZHOODVIUDPHZRUNEDVHGGHOLYHU\RIFRQWHQWREVHUYHUXSGDWH
PHVVDJHV 6LQFH FOLHQWV LQ GLIIHUHQW SURFHVVHV VKDUH Cursor REMHFWV D
FRQWHQWSURYLGHULPSOHPHQWDWLRQPXVWWDNHFDUHQRWWRFORVHDFXUVRU
WKDWLWKDVVHUYHGIURPLWV queryPHWKRG,IDFXUVRULVFORVHGLQWKLV
PDQQHUFOLHQWVZLOOQRWVHHH[FHSWLRQVWKURZQLQVWHDGWKHFXUVRUZLOO
DOZD\VDFWOLNHLWLVHPSW\DQGLWZLOOQRORQJHUUHFHLYHXSGDWHHYHQWV¢
LW¦VXSWRWKHDFWLYLW\WRSURSHUO\PDQDJHWKHUHWXUQHGFXUVRUV
:KHQWKHGDWDEDVHTXHU\FRPSOHWHVRXUSURYLGHUWKHQFDOOV Cursor.setNotificatio
nUriWRVHWWKH85,WKDWWKHSURYLGHULQIUDVWUXFWXUHZLOOXVHWRGHFLGHZKLFKSURYLGHU
XSGDWHHYHQWVJHWGHOLYHUHGWRWKHQHZO\FUHDWHGFXUVRU7KLV85,EHFRPHVWKHSRLQW
RILQWHUDFWLRQEHWZHHQFOLHQWVWKDWREVHUYHGDWDUHIHUHQFHGE\WKDW85,DQGWKHFRQWHQW
SURYLGHUWKDWQRWLILHVWKDW85,7KLVVLPSOHPHWKRGFDOOGULYHVWKHFRQWHQWSURYLGHU
XSGDWH PHVVDJHV WKDW ZH GLVFXVVHG LQ £$QGURLG 09& DQG &RQWHQW 2EVHUYD
WLRQ¤RQSDJH
+HUHZHSURYLGHWKHFRGHIRURXUVLPSOHFRQWHQWSURYLGHU¦VqueryPHWKRGZKLFKSHU
IRUPV85,PDWFKLQJTXHULHVWKHGDWDEDVHDQGWKHQUHWXUQVWKHFXUVRU
@Override
public Cursor query(Uri uri, String[] projection, String where,
String[] whereArgs, String sortOrder)
{
// If no sort order is specified use the default
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = FinchVideo.SimpleVideos.DEFAULT_SORT_ORDER;
} else {
orderBy = sortOrder;
}
int match = sUriMatcher.match(uri);
Cursor c;
switch (match) {
case VIDEOS:
// query the database for all videos
c = mDb.query(VIDEO_TABLE_NAME, projection,
where, whereArgs,
null, null, sortOrder);
c.setNotificationUri(
getContext().getContentResolver(),
FinchVideo.SimpleVideos.CONTENT_URI);
break;
case VIDEO_ID:
// query the database for a specific video
long videoID = ContentUris.parseId(uri);
c = mDb.query(VIDEO_TABLE_NAME, projection,
A Complete Content Provider: The SimpleFinchVideoContentProvider Code | 323
}
FinchVideo.Videos._ID + " = " + videoID +
(!TextUtils.isEmpty(where) ?
" AND (" + where + ')' : ""),
whereArgs, null, null, sortOrder);
c.setNotificationUri(
getContext().getContentResolver(),
FinchVideo.SimpleVideos.CONTENT_URI);
break;
default:
throw new IllegalArgumentException("unsupported uri: " + uri);
return c;
}
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
7KLVPDWFKHVWKH85,XVLQJRXUSUHEXLOW85,PDWFKHU
6HWWLQJ WKH QRWLILFDWLRQ 85, WR FinchVideo.SimpleVideos.CONTENT_URI FDXVHV WKH
FXUVRUWRUHFHLYHDOOFRQWHQWUHVROYHUQRWLILFDWLRQHYHQWVIRUGDWDUHIHUHQFHGE\WKDW
85,,QWKLVFDVHWKHFXUVRUZLOOUHFHLYHDOOHYHQWVUHODWHGWRDOOYLGHRVVLQFHWKDWLV
ZKDWFinchVideo.SimpleVideos.CONTENT_URIUHIHUHQFHV
7KHFXUVRULVUHWXUQHGGLUHFWO\$VPHQWLRQHGWKH$QGURLGFRQWHQWSURYLGHUV\VWHP
SURYLGHVVXSSRUWIRUVKDULQJDQ\GDWDLQWKHFXUVRUDFURVVSURFHVVHV,QWHUSURFHVV
GDWDVKDULQJKDSSHQV£IRUIUHH¤DVSDUWRIWKHFRQWHQWSURYLGHUV\VWHP\RXFDQMXVW
UHWXUQWKHFXUVRUDQGLWZLOOEHFRPHDYDLODEOHWRDFWLYLWLHVLQGLIIHUHQWSURFHVVHV
The insert method
/HW¦VPRYHRQWRWKH insertPHWKRGZKLFKUHFHLYHVYDOXHVIURPDFOLHQWYDOLGDWHV
WKHPDQGWKHQDGGVDQHZURZWRWKHGDWDEDVHFRQWDLQLQJWKRVHYDOXHV7KHYDOXHVDUH
SDVVHGWRWKHContentProviderFODVVLQDContentValuesREMHFW
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
// Validate the requested uri
if (sUriMatcher.match(uri) != VIDEOS) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
verifyValues(values);
// insert the initialValues into a new database row
SQLiteDatabase db = mOpenDbHelper.getWritableDatabase();
324 | Chapter 12:ಗUsing Content Providers
long rowId = db.insert(VIDEO_TABLE_NAME,
FinchVideo.SimpleVideos.VIDEO_NAME, values);
if (rowId > 0) {
Uri videoURi =
ContentUris.withAppendedId(
FinchVideo.SimpleVideos.CONTENT_URI, rowId);
getContext().getContentResolver().
notifyChange(videoURi, null);
return videoURi;
}
throw new SQLException("Failed to insert row into " + uri);
}
7KHinsertPHWKRGZLOODOVRPDWFKWKHLQFRPLQJ85,SHUIRUPDFRUUHVSRQGLQJGDWD
EDVHLQVHUWRSHUDWLRQDQGWKHQUHWXUQD85,WKDWUHIHUHQFHVWKHQHZGDWDEDVHURZ
6LQFH WKH SQLiteDatabase.insert PHWKRG UHWXUQV WKH GDWDEDVH URZ ,' RI WKH QHZO\
LQVHUWHGURZZKLFKLVDOVRLWVYDOXHIRUWKH _idILHOGWKHFRQWHQWSURYLGHUFDQHDVLO\
SXWWRJHWKHUWKHULJKW85,E\DSSHQGLQJWKH rowIDYDULDEOHWRWKHFRQWHQWSURYLGHU
DXWKRULW\GHILQHGLQWKHFRQWHQWSURYLGHUSXEOLF$3,WKDWZHGLVFXVVHGLQ&KDSWHU
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
:HXVH$QGURLG¦VXWLOLWLHVIRUPDQLSXODWLQJFRQWHQWSURYLGHU85,V¢VSHFLILFDOO\WKH
PHWKRGContentUris.withAppendedIdWRDSSHQGWKHrowIdDVWKH,'RIWKHUHWXUQHG
LQVHUWLRQ85,&OLHQWVFDQWXUQDURXQGDQGTXHU\WKHFRQWHQWSURYLGHUXVLQJWKLV
VDPH85,WRVHOHFWDFXUVRUFRQWDLQLQJWKHGDWDYDOXHVIRUWKHLQVHUWHGURZ
+HUHWKHFRQWHQWSURYLGHUQRWLILHVD85,WKDWZLOOFDXVHDFRQWHQWXSGDWHHYHQWWR
EHILUHGDQGGHOLYHUHGWRREVHUYLQJFXUVRUV1RWHWKDWWKHSURYLGHU¦VLQYRFDWLRQRI
QRWLI\LVWKHRQO\UHDVRQDQHYHQWZLOOEHVHQWWRFRQWHQWREVHUYHUV
The update method
7KHupdatePHWKRGRSHUDWHVLQWKHVDPHPDQQHUDVinsertEXWLQVWHDGFDOOVupdateRQ
WKH DSSURSULDWH GDWDEDVH WR FKDQJH GDWDEDVH URZV WKDW WKH 85, UHIHUHQFHV 7KH
updatePHWKRGUHWXUQVWKHQXPEHURIURZVDIIHFWHGE\WKHXSGDWHRSHUDWLRQ
@Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs)
{
// the call to notify the uri after deletion is explicit
getContext().getContentResolver().notifyChange(uri, null);
SQLiteDatabase db = mOpenDbHelper.getWritableDatabase();
int affected;
switch (sUriMatcher.match(uri)) {
case VIDEOS:
affected = db.update(VIDEO_TABLE_NAME, values,
where, whereArgs);
break;
A Complete Content Provider: The SimpleFinchVideoContentProvider Code | 325
case VIDEO_ID:
String videoId = uri.getPathSegments().get(1);
affected = db.update(VIDEO_TABLE_NAME, values,
FinchVideo.SimpleVideos._ID + "=" + videoId
+ (!TextUtils.isEmpty(where) ?
" AND (" + where + ')' : ""),
whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return affected;
}
The delete method
7KH deletePHWKRGLVVLPLODUWR updateEXWZLOOGHOHWHURZVUHIHUHQFHGE\WKHJLYHQ
85,/LNHupdatedeleteUHWXUQVWKHQXPEHURIURZVDIIHFWHGE\WKHGHOHWHRSHUDWLRQ
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
int match = sUriMatcher.match(uri);
int affected;
switch (match) {
case VIDEOS:
affected = mDb.delete(VIDEO_TABLE_NAME,
(!TextUtils.isEmpty(where) ?
" AND (" + where + ')' : ""),
whereArgs);
break;
case VIDEO_ID:
long videoId = ContentUris.parseId(uri);
affected = mDb.delete(VIDEO_TABLE_NAME,
FinchVideo.SimpleVideos._ID + "=" + videoId
+ (!TextUtils.isEmpty(where) ?
" AND (" + where + ')' : ""),
whereArgs);
// the call to notify the uri after deletion is explicit
getContext().getContentResolver().
notifyChange(uri, null);
break;
default:
throw new IllegalArgumentException("unknown video element: " +
uri);
}
return affected;
}
326 | Chapter 12:ಗUsing Content Providers
1RWHWKDWWKHSUHFHGLQJGHVFULSWLRQVUHODWHRQO\WRRXUVLPSOHLPSOHPHQWDWLRQRID
FRQWHQW SURYLGHU PRUH LQYROYHG VFHQDULRV FRXOG LQYROYH MRLQLQJ DFURVV WDEOHV IRU D
TXHU\RUFDVFDGHGGHOHWHVIRUGHOHWLQJDJLYHQGDWDLWHP7KHFRQWHQWSURYLGHULVIUHH
WRSLFNLWVRZQVFKHPHIRUGDWDPDQDJHPHQWXVLQJWKH$QGURLG64/LWH$3,VRORQJDV
LWGRHVQRWEUHDNWKHFRQWHQWSURYLGHUFOLHQW$3,
Determining How Often to Notify Observers
$VZH¦YHVHHQIURPRXUOLVWLQJRIWKHFRQWHQWSURYLGHUGDWDPDQDJHPHQWRSHUDWLRQV
QRWLILFDWLRQGRHVQRWKDSSHQIRUIUHHLQWKH$QGURLGFRQWHQWPDQDJHPHQWV\VWHPDQ
LQVHUWLQWRD64/LWHWDEOHGRHVQRWDXWRPDWLFDOO\VHWXSDGDWDEDVHWULJJHUWKDWILUHV
QRWLILFDWLRQRQEHKDOIRIDFRQWHQWSURYLGHU,W¦VXSWRWKHGHYHORSHURIWKHSURYLGHUWR
LPSOHPHQWDVFKHPHWKDWGHWHUPLQHVWKHDSSURSULDWHWLPHWRVHQGQRWLILFDWLRQVDQG
GHFLGHVZKLFK85,VWRVHQGZKHQFRQWHQWSURYLGHUGDWDFKDQJHV8VXDOO\FRQWHQWSUR
YLGHUVLQ$QGURLGVHQGQRWLILFDWLRQVLPPHGLDWHO\IRUDOO85,VWKDWKDYHFKDQJHGGXULQJ
DSDUWLFXODUGDWDRSHUDWLRQ
:KHQGHVLJQLQJDQRWLILFDWLRQVFKHPHDGHYHORSHUVKRXOGFRQVLGHUWKHIROORZLQJWUDGH
RIIILQHJUDLQHGQRWLILFDWLRQUHVXOWVLQPRUHSUHFLVHFKDQJHXSGDWHVWKDWFDQUHGXFH
ORDGRQWKHXVHULQWHUIDFHV\VWHP,IDOLVWLVWROGDVLQJOHHOHPHQWKDVFKDQJHGLWFDQ
GHFLGHWRUHSDLQWRQO\WKDWHOHPHQWLILWKDSSHQVWREHYLVLEOH%XWILQHJUDLQHGQRWLIL
FDWLRQDOVRKDVWKHGUDZEDFNWKDWPRUHHYHQWVJHWSXVKHGWKURXJKWKHV\VWHP7KH8,
ZLOOOLNHO\UHSDLQWPRUHWLPHVVLQFHLWZLOOEHJHWWLQJPRUHLQGLYLGXDOQRWLILFDWLRQHYHQWV
&RDUVHJUDLQHGQRWLILFDWLRQUXQVIHZHUHYHQWVWKURXJKWKHV\VWHPEXWUXQQLQJIHZHU
HYHQWVRIWHQPHDQVWKDWWKH8,ZLOOKDYHWRUHSDLQWPRUHRILWVHOIRQUHFHLYLQJQRWLILFD
WLRQ)RUH[DPSOHDOLVWFRXOGUHFHLYHDVLQJOHHYHQWGLUHFWLQJLWWRXSGDWHDOOHOHPHQWV
ZKHQRQO\WKUHHLQGLYLGXDOHOHPHQWVKDGDFWXDOO\FKDQJHG:HVXJJHVWNHHSLQJWKLV
WUDGHRIILQPLQGZKHQSLFNLQJDQRWLILFDWLRQVFKHPH)RUH[DPSOH\RXPLJKWFRQVLGHU
ZDLWLQJXQWLO\RXILQLVKUHDGLQJDODUJHQXPEHURIHYHQWVDQGWKHQILULQJDVLQJOH£HY
HU\WKLQJFKDQJHG¤HYHQWUDWKHUWKDQVHQGLQJDQXSGDWHIRUHDFKHYHQW
2IWHQFRQWHQWSURYLGHUVVLPSO\QRWLI\FOLHQWVRIZKDWHYHU85,VZHUHLQYROYHGZKHQ
GDWDFKDQJHV
Declaring Your Content Provider
,Q£8VLQJDFRQWHQWSURYLGHU¤RQSDJHZHVDZKRZFOLHQWVDFFHVVDQGXVHDFRQWHQW
SURYLGHU1RZWKDWZHKDYHRXURZQVLPSOHFRQWHQWSURYLGHUDOOWKDWLVOHIWLVWRPDNH
LWDYDLODEOHWRFOLHQWVE\DGGLQJWKHIROORZLQJOLQHRI;0/WR\RXU$QGURLG0DQLIHVW[PO
<provider android:name=".provider.SimpleFinchVideoContentProvider"
android:authorities="oreilly.demo.pa.finchvideo.SimpleFinchVideo"/>
$IWHU\RXKDYHEXLOW\RXUDSSOLFDWLRQLWVDSNILOHFRQWDLQVWKHSURYLGHULPSOHPHQWDWLRQ
FODVVHVDQGLWVPDQLIHVWILOHFRQWDLQVDOLQHVLPLODUWRWKHOLQHRI;0/ZHMXVWDGGHG
Declaring Your Content Provider | 327
DOODSSOLFDWLRQFRGHRQWKH$QGURLGSODWIRUPZLOOEHDEOHWRDFFHVVLWDVVXPLQJLWKDV
UHTXHVWHGDQGEHHQJUDQWHGSHUPLVVLRQWRGRVRDVGHVFULEHGLQ&KDSWHU
+DYLQJFRPSOHWHGWKHWDVNRIFUHDWLQJ\RXURZQVLPSOHFRQWHQWSURYLGHULQWKLVFKDSWHU
LW¦V WLPH WR ORRN LQWR VRPH QRYHO FRQWHQW SURYLGHU SDWWHUQV ZKLFK ZH¦OO GR LQ
&KDSWHU
328 | Chapter 12:ಗUsing Content Providers
CHAPTER 13
Exploring Content Providers
,Q&KDSWHUZHVDZWKDWXVHULQWHUIDFHVWKDWQHHGWRLQWHUDFWZLWKUHPRWHVHUYLFHVIDFH
LQWHUHVWLQJFKDOOHQJHVVXFKDVQRWW\LQJXSWKH8,WKUHDGZLWKORQJUXQQLQJWDVNV:H
DOVRQRWHGLQ&KDSWHUWKDWWKH$QGURLGFRQWHQWSURYLGHU$3,VKDUHVV\PPHWU\ZLWK
5(67VW\OHZHEVHUYLFHV&RQWHQWSURYLGHUGDWDRSHUDWLRQVPDSVWUDLJKWRQWR5(67
GDWDRSHUDWLRQVDQGQRZZH¦OOVKRZ\RXKRZWRWUDQVODWHFRQWHQWSURYLGHU85,VWR
UHTXHVWQHWZRUNGDWD:HVXJJHVWWDNLQJDGYDQWDJHRIWKLVV\PPHWU\E\ZULWLQJFRQWHQW
SURYLGHUVWRRSHUDWHDVDQDV\QFKURQRXVEXIIHUEHWZHHQWKHGRPDLQRUXQLTXHDVSHFWV
RI \RXU DSSOLFDWLRQ DQG WKH QHWZRUN UHTXHVWV WKDW DFTXLUH WKH GDWD RQ ZKLFK \RXU
DSSOLFDWLRQRSHUDWHV:ULWLQJ\RXUDSSOLFDWLRQLQWKLVZD\ZLOOVLPSOLI\\RXUDSSOLFD
WLRQDQGZLOOVROYHFRPPRQ8,DQGQHWZRUNSURJUDPPLQJHUURUVHQFRXQWHUHGLQ$Q
GURLGDQGRWKHUW\SHVRI-DYDSURJUDPPLQJ
+LVWRULFDOO\-DYD8,SURJUDPPHUVERWKHQWHUSULVHDQGPRELOHKDYHZULWWHQPRELOH
DQGGHVNWRSEDVHGDSSOLFDWLRQVLQDUDWKHUEULWWOHZD\DQGVRPHWLPHVGLGUXQQHWZRUN
UHTXHVWVGLUHFWO\RQWKH8,WKUHDGRIWHQZLWKRXWFDFKLQJGDWDREWDLQHGIURPWKRVH
UHTXHVWV,QPRVWDSSOLFDWLRQVVKRZLQJDQ\WKLQJLQD8,ZRXOGUHTXLUHDFFHVVLQJWKH
QHWZRUNHYHU\WLPHDXVHUUHTXHVWHGWKHGLVSOD\RIGDWD%HOLHYHLWRUQRW8QL[ZRUN
VWDWLRQVIURPWKHVDQGVZRXOGIUHTXHQWO\ORFNXSZKHQDFFHVVWRUHPRWHO\
PRXQWHG ILOHV\VWHPV EHFDPH XQDYDLODEOH ,I DSSOLFDWLRQV KDG XVHG D ORFDO G\QDPLF
FDFKLQJVFKHPHWKH\ZRXOGKDYHEHHQDEOHWRFRQWLQXHUXQQLQJIRUWKHGXUDWLRQLQ
ZKLFKWKHILOHVHUYHUZDVDEVHQWDQGWKHQV\QFKURQL]HZKHQLWUHWXUQHG'HYHORSHUV
QHHGHGWRSD\FRQVFLRXVDWWHQWLRQEXWRIWHQGLGQRWWRPDNHFHUWDLQWKDWWKHLUDSSOL
FDWLRQVDFFHVVHGDQGVWRUHGQHWZRUNGDWDFRUUHFWO\
7KHWUHQGFRQWLQXHGLQ-0(ZKHUHGHYHORSHUVFRXOGFDFKHQHWZRUNVWDWHLQWKHDQH
PLFUHFRUGPDQDJHPHQWV\VWHPNQRZQDV5067KLVOLEUDU\GLGQRWVXSSRUWDTXHU\
ODQJXDJHRUDQ09&QRWLILFDWLRQV\VWHP-0(GHYHORSHUVZRXOGQHHGWRVSDZQWKHLU
RZQSODLQ-DYDWKUHDGVWRPDNHQHWZRUNUHTXHVWVEXWLQPDQ\FDVHVGLGQRWZKLFK
OHGWREULWWOHDSSOLFDWLRQV,IZHEEURZVHUVZHUHWRORDGQHWZRUNGDWDRQWKH8,WKUHDG
\RXZRXOGRIWHQVHHWKHPFRPSOHWHO\IUHH]HWRWKHSRLQWZKHUHWKHRSHUDWLQJV\VWHP
ZRXOGKDYHWRNLOOWKHEURZVHUWRJHWULGRILW¢ZKHQHYHUWKHQHWZRUNZRXOGKDQJWKH
8,WKUHDGZRXOGORFNXS3DJHVDQGDOOWKHLPDJHVWKH\UHIHUHQFHGZRXOGDOZD\VKDYH
329
WREHGRZQORDGHGDWHYHU\YLHZLQJPDNLQJIRUDYHU\VORZH[SHULHQFH¢DVVXPLQJRQH
RIWKHUHTXHVWVGLGQRWKDQJWKHZKROHDSSOLFDWLRQ7KHWDNHDZD\IURPWKHVHDQHFGRWHV
LVWKDWWUDGLWLRQDOO\RSHUDWLQJV\VWHPVKDYHOHIWWKHORDGLQJDQGFDFKLQJRIQHWZRUN
GDWDXSWRWKHDSSOLFDWLRQSURYLGLQJOLWWOHGLUHFWOLEUDU\VXSSRUWWRKHOSGHYHORSHUV
LPSOHPHQWWKHVHWDVNVFRUUHFWO\
7RUHVROYHWKHVHSUREOHPV\RXFRXOGXVHDFRPSOHWHO\DV\QFKURQRXVLQWHUIDFHWRKDQ
GOHQHWZRUNLQWHUDFWLRQDQGGDWDVWRUDJH:LWKVXFKDQDSSURDFKGHYHORSHUVZRXOG
QRWKDYHWRWKLQNDERXWZKHQLWZDV2.WRUHTXHVWGDWDIURPWKHQHWZRUN¢LWZRXOG
DOZD\VEHVDIHWRXVHVXFKDQ$3,RQRURIIWKH8,WKUHDG6XFKFRQVLGHUDWLRQVEHFRPH
VLJQLILFDQWO\ PRUH LPSRUWDQW LQ D PRELOH HQYLURQPHQW ZKHUH LQWHUPLWWHQW QHWZRUN
FRQQHFWLYLW\LQFUHDVHVWKHOLNHOLKRRGRIDKDQJLQLQFRUUHFWO\ZULWWHQFRGH
:HVXJJHVWXVLQJWKHFRQWHQWSURYLGHU$3,DVDQDV\QFKURQRXVPRGHORIWKHQHWZRUN
DQGDVDFDFKHRIQHWZRUNVWDWHVRWKDW\RXUDSSOLFDWLRQ9LHZDQG&RQWUROOHUGRQRW
QHHGWKHLURZQPHFKDQLVPVIRURSHQLQJFRQQHFWLRQVRUDFFHVVLQJDGDWDEDVH,W¦VHDV\
WRPDSWKHSURYLGHU$3,RQWRWKH$3,RIH[LVWLQJ5(67EDVHGZHEVHUYLFHV¢WKHSUR
YLGHUVLPSO\VLWVLQEHWZHHQWKHDSSOLFDWLRQIRUZDUGLQJUHTXHVWVWRWKHQHWZRUNDQG
FDFKLQJUHVXOWVDVQHHGHG,QWKLVFKDSWHUZHZLOOVKRZ\RXKRZWKLVDSSURDFKFDQ
VLPSOLI\\RXUDSSOLFDWLRQDQGZHZLOOH[SODLQPRUHJHQHUDOEHQHILWVRIWKHWHFKQLTXH
LQFOXGLQJKRZLWLQWURGXFHVVRPHRIWKHPRUHSRVLWLYHFKDUDFWHULVWLFVRIZHEDQG$-$;
SURJUDPPLQJWR$QGURLGDSSOLFDWLRQV)RUPRUHLQIRUPDWLRQRQ$-$;SURJUDPPLQJ
JRWRKWWSHQZLNLSHGLDRUJZLNL$MD[B SURJUDPPLQJ Developing RESTful Android Applications
:HDUHQRWWKHRQO\RQHVZKRVHHWKHEHQHILWVRIWKLVDSSURDFK$WWKH*RRJOH,2
FRQIHUHQFHLQ0D\9LUJLO'REMDQVFKLRI*RRJOHSUHVHQWHGDWDONWKDWRXWOLQHGWKH
IROORZLQJWKUHHSDWWHUQVIRUXVLQJFRQWHQWSURYLGHUVWRLQWHJUDWH5(67IXOZHEVHUYLFHV
LQWR$QGURLGDSSOLFDWLRQV
ActivityൺServiceൺContentProvider
7KLVSDWWHUQLQYROYHVDQDFWLYLW\FRQWDFWLQJDVHUYLFHWRDFFHVVDSSOLFDWLRQGDWD
ZKLFKLQWXUQGHOHJDWHVWRDFRQWHQWSURYLGHUWRDFFHVVWKDWGDWD,QWKLVVFHQDULR
WKHDFWLYLW\LQYRNHVDQDV\QFKURQRXVPHWKRGRQDVHUYLFHWKDWSHUIRUPVDV\QFKUR
QRXV5(67IXOLQYRFDWLRQV
ActivityൺContentProviderൺService
$Q DFWLYLW\ FRQWDFWV D FRQWHQW SURYLGHU ZKLFK LQ WXUQ GHOHJDWHV WR D VHUYLFH WR
DV\QFKURQRXVO\ORDGGDWD7KLVDSSURDFKDOORZVWKHDFWLYLW\WRXVHWKHFRQYHQLHQFH
RIWKHFRQWHQWSURYLGHU$3,WRLQWHUDFWZLWKGDWD7KHFRQWHQWSURYLGHULQYRNHV
PHWKRGVRQWKHDV\QFKURQRXVVHUYLFHLPSOHPHQWDWLRQWRLQYRNHD5(67IXOUHTXHVW
7KLVDSSURDFKFDSLWDOL]HVRQWKHFRQYHQLHQWV\PPHWU\EHWZHHQWKHFRQWHQWSUR
YLGHU$3,DQG5(67IXOXVHRI+773
330 | Chapter 13:ಗExploring Content Providers
ActivityൺContentProviderൺSyncAdapter
$QGURLGV\QFDGDSWHUVSURYLGHDIUDPHZRUNIRUV\QFKURQL]LQJXVHUGDWDEHWZHHQ
DGHYLFHDQGWKHFORXG*RRJOH&RQWDFWVXVHVDV\QFDGDSWHU,QWKLVVFHQDULRDQ
DFWLYLW\ XVHV WKH FRQWHQW SURYLGHU $3, WR DFFHVV GDWD V\QFKURQL]HG E\ D V\QF
DGDSWHU
,QWKLVFKDSWHUZH¦OOH[SORUHWKHVHFRQGSDWWHUQLQGHWDLOZLWKRXUVHFRQG)LQFKYLGHR
H[DPSOHWKLVVWUDWHJ\ZLOO\LHOGDQXPEHURILPSRUWDQWEHQHILWVIRU\RXUDSSOLFDWLRQV
'XHWRWKHHOHJDQFHZLWKZKLFKWKLVDSSURDFKLQWHJUDWHVQHWZRUNRSHUDWLRQVLQWR$Q
GURLG09&ZH¦YHJLYHQLWWKHPRQLNHU£1HWZRUN09&¤
$IXWXUHHGLWLRQRI3URJUDPPLQJ$QGURLGPD\DGGUHVVWKHRWKHUWZRDSSURDFKHVDV
ZHOODVGRFXPHQWPRUHGHWDLOVRIWKLV*RRJOHSUHVHQWDWLRQ$IWHU\RXILQLVKUHDGLQJWKLV
FKDSWHUZHVXJJHVWWKDW\RXYLHZ*RRJOH¦VWDON
A “Network MVC”
:HOLNHWRWKLQNRIWKHVHFRQGSDWWHUQDVDQHWZRUNHGIRUPRI09&ZKHUHWKHFRQWHQW
SURYLGHULWVHOISXOOVGDWDIURPWKHQHWZRUNDQGWKHQSXPSVLWLQWRWKHUHJXODU$QGURLG
09&:H¦OOYLHZWKHFRQWHQWSURYLGHUDVDPRGHORIQHWZRUNVWDWH¢WKHSURYLGHUFDQ
IXOILOOGDWDUHTXHVWVZLWKORFDOVWDWHRUFDQUHWULHYHGDWDIURPWKHQHWZRUN:LWKWKLV
DSSURDFKWKH&RQWUROOHUDQG9LHZFRGHVKRXOGQRWGLUHFWO\FUHDWHQHWZRUNUHTXHVWV
WRDFFHVVDQGPDQDJHDSSOLFDWLRQGDWD,QVWHDG\RXUDSSOLFDWLRQ9LHZDQG&RQWUROOHU
VKRXOGXVHWKHContentResolver$3,WRPDNHGDWDTXHULHVWKURXJKDFRQWHQWSURYLGHU
ZKLFKDORQHVKRXOGDV\QFKURQRXVO\ORDGQHWZRUNUHVRXUFHVDQGVWRUHWKHUHVXOWVLQD
ORFDOGDWDFDFKH$GGLWLRQDOO\WKHSURYLGHUVKRXOGDOZD\VUHVSRQGTXLFNO\WRDUHTXHVW
E\LQLWLDOO\DYRLGLQJDQHWZRUNLQYRFDWLRQWKDWPLJKWEHQHHGHGWRIXOILOOWKHUHTXHVWE\
XVLQJZKDWHYHUGDWDLVDOUHDG\DYDLODEOHLQWKHORFDOGDWDEDVH([HFXWLQJWKHUHTXHVWLQ
WKLVPDQQHUHQVXUHVWKDWWKH8,WKUHDGLVEORFNHGIRUQRORQJHUWKDQDEVROXWHO\QHFHV
VDU\DQGWKDW WKH8, KDV VRPH GDWD WR GLVSOD\ DV VRRQ DV SRVVLEOHWKXVLPSURYLQJ
RYHUDOOVQDSSLQHVVDQGXVHUVDWLVIDFWLRQZKHQXVLQJWKH8,+HUHLVWKHSURYLGHUVH
TXHQFHIRUTXHU\LQJGDWDLQPRUHGHWDLO
7KHSURYLGHUPDWFKHVWKHLQFRPLQJ85,DQGTXHULHVORFDOGDWDEDVHFRQWHQWVIRU
LWHPVWKDWSUHYLRXVO\PDWFKHGWKHTXHU\
2XUSURYLGHUDOZD\VDWWHPSWVWRREWDLQWKHODWHVWVWDWHIRUWKHTXHU\DQGVXEVH
TXHQWO\VSDZQVDQDV\QFKURQRXV5(67UHTXHVWWRORDGFRQWHQWIURPWKHQHWZRUN
<RXFRXOGPDNHWKLVEHKDYLRUFRQILJXUDEOHEDVHGRQWKHUHTXHVW
7KHSURYLGHUUHWXUQVWKHFXUVRUIURPWKHLQLWLDOORFDOTXHU\WRWKHFOLHQW
7KHDV\QFKURQRXVORDGLQJWKUHDGVKRXOGGHFLGHLIGDWDLQWKHSURYLGHUFDFKHQHHGV
WREHUHIUHVKHGLILWGRHVWKHSURYLGHUORDGVDQGSDUVHVGDWDIURPWKHQHWZRUN
:KHQFRQWHQWDUULYHVIURPWKHQHWZRUNWKHSURYLGHUGLUHFWO\LQVHUWVHDFKQHZGDWD
LWHPLQWRWKHGDWDEDVHDQGWKHQQRWLILHVFOLHQWVRIWKH85,VIRUWKHQHZGDWD6LQFH
WKHLQVHUWLRQLVDOUHDG\KDSSHQLQJLQVLGHWKHFRQWHQWSURYLGHUWKHUHLVQRQHHGWR
A “Network MVC” | 331
FDOOContentResolver.insert&OLHQWVKROGLQJH[LVWLQJFXUVRUVWKDWFRQWDLQDQROGHU
YHUVLRQRIGDWDFDQFDOOCursor.requeryWRUHIUHVKWKHLUGDWD
:LWKWKLVVHTXHQFHWKH9LHZDQG&RQWUROOHUHYHQWXDOO\JHWXSGDWHGZLWKQHWZRUNGDWD
EXWRQO\WKHFRQWHQWSURYLGHUFUHDWHVWKHQHWZRUNUHTXHVW:HYLHZDUHTXHVWIRUD
UHVRXUFHWKDWGRHVQRWFXUUHQWO\H[LVWLQWKHSURYLGHU¦VGDWDVHWDVDUHTXHVWWRORDGWKH
UHVRXUFH¢WKH QHWZRUN UHTXHVW WKDW ORDGV GDWD LQWR WKH FDFKH LV D VLGH HIIHFW RI WKH
DFWLYLW\SURYLGHUTXHU\
)LJXUHLOOXVWUDWHVWKHRSHUDWLRQVWDNLQJSODFHLQVLGHWKHFRQWHQWSURYLGHUGXULQJ
H[HFXWLRQRIRSHUDWLRQVLQWKHVHTXHQFH
)LJXUH1HWZRUNSURYLGHUFDFKLQJFRQWHQWRQEHKDOIRIWKHFOLHQW
)RUHDFKTXHU\WKLVVHTXHQFHXVHVDVLQJOHCursorREMHFWFUHDWHGE\DSURYLGHUDQGWKHQ
UHWXUQHGWRWKHYLHZ2QO\WKHSURYLGHUKDVWKHUHTXLUHPHQWWRQRWLI\WKH8,ZKHQGDWD
FKDQJHV7KH9LHZDQG&RQWUROOHUGRQRWKDYHWRFROOHFWGDWDDQGGRQRWKDYHWRXSGDWH
WKHPRGHO:KHQGDWDLVDYDLODEOHWKHFRQWHQWSURYLGHUQRWLILHVWKHFXUVRUIRUWKHTXHU\
7KHUROHRIGDWDPDQDJHPHQWLVHQFDSVXODWHGLQVLGHWKHFRQWHQWSURYLGHUZKLFKVLP
SOLILHVWKHFRGHLQWKH9LHZDQG&RQWUROOHU7KHSURYLGHUFOLHQWUHTXHVWVGDWDDQGUH
FHLYHVDFXUVRUTXLFNO\WKHFXUVRULVQRWLILHGZKHQQHWZRUNGDWDDUULYHV,W¦VFULWLFDOWR
UHFDOOWKDWQRWLILFDWLRQGHSHQGVRQGDWDEDVHDQGCursorREMHFWVUHPDLQLQJRSHQDVORQJ
DVFRQWHQWSURYLGHUFOLHQWVDUHXVLQJWKHP&ORVHGFXUVRUVDQGGDWDEDVHVZLOOUHVXOWLQ
FOLHQWYLHZVVKRZLQJQRUHVXOWVZKLFKFDQPDNHLWGLIILFXOWWRNQRZLIDFRPSRQHQW
VXFKDVDOLVWLVHPSW\EHFDXVHLWVFXUVRUZDVFORVHGHUURQHRXVO\RULIDJLYHQTXHU\
DFWXDOO\KDGQRUHVXOWV
332 | Chapter 13:ಗExploring Content Providers
Summary of Benefits
,W¦VZRUWKVXPPDUL]LQJWKHEHQHILWVRIWKH1HWZRUN09&DSSURDFK
‡ ,QFUHDVHGSHUFHLYHGSHUIRUPDQFHRYHUDOODQGLQFUHDVHGDFWXDOSHUIRUPDQFHIURP
FDFKLQJDUHDPRQJWKHPDLQEHQHILWVRIWKLVSDWWHUQ0RELOHSURJUDPPLQJRIWHQ
SHUIRUPVOLNHWKH:HEZRXOGZLWKQRFDFKLQJV\VWHP
‡ 6WRULQJGDWDLQPHPRU\LVQRWDJRRGLGHDVLQFH\RXGRQRWNQRZZKHQ$QGURLG
ZLOOUHPRYH\RXUDFWLYLW\IURPPHPRU\7KLVSDWWHUQHPSKDVL]HVVWRULQJGDWDLQ
WKHFRQWHQWSURYLGHUDVTXLFNO\DVSRVVLEOH
‡ 0RVWSRWHQWLDO8,WKUHDGVDIHW\YLRODWLRQVFDQQRWKDSSHQ$QGURLG9LHZFRPSR
QHQWVKDYHDOUHDG\EHHQZULWWHQWRG\QDPLFDOO\XSGDWHWRUHIOHFWFXUUHQWFXUVRU
FRQWHQWV,IWKHVL]HRIWKHGDWDLQWKHPRGHOVKULQNV ListViewZLOOPDNHVXUHWR
UHGXFHWKHQXPEHURIWLPHVLWLWHUDWHVRYHUWKHFXUVRU2WKHUFRPSRQHQWV\VWHPV
IRUUHDGHUVIDPLOLDUZLWK-6(6ZLQJZRXOGOHDYHWKLVW\SHRIWDVNXSWRWKHGH
YHORSHU ZKLFK ZRXOG OHDYH RSHQ WKH SRVVLELOLW\ WKDW WKH OLVW FRPSRQHQW PLJKW
LWHUDWHEH\RQGWKHERXQGVRILWVPRGHORQGHOHWLRQRIGDWDHOHPHQWV
‡ 7KLVDSSURDFKOHYHUDJHVWKHFXUVRUPDQDJHPHQWV\VWHPDQGWKHXVHULQWHUIDFH¦V
EXLOWLQFDSDELOLWLHVIRUG\QDPLFXSGDWHVLQUHVSRQVHWRFRQWHQWREVHUYDWLRQHYHQWV
8VHULQWHUIDFHGHYHORSHUVGRQ¦WQHHGWRZULWHWKHLURZQSROOLQJDQGXSGDWHV\VWHPV
WKH\MXVWUHO\RQFRQWHQWREVHUYDWLRQDQGWKHFRQWHQWSURYLGHULQWHUIDFH
‡ /LNHZLWKDQ\FRUUHFWUHTXHVWIRUQHWZRUNUHVRXUFHVLW¦VQRWSRVVLEOHIRUWKH8,
WKUHDGWRKDQJRQWKHQHWZRUN
‡ 'HOLYHU\RIQHWZRUNHYHQWVKDSSHQVZLWKRXWUHTXLULQJWKHSUHVHQFHRIDXVHULQ
WHUIDFH(YHQLIDSDUWLFXODUDFWLYLW\LVQRWSUHVHQWZKHQDQHWZRUNHYHQWDUULYHV
WKH FRQWHQW SURYLGHU ZLOO VWLOO EH DURXQG WR KDQGOH LW :KHQ WKH XVHU ORDGV WKH
DFWLYLW\DTXHU\ZLOOUHYHDOWKHHYHQWWKDWDUULYHGLQWKHEDFNJURXQG7KHDEVHQFH
RIDQDFWLYH8,DFWLYLW\ZLOOQRWUHVXOWLQHYHQWVVLPSO\JHWWLQJGURSSHG
‡ (OHPHQWVRIWKHDSSOLFDWLRQDUHHQFDSVXODWHGDQGKDYHDVSHFLDOSXUSRVHVLQFHDV
ZH¦YHPHQWLRQHGWKHFRQWHQWSURYLGHUKDQGOHVDOOQHWZRUNDQG64/LWHLQWHUDF
WLRQV7KH9LHZDQG&RQWUROOHUMXVWXVHDSURYLGHUDVDJHQHULFV\VWHPIRUGDWD
PDQDJHPHQW
‡ ,W¦VHDVLHUWRZULWHDSSOLFDWLRQVVLQFHLW¦VGLIILFXOWWRXVHWKH$3,LQFRUUHFWO\¢MXVW
PDNHFRQWHQWSURYLGHUFDOOVDQGWKHV\VWHPKDQGOHVWKH5(67 SXQLQWHQGHG ‡ )LQDOO\LQDERRNRQPRELOHSURJUDPPLQJLW¦VHDV\WRIRFXVRQGHYLFHLVVXHVEXW
LIFOLHQWVHQGXSUHO\LQJRQWKHLUFDFKHDQGUHIHUULQJWRWKHQHWZRUNRQO\ZKHQ
DEVROXWHO\QHFHVVDU\WKH\ZLOOHQGXSVLJQLILFDQWO\UHGXFLQJWKHQHWZRUNORDGRQ
V\VWHPVWKDWVHUYHGDWDWRGHYLFHV7KLVSDWWHUQSURYLGHVDVLJQLILFDQWEHQHILWIRU
VHUYHUVDVZHOODVFOLHQWV
Summary of Benefits | 333
Our Approach in Context
7REHFOHDUZHDUHVXJJHVWLQJWKDWDSSOLFDWLRQVVKRXOGZULWHFRQWHQWSURYLGHUVWRDFFHVV
DQGVWRUHQHWZRUNGDWDZKHUHYHUSRVVLEOH:KLOHWKLVPLJKWVHHPOLNHDQRQHURXVEXU
GHQDWILUVWFRQVLGHUWKDWZHEEURZVHUVDOVRXVHDQDV\QFKURQRXVPHFKDQLVPIRUORDG
LQJ 85, UHIHUHQFHG FRQWHQW )RU UHDGHUV IDPLOLDU ZLWK EDVLF ZHE SURJUDPPLQJ WKH
GHIDXOW$QGURLG$3,PD\EHPRUHIOH[LEOHDQGH[WHQVLYHWKDQWKDWIRXQGLQ$-$;EXW
$-$;KDVORQJKDGDIRROSURRIDUFKLWHFWXUH0RGHUQEURZVHUVORDG85,GDWDXVLQJ
DV\QFKURQRXV ,2 PHFKDQLVPV VHH KWWSHQZLNLSHGLDRUJZLNL$V\QFKURQRXVBLR ZKLFKSUHYHQWVPRVWRSSRUWXQLWLHVIRUDEURZVHUXVHULQWHUIDFHWRKDQJ:KLOHLWPD\
QRWVHHPOLNHWKHEURZVHULVGRLQJPXFKZKHQDJLYHQ85,IDLOVWRORDGWKH8,WKUHDG
LWVHOILVQHYHULQGDQJHURIEORFNLQJGXHWRDQHWZRUNFRQQHFWLRQEHFRPLQJXQUHVSRQ
VLYH,IWKH8,WKUHDGZHUHWRKDQJWKHZKROHEURZVHUZRXOGVWRSZRUNLQJ,WZRXOG
QRWHYHQEHDEOHWRWHOO\RXWKDWLWZDVKXQJ¢HVSHFLDOO\VLQFHPDQ\EURZVHUVDUHHQWLUHO\
VLQJOHWKUHDGHG,QVWHDGEURZVHUVDUHDEOHWRSURYLGH\RXZLWKWKHRSSRUWXQLW\WRKDOW
DQ\JLYHQSDJHORDGUHTXHVWDQGWKHQORDGDQRWKHUSDJHWKDWZLOOKRSHIXOO\EHPRUH
UHVSRQVLYH*RLQJIXUWKHUDOOPRGHUQEURZVHUVPDNHXVHRIDSHUVLVWHQWZHEFDFKH
DQG ZH DUH VLPSO\ VXJJHVWLQJ WKDW $QGURLG DSSOLFDWLRQV VKRXOG DOVR KDYH D VLPLODU
FRQVWUXFW
%H\RQGWKHSDWWHUQZHDUHGHVFULELQJ*RRJOHSURYLGHVVSHFLILFGRFXPHQWDWLRQIRULP
SURYLQJDSSOLFDWLRQUHVSRQVLYHQHVVDQGUHGXFLQJWKHOLNHOLKRRGRI£$SSOLFDWLRQ1RW
5HVSRQGLQJ¤ QRWLILFDWLRQV DW KWWSGHYHORSHUDQGURLGFRPJXLGHSUDFWLFHVGHVLJQUH
VSRQVLYHQHVVKWPO
Code Example: Dynamically Listing and Caching YouTube
Video Content
7RGHPRQVWUDWHWKHSUHVFULEHGDUFKLWHFWXUHZHSUHVHQWWKH)LQFKYLGHROLVWLQJDSSOL
FDWLRQWKDWDOORZVDXVHUWRSHUIRUPDPRELOHYLGHRVHDUFKXVLQJWKH5(67IXO$3,DW
KWWSJGDWD\RXWXEHFRP2XUH[DPSOHFRGHLVZULWWHQZLWKDQH\HWRZDUGLQWHUPLWWHQW
FRQQHFWLYLW\LQDPRELOHHQYLURQPHQW7KHDSSOLFDWLRQSUHVHUYHVXVHUGDWDVRWKDWLW
ZLOOUHPDLQXVDEOHHYHQZKHQWKHQHWZRUNFDQQRWEHUHDFKHG¢HYHQLIWKDWPHDQVRXU
DSSOLFDWLRQFDQRQO\GLVSOD\ROGHUORFDOO\FDFKHGUHVXOWVZKHQWKDWKDSSHQV
:KHQ D XVHU UXQV D TXHU\ WKH DSSOLFDWLRQ DWWHPSWV WR UHWULHYH WKH ODWHVW <RX7XEH
UHVXOWV IRU WKDW TXHU\ ,I WKH DSSOLFDWLRQ VXFFHVVIXOO\ ORDGV QHZ UHVXOWV LW ZLOO IOXVK
UHVXOWVWKDWDUHROGHUWKDQRQHZHHN,IWKHDSSOLFDWLRQZHUHWREOLQGO\GURSROGUHVXOWV
EHIRUHUXQQLQJDQXSGDWHTXHU\LWPLJKWHQGXSZLWKQRUHVXOWVWRYLHZZKLFKZRXOG
UHQGHUWKHDSSXVHOHVVXQWLOQHWZRUNDFFHVVUHWXUQHG7KHVFUHHQLQ)LJXUHVKRZV
DTXHU\IRUWKHNH\ZRUG£GRJV¤3UHVVLQJ(QWHULQWKHVHDUFKER[RUKLWWLQJWKHUHIUHVK
EXWWRQVSDZQVDQHZTXHU\
334 | Chapter 13:ಗExploring Content Providers
)LJXUH)LQFKYLGHR6DPSOH$SSOLFDWLRQ
2XUDSSOLFDWLRQLQFOXGHVDFDFKLQJFRQWHQWSURYLGHUWKDWTXHULHVWKH<RX7XEH$3,WR
DFFHVV <RX7XEH YLGHR PHWDGDWD 4XHU\ UHVXOWV DUH FDFKHG LQ D 64/LWH WDEOH FDOOHG
videoDVSDUWRIWKHFRQWHQWSURYLGHU queryPHWKRG7KHSURYLGHUPDNHVXVHRIWKH
)LQFK IUDPHZRUN IRU LQYRNLQJ DV\QFKURQRXV 5(67 UHTXHVWV 7KH 8, FRQVLVWV RI DQ
DFWLYLW\DVVKRZQLQ)LJXUHDOLVWZLWKDVHDUFKTXHU\ER[DQGDUHIUHVKEXWWRQ
7KHOLVWG\QDPLFDOO\UHIUHVKHVRQFRQWHQWSURYLGHUGDWDQRWLILFDWLRQ:KHQHYHUWKHXVHU
HQWHUVDVHDUFKTXHU\DQGWKHQSUHVVHV(QWHUWKHDFWLYLW\LQYRNHVWKHTXHU\UHTXHVWRQ
WKHFinchVideoContentProviderZLWKWKHDSSURSULDWH85,TXHU\:H¦OOQRZH[SORUHWKH
GHWDLOVRIWKLVH[DPSOH
Structure of the Source Code for the Finch YouTube
Video Example
7KLVVHFWLRQEULHIO\H[DPLQHVUHOHYDQW-DYDVRXUFHZLWKLQWKH)LQFK<RX7XEHYLGHR
DSSOLFDWLRQWKDWLVXQLTXHWRWKHVLPSOHYHUVLRQRIRXUYLGHROLVWLQJDSSOLFDWLRQ7RVWDUW
WKHILOHVUHVLGHLQWZRGLIIHUHQWGLUHFWRULHVWKDWRIWKH)LQFKYLGHRDSSOLFDWLRQGLUHFWRU\
IRU&KDSWHUDQGWKDWRIWKH)LQFK)UDPHZRUNOLEUDU\RQZKLFK&KDSWHUKDVD
GHSHQGHQF\7KHVRXUFHILOHVWKDWPDNHXSRXU<RX7XEHDSSOLFDWLRQLQFOXGH
Structure of the Source Code for the Finch YouTube Video Example | 335
&KDSWHUILOHVLQ )LQFK9LGHR VUF
)LQFK9LGHR VUFFRPRUHLOO\GHPRSDILQFKYLGHR)LQFK9LGHRMDYD
7KHFinchVideoFODVVFRQWDLQVWKHVideosFODVVZKLFKVHUYHVWKHVDPHIXQFWLRQ
DVFinchVideo.SimpleVideosGLGLQWKHVLPSOHYLGHRDSS7KHFinchVideo.Vid
eosFODVVGHILQHVVHYHUDOPRUHFRQVWDQWVLQDGGLWLRQWRWKHQDPHVRIWKHFRQWHQW
SURYLGHUFROXPQVWKDWRXUVLPSOHYHUVLRQGHILQHGIRUWKH<RX7XEHDSSOLFDWLRQ
1HLWKHUWKHFinchVideoFODVVQRUWKHVideosFODVVFRQWDLQDQ\H[HFXWDEOHFRGH
)LQFK9LGHR VUFFRPRUHLOO\GHPRSDILQFKYLGHRSURYLGHU)LQFK9LGHR&RQWHQW
3URYLGHUMDYD
7KLVLVWKHPDLQFRQWHQWSURYLGHUWKDWVHUYHV<RX7XEHPHWDGDWDDQGFDUULHV
RXWDV\QFKURQRXV5(67IXOUHTXHVWVRQWKH<RX7XEH*'DWD$3,
)LQFK9LGHR OLEVUFFRPRUHLOO\GHPRSDILQFKYLGHRSURYLGHU<RX7XEH+DQGOHU
MDYD
7KLVSDUVHVUHVSRQVHVIURPWKH<RX7XEH*'DWD$3,DQGLQVHUWVGDWDHQWULHV
DVWKH\DUULYH
)LQFKIUDPHZRUNVRXUFHFRGHLQ )LQFK)UDPHZRUN OLEVUF
)LQFK)UDPHZRUN OLEVUFFRPILQFKIUDPHZRUNILQFKUHVW5(67IXO&RQWHQW
3URYLGHUMDYD
7KLVFRQWDLQVDVLPSOHIUDPHZRUNIRULQYRNLQJ5(67IXO+773UHTXHVWVIURP
ZLWKLQDQ$QGURLGFRQWHQWSURYLGHUFinchVideoContentProviderH[WHQGVWKLV
FODVVWRUHXVHEHKDYLRUIRUDV\QFKURQRXVO\PDQDJLQJ+773UHTXHVWV
)LQFK)UDPHZRUN OLEVUFFRPILQFKIUDPHZRUNILQFKUHVW)LOH+DQGOHUMDYD
)LQFK)UDPHZRUN OLEVUFFRPILQFKIUDPHZRUNILQFKUHVW)LOH+DQGOHU)DFWRU\
MDYD
7KHVH DUH VLPSOH IUDPHZRUNV IRU GRZQORDGLQJ 85, FRQWHQW WR D ILOHEDVHG
FDFKH7KH\KDQGOHWKHUHVSRQVHZKHQWKHDSSUHTXHVWVWKXPEQDLO85,V
)LQFK)UDPHZRUN OLEVUFFRPILQFKIUDPHZRUNILQFKUHVW5HVSRQVH+DQGOHUMDYD
7KLVSURYLGHVDVLPSOHDEVWUDFWLRQOD\HUIRUKDQGOLQJGRZQORDGHG+773FRQ
WHQWIURPWKH<RX7XEH$3,YouTubeHandlerH[WHQGVWKLVFODVV
)LQFK)UDPHZRUN OLEVUFFRPILQFKIUDPHZRUNILQFKUHVW8UL5HTXHVW7DVNMDYD
7KLVLVDUXQQQDEOHREMHFWVSHFLDOL]HGWRGRZQORDG+773FRQWHQW,WXVHVWKH
$SDFKH+773FOLHQWIUDPHZRUN
Stepping Through the Search Application
,Q)LJXUHZHGHSLFWWKHVWHSVLQYROYHGDVRXUFRQWHQWSURYLGHUVHUYLFHVVHDUFK
UHTXHVWVIURPWKH9LHZDQG&RQWUROOHUXVLQJD5(67VW\OHQHWZRUNUHTXHVW7KHFRQWHQW
SURYLGHUKDVWKHRSSRUWXQLW\WRFDFKHQHWZRUNUHVXOWVLQ64/LWHWDEOHVEHIRUHQRWLI\LQJ
REVHUYHUVOLVWHQLQJWR85,VDVVRFLDWHGZLWKWKHUHOHYDQWGDWD5HTXHVWVVKRXOGPRYH
DV\QFKURQRXVO\EHWZHHQFRPSRQHQWV7KH9LHZDQG&RQWUROOHUVKRXOGQRWGLUHFWO\RU
V\QFKURQRXVO\LQYRNHWKHLURZQQHWZRUNUHTXHVWV
336 | Chapter 13:ಗExploring Content Providers
)LJXUH7KHVHTXHQFHRIHYHQWVWKDWLPSOHPHQWDFOLHQWUHTXHVWIRUFRQWHQWSURYLGHUGDWD
7KHUHVWRIWKLVFKDSWHUVWHSVWKURXJKRXUVHFRQG)LQFKYLGHRH[DPSOHWRLPSOHPHQW
WKLVSDWWHUQLQDQ$QGURLGDSSOLFDWLRQ:HUHFRPPHQGNHHSLQJ)LJXUHDQGLWV
VWHSVLQPLQGDVZHPRYHIRUZDUG1RWHWKDWWKHVWHSVGRQRWDOZD\VDSSHDULQRUGHU
DVZHGHVFULEHWKHFRGHWR\RXEXWZH¦OOQRWHWKHVWHSVLQEROGZLWKRXWKDYLQJWREUHDN
IURPWKHIORZRIWKHFRGH
Step 1: Our UI Collects User Input
2XU8,LQ)LJXUHXVHVDVLPSOHEditTextWRFROOHFWVHDUFKNH\ZRUGV
Step 2: Our Controller Listens for Events
2XUFinchVideoActivityUHJLVWHUVDWH[WOLVWHQHURXU£&RQWUROOHU¤WKDWUHFHLYHVDQHYHQW
ZKHQWKHXVHUSUHVVHVWKH(QWHUNH\
class FinchVideoActivity {
...
mSearchText.setOnEditorActionListener(
new EditText.OnEditorActionListener() {
public boolean onEditorAction(TextView textView,
int actionId,
KeyEvent keyEvent)
{
...
query();
...
Step 2: Our Controller Listens for Events | 337
);
}
Step 3: The Controller Queries the Content Provider with a
managedQuery on the Content Provider/Model
7KHFRQWUROOHUWKHQLQYRNHVWKHDFWLYLW\¦VqueryPHWKRGLQUHVSRQVHWRXVHUWH[WLQSXW
IRUDVHDUFK // inside FinchVideoActivity
...
// sends the query to the finch video content provider
private void query() {
if (!mSearchText.searchEmpty()) {
String queryString =
FinchVideo.Videos.QUERY_PARAM_NAME + "=" +
Uri.encode(mSearchText.getText().toString());
Uri queryUri =
Uri.parse(FinchVideo.Videos.CONTENT_URI + "?" +
queryString);
Cursor c = managedQuery(queryUri, null, null, null, null);
mAdapter.changeCursor(c);
}
}
Step 4: Implementing the RESTful Request
6WHSLVTXLWHDELWPRUHLQYROYHGWKDQWKHRWKHUFRPSRQHQWVRIWKHVHTXHQFHVRIDU
:H¦OO QHHG WR ZDON WKURXJK RXU 5(67IXO FinchVideoContentProvider DV ZH GLG IRU
SimpleFinchVideoContentProvider 7R VWDUW FinchVideoContentProvider H[WHQGV RXU
XWLOLW\FDOOHGRESTfulContentProviderZKLFKLQWXUQH[WHQGVContentProvider
FinchVideoContentProvider extend RESTfulContentProvider {
RESTfulContentProviderSURYLGHVDV\QFKURQRXV5(67RSHUDWLRQVLQDZD\WKDWDOORZV
WKH)LQFKSURYLGHUWRSOXJLQFXVWRPUHTXHVWUHVSRQVHKDQGOHUFRPSRQHQWV:H¦OOH[
SODLQWKLVLQPRUHGHWDLOVKRUWO\ZKHQZHGLVFXVVRXUHQKDQFHGqueryPHWKRG
Constants and Initialization
FinchVideoContentProvider LQLWLDOL]DWLRQ LV SUHWW\ FORVH WR WKH VLPSOH YLGHR FRQWHQW
SURYLGHU$VZLWKWKHVLPSOHYHUVLRQZHVHWXSD85,PDWFKHU2XURQO\H[WUDWDVNLV
WRDGGVXSSRUWIRUPDWFKLQJVSHFLILFWKXPEQDLOV:HGRQ¦WDGGVXSSRUWIRUPDWFKLQJ
PXOWLSOH WKXPEQDLOV VLQFH RXU YLHZHU DFWLYLW\ GRHV QRW QHHG WKDW VXSSRUW¢LW RQO\
QHHGVWRORDGLQGLYLGXDOWKXPEQDLOV
338 | Chapter 13:ಗExploring Content Providers
sUriMatcher.addURI(FinchVideo.AUTHORITY,
FinchVideo.Videos.THUMB + "/#", THUMB_ID);
Creating the Database
:HFUHDWHWKH)LQFKYLGHRGDWDEDVHZLWK-DYDFRGHWKDWH[HFXWHVWKHIROORZLQJ64/
CREATE TABLE video (_ID INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT, description TEXT, thumb_url TEXT,
thumb_width TEXT, thumb_height TEXT, timestamp TEXT,
query_text TEXT, media_id TEXT UNIQUE);
1RWHWKDWZH¦YHDGGHGWKHDELOLW\WRVWRUHWKHIROORZLQJDWWULEXWHVEH\RQGWKHVLPSOH
YHUVLRQRIRXUGDWDEDVH
thumb_urlthumb_widththumb_height
7KLVLVWKH85/ZLGWKDQGKHLJKWDVVRFLDWHGZLWKDJLYHQYLGHRWKXPEQDLO
timestamp
:KHQZHLQVHUWDQHZYLGHRUHFRUGZHVWDPSLWZLWKWKHFXUUHQWWLPH
query_text
:HVWRUHWKHTXHU\WH[WRUTXHU\NH\ZRUGVLQWKHGDWDEDVHZLWKHDFKUHVXOWIRU
WKDWTXHU\
media_id
7KLVLVDXQLTXHYDOXHIRUHDFKYLGHRUHVSRQVHWKDWZHUHFHLYHIURPWKH*'DWD$3,
:HGRQ¦WDOORZWZRYLGHRHQWULHVWRKDYHWKHVDPHmedia_id
A Networked Query Method
+HUH¦V ZKDW ZH¦YH EHHQ OHDGLQJ XS WR WKH LPSOHPHQWDWLRQ RI WKH FinchYouTubePro
vider TXHU\ PHWKRG FDOOV RXW WR WKH QHWZRUN WR VDWLVI\ D TXHU\ UHTXHVW IRU
<RX7XEH GDWD ,W GRHV WKLV E\ FDOOLQJ D PHWKRG RI LWV VXSHUFODVV
RESTfulContentProvider.asyncQueryRequest(String queryTag, String queryUri)
+HUH queryTagLVDXQLTXHVWULQJWKDWDOORZVXVWRUHMHFWGXSOLFDWHUHTXHVWVZKHQDS
SURSULDWHDQGqueryUriLVWKHFRPSOHWH85,WKDWZHQHHGWRDV\QFKURQRXVO\GRZQORDG
6SHFLILFDOO\ZHLQYRNHUHTXHVWVRQWKHIROORZLQJ85,DIWHUZHKDYHDSSHQGHG URLEn
coder.encodeG TXHU\ SDUDPHWHUV REWDLQHG IURP RXU DSSOLFDWLRQ¦V VHDUFK WH[W LQSXW
ILHOG
/** URI for querying video, expects appended keywords. */
private static final String QUERY_URI =
"http://gdata.youtube.com/feeds/api/videos?" +
"max-results=15&format=1&q=";
Step 4: Implementing the RESTful Request | 339
<RXFDQOHDUQKRZWRFUHDWHD*'DWD<RX7XEH85,WKDWPHHWVWKHQHHGV
RI\RXUDSSOLFDWLRQTXLWHHDVLO\*RRJOHKDVFUHDWHGDEHWD ZKDWHOVH"
XWLOLW\ORFDWHGDWKWWSJGDWD\RXWXEHFRP,I\RXYLVLWWKLVSDJHLQ\RXU
EURZVHULWZLOOVKRZ\RXDZHE8,FRQVLVWLQJRIDSOHWKRUDRIRSWLRQV
WKDW\RXFDQFXVWRPL]HWRFUHDWHD85,OLNHWKHRQHVKRZQLQWKHSUHYLRXV
FRGHOLVWLQJ:HKDYHXVHGWKH8,WRVHOHFWXSWRUHVXOWVDQGKDYH
VHOHFWHGWKHXVHRIDPRELOHYLGHRIRUPDW
2XU QHWZRUNHG query PHWKRG GRHV WKH XVXDO 85, PDWFK DQG WKHQ DGGV WKH
IROORZLQJWDVNVZKLFKUHSUHVHQW£6WHS,PSOHPHQWLQJWKH5(67IXO5HTXHVW¤IURP
RXUVHTXHQFH
/**
* Content provider query method that converts its parameters into a YouTube
* RESTful search query.
*
* @param uri a reference to the query for videos, the query string can
* contain, "q='key_words'". The keywords are sent to the google YouTube
* API where they are used to search the YouTube video database.
* @param projection
* @param where not used in this provider.
* @param whereArgs not used in this provider.
* @param sortOrder not used in this provider.
* @return a cursor containing the results of a YouTube search query.
*/
@Override
public Cursor query(Uri uri, String[] projection, String where,
String[] whereArgs, String sortOrder)
{
Cursor queryCursor;
int match = sUriMatcher.match(uri);
switch (match) {
case VIDEOS:
// the query is passed out of band of other information passed
// to this method -- it's not an argument.
String queryText = uri.
getQueryParameter(FinchVideo.Videos.QUERY_PARAM_NAME);
if (queryText == null) {
// A null cursor is an acceptable argument to the method,
// CursorAdapter.changeCursor(Cursor c), which interprets
// the value by canceling all adapter state so that the
// component for which the cursor is adapting data will
// display no content.
return null;
}
String select = FinchVideo.Videos.QUERY_TEXT_NAME +
" = '" + queryText + "'";
// quickly return already matching data
queryCursor =
340 | Chapter 13:ಗExploring Content Providers
Download from Wow! eBook <www.wowebook.com>
mDb.query(VIDEOS_TABLE_NAME, projection,
select,
whereArgs,
null,
null, sortOrder);
// make the cursor observe the requested query
queryCursor.setNotificationUri(
getContext().getContentResolver(), uri);
/*
* Always try to update results with the latest data from the
* network.
*
* Spawning an asynchronous load task thread guarantees that
* the load has no chance to block any content provider method,
* and therefore no chance to block the UI thread.
*
* While the request loads, we return the cursor with existing
* data to the client.
*
* If the existing cursor is empty, the UI will render no
* content until it receives URI notification.
*
* Content updates that arrive when the asynchronous network
* request completes will appear in the already returned cursor,
* since that cursor query will match that of
* newly arrived items.
*/
if (!"".equals(queryText)) {
asyncQueryRequest(queryText, QUERY_URI + encode(queryText));
}
break;
case VIDEO_ID:
case THUMB_VIDEO_ID:
long videoID = ContentUris.parseId(uri);
queryCursor =
mDb.query(VIDEOS_TABLE_NAME, projection,
FinchVideo.Videos._ID + " = " + videoID,
whereArgs, null, null, null);
queryCursor.setNotificationUri(
getContext().getContentResolver(), uri);
break;
case THUMB_ID:
String uriString = uri.toString();
int lastSlash = uriString.lastIndexOf("/");
String mediaID = uriString.substring(lastSlash + 1);
queryCursor =
mDb.query(VIDEOS_TABLE_NAME, projection,
FinchVideo.Videos.MEDIA_ID_NAME + " = " +
mediaID,
whereArgs, null, null, null);
queryCursor.setNotificationUri(
getContext().getContentResolver(), uri);
Step 4: Implementing the RESTful Request | 341
break;
}
default:
throw new IllegalArgumentException("unsupported uri: " +
QUERY_URI);
return queryCursor;
}
([WUDFWDTXHU\SDUDPHWHURXWRIWKHLQFRPLQJ85,:HQHHGWRVHQGWKLVSDUDPHWHU
LQWKH85,LWVHOIDQGQRWZLWKWKHRWKHUDUJXPHQWVWRWKHqueryPHWKRGVLQFHWKH\
KDYHGLIIHUHQWIXQFWLRQVLQWKH queryPHWKRGDQGFRXOGQRWEHXVHGWRKROGTXHU\
NH\ZRUGV
&KHFNILUVWIRUGDWDDOUHDG\LQWKHORFDOGDWDEDVHWKDWPDWFKHVWKHTXHU\NH\ZRUGV
6HWWKHQRWLILFDWLRQ85,VRWKDWFXUVRUVUHWXUQHGIURPWKHqueryPHWKRGZLOOUHFHLYH
XSGDWHHYHQWVZKHQHYHUWKHSURYLGHUFKDQJHVGDWDWKH\DUHREVHUYLQJ7KLVDFWLRQ
VHWVXS6WHSRIRXUVHTXHQFHZKLFKZLOOHQDEOHWKHYLHZWRXSGDWHZKHQWKHSUR
YLGHUILUHVQRWLILFDWLRQHYHQWVZKHQLWFKDQJHVGDWDDVLWZLOOZKHQGDWDUHWXUQVIURP
DJLYHQUHTXHVW2QFHQRWLILFDWLRQDUULYHV6WHSRFFXUVZKHQWKH8,UHSDLQWV1RWH
WKDW6WHSVDQGDUHRXWRIRUGHULQRXUGHVFULSWLRQEXWLW¦VDSSURSULDWHWRWDON
DERXWWKRVHVWDJHVKHUHVLQFHWKH\UHODWHWRWKHQRWLILFDWLRQ85,DQGWKHTXHU\
6SDZQ DQ DV\QFKURQRXV TXHU\ WR GRZQORDG WKH JLYHQ TXHU\ 85, 7KH PHWKRG
asyncQueryRequestHQFDSVXODWHVWKHFUHDWLRQRIDQHZWKUHDGWRVHUYLFHHDFKUHTXHVW
1RWHWKDWWKLVLV6WHSLQRXUGLDJUDPWKHDV\QFKURQRXVUHTXHVWZLOOVSDZQDWKUHDG
WRDFWXDOO\LQLWLDWHQHWZRUNFRPPXQLFDWLRQDQGWKH<RX7XEHVHUYLFHZLOOUHWXUQD
UHVSRQVH
RESTfulContentProvider: A REST helper
1RZ ZH¦OO ORRN LQWR WKH EHKDYLRUV WKDW FinchVideoProvider LQKHULWV IURP RESTful
ContentProviderLQRUGHUWRH[HFXWH5(67IXOUHTXHVWV7RVWDUWZH¦OOFRQVLGHUWKHEH
KDYLRURIDJLYHQ<RX7XEHUHTXHVWDVZH¦YHVHHQTXHU\UHTXHVWVUXQDV\QFKURQRXVO\
IURPWKHPDLQWKUHDG$5(67IXOSURYLGHUQHHGVWRKDQGOHDIHZVSHFLDOFDVHVLIDXVHU
VHDUFKHVIRU£)XQQ\&DWV¤ZKLOHDQRWKHUUHTXHVWIRUWKHVDPHNH\ZRUGVLVLQSURJUHVV
RXUSURYLGHUZLOOGURSWKHVHFRQGUHTXHVW2QWKHRWKHUKDQGLIDXVHUVHDUFKHVIRU
£GRJV¤DQGWKHQ£FDWV¤EHIRUH£GRJV¤ILQLVKHVRXUSURYLGHUDOORZV£GRJV¤WRUXQLQ
SDUDOOHOWR£FDWV¤VLQFHWKHXVHUPLJKWVHDUFKDJDLQIRU£GRJV¤DQGWKHQREWDLQWKH
EHQHILWRIFDFKHGUHVXOWVLQZKLFKVKHKDGVKRZQVRPHLQWHUHVW
RESTfulContentProvider HQDEOHV D VXEFODVV WR DV\QFKURQRXVO\ VSDZQ UHTXHVWV DQG
ZKHQUHTXHVWGDWDDUULYHVVXSSRUWVFXVWRPKDQGOLQJRIWKHUHVSRQVHXVLQJDVLPSOH
SOXJLQ LQWHUIDFH FDOOHG ResponseHandler 6XEFODVVHV VKRXOG RYHUULGH WKH DEVWUDFW
PHWKRG RESTfulContentProvider.newResponseHandlerWRUHWXUQKDQGOHUVVSHFLDOL]HG
WRSDUVHUHVSRQVHGDWDUHTXHVWHGE\WKHLUKRVWSURYLGHU(DFKKDQGOHUZLOORYHUULGHWKH
PHWKRG ResponseHandler.handleResponse(HttpResponse)WRSURYLGHFXVWRPKDQGOLQJ
342 | Chapter 13:ಗExploring Content Providers
IRU HttpEntityVFRQWDLQHGLQSDVVHG HttpResponseREMHFWV)RUH[DPSOHRXUSURYLGHU
XVHV YouTubeHandlerWRSDUVHD<RX7XEH566IHHGLQVHUWLQJGDWDEDVHYLGHRURZVIRU
HDFKHQWU\LWUHDGV0RUHGHWDLORQWKLVLQDELW
$GGLWLRQDOO\WKHFODVVRESTfulContentProviderHQDEOHVDVXEFODVVWRHDVLO\PDNHDV\Q
FKURQRXVUHTXHVWVDQGUHMHFWGXSOLFDWHUHTXHVWV RESTfulContentProviderWUDFNVHDFK
UHTXHVWZLWKDXQLTXHWDJWKDWHQDEOHVDVXEFODVVWRGURSGXSOLFDWHTXHULHV2XUFinch
VideoContentProvider XVHV WKH XVHU¦V TXHU\ NH\ZRUGV DV WKH UHTXHVW WDJ VLQFH WKH\
XQLTXHO\LGHQWLI\DJLYHQVHDUFKUHTXHVW
2XUFinchVideoContentProviderRYHUULGHVnewResponseHandlerDVIROORZV
/**
* Provides a handler that can parse YouTube GData RSS content.
*
* @param requestTag unique tag identifying this request.
* @return a YouTubeHandler object.
*/
@Override
protected ResponseHandler newResponseHandler(String requestTag) {
return new YouTubeHandler(this, requestTag);
}
1RZ ZH¦OO GLVFXVV WKH LPSOHPHQWDWLRQ RI RESTfulContentProvider WR H[SODLQ WKH
RSHUDWLRQVLWSURYLGHVWRVXEFODVVHV7KHFODVVUriRequestTaskSURYLGHVDUXQQDEOHIRU
DV\QFKURQRXVO\ H[HFXWLQJ 5(67 UHTXHVWV RESTfulContentProvider XVHV D PDS
mRequestsInProgressNH\HGE\DVWULQJWRJXDUDQWHHXQLTXHQHVVRIUHTXHVWV
/**
* Encapsulates functions for asynchronous RESTful requests so that subclass
* content providers can use them for initiating requests while still using
* custom methods for interpreting REST-based content such as RSS, ATOM,
* JSON, etc.
*/
public abstract class RESTfulContentProvider extends ContentProvider {
protected FileHandlerFactory mFileHandlerFactory;
private Map<String, UriRequestTask> mRequestsInProgress =
new HashMap<String, UriRequestTask>();
public RESTfulContentProvider(FileHandlerFactory fileHandlerFactory) {
mFileHandlerFactory = fileHandlerFactory;
}
public abstract Uri insert(Uri uri, ContentValues cv, SQLiteDatabase db);
private UriRequestTask getRequestTask(String queryText) {
return mRequestsInProgress.get(queryText);
}
/**
* Allows the subclass to define the database used by a response handler.
*
* @return database passed to response handler.
*/
Step 4: Implementing the RESTful Request | 343
public abstract SQLiteDatabase getDatabase();
public void requestComplete(String mQueryText) {
synchronized (mRequestsInProgress) {
mRequestsInProgress.remove(mQueryText);
}
}
/**
* Abstract method that allows a subclass to define the type of handler
* that should be used to parse the response of a given request.
*
* @param requestTag unique tag identifying this request.
* @return The response handler created by a subclass used to parse the
* request response.
*/
protected abstract ResponseHandler newResponseHandler(String requestTag);
UriRequestTask newQueryTask(String requestTag, String url) {
UriRequestTask requestTask;
final HttpGet get = new HttpGet(url);
ResponseHandler handler = newResponseHandler(requestTag);
requestTask = new UriRequestTask(requestTag, this, get,
handler, getContext());
mRequestsInProgress.put(requestTag, requestTask);
return requestTask;
}
/**
* Creates a new worker thread to carry out a RESTful network invocation.
*
* @param queryTag unique tag that identifies this request.
*
* @param queryUri the complete URI that should be accessed by this request.
*/
public void asyncQueryRequest(String queryTag, String queryUri) {
synchronized (mRequestsInProgress) {
UriRequestTask requestTask = getRequestTask(queryTag);
if (requestTask == null) {
requestTask = newQueryTask(queryTag, queryUri);
Thread t = new Thread(requestTask);
// allows other requests to run in parallel.
t.start();
}
}
}
...
}
7KH PHWKRG getRequestTask XVHV mRequestsInProgress WRDFFHVVDQ\LGHQWLFDOUH
TXHVWVLQSURJUHVVZKLFKDOORZVWKHasyncQueryRequestWREORFNGXSOLFDWHUHTXHVWV
ZLWKDVLPSOHifVWDWHPHQW
344 | Chapter 13:ಗExploring Content Providers
:KHQ D UHTXHVW FRPSOHWHV DIWHU WKH ResponseHandler.handleResponse PHWKRG UH
WXUQVRESTfulContentProviderUHPRYHVWKHWDVNIURPmRequestsInProgress
newQueryTaskFUHDWHVLQVWDQFHVRIUriRequestTaskWKDWDUHLQVWDQFHVRIRunnableWKDW
ZLOOLQWXUQRSHQDQ+773FRQQHFWLRQDQGWKHQFDOO handleResponseRQWKHDS
SURSULDWHKDQGOHU
)LQDOO\RXUFRGHKDVDXQLTXHUHTXHVWFUHDWHVDWDVNWRUXQLWDQGWKHQZUDSVWKH
WDVNLQDWKUHDGIRUDV\QFKURQRXVH[HFXWLRQ
:KLOHRESTfulContentProviderFRQWDLQVWKHJXWVRIWKHUHXVDEOHWDVNV\VWHPIRUFRP
SOHWHQHVVZH¦OOVKRZ\RXWKHRWKHUFRPSRQHQWVLQRXUIUDPHZRUN
UriRequestTask. UriRequestTask HQFDSVXODWHV WKH DV\QFKURQRXV DVSHFWV RI KDQGOLQJ D
5(67UHTXHVW,W¦VDVLPSOHFODVVWKDWKDVILHOGVWKDWHQDEOHLWWRH[HFXWHD5(67IXO
GETLQVLGHLWVrunPHWKRG6XFKDQDFWLRQZRXOGEHSDUWRI6WHS£,PSOHPHQWLQJWKH
5(67IXO5HTXHVW¤RIRXUVHTXHQFH$VGLVFXVVHGRQFHLWKDVWKHUHVSRQVHIURPWKH
UHTXHVWLWSDVVHVLWWRDQLQYRFDWLRQRI ResponseHandler.handleResponse:HH[SHFW
WKH handleResponse PHWKRG WR LQVHUW GDWDEDVH HQWULHV DV QHHGHG ZKLFK ZH¦OO VHH LQ
YouTubeHandler
/**
* Provides a runnable that uses an HttpClient to asynchronously load a given
* URI. After the network content is loaded, the task delegates handling of the
* request to a ResponseHandler specialized to handle the given content.
*/
public class UriRequestTask implements Runnable {
private HttpUriRequest mRequest;
private ResponseHandler mHandler;
protected Context mAppContext;
private RESTfulContentProvider mSiteProvider;
private String mRequestTag;
//
private int mRawResponse = -1;
private int mRawResponse = R.raw.map_src;
public UriRequestTask(HttpUriRequest request,
ResponseHandler handler, Context appContext)
{
this(null, null, request, handler, appContext);
}
public UriRequestTask(String requestTag,
RESTfulContentProvider siteProvider,
HttpUriRequest request,
ResponseHandler handler, Context appContext)
{
mRequestTag = requestTag;
mSiteProvider = siteProvider;
mRequest = request;
mHandler = handler;
Step 4: Implementing the RESTful Request | 345
}
mAppContext = appContext;
public void setRawResponse(int rawResponse) {
mRawResponse = rawResponse;
}
/**
* Carries out the request on the complete URI as indicated by the protocol,
* host, and port contained in the configuration, and the URI supplied to
* the constructor.
*/
public void run() {
HttpResponse response;
try {
response = execute(mRequest);
mHandler.handleResponse(response, getUri());
} catch (IOException e) {
Log.w(Finch.LOG_TAG, "exception processing asynch request", e);
} finally {
if (mSiteProvider != null) {
mSiteProvider.requestComplete(mRequestTag);
}
}
}
private HttpResponse execute(HttpUriRequest mRequest) throws IOException {
if (mRawResponse >= 0) {
return new RawResponse(mAppContext, mRawResponse);
} else {
HttpClient client = new DefaultHttpClient();
return client.execute(mRequest);
}
}
}
public Uri getUri() {
return Uri.parse(mRequest.getURI().toString());
}
YouTubeHandler. $V UHTXLUHG E\ WKH DEVWUDFW PHWKRG RESTfulContentProvider.newRes
ponseHandlerZH¦YHVHHQWKDWRXUFinchVideoContentProviderUHWXUQVYouTubeHandler
WRKDQGOH<RX7XEH566IHHGVYouTubeHandlerXVHVDPHPRU\VDYLQJ;0/3XOOSDUVHU
WRSDUVHLQFRPLQJGDWDLWHUDWLQJWKURXJKUHTXHVWHG;0/566GDWD YouTubeHandler
FRQWDLQV VRPH FRPSOH[LW\ EXW JHQHUDOO\ LW¦V MXVW PDWFKLQJ ;0/ WDJV DV QHHGHG WR
FUHDWHD ContentValuesREMHFWWKDWLWFDQLQVHUWLQWRWKH FinchVideoContentProvider¦V
GDWDEDVH 3DUW RI 6WHS RFFXUV ZKHQ WKH KDQGOHU LQVHUWV WKH SDUVHG UHVXOW LQWR WKH
SURYLGHUGDWDEDVH
/**
* Parses YouTube Entity data and inserts it into the finch video content
* provider.
*/
346 | Chapter 13:ಗExploring Content Providers
public class YouTubeHandler implements ResponseHandler {
public static final String MEDIA = "media";
public static final String GROUP = "group";
public static final String DESCRIPTION = "description";
public static final String THUMBNAIL = "thumbnail";
public static final String TITLE = "title";
public static final String CONTENT = "content";
public static final String WIDTH = "width";
public static final String HEIGHT = "height";
public static final String YT = "yt";
public static final String DURATION = "duration";
public static final String FORMAT = "format";
public static final String URI = "uri";
public static final String THUMB_URI = "thumb_uri";
public static final String MOBILE_FORMAT = "1";
public static final String ENTRY = "entry";
public static final String ID = "id";
private static final String FLUSH_TIME = "5 minutes";
private RESTfulContentProvider mFinchVideoProvider;
private String mQueryText;
private boolean isEntry;
public YouTubeHandler(RESTfulContentProvider restfulProvider,
String queryText)
{
mFinchVideoProvider = restfulProvider;
mQueryText = queryText;
}
/*
* Handles the response from the YouTube GData server, which is in the form
* of an RSS feed containing references to YouTube videos.
*/
public void handleResponse(HttpResponse response, Uri uri)
throws IOException
{
try {
int newCount = parseYoutubeEntity(response.getEntity());
// only flush old state now that new state has arrived
if (newCount > 0) {
deleteOld();
}
} catch (IOException e) {
// use the exception to avoid clearing old state, if we cannot
// get new state. This way we leave the application with some
Step 4: Implementing the RESTful Request | 347
// data to work with in absence of network connectivity.
}
}
// we could retry the request for data in the hope that the network
// might return.
private void deleteOld() {
// delete any old elements, not just ones that match the current query.
Cursor old = null;
try {
SQLiteDatabase db = mFinchVideoProvider.getDatabase();
old = db.query(FinchVideo.Videos.VIDEO, null,
"video." + FinchVideo.Videos.TIMESTAMP +
" < strftime('%s', 'now', '-" + FLUSH_TIME + "')",
null, null, null, null);
int c = old.getCount();
if (old.getCount() > 0) {
StringBuffer sb = new StringBuffer();
boolean next;
if (old.moveToNext()) {
do {
String ID = old.getString(FinchVideo.ID_COLUMN);
sb.append(FinchVideo.Videos._ID);
sb.append(" = ");
sb.append(ID);
// get rid of associated cached thumb files
mFinchVideoProvider.deleteFile(ID);
next = old.moveToNext();
if (next) {
sb.append(" OR ");
}
} while (next);
}
String where = sb.toString();
db.delete(FinchVideo.Videos.VIDEO, where, null);
}
Log.d(Finch.LOG_TAG, "flushed old query results: " + c);
}
} finally {
if (old != null) {
old.close();
}
}
private int parseYoutubeEntity(HttpEntity entity) throws IOException {
InputStream youTubeContent = entity.getContent();
InputStreamReader inputReader = new InputStreamReader(youTubeContent);
348 | Chapter 13:ಗExploring Content Providers
int inserted = 0;
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(inputReader);
int eventType = xpp.getEventType();
String startName = null;
ContentValues mediaEntry = null;
// iterative pull parsing is a useful way to extract data from
// streams, since we don't have to hold the DOM model in memory
// during the parsing step.
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
} else if (eventType == XmlPullParser.END_DOCUMENT) {
} else if (eventType == XmlPullParser.START_TAG) {
startName = xpp.getName();
if ((startName != null)) {
if ((ENTRY).equals(startName)) {
mediaEntry = new ContentValues();
mediaEntry.put(FinchVideo.Videos.QUERY_TEXT_NAME,
mQueryText);
}
if ((MEDIA + ":" + CONTENT).equals(startName)) {
int c = xpp.getAttributeCount();
String mediaUri = null;
boolean isMobileFormat = false;
for (int i = 0; i < c; i++) {
String attrName = xpp.getAttributeName(i);
String attrValue = xpp.getAttributeValue(i);
if ((attrName != null) &&
URI.equals(attrName))
{
mediaUri = attrValue;
}
}
if ((attrName != null) && (YT + ":" + FORMAT).
equals(MOBILE_FORMAT))
{
isMobileFormat = true;
}
if (isMobileFormat && (mediaUri != null)) {
mediaEntry.put(URI, mediaUri);
Step 4: Implementing the RESTful Request | 349
}
}
if ((MEDIA + ":" + THUMBNAIL).equals(startName)) {
int c = xpp.getAttributeCount();
for (int i = 0; i < c; i++) {
String attrName = xpp.getAttributeName(i);
String attrValue = xpp.getAttributeValue(i);
}
if (attrName != null) {
if ("url".equals(attrName)) {
mediaEntry.put(
FinchVideo.Videos.
THUMB_URI_NAME,
attrValue);
} else if (WIDTH.equals(attrName))
{
mediaEntry.put(
FinchVideo.Videos.
THUMB_WIDTH_NAME,
attrValue);
} else if (HEIGHT.equals(attrName))
{
mediaEntry.put(
FinchVideo.Videos.
THUMB_HEIGHT_NAME,
attrValue);
}
}
}
if (ENTRY.equals(startName)) {
isEntry = true;
}
}
} else if(eventType == XmlPullParser.END_TAG) {
String endName = xpp.getName();
if (endName != null) {
if (ENTRY.equals(endName)) {
isEntry = false;
} else if (endName.equals(MEDIA + ":" + GROUP)) {
// insert the complete media group
inserted++;
// Directly invoke insert on the finch video
// provider, without using content resolver. We
// would not want the content provider to sync this
// data back to itself.
SQLiteDatabase db =
mFinchVideoProvider.getDatabase();
String mediaID = (String) mediaEntry.get(
FinchVideo.Videos.MEDIA_ID_NAME);
350 | Chapter 13:ಗExploring Content Providers
// insert thumb uri
String thumbContentUri =
FinchVideo.Videos.THUMB_URI + "/" + mediaID;
mediaEntry.put(FinchVideo.Videos.
THUMB_CONTENT_URI_NAME,
thumbContentUri);
String cacheFileName =
mFinchVideoProvider.getCacheName(mediaID);
mediaEntry.put(FinchVideo.Videos._DATA,
cacheFileName);
Uri providerUri = mFinchVideoProvider.
insert(FinchVideo.Videos.CONTENT_URI,
mediaEntry, db);
if (providerUri != null) {
String thumbUri = (String) mediaEntry.
get(FinchVideo.Videos.THUMB_URI_NAME);
// We might consider lazily downloading the
// image so that it was only downloaded on
// viewing. Downloading more aggressively
// could also improve performance.
mFinchVideoProvider.
cacheUri2File(String.valueOf(ID),
thumbUrl);
}
}
}
} else if (eventType == XmlPullParser.TEXT) {
// newline can turn into an extra text event
String text = xpp.getText();
if (text != null) {
text = text.trim();
if ((startName != null) && (!"".equals(text))){
if (ID.equals(startName) && isEntry) {
int lastSlash = text.lastIndexOf("/");
String entryId =
text.substring(lastSlash + 1);
mediaEntry.put(FinchVideo.Videos.MEDIA_ID_NAME,
entryId);
} else if ((MEDIA + ":" + TITLE).
equals(startName)) {
mediaEntry.put(TITLE, text);
} else if ((MEDIA + ":" +
DESCRIPTION).equals(startName))
{
mediaEntry.put(DESCRIPTION, text);
}
}
}
}
Step 4: Implementing the RESTful Request | 351
}
eventType = xpp.next();
// an alternate notification scheme might be to notify only after
// all entries have been inserted.
} catch (XmlPullParserException e) {
Log.d(Ch11.LOG_TAG,
"could not parse video feed", e);
} catch (IOException e) {
Log.d(Ch11.LOG_TAG,
"could not process video stream", e);
}
return inserted;
}
}
2XUKDQGOHULPSOHPHQWVhandleResponseE\SDUVLQJD<RX7XEH+773HQWLW\LQLWV
PHWKRGparseYoutubeEntityZKLFKLQVHUWVQHZYLGHRGDWD7KHKDQGOHUWKHQGHOHWHV
ROGYLGHRGDWDE\TXHU\LQJIRUHOHPHQWVWKDWDUHROGHUWKDQDWLPHRXWSHULRGDQG
WKHQGHOHWLQJWKHURZVRIGDWDLQWKDWTXHU\
7KHKDQGOHUKDVILQLVKHGSDUVLQJDPHGLDHOHPHQWDQGXVHVLWVFRQWDLQLQJFRQWHQW
SURYLGHUWRLQVHUWLWVQHZO\SDUVHG ContentValuesREMHFW1RWHWKDWWKLVLV6WHS
£5HVSRQVHKDQGOHULQVHUWVHOHPHQWVLQWRORFDOFDFKH¤LQRXUVHTXHQFH
7KHSURYLGHULQLWLDWHVLWVRZQDV\QFKURQRXVUHTXHVWDIWHULWLQVHUWVDQHZPHGLDHQWU\
WRDOVRGRZQORDGWKXPEQDLOFRQWHQW:H¦OOH[SODLQPRUHDERXWWKLVIHDWXUHRIRXU
SURYLGHUVKRUWO\
insert and ResponseHandlers
*RLQJLQWR6WHSLQDELWPRUHGHWDLORXU)LQFKYLGHRSURYLGHULPSOHPHQWVinsertLQ
PXFKWKHVDPHZD\DVRXUVLPSOHYLGHRSURYLGHU$OVRDVZH¦YHVHHQLQRXUDSSOLFDWLRQ
YLGHRLQVHUWLRQKDSSHQVDVDVLGHHIIHFWRIWKH queryPHWKRG,W¦VZRUWKSRLQWLQJRXW
WKDWRXU insertPHWKRGLVEURNHQLQWRWZRSLHFHV:HLQWHQGWKDWFRQWHQWSURYLGHU
FOLHQWVFDOOWKHILUVWIRUPDQGWKDWUHVSRQVHKDQGOHUVFDOOWKHVHFRQGIRUPVKRZQLQWKH
IROORZLQJFRGH7KHILUVWIRUPGHOHJDWHVWRWKHVHFRQG:HEUHDNXS insertEHFDXVH
WKHUHVSRQVHKDQGOHULVSDUWRIWKHFRQWHQWSURYLGHUDQGGRHVQRWQHHGWRURXWHWKURXJK
WKHFRQWHQWUHVROYHUWRLWVHOI
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
// Validate the requested uri
if (sUriMatcher.match(uri) != VIDEOS) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null) {
352 | Chapter 13:ಗExploring Content Providers
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
SQLiteDatabase db = getDatabase();
return insert(uri, initialValues, db);
}
YouTubeHandlerXVHVWKHIROORZLQJPHWKRGWRGLUHFWO\LQVHUWURZVLQWRWKHVLPSOHYLGHR
GDWDEDVH1RWHWKDWZHGRQ¦WLQVHUWWKHPHGLDLIWKHGDWDEDVHDOUHDG\FRQWDLQVDYLGHR
HQWU\ZLWKWKHVDPHmediaIDDVWKHRQHZHDUHLQVHUWLQJ,QWKLVZD\ZHDYRLGGXSOLFDWH
YLGHRHQWULHVZKLFKFRXOGRFFXUZKHQLQWHJUDWLQJQHZGDWDZLWKROGHUEXWQRWH[SLUHG
GDWD
public Uri insert(Uri uri, ContentValues values, SQLiteDatabase db) {
verifyValues(values);
// Validate the requested uri
int m = sUriMatcher.match(uri);
if (m != VIDEOS) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
// insert the values into a new database row
String mediaID = (String) values.get(FinchVideo.Videos.MEDIA_ID);
Long rowID = mediaExists(db, mediaID);
if (rowID == null) {
long time = System.currentTimeMillis();
values.put(FinchVideo.Videos.TIMESTAMP, time);
long rowId = db.insert(VIDEOS_TABLE_NAME,
FinchVideo.Videos.VIDEO, values);
if (rowId >= 0) {
Uri insertUri =
ContentUris.withAppendedId(
FinchVideo.Videos.CONTENT_URI, rowId);
mContentResolver.notifyChange(insertUri, null);
return insertUri;
} else {
throw new IllegalStateException("could not insert " +
"content values: " + values);
}
}
}
return ContentUris.withAppendedId(FinchVideo.Videos.CONTENT_URI, rowID);
File Management: Storing Thumbnails
1RZWKDWZH¦YHH[SODLQHGKRZRXU5(67IXOSURYLGHUIUDPHZRUNRSHUDWHVZH¦OOHQG
WKHFKDSWHUZLWKDQH[SODQDWLRQRIKRZWKHSURYLGHUKDQGOHVWKXPEQDLOV
Step 4: Implementing the RESTful Request | 353
(DUOLHUZHGHVFULEHGWKHContentResolver.openInputStreamPHWKRGDVDZD\IRUFRQWHQW
SURYLGHUVWRVHUYHILOHVWRFOLHQWV,QRXU)LQFKYLGHRH[DPSOHZHXVHWKLVIHDWXUHWR
VHUYHWKXPEQDLOLPDJHV6WRULQJLPDJHVDVILOHVDOORZVXVWRDYRLGXVHRIGDWDEDVHEOREV
DQGWKHLUSHUIRUPDQFHRYHUKHDGDQGDOORZVXVWRRQO\GRZQORDGLPDJHVZKHQDFOLHQW
UHTXHVWV WKHP )RU D FRQWHQW SURYLGHU WR VHUYH ILOHV LW PXVW RYHUULGH WKH PHWKRG
ContentProvider.openFileZKLFKRSHQVDILOHGHVFULSWRUWRWKHILOHEHLQJVHUYHG7KH
FRQWHQWUHVROYHUWDNHVFDUHRIFUHDWLQJDQLQSXWVWUHDPIURPWKHILOHGHVFULSWRU7KH
VLPSOHVWLPSOHPHQWDWLRQRIWKLVPHWKRGZLOOFDOO openFileHelperWRDFWLYDWHWKHFRQ
YHQLHQFHXWLOLW\WKDWDOORZVWKHContentResolverWRUHDGWKH_dataYDULDEOHWRORDGWKH
ILOHLWUHIHUHQFHV,I\RXUSURYLGHUGRHVQRWRYHUULGHWKLVPHWKRGDWDOO\RXZLOOVHHDQ
H[FHSWLRQJHQHUDWHGWKDWKDVDPHVVDJHDVIROORZV No files supported by provider
at ...2XUVLPSOHLPSOHPHQWDWLRQRQO\DOORZVUHDGRQO\DFFHVVDVVKRZQLQWKHIRO
ORZLQJFRGH
/**
* Provides read-only access to files that have been downloaded and stored
* in the provider cache. Specifically, in this provider, clients can
* access the files of downloaded thumbnail images.
*/
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException
{
// only support read-only files
if (!"r".equals(mode.toLowerCase())) {
throw new FileNotFoundException("Unsupported mode, " +
mode + ", for uri: " + uri);
}
return openFileHelper(uri, mode);
}
)LQDOO\ZHXVHDFileHandlerLPSOHPHQWDWLRQRIResponseHandlerWRGRZQORDGLPDJH
GDWDIURP<RX7XEHWKXPEQDLO85/VFRUUHVSRQGLQJWRHDFKPHGLDHQWU\2XU File
HandlerFactoryDOORZVXVWRPDQDJHFDFKHILOHVVWRUHGLQDVSHFLILHGFDFKHGLUHFWRU\
:HDOORZWKHIDFWRU\WRGHFLGHZKHUHWRVWRUHWKHILOHV
/**
* Creates instances of FileHandler objects that use a common cache directory.
* The cache directory is set in the constructor to the file handler factory.
*/
public class FileHandlerFactory {
private String mCacheDir;
public FileHandlerFactory(String cacheDir) {
mCacheDir = cacheDir;
init();
}
private void init() {
File cacheDir = new File(mCacheDir);
if (!cacheDir.exists()) {
354 | Chapter 13:ಗExploring Content Providers
}
}
cacheDir.mkdir();
public FileHandler newFileHandler(String id) {
return new FileHandler(mCacheDir, id);
}
// not really used since ContentResolver uses _data field.
public File getFile(String ID) {
String cachePath = getFileName(ID);
}
File cacheFile = new File(cachePath);
if (cacheFile.exists()) {
return cacheFile;
}
return null;
public void delete(String ID) {
String cachePath = mCacheDir + "/" + ID;
File cacheFile = new File(cachePath);
if (cacheFile.exists()) {
cacheFile.delete();
}
}
public String getFileName(String ID) {
return mCacheDir + "/" + ID;
}
}
/**
* Writes data from URLs into a local file cache that can be referenced by a
* database ID.
*/
public class FileHandler implements ResponseHandler {
private String mId;
private String mCacheDir;
public FileHandler(String cacheDir, String id) {
mCacheDir = cacheDir;
mId = id;
}
public
String getFileName(String ID) {
return mCacheDir + "/" + ID;
}
public void handleResponse(HttpResponse response, Uri uri)
throws IOException
{
InputStream urlStream = response.getEntity().getContent();
Step 4: Implementing the RESTful Request | 355
FileOutputStream fout =
new FileOutputStream(getFileName(mId));
byte[] bytes = new byte[256];
int r = 0;
do {
r = urlStream.read(bytes);
if (r >= 0) {
fout.write(bytes, 0, r);
}
} while (r >= 0);
urlStream.close();
fout.close();
}
}
356 | Chapter 13:ಗExploring Content Providers
PART IV
Advanced Topics
,Q3DUW,9ZHFRYHU$QGURLG$3,VWKDWDUHLPSRUWDQWWRPDQ\DSSOLFDWLRQVEXWWKDWDUH
QRWSDUWRIWKHFRUH$QGURLG)UDPHZRUNDQGWKDWQRWHYHU\DSSOLFDWLRQLVOLNHO\WRPDNH
XVHRI
CHAPTER 14
Multimedia
,QWRGD\¦VZRUOGRIFRQYHUJLQJWHFKQRORJLHVWKHPRELOHSKRQHLVXVHGIRUDYDULHW\RI
WDVNVEH\RQGVLPSOHYRLFHFDOOV0XOWLPHGLDFDSDELOLWLHVRUWKHSOD\LQJDQGUHFRUGLQJ
RIDXGLRDQGYLGHRLVRQHVXFKVLJQLILFDQWWDVNWKDWPDQ\XVHUVILQGWREHRIJUHDWYDOXH
7DNHDTXLFNORRNDURXQGDQG\RXZLOOILQGSHRSOHXVLQJWKHSKRQHDVDPHDQVWRHQMR\
D YDULHW\ RI SURJUDPV DV ZHOO DV VKDUH VHOIUHFRUGHG PHGLD DPRQJ IULHQGV $QGURLG
SURYLGHVWKH$3,VWRHDVLO\DFFHVVWKLVFDSDELOLW\DVZHOODVHPEHGPXOWLPHGLDDQGLWV
PDQLSXODWLRQGLUHFWO\ZLWKLQDQDSSOLFDWLRQ
Audio and Video
$QGURLGVXSSRUWVSOD\EDFNRIPRVWSRSXODUDXGLRDQGYLGHRIRUPDWV,WDOVROHWV\RX
UHFRUG VRPH IRUPDWV 5HFRUGLQJV DUH VWRUHG LQ ILOHV DQG FDQ RSWLRQDOO\ EH SXW LQ D
SHUVLVWHQWPHGLDVWRUH7KH0HGLD6WRUHLVWKHFRQWHQWSURYLGHUZLWKLQ$QGURLGWKDW
HQDEOHVWKHVWRULQJDQGVKDULQJRIPHGLDGDWDVXFKDVLPDJHVYLGHRDQGDXGLR2QFH
SODFHGZLWKLQWKLVFRQWHQWSURYLGHUPHWDGDWDDVVRFLDWHGZLWKWKHPHGLDILOHVEHFRPHV
DYDLODEOHIRURWKHUDSSOLFDWLRQVWRXVH
$VRIWKLVZULWLQJPRVW$QGURLGGHYLFHVFXUUHQWO\RQWKHPDUNHWVXSSRUWWKHIROORZLQJ
DXGLRDQGYLGHRIRUPDWV1RWHWKDWGHYLFHPDNHUVFDQDGGVXSSRUWIRURWKHUIRUPDWV
QRWOLVWHGKHUH
$XGLR
$$&/&/73
+($$&Y $$&
+($$&Y HQKDQFHG$$&
$051%
$05:%
03
0,',
2JJ9RUELV
3&0:$9(
359
9LGHR
+
+$9&
03(*63
7KHDVWHULVN LQGLFDWHVWKHIRUPDWVIRUZKLFKHQFRGLQJLVDYDLODEOH)RUDOORWKHUV
RQO\GHFRGLQJLVSRVVLEOH
&KHFN WKH 'HYHORSHUV VLWH DW KWWSGHYHORSHUDQGURLGFRPJXLGHDSSHQGL[PHGLDIRU
PDWVKWPOIRUIXUWKHUGHWDLOVDQGFKDQJHV
Playing Audio and Video
$QGURLGSURYLGHVDVWDQGDUGPHDQVWRSOD\DXGLRRUYLGHRWKHMediaPlayerFODVV)RU
DXGLRFRQWHQW\RXFDQDOVRSOD\EDFNUDZGDWDZKLFKLVXVHIXOLQVRSKLVWLFDWHGDSSOL
FDWLRQVZKHUH\RXJHQHUDWHWKHDXGLRG\QDPLFDOO\
$MediaPlayerJRHVWKURXJKVHYHUDOVWDWHVGXULQJLWVOLIHF\FOH
,GOH
7KHMediaPlayerLVLQVWDQWLDWHG
,QLWLDOL]HG
7KHPHGLDVRXUFHLVVHW
3UHSDULQJ
7KHMediaPlayerLVSUHSDULQJWKHPHGLDVRXUFHIRUSOD\EDFN
3UHSDUHG
7KHMediaPlayerLVSUHSDUHGIRUSOD\EDFN
6WDUWHG
3OD\EDFNLVLQSURJUHVV
3DXVHG
3OD\EDFNKDVEHHQSDXVHG
3OD\EDFNFRPSOHWH
3OD\EDFNRIVRXUFHLVGRQH WKHSOD\EDFNFDQEHVWDUWHGDJDLQ 6WRSSHG
7KHMediaPlayerLVQRORQJHUSUHSDUHGWRSOD\WKHVRXUFH
(QG
7KHMediaPlayerLVQRPRUHDQGDOODVVRFLDWHGUHVRXUFHVDUHUHOHDVHG
360 | Chapter 14:ಗMultimedia
Download from Wow! eBook <www.wowebook.com>
)RUGHWDLOVRQWKHVHVWDWHVYLHZWKHVWDWHGLDJUDPSURYLGHGRQWKH'HYHORSHUVVLWHDW
KWWSGHYHORSHUDQGURLGFRPUHIHUHQFHDQGURLGPHGLD0HGLD3OD\HUKWPO6WDWH'LD
JUDP7RJHWVWDUWHGZLWKMediaPlayerLW¦VXVHIXODWWKLVSRLQWWRYLHZLWDVDVHULHVRI
VWHSVLQ\RXUDSSOLFDWLRQ
&UHDWHDMediaPlayerLQVWDQFHWKURXJKWKHcreate()PHWKRG LGOHVWDWH ,QLWLDOL]HWKHMediaPlayerZLWKWKHPHGLDVRXUFHWRSOD\ LQLWLDOL]HGVWDWH 3UHSDUHWKH MediaPlayerIRUSOD\EDFNWKURXJKWKH prepare()PHWKRG SUHSDULQJ
DQGSUHSDUHGVWDWHV 3OD\WKHMediaPlayerWKURXJKWKHstart()PHWKRG VWDUWHGVWDWH 'XULQJSOD\EDFNLIGHVLUHG\RXFDQSDXVHVWRSRUUHSOD\WKHMediaPlayer VWDUWHG
SDXVHGSOD\EDFNFRPSOHWHDQGVWRSSHGVWDWHV 2QFHSOD\EDFNLVILQLVKHGPDNHVXUHWRUHOHDVHWKH MediaPlayer¦VDVVRFLDWHGUH
VRXUFHVE\FDOOLQJrelease() HQGVWDWH 7KHIROORZLQJVHFWLRQVSURYLGHPRUHGHWDLO
Audio Playback
$XGLRFDQEHSOD\HGWKURXJKWZRPHWKRGV MediaPlayerDQGAudioTrackMediaPlayer
LVWKHVWDQGDUGVLPSOHZD\WRGRSOD\EDFN,WVGDWDPXVWEHLQDILOHRUEHVWUHDPEDVHG
AudioTrackLQFRQWUDVWSURYLGHVGLUHFWDFFHVVWRUDZDXGLRLQPHPRU\
MediaPlayer audio playback
:KHQ\RXILUVWVWDUWXVLQJWKHMediaPlayer\RXVKRXOGGHWHUPLQHZKHWKHUDILOHSODFHG
ZLWKLQWKHDSSOLFDWLRQ¦VUHVRXUFHVLVWREHXVHG,IVR MediaPlayerKDVDFRQYHQLHQW
VWDWLFPHWKRGWKDWZLOOVHWXSWKHGDWDVRXUFHDQGSUHSDUHWKHSOD\HU
MediaPlayer mediaplayer = MediaPlayer.create(this, R.raw.example);
,I\RXDUHQRWXVLQJDQDSSOLFDWLRQUHVRXUFHVXFKDVUHIHUHQFLQJDQDXGLRILOHUHVLGLQJ
RQWKHILOHV\VWHP 6'FDUGDQGWKHOLNH RURQDZHEVLWH HJKWWSSomeServerSome
AudioFilePS \RX¦OOKDYHWRPDQXDOO\VHWXSDQGFDOO\RXUGDWDVRXUFH<RXFDQWDNH
WKHGDWDIURPD85,WKURXJKDFDOOWR
setDataSource(context, uri)
7KHFRQWH[WLQWKHILUVWDUJXPHQWLVDPHDQVIRUWKHMediaPlayerWRDFFHVVWKHUHVRXUFHV
RIWKHDSSOLFDWLRQLWVHOIDQGWKXVEHDEOHWRUHVROYHWKH85,(LWKHUWKHDSSOLFDWLRQRU
DFWLYLWLHVFRQWH[WZLOOGR
7KHDOWHUQDWLYHLVWRVSHFLI\DQDEVROXWHILOHSDWKWKURXJK
setDataSource(path)
$3,YHUVLRQOHWV\RXDWWDFKVRPHDX[LOLDU\HIIHFWV VXFKDVUHYHUE WRWKHSOD\HU6HW
DQ\HIIHFWV\RXZDQWZKLOHVHWWLQJWKHGDWDVRXUFHEHIRUHFDOOLQJprepare()
Playing Audio and Video | 361
MediaPlayer mediaplayer = new MediaPlayer();
// Uri mediaReference = "http://someUriToaMediaFile.mp3";
// mediaplayer.setDataSource(this, mediaReference);
// use absolute path
mediaplayer.setDataSource("/sdcard/somefile.mp3");
// prepare mediaplayer
mediaplayer.prepare();
2QFHWKHMediaPlayerLVSUHSDUHG\RXFDQSOD\LW
mediaplayer.start();
'XULQJSOD\WKHSOD\HUFDQEHSDXVHGRUVWRSSHG:KHQLQWKHSDXVHGVWDWHLWPD\EH
XQSDXVHGVLPSO\E\FDOOLQJstart()DJDLQ2QFHWKHMediaPlayerLVVWRSSHG\RXFDQ¦W
VWDUWLWDJDLQZLWKRXWUHVHWWLQJLWWKURXJKWKHreset()PHWKRGUHLQLWLDOL]LQJLWZLWKWKH
GDWDVRXUFHDVVKRZQHDUOLHUDQGLVVXLQJprepare()+RZHYHUORRNDWWKHIROORZLQJ
mediaplayer.pause();
mediaplayer.start();
// pausing
// going from pause to play
mediaplayer.stop();
// stopping
...
// to be able to play again reset must be called
mediaplayer.reset();
// now the media player must be reinitialized to play again
:KLOHWKHMediaPlayerLVSOD\LQJ\RXFDQWUDFNLWVFXUUHQWSRVLWLRQLQWKHILOHWKURXJK
getCurrentPosition()7KLVUHWXUQVWKHDPRXQWRIWLPHSOD\HGWKURXJKLQWKHILOHLQ
PLOOLVHFRQGXQLWV
mediaplayer.getCurrentPosition();
2QFHWKHMediaPlayerLVQRORQJHUQHHGHGPDNHVXUHWRUHOHDVHLWVRWKDWWKHUHVRXUFHV
DUHFOHDQHGXSDQGPDGHDYDLODEOHIRUWKHV\VWHP
mediaplayer.release();
AudioTrack audio playback
AudioTrackSURYLGHVDPXFKPRUHGLUHFWPHWKRGRISOD\LQJDXGLR7KHIROORZLQJH[
DPSOHVKRZVWKHSDUDPHWHUVUHTXLUHGWRVHWXSDQAudioTrack
File mediafile = new File(mediaFilePath);
short[] audio = new short[(int) (mediafile.length()/2)];
// read in file and fill up audio[]
AudioTrack audiotrack = new AudioTrack(
// stream type
AudioManager.STREAM_MUSIC,
// frequency
362 | Chapter 14:ಗMultimedia
11025,
// channel config—mono, stereo, etc.
AudioFormat.CHANNEL_CONFIGURATION_MONO,
// audio encoding
AudioFormat.ENCODING_PCM_16BIT,
// length
audio.length,
// mode
AudioTrack.MODE_STREAM
);
7KH AudioTrack PHWKRG SURYLGHV WKH W\SH RI DXGLR VWUHDP PXVLF ULQJWRQH DODUP
YRLFHFDOOHWF WKHVDPSOHUDWHLQ+HUW] WKHDXGLRFRQILJXUDWLRQ
PRQRRUVWHUHR WKHDXGLRIRUPDWHQFRGLQJWKHOHQJWKRIWKHDXGLRLQQXPEHURI
E\WHVDQGWKHPRGH VWDWLFRUVWUHDP $QGURLG¦V AudioTrackRQFHFRQILJXUHGZLOO
DXWRPDWLFDOO\NQRZKRZWRLQWHUIDFHZLWKWKHKDUGZDUHRQWKHGHYLFHWKXVSURYLGLQJ
DSDLQOHVVH[SHULHQFH
7RSOD\WKHDXGLRLVVXHWKHplay()PHWKRGDQGZULWHWKHGDWDRXWWRWKHKDUGZDUH
// start playing state
audiotrack.play();
// write audio to hardware
audiotrack.write(audio, 0, audio.length);
7RSDXVHWKHWUDFNXWLOL]HWKHpause()PHWKRG
// pause
audiotrack.pause();
7RVWRSSOD\LQJWKHWUDFNVHWLWWRWKHVWRSSHGVWDWH,I\RXGRQ¦WQHHGWKHWUDFNDQ\PRUH
UHOHDVHLW2WKHUZLVHWRUHSOD\WKHDXGLR\RXPXVWUHLQLWLDOL]HLW
// stop
audiotrack.stop();
// release all resources
audiotrack.release();
Video Playback
9LGHRSOD\EDFNXQOLNHDXGLRSOD\EDFNFDQXVHRQO\WKHMediaPlayer7KHUHLVQRYLGHR
HTXLYDOHQWWRAudioTrack9LGHRXVHVWKHMediaPlayerVLPLODUO\WRDXGLRILOHVEXW\RX
PXVWDGGLWLRQDOO\VSHFLI\DYLHZ FDOOHGDVXUIDFH RQZKLFKWKHYLGHRFDQEHGLVSOD\HG
$QGURLGRIIHUVDFRQYHQLHQWFRQWUROWKDWLQFOXGHVLWVRZQVXUIDFHWKHVideoViewYLHZ
$QH[DPSOHRILWVXVHIROORZV,WLQFOXGHVWKHDGGLWLRQRIDQRSWLRQDOFRQWUROOHUWKDW
OHWVWKHXVHUFRQWUROWKHSOD\EDFNWKURXJKDVLPSOHLQWHUIDFHWKDWLQFOXGHVEXWWRQVWR
VWDUWVWRSDQGSDXVHWKHSOD\EDFNDVZHOODVDVHHNEDUWRVNLSIRUZDUGRUEDFNZLWKLQ
WKHYLGHR¦VSOD\EDFNSURJUHVV
Playing Audio and Video | 363
// create the view (in this case it is already included in the layout resource)
VideoView videoview = (VideoView) findViewById(R.id.videoview);
videoview.setKeepScreenOn(true);
// used if streaming
if (videouri != null) videoview.setVideoURI(videouri);
// absolute path if it is a file
else videoview.setVideoPath(videopath);
// let's add a media control so we can control the playback
mediacontroller = new MediaController(this);
mediacontroller.setAnchorView(videoview);
videoview.setMediaController(mediacontroller);
if (videoview.canSeekForward())
videoview.seekTo(videoview.getDuration()/2);
// start the playback
videoview.start();
Recording Audio and Video
7KHVWDQGDUGFODVVWKDWVXSSRUWVUHFRUGLQJLVWKH MediaRecorder0XFKOLNHWKHMedia
PlayerLWSDVVHVWKURXJKYDULRXVVWDWHVGXULQJLWVOLIHF\FOH7KHVWDWHVDUHDVIROORZV
IRU PRUH GHWDLOV YLHZ WKH VWDWH GLDJUDP SURYLGHG E\ WKH 'HYHORSHUV VLWH DW KWWS
GHYHORSHUDQGURLGFRPUHIHUHQFHDQGURLGPHGLD0HGLD5HFRUGHUKWPO ,QLWLDOL]H
7KHMediaRecorderFODVVLVLQVWDQWLDWHG
,QLWLDOL]HG
7KHMediaRecorderLVUHDG\WREHXVHG
'DWD6RXUFHFRQILJXUHG
7KHPHGLDVRXUFH ZKHUHWKHRXWSXWZLOOEHSODFHG LVFRQILJXUHG
3UHSDUHG
7KHMediaRecorderLVSUHSDUHGWRUHFRUG
5HFRUGLQJ
5HFRUGLQJLVXQGHUZD\
5HOHDVHG
$OOUHVRXUFHVDUHUHOHDVHG
7RXWLOL]HWKHMediaRecorderVRPHSHUPLVVLRQVPD\QHHGWREHVHWLQWKHPDQLIHVW
‡ 7RHQDEOHYLGHRUHFRUGLQJHQDEOHRECORD_VIDEODQGWKHCAMERA
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.CAMERA"/>
‡ 7RUHFRUGDXGLRHQDEOHRECORD_AUDIO
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
364 | Chapter 14:ಗMultimedia
Audio Recording
7KHUHDUHWKUHHPHWKRGVWRUHFRUGDXGLR7KHMediaRecorderLVWKHVWDQGDUGPHWKRG
XVLQJDQ IntentLVWKHVLPSOHVWPHWKRGDQGWKH AudioRecorderFDQEHXVHGWRUHFRUG
GLUHFWO\IURPKDUGZDUHEXIIHUV
MediaRecorder audio recording
)LUVWLQLWLDOL]HWKHMediaRecorder7KHQVHWWKHGDWDVRXUFHLQIRUPDWLRQ WKHDXGLRLQSXW
VRXUFHWKHRXWSXWIRUPDWWKHHQFRGLQJW\SHZKHUHWKHILOHLVWREHUHFRUGHGWRHWF 6WDUWLQJZLWKYHUVLRQ\RXFDQVHWWKHELWUDWHDQGVDPSOLQJUDWH2QFHDOOWKLVLVGRQH
FDOOWKHprepare()PHWKRG
// initialize the MediaRecorder
MediaRecorder mediarecorder = new MediaRecorder();
// configure the data source
// the source of the audio input
mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// output format
mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// encoding
mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// use absolute path to file where output is stored
mediarecorder.setOutputFile("/sdcard/audiorecordexample.3gpp");
// prepare to record
mediarecorder.prepare();
7KHQZKHQWKHUHFRGLQJQHHGVWRVWDUWFDOOWKHstart()PHWKRG
mediarecorder.start();
:KHQWKHUHFRUGLQJQHHGVWREHVWRSSHGFDOOWKHstop()PHWKRG,I\RXZDQWWRFRQ
WLQXHUHFRUGLQJDIWHUWKLVFDOOreset()WRIRUFHWKHMediaRecorderEDFNWRWKHLGOHVWDWH
7KHQUHFRQILJXUHWKHGDWDVRXUFHWRSUHSDUHWKHMediaRecorderDJDLQ
mediarecorder.stop();
...
mediarecorder.reset();
2QFHWKHMediaRecorderLVQRORQJHUQHHGHGPDNHVXUHWRUHOHDVHLW
mediarecorder.release();
7KHIROORZLQJH[DPSOHLVDFRQYHQLHQWOLWWOHDSSWKDWXVHVWKHFRGHZHGHYHORSHGWR
SURYLGHD£UHFRUG¤EXWWRQIRUWKHXVHU:KHQWKHEXWWRQLVFOLFNHGWKHrecordPHWKRG
H[HFXWHVZLWKWKHILOHSDWKDOUHDG\UHIHUHQFHG$£VWRS¤EXWWRQLVWKHQPDGHYLVLEOHDQG
WKH£UHFRUG¤EXWWRQEHFRPHVLQYLVLEOH:KHQWKH£VWRS¤EXWWRQLVFOLFNHGWKH stop
RecordPHWKRGLVFDOOHGDQGWKH£UHFRUG¤EXWWRQFRPHVEDFN
Recording Audio and Video | 365
public class AudioRecorder extends Activity {
private MediaRecorder mediarecorder;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audiorecorderlayout);
ImageButton recordbutton = (ImageButton) findViewById(R.id.record);
recordbutton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
record("/sdcard/audiorecordexample.3gpp");
}
});
ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
stopbutton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
stopRecord();
}
});
}
private void record(String filePath) {
try {
File mediafile = new File(filePath);
if(mediafile.exists()) {
mediafile.delete();
}
mediafile = null;
// record button goes away
ImageButton button = (ImageButton) findViewById(R.id.record);
button.setVisibility(View.GONE);
// stop button shows up
ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
stopbutton.setVisibility(View.VISIBLE);
// set up media recorder
if(mediarecorder == null) mediarecorder = new MediaRecorder();
mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediarecorder.setOutputFile(filePath);
// prepare media recorder
mediarecorder.prepare();
// start media recorder
mediarecorder.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
366 | Chapter 14:ಗMultimedia
private void stopRecord() {
// stop media recorder
mediarecorder.stop();
// reset media recorder
mediarecorder.reset();
// record button shows up
ImageButton button = (ImageButton) findViewById(R.id.record);
button.setVisibility(View.VISIBLE);
// stop button goes away
ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
stopbutton.setVisibility(View.GONE);
}
}
Intent audio recording
5HFRUGLQJ YLD Intent LV WKH HDVLHVW RI WKH PHWKRGV -XVW FRQVWUXFW WKH Media
Store.Audio.Media.RECORD_SOUND_ACTION LQWHQW DQG VWDUW LW XVLQJ WKH startActivity
ForResult()IURPZLWKLQWKHActivity7KLVZLOOODXQFKWKHGHIDXOWDXGLRUHFRUGHUWKDW
LVSURYLGHGLQPRVW$QGURLGGHYLFHVDQGSURFHHGVWRUHFRUGVRPHDXGLR
Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
startActivityForResult(intent, 1); // intent and requestCode of 1
2QFHWKHUHFRUGLQJLVFRPSOHWHDQGWKHDXGLRUHFRUGHUILQLVKHV\RXU ActivityWKDW
RULJLQDWHGWKHFDOOWRstartActivityForResult()ZLOOEHEURXJKWEDFNWRWKHIRUH:KHQ
WKDW RFFXUV \RXU Activity¦V onActivityResult() PHWKRG ZLOO EH WULJJHUHG ZLWK WKH
requestCode\RXSURYLGHG LQWKLVFDVH DUHVXOWFRGH 2.RUHUURU DQGDQLQWHQW
FDUU\LQJWKH85,UHIHUHQFLQJWKHUHFRUGHGDXGLRILOH
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// is it our requestCode?
if (requestCode == 1) {
// is the resultCode OK?
if (resultCode == RESULT_OK) {
// lets get the uri
Uri audioUri = intent.getData();
// lets play the uri or do something with it.
playAudio(audioUri);
}
}
}
AudioRecorder audio recording
,Q SDUDOOHO ZLWK AudioTrack AudioRecorder SURYLGHV D PXFK PRUH GLUHFW UHFRUGLQJ
H[SHULHQFH
short[] buffer = new short[10000];
recorder = new AudioRecord(
// source to record from
MediaRecorder.AudioSource.MIC,
// frequency
Recording Audio and Video | 367
11025,
// channel config—mono, stereo, etc.
AudioFormat.CHANNEL_CONFIGURATION_MONO,
// audio encoding
AudioFormat.ENCODING_PCM_16BIT,
// buffer size
buffer.length
);
7KHAudioRecordPHWKRGSURYLGHVWKHW\SHRIVRXUFHWRUHFRUGDXGLRIURP 0LF&DP
FRUGHU>PLFIDFLQJWKHVDPHGLUHFWLRQDVWKHFDPHUD@RU9RLFH&DOO WKHVDPSOHUDWHLQ
+HUW] RU WKHDXGLRFRQILJXUDWLRQ PRQRRUVWHUHR WKHDXGLR
IRUPDWHQFRGLQJDQGWKHOHQJWKRIWKHEXIIHULQQXPEHURIE\WHV1RWHWKDWWKHVL]HRI
WKLVEXIIHUGHWHUPLQHVKRZORQJDQAudioRecordFDQUHFRUGEHIRUH£RYHUUXQQLQJ¤GDWD
WKDWKDVQRWEHHQUHDG\HW'DWDVKRXOGEHUHDGIURPWKHDXGLRKDUGZDUHLQFKXQNVRI
VL]HVOHVVWKDQWKHWRWDOUHFRUGLQJEXIIHUVL]H$QGURLG¦VAudioRecordRQFHFRQILJXUHG
ZLOODXWRPDWLFDOO\NQRZKRZWRLQWHUIDFHZLWKWKHKDUGZDUHRQWKHGHYLFHWKXVSUR
YLGLQJDSDLQOHVVH[SHULHQFH
7RVWDUWUHFRUGLQJVHWWKHAudioRecord¦VVWDWHWRWKH5HFRUGVWDWHDQGUHDGGDWDUHSHDW
HGO\IURPWKHKDUGZDUHEXIIHU
recorder.startRecording();
while(recordablestate) {
try {
// read in up to buffer size
int readBytes = recorder.read(buffer, 0, buffer.length);
// do something with the bytes that are read
} catch (Exception t) {
recordablestate = false;
}
}
7RVWRSUHFRUGLQJVHWWKHAudioRecord¦VVWDWHWR6WRS,I\RXQRORQJHUZLVKWRUHFRUG
GRQRWIRUJHWWRUHOHDVHDOOUHVRXUFHVDVVRFLDWHGZLWKWKHUHFRUGLQJ2WKHUZLVH\RXPD\
FDOOstartRecording()WRVWDUWUHFRUGLQJDJDLQ
// stop recording
recorder.stop();
// release recording resources
recorder.release();
Video Recording
<RXFDQUHFRUGYLGHRLQWZRZD\VE\XVLQJWKHMediaRecorderRUE\XVLQJDQIntent
5DZUHFRUGLQJLVQRWVXSSRUWHGDVLWLVIRUDXGLR
368 | Chapter 14:ಗMultimedia
MediaRecorder video recording
7KHSURFHVVIRUUHFRUGLQJYLGHRZLWKWKH MediaRecorderLVPXFKWKHVDPHDVWKDWIRU
UHFRUGLQJDXGLRLQLWLDOL]HWKH MediaRecorderSUHSDUHWKHGDWDVRXUFHDQGVWDUWWKH
MediaRecorder<RXFDQRIIHUWKHXVHUDSUHYLHZZLQGRZVRWKDWKHFDQSUHYLHZWKH
YLGHREHLQJFDSWXUHGE\SURYLGLQJDVXUIDFHDVVKRZQHDUOLHUIRUSOD\LQJEDFNYLGHR
*HQHUDOO\DVideoViewLVXVHG
// initialize
MediaRecorder mediarecorder = new MediaRecorder();
// set data source
mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mediarecorder.setOutputFile("/sdcard/someexamplevideo.mp4");
// provide a surface to show the preview in. in this case a VideoView is used
videoview = (VideoView) findViewById(R.id.videosurface);
SurfaceHolder holder = videoview.getHolder();
mediarecorder.setPreviewDisplay(holder.getSurface());
// prepare
mediarecorder.prepare();
// start recording
mediarecorder.start();
Intent video recording
IntentEDVHGYLGHRUHFRUGLQJLVOLNHXVLQJDQLQWHQWWRUHFRUGDXGLR7KHLQWHQWWRXVH
LVMediaStore.ACTION_VIDEO_CAPTUREDQGWKHUHVXOWDQWGDWDLVWKH85,RIWKHYLGHRILOH
Stored Media Content
(YHQZKHQPHGLDLVVDYHGWRDILOH DVLQWKHFDVHRIUHFRUGLQJ WKHPHGLDILOHLVQRW
LPPHGLDWHO\DYDLODEOHWRRWKHUDSSOLFDWLRQV7RPDNHWKHILOHDYDLODEOH\RXPXVWLQVHUW
LWLQWRWKH0HGLD6WRUH7KH0HGLD6WRUHLVDFRQWHQWSURYLGHUGHGLFDWHGWRWKHVWRUDJH
DQGUHWULHYDORIPHGLDGDWD LPDJHVYLGHRDXGLR ZLWKWKHGHYLFH7RVWRUHDUHIHUHQFH
WRWKHILOHFUHDWHDContentValuesREMHFWDQGLQVHUWLWLQWRWKHDSSURSULDWH0HGLD6WRUH
FRQWHQWSURYLGHU7KHIROORZLQJH[DPSOHLQVHUWVDQDXGLRILOHZLWKDSSURSULDWHPHWD
GDWDVXFKDVWLWOHDQGDUWLVW
// generate ContentValues and add appropriate metadata values
ContentValues content = new ContentValues();
// VERY IMPORTANT! Must reference the absolute path of the data.
content.put(MediaStore.MediaColumns.DATA, "/sdcard/AudioExample.3gpp");
Stored Media Content | 369
content.put(MediaStore.MediaColumns.TITLE, "AudioRecordExample");
content.put(MediaStore.MediaColumns.MIME_TYPE, "audio/amr");
content.put(MediaStore.Audio.Media.ARTIST, "Me");
content.put(MediaStore.Audio.Media.IS_MUSIC, true);
// get the Content Resolver
ContentResolver resolve = getContentResolver();
// insert into the content resolver
Uri uri = resolve.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, content);
// announce to everyone that cares that it was inserted
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
370 | Chapter 14:ಗMultimedia
CHAPTER 15
Location and Mapping
(YHUVLQFHPRELOHSKRQHVVWDUWHGWRLQFRUSRUDWHVWDQGDORQH*36UHFHLYHUVGHYHORSHUV
KDYHIRUHVHHQDQHZHUDRIORFDWLRQEDVHGDSSOLFDWLRQV/RFDWLRQDZDUHQHVVHQDEOHVD
QHZJHQHUDWLRQRIPRELOHDSSOLFDWLRQV,I\RXUDSSOLFDWLRQLVORRNLQJXSUHVWDXUDQWV
LW¦VFOHDUO\DGYDQWDJHRXVLI\RXFDQUHVWULFW\RXUVHDUFKWRWKHDUHDDURXQG\RX,W¦VHYHQ
EHWWHU LI \RX FDQ VHH D PDS RI WKH UHVWDXUDQWV¦ ORFDWLRQV DQG SHUKDSV EH DEOH WR
ORRNXSGULYLQJRUZDONLQJGLUHFWLRQV,I\RX¦UHORRNLQJIRUDWHPSRUDU\MREDVLQWKH
0-$QGURLG DSSOLFDWLRQ KLJKOLJKWHG LQ £8VLQJ WKH 'DWDEDVH $3, 0-$Q
GURLG¤ RQ SDJH LW¦V GHILQLWHO\ D EHQHILW WR EH DEOH WR JUDSKLFDOO\ YLHZ MRE
RSSRUWXQLWLHVRQDPDS
1DYLJDWLRQLVUHDOO\MXVWWKHILUVWJHQHUDWLRQRIORFDWLRQEDVHGVHUYLFHV /%6 $SSOLFD
WLRQVWKDWHQDEOHXVHUVHLWKHUWRRSWLQWRDOORZVKDULQJRIWKHLUORFDWLRQZLWKIULHQGV
VXFKDV*RRJOH/DWLWXGHRUWRDWWDFKLPSRUWDQFHWRJHRJUDSKLFVLWHVVXFKDV)RXU
VTXDUHKDYHEHJXQWRDUULYHLQDELJZD\7KHZRUOGRI/%6LVUHDOO\WDNLQJRIIDQGDV
ZH¦OOVHH*RRJOH¦V$QGURLGSURYLGHVSRZHUIXOIHDWXUHVWKDWJUHDWO\VLPSOLI\GHYHORS
PHQWRIWKLVW\SHRIDSSOLFDWLRQ
,QHFRQRPLFWHUPVORFDWLRQEDVHGDSSOLFDWLRQVDUHDPDMRUIDFWRULQPRELOHWHOHSKRQ\
PDNLQJXSDVLJQLILFDQWSRUWLRQRIWKHUHYHQXHIURPPRELOHDSSOLFDWLRQVDQGJURZLQJ
IDVW%HFDXVHWKH\DUHEDVHGRQWKHDELOLW\RIWKHPRELOHQHWZRUNWRORFDWHGHYLFHVDQG
WKH UHODWLRQVKLS RI PRELOLW\ DQG ORFDWLRQ ORFDWLRQEDVHG DSSOLFDWLRQV DUH DV IXQGD
PHQWDOWRPRELOHWHOHSKRQ\DVFRPPXQLFDWLRQ
$SSOLFDWLRQVRIWHQFRPELQHORFDWLRQDZDUHQHVVZLWKVHDUFK:KHUHDUHP\FRQWDFWV"
:KHUH DUH VHUYLFHV RU SURGXFWV ,¦P ORRNLQJ IRU" :KHUH DUH SHRSOH ZLWK FRPPRQ
LQWHUHVWV"
,QWKLVFKDSWHUZH¦OOH[SORUHKRZWKH0-$QGURLGDSSOLFDWLRQXVHV$QGURLGWRDGGUHVV
VRPHRIWKHVHTXHVWLRQV
371
Location-Based Services
0RELOHSKRQHVXVHVHYHUDOUHODWHGPHWKRGVDORQHDQGLQFRPELQDWLRQWRGHWHUPLQH
ZKHUHWKH\DUH
&HOO,'
:KHWKHU\RX¦UHDFWXDOO\WDONLQJRQWKHSKRQHRUQRWDVORQJDVLW¦VSRZHUHGXS
\RXUPRELOHSKRQHFDUULHVRQDFRQVWDQWFRQYHUVDWLRQZLWKQHDUE\FHOOWRZHUV,W
KDVWRGRWKLVWREHDEOHWRUHVSRQGZKHQVRPHRQHFDOOV\RXVRHYHU\IHZVHFRQGV
LW£SLQJV¤WKHFHOOWRZHULWZDVXVLQJODVWWRWHOOLWWKDWLW¦VVWLOOLQUDQJHDQGWRQRWH
QHWZRUNSDUDPHWHUVVXFKDVWKHFXUUHQWWLPHWKHFXUUHQWVLJQDOVWUHQJWK XSOLQN
DQGGRZQOLQN DQGVRRQ
,I\RXKDSSHQWREHPRYLQJ\RXUSKRQHPD\LQLWLDWHDKDQGRYHUWRDQRWKHUFHOO
WRZHUDOOLQWKHEDFNJURXQGDQGZLWKRXW\RXKDYLQJWRLQWHUYHQH(DFKFHOOWRZHU
ZRUOGZLGHKDVDXQLTXHLGHQWLILHUFDOOHGDSSURSULDWHO\HQRXJKLWV&HOO,'DQG
HDFKWRZHUNQRZVLWVODWLWXGHDQGORQJLWXGHVRLW¦VHDV\HQRXJKIRUDPRELOHSKRQH
WRNQRZDSSUR[LPDWHO\ZKHUH\RXDUHORFDWHGE\QRWLQJWKHFXUUHQW&HOO,'¦VJHR
JUDSKLFORFDWLRQ&HOOQHWZRUNVL]HVYDU\GHSHQGLQJRQWKHH[SHFWHGWUDIILFLQDQ
DUHDEXWLQWKH8QLWHG6WDWHVWKHLUUDGLXVUDQJHVIURPDKDOIPLOH FLWLHV WRILYH
PLOHVRUPRUH ZLGHRSHQVSDFHV 7ULDQJXODWLRQ
0RVWRIWKHWLPH\RXUPRELOHSKRQHLVLQUDQJHRIPRUHWKDQRQHFHOOWRZHU,Q*
DQGODWHUPRELOHWHFKQRORJLHVWKHFHOOWRZHUKDVWKHDELOLW\WRWHOOZKDWGLUHFWLRQ
\RXUVLJQDOLVFRPLQJIURP,IWKHUHDUHWZRRUWKUHHWRZHUVWKDWFDQVHH\RXUSKRQH
WRJHWKHUWKH\FDQWULDQJXODWHRQ\RXUSKRQH¦VORFDWLRQ:LWKVRPHRSHUDWRUV\RXU
SKRQHWKHQKDVWKHDELOLW\WRTXHU\WKHQHWZRUNWRILQGRXWZKHUHLW¦VEHHQORFDWHG
7KLVVRXQGVDOLWWOHEDFNZDUGEXWLWFDQEHYHU\DFFXUDWHDQGLWGRHVQ¦WGHSHQG
RQDQ\H[WUDKDUGZDUHRQWKHPRELOHSKRQH
*36
7KHVDWHOOLWHEDVHG*OREDO3RVLWLRQLQJ6\VWHPLVXELTXLWRXVWKHVHGD\VIRXQGLQ
FDUQDYLJDWLRQXQLWVKDQGKHOGQDYLJDWRUVDQGPRELOHSKRQHV7KHJRRGQHZVLV
WKDWXVLQJ*36\RXUPRELOHSKRQHFDQGHWHUPLQHLWVORFDWLRQYHU\DFFXUDWHO\
LQFOXGLQJLWVDOWLWXGHLIWKDW¦VLPSRUWDQWIRUVRPHSDUWLFXODUDSSOLFDWLRQ7KHUHDUH
VHYHUDOGRZQVLGHVWR*36EXWLWLVJDLQLQJSRSXODULW\QRQHWKHOHVV7KHGRZQVLGHV
DUH
,QFUHDVHGFRVW
*36UDGLRVDQGSURFHVVRUVDUHIDLUO\LQH[SHQVLYHEXWVWLOODQLQFUHDVHRIHYHQ
LQWKHELOORIPDWHULDOVFRVWRIDPRELOHSKRQHLVFRQVLGHUDEOH
5HGXFHGEDWWHU\OLIH
7KHUHKDYHEHHQJUHDWVWULGHVLQUHGXFLQJWKHSRZHUUHTXLUHGE\*36UDGLRV
DQGSURFHVVRUVEXWWKH\VWLOOVXFNEDWWHU\SRZHU0RVWSKRQHVWKDWLQFOXGH
*36DOVRKDYHDIHDWXUHWKDWOHWVWKHXVHUWXUQLWRQDQGRII,I\RXUDSSOLFDWLRQ
GHSHQGVRQ*36DFFXUDF\LW¦VJRRGWRUHPHPEHUWKDW\RXUDSSOLFDWLRQPLJKW
372 | Chapter 15:ಗLocation and Mapping
KDYHWRFKHFNWRVHHZKHWKHUWKH*36GHYLFHLVWXUQHGRQDQGQRWLI\WKHXVHU
LILWLVQ¦W
8QUHOLDEOHDYDLODELOLW\
1RWKLQJ£DOZD\VZRUNV¤EXW*36LQSDUWLFXODUGHSHQGVRQ\RXUPRELOHGHYLFH
EHLQJDEOHWRVHHWKHVDWHOOLWHVFXUUHQWO\RYHUKHDG,I\RX¦UHLQWKHEDVHPHQWRI
DKLJKULVHEXLOGLQJVXUURXQGHGE\VWHHOUHLQIRUFHGFRQFUHWH\RXSUREDEO\
DUHQ¦WJRLQJWREHDEOHWRXVH*36
,W¦VUHDVRQDEOHWRH[SHFWWKDWDOO$QGURLGSKRQHVZLOOLQFOXGHRQHRUDOORIWKHVHORFDWLRQ
ILQGLQJPHWKRGV0RVWUHFHQW$QGURLGSKRQHVLQSDUWLFXODUFDQXVHWKHPDOO6RQRZ
ZH¦OOSURFHHGWRWHFKQLTXHVIRUXVLQJWKHORFDWLRQFDSDELOLWLHV
Mapping
*RRJOHLVPRVWIDPRXVIRULWVVHDUFKHQJLQHEXWQRWIDUEHKLQGWKDWFRPHVWKHDFFODLP
RI*RRJOH0DSV:KHQFUHDWLQJ$QGURLGWKHIRONVDW*RRJOHFRXOGHDVLO\VHHWKHSR
WHQWLDOLQ/%6DQGKRZZHOOWKDWILWZLWKWKHLUPDSSLQJH[SHUWLVH0RVW/%6DSSOLFDWLRQV
HQGXSGLVSOD\LQJDPDS0HDQZKLOH*RRJOHDOUHDG\KDGWKHWHFKQRORJ\WRGLVSOD\
DQGXSGDWHLQWHUDFWLYHPDSVDQGWKHEXVLQHVVSURFHVVHVLQSODFHWRDOORZRWKHUVWRXVH
WKRVHPDSVDQGDGGIHDWXUHVIRUWKHLURZQZHEVLWHV,WVWLOOUHTXLUHGDVLJQLILFDQWOHDS
WR PDNH WKDW PDSSLQJ WHFKQRORJ\ DYDLODEOH WR DSSOLFDWLRQ GHYHORSHUV IRU PRELOH
SKRQHVEXW*RRJOHKDVFHUWDLQO\DQVZHUHGWKHFKDOOHQJHLQ$QGURLG
The Google Maps Activity
2QHRIWKHDSSOLFDWLRQVWKDWFRPHVZLWK$QGURLGLVWKH*RRJOH0DSVDSSOLFDWLRQLWVHOI
,ILW¦VDSSURSULDWH\RXFDQVWDUW*RRJOH0DSVIURP\RXUDSSOLFDWLRQWKHVDPHZD\\RX
VWDUWDQ\RWKHUActivity
&UHDWH DQ Intent new Intent(String action, Uri uri) WKDW VD\V \RX QHHG WR
GLVSOD\DPDS7KHSDUDPHWHUVDUH
‡ $QactionIRUZKLFK\RXPXVWVSHFLI\ACTION_VIEW
‡ $UriIRUZKLFK\RXVKRXOGVSHFLI\RQHRIWKHIROORZLQJ85,VFKHPHVVXEVWL
WXWLQJ\RXUGDWD
¢ geo:latitude, longitude
¢ geo:latitude,longitude?z=zoom
¢ geo:0,0?qmy_street_address
¢ geo:0,0?qbusiness_near_city
&DOOstartActivity(Intent intent)XVLQJWKHLQWHQW\RXMXVWFUHDWHG
$QH[DPSOHWKDWFUHDWHVDPDSLV
The Google Maps Activity | 373
Intent intent = new Intent(ACTION_VIEW, "geo:37.422006,-122.084095");
startActivity(intent);
7KLVLVFHUWDLQO\HDV\DQGLWJHWV\RXDOOWKHSRZHURI*RRJOH0DSVEXW\RXFDQ¦WUHDOO\
LQWHJUDWHWKHPDSLQWR\RXUDSSOLFDWLRQWKLVZD\*RRJOH0DSVLVDQDSSOLFDWLRQXQWR
LWVHOIDQGWKHUH¦VQRZD\IRU\RXWRFKDQJHDQ\WKLQJDERXWWKHXVHULQWHUIDFHRUDGG
RYHUOD\JUDSKLFVWRWKHPDSWRSRLQWRXWZKDWHYHULVRILQWHUHVWWR\RXUXVHUV$QGURLG
SURYLGHVPRUHIOH[LEOHSDFNDJHVWRDGGWKDWSRZHU
The MapView and MapActivity
&KDSWHU¦V0-$QGURLGVDPSOHDSSOLFDWLRQQHHGVWRDGGRYHUOD\VWKDWVKRZWKHOR
FDWLRQVIRUMREVLQWKHDUHD6RLQVWHDGRIXVLQJWKH*RRJOH0DSVDSSOLFDWLRQZHZLOO
XVHDMapViewZKLFKZHFDQRYHUOD\ZLWKJUDSKLFVDVQHHGHG<RXFDQKDYHRQO\RQH
MapViewSHUActivityDQGWKDWDFWLYLW\KDVWRH[WHQGMapActivity$V\RX¦OOVHHWKDW¦V
DVPDOOSULFHWRSD\IRUWKHSRZHUIXOJHRJUDSKLFIXQFWLRQVWKDW MapViewDGGVWR\RXU
DSSOLFDWLRQ
7KHUHDUHDFRXSOHRIXQLTXHSUHUHTXLVLWHVIRUXVLQJMapViewVDQGZHWRXFKHGRQERWK
RIWKHPZKHQZHORRNHGDWWKHLQLWLDOL]DWLRQRI0-$QGURLGLQ&KDSWHU
,QFOXGHWKHMapViewVOLEUDU\
7KHMapViewLVQRWLQFOXGHGLQWKHGHIDXOW$QGURLGOLEUDULHV,QVWHDG\RXQHHGWR
VSHFLI\LQ$QGURLG0DQLIHVW[POWKDW\RXDUHXVLQJWKLVDGGLWLRQDOOLEUDU\
<application android:icon="@drawable/icon2">
<uses-library android:name="com.google.android.maps" />
<RXFDQ¦WSXWWKHuses-libraryOLQHMXVWDQ\ZKHUHLQ$QGURLG0DQLIHVW[POLWQHHGV
WREHZLWKLQWKHapplication!WDJDQGRXWVLGHWKHactivity!WDJGHILQLWLRQV
6LJQ\RXUDSSOLFDWLRQDQGREWDLQD0DSV$3,NH\IURP*RRJOH
:KHQ\RXXVHD MapViewLQ\RXUDSSOLFDWLRQ\RXDUHXVLQJDFWXDO*RRJOH0DSV
GDWDWRGUDZWKHPDS)RUOHJDOUHDVRQV*RRJOHQHHGVWRWUDFNZKRLVXVLQJLWV
PDSGDWD*RRJOHGRHVQ¦WFDUHZKDW\RXUDSSOLFDWLRQGRHVZLWKWKHGDWDEXW\RX
QHHGWRUHJLVWHUZLWK*RRJOHIRUDQ$3,NH\DQGDJUHHWRDSSURSULDWH7HUPVRI
6HUYLFH7KLVWHOOV*RRJOH\RXUDSSOLFDWLRQLVXVLQJPDSSLQJGDWDDQGZKHWKHU\RX
DUHDOVRXVLQJWKHURXWLQJGDWDWKDWLVDYDLODEOHIURP*RRJOH0DSV£$SSOLFDWLRQ
6LJQLQJ¤RQSDJHFRYHUHGWKHSURFHVVHVRIVLJQLQJ\RXUDSSOLFDWLRQDQGJHWWLQJ
DQ$3,NH\
5HPHPEHUWKDWSURJUDPVXVLQJD MapViewPXVWEHVLJQHG7RPDNHLW
HDV\IRU\RXWRWU\RXWWKH0-$QGURLGH[DPSOHIURPWKLVERRNZH¦YH
LQFOXGHGDQDSNILOHDVGHVFULEHGLQ£$SSOLFDWLRQ6LJQLQJ¤RQSDJH
,I\RXFKDQJHWKHFRGHRUGRDQ\FRGLQJRI\RXURZQJHW\RXURZQNH\
ZKLFKLVDOVRGHVFULEHGLQ£$SSOLFDWLRQ6LJQLQJ¤RQSDJH
374 | Chapter 15:ಗLocation and Mapping
Working with MapViews
7KHMapViewHQFDSVXODWHVDORWRIYHU\FRPSOH[PDSSLQJVRIWZDUHDQGLVDYDLODEOHIRU
\RXWRXVHLQ\RXU$QGURLGDSSOLFDWLRQV¢IRUIUHH+HUHDUHVRPHRIWKHWKLQJV\RXFDQ
GRZLWKDMapViewZLWKRQO\DOLWWOHSURJUDPPLQJRQ\RXUSDUW
‡ 6KRZDVWUHHWPDSRIDQ\DUHDLQWKHZRUOGZLWKXSWRGDWHPDSSLQJLQIRUPDWLRQ
FRXUWHV\RI*RRJOH
‡ &KDQJHWKHPDSYLHZWRVKRZ
6WUHHWYLHZ
3KRWRJUDSKVWDNHQDWVWUHHWOHYHOIRUPDQ\DUHDVLQ1RUWK$PHULFD
6DWHOOLWHYLHZ
$QDHULDOSKRWRJUDSKLFYLHZRIWKHDUHD
7UDIILFYLHZ
5HDOWLPHWUDIILFLQIRUPDWLRQVXSHULPSRVHGRQWKHPDSRUVDWHOOLWHYLHZV
‡ 0RYHWKHPDSXQGHUSURJUDPFRQWURO
‡ 3ORW\RXURZQJUDSKLFVLQRYHUOD\VRQWRSRIWKHPDS
‡ 5HVSRQGWRXVHUWRXFKHYHQWVRQWKHPDS
MapView and MyLocationOverlay Initialization
7KHPDSLQ0LFUR-REVKDVWZRPRGHV
‡ $WVWDUWXSDQGZKHQZHVHOHFW&XUUHQW/RFDWLRQIURPWKH6SLQQHUZHZDQWWR
GLVSOD\DPDSRIRXUFXUUHQWORFDWLRQDQGZHZDQWWKDWPDSWRWUDFNXVDVZHPRYH
DURXQG)RUWKLVPDSZHZLOOXVHWKHMyLocationOverlayFODVV
‡ :KHQZHVHOHFWDVSHFLILFORFDWLRQIURPWKH6SLQQHUZHZDQWWRGLVSOD\DPDSRI
WKDWORFDWLRQWXUQRIIORFDWLRQXSGDWHVDQGQRWWUDFNPRYHPHQW
/HW¦V ORRN DW WKH FRGH LQ 0LFUR-REVMDYD WKDW LQLWLDOL]HV WKH MapView DQG WKH My
LocationOverlayWKDWWUDFNVRXUFXUUHQWORFDWLRQ
@Override
public void onCreate(Bundle savedInstanceState) {
...
mvMap = (MapView) findViewById(R.id.mapmain);
// get the map controller
final MapController mc = mvMap.getController();
mMyLocationOverlay = new MyLocationOverlay(this, mvMap);
mMyLocationOverlay.runOnFirstFix(
new Runnable() {
public void run() {
MapView and MyLocationOverlay Initialization | 375
}
mc.animateTo(mMyLocationOverlay.getMyLocation());
mc.setZoom(16);
});
Drawable marker = getResources().getDrawable(R.drawable.android_tiny_image);
marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
mvMap.getOverlays().add(new MJJobsOverlay(marker));
mvMap.setClickable(true);
mvMap.setEnabled(true);
mvMap.setSatellite(false);
mvMap.setTraffic(false);
mvMap.setStreetView(false);
// start out with a general zoom
mc.setZoom(16);
...
/**
* Required method to indicate whether we display routes
*/
@Override
protected boolean isRouteDisplayed() { return false; }
+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
:HILUVWILQGWKHMapViewLQWKHPDLQ[POOD\RXWILOHWKHVDPHZD\ZHILQGDQ\RWKHU
YLHZDQGDVVLJQLWWRWKHYDULDEOH mvMapRIW\SH MapViewVRWKDWZHFDQUHIHUWRLW
ZKHQZHQHHGWR
:HDOVRJHWDKDQGOHRQWKHMapControllerDVVRFLDWHGZLWKMapView:H¦OOXVHWKDW
WRSDQ DQLPDWH WKHPDS]RRPLQ]RRPRXWFKDQJHYLHZVDQGVRRQ
7RXVH MyLocationOverlayZHFUHDWHDQHZLQVWDQFHJLYLQJLWWKHKLJKO\FUHDWLYH
QDPHmMyLocationOverlay
7KHILUVWWKLQJZHGRZLWKmMyLocationOverlayLVGHILQHDPHWKRGWKDW$QGURLGZLOO
FDOOZKHQZHUHFHLYHRXUILUVWORFDWLRQIL[IURPWKHORFDWLRQSURYLGHU
7KLV runOnFirstFix PHWKRG PRYHV WKH PDS WR WKH FXUUHQW ORFDWLRQ JLYHQ E\
mMyLocationOverlay.getMyLocation() DQG]RRPVWRDUHDVRQDEOHOHYHOIRUXVWRVHH
QHDUE\MRESURVSHFWV
1H[WZHLGHQWLI\DPDUNHUWKDWZH¦YHGHFLGHGWRXVHRQmMyLocationOverlayWRPDUN
DYDLODEOHMREV:HXVHDQLPDJHWKDW¦VVWRUHGLQRXUUHVGUDZDEOHGLUHFWRU\FDOOHG
DQGURLGBWLQ\BLPDJH,W¦VDSLFWXUHRIDOLWWOH$QGURLGURERW:HGHILQHWKHERXQGV
RIWKH DrawableDQGDGGWKHPDUNHURYHUOD\WRWKHOLVWRIRYHUOD\VIRUWKH MapView
mvMap
1RZZH¦GOLNHWRVHWVRPHLQLWLDODWWULEXWHVIRUmvMapGHVFULEHGODWHULQWKLVVHFWLRQ
:H¦OODOORZWKHXVHUWRFKDQJHPRVWRIWKHVHWKURXJKPHQXEXWWRQV
376 | Chapter 15:ಗLocation and Mapping
7KHQIROORZLQJDEHOWDQGVXVSHQGHUVSKLORVRSK\MXVWLQFDVHWKHUHLVQ¦WDORFDWLRQ
SURYLGHUWRWULJJHUrunOnFirstFixZH¦OOVHWWKH]RRPOHYHODJDLQKHUH
)LQDOO\MapViewUHTXLUHVXVWRRYHUULGHWKHisRouteDisplayed()PHWKRGWRLQGLFDWH
ZKHWKHUZHDUHGLVSOD\LQJURXWHLQIRUPDWLRQRQRXUPDS:HDUHQRWVRZHUHWXUQ
false
MyLocationOverlayHQFDSVXODWHVDZHDOWKRIORFDWLRQDQGPDSSLQJFRGH,QRXUVLQJOH
FDOOWRWKHFRQVWUXFWRUZH
‡ $VN$QGURLGWRILJXUHRXWZKDWORFDWLRQSURYLGHUVDUHDYDLODEOHLQRXUHQYLURQPHQW
*36&HOO,'WULDQJXODWLRQ ‡ &RQQHFWWRWKH£EHVW¤RIWKRVHORFDWLRQSURYLGHUV
‡ $VN WKH ORFDWLRQ SURYLGHU WR SURYLGH XV ZLWK SHULRGLF ORFDWLRQ XSGDWHV DV RXU
KDQGVHWPRYHV
‡ /LQN WR URXWLQHV WKDW ZLOO DXWRPDWLFDOO\ PRYH RXU PDS DV QHHGHG WR WUDFN DQ\
FKDQJHVLQORFDWLRQ
MyLocationOverlayDOVRDOORZVXVWRSODFHDFRPSDVVURVHRQWKHMapViewDQGKDYHWKDW
XSGDWHGDVZHOOEXWZHZRQ¦WEHXVLQJWKDWLQ0-$QGURLG
7KHPDSDWWULEXWHVVHWE\WKHFRGHDUH
setClickable
:HZDQWXVHUVWREHDEOHWRWDSRQDMREWRFDXVH0-$QGURLGWRGLVSOD\PRUHGHWDLO
DERXWWKDWMREVRZHVHWWKLVWRtrue
setEnabled
7KLVPHWKRGLVDFWXDOO\LQKHULWHGIURPandroid.view.View*RRJOHGRHVQ¦WWHOOXV
H[DFWO\ZKDWWKLVPHDQVLQWKHFDVHRID MapViewEXWSUHVXPDEO\LWHQDEOHVWKH
VWDQGDUGPDSIXQFWLRQV¢]RRPLQJSDQQLQJDQGVRRQ
setSatellite
6HWWLQJWKLVIODJDGGVDVDWHOOLWHYLHZIURPWKHFRPSRVLWHPDSZKHUHDVFOHDULQJWKH
IODJUHPRYHVWKHYLHZ7RVWDUWZLWKZHGRQ¦WZDQWWKHVDWHOOLWHLQIRUPDWLRQRQ
WKHPDS
setTraffic
6LPLODUO\VHWWLQJRUFOHDULQJWKLVIODJDGGVRUUHPRYHVFXUUHQWWUDIILFLQIRUPDWLRQ
IURPWKHPDSUHVSHFWLYHO\$JDLQZHGRQ¦WZDQWWRVWDUWZLWKWUDIILFLQIRUPDWLRQ
RQWKHPDS
setStreetView
:HGRQ¦WZDQWVWUHHWYLHZVULJKWQRZHLWKHUDOWKRXJKZH¦OOOHWWKHXVHUHQDEOH
WKHPODWHU
MapView and MyLocationOverlay Initialization | 377
Zooming in Android Maps
$QGURLGPDSVFRPHHTXLSSHGZLWKVXSSRUWIRU]RRPLQJLQDQGRXW7KH£L¤NH\]RRPV
LQRQWKHPDSZKHUHDVWKH£R¤NH\]RRPVRXW0DSVFDQDOVR]RRPLQDQGRXWXQGHU
SURJUDPFRQWUROWKURXJKWKHMapController
6HYHUDOPHWKRGVDUHGHILQHGIRU]RRPLQJDOOXVLQJWKHMapController$QGURLGGHILQHV
]RRPOHYHOVIRUPDSV$W]RRPOHYHOWKHHTXDWRURIWKH(DUWKLVSL[HOVORQJ
(YHU\VWHSXSLQ]RRPOHYHOPXOWLSOLHVWKDWE\*RRJOHZDUQVWKDWWKHKLJKHUUHVROXWLRQ
PDSVDUHQRWDYDLODEOHZRUOGZLGH$OOWKH]RRPPHWKRGVFODPSWKH]RRPOHYHOWRWKH
UDQJHWKURXJKLI\RXDVNLWWRJREH\RQGWKRVHOLPLWV
7KHPHWKRGVWKDWFRQWURO]RRPDORQJZLWKWKHLUSDUDPHWHUVDUH
zoomIn
=RRPVLQRQHOHYHO
zoomOut
=RRPVRXWRQHOHYHO
setZoom(int zoomlevel)
=RRPVWRWKHJLYHQOHYHOUHVWULFWLQJLWWRWKHUDQJHWR
zoomInFixing(int xpixel, int ypixel), zoomOutFixing(int xpixel, int ypixel)
=RRPLQRQHOHYHOEXWNHHSWKHJLYHQSRLQWIL[HGRQWKHVFUHHQ1RUPDOO\ZKHQ
\RX]RRPLQDQGRXWWKHFHQWHURIWKHVFUHHQLVWKHRQO\SRLQWWKDWVWD\VIL[HG
7KHVHURXWLQHVOHW\RXSLFNDQ\SRLQWRQWKHPDSWREHWKHIL[HGSRLQW
zoomToSpan(int latSpanE6, int longSpanE6)
$WWHPSWVWR]RRPVRWKDWWKHJLYHQVSDQLVGLVSOD\HGRQWKHPDS:KDWLWDFWXDOO\
GRHVLVVHOHFWWKH]RRPOHYHOWKDWLVWKHFORVHVWPDWFKIRUWKHVSDQUHTXHVWHG7KH
ODWLWXGH DQG ORQJLWXGH VSDQ SDUDPHWHUV DUH H[SUHVVHG DV LQWHJHUV ZLWK D YDOXH
WLPHVWKHDFWXDOYDOXHLQGHJUHHV)RULQVWDQFHDODWLWXGHORQJLWXGHVSDQRI
GHJUHHVE\GHJUHHVZRXOGEHH[SUHVVHGDVzoomToSpan(2500000, 1000000)
Pausing and Resuming a MapActivity
)RUDPLQXWHOHW¦VIRFXVRQPDSDFWLYLWLHVDQGQRWHDZD\ZHFDQKHOSVDYHEDWWHU\
SRZHU7KHJRRGQHZVLVWKDW$QGURLGPDNHVWKLVSUHWW\HDV\
,QDPRELOHHQYLURQPHQWEDWWHU\OLIHLVHYHU\WKLQJDQGLIZH¦UHQRWWKHDSSOLFDWLRQWKDW
LVFXUUHQWO\EHLQJGLVSOD\HGZHZDQWWRGRHYHU\WKLQJZHFDQWRPLQLPL]HWKHSRZHU
ZHFRQVXPH5HFDOOIURPWKHGLVFXVVLRQRIWKH$QGURLGOLIHF\FOH £9LVXDOL]LQJ/LIH
&\FOHV¤ RQ SDJH WKDW ZKHQ DQ Activity VXFK DV 0LFUR-REV VWDUWV DQRWKHU
Activity VXFKDV0LFUR-REV/LVW WKHQHZActivityWDNHVRYHUWKHVFUHHQDQGWKHFDOO
LQJActivityJHWVSXVKHGRQWRDVWDFNRIDFWLYLWLHVWKDWDUHZDLWLQJWRUXQ$WWKDWWLPH
$QGURLGFDOOVWKHonPauseURXWLQHLQWKHFDOOLQJActivityVRWKDWLWFDQSUHSDUHLWVHOIWR
JRLQWRKLEHUQDWLRQ$WWKLVSRLQWLQ0LFUR-REVMDYD RUMXVWDERXWDQ\MapActivityWKDW
XVHVORFDWLRQXSGDWHV ZHZDQWWRWXUQRIIORFDWLRQXSGDWHV'RLQJVRZLOODWOHDVWVDYH
378 | Chapter 15:ಗLocation and Mapping
WKHF\FOHVGHYRWHGWRGRLQJWKHXSGDWHDQGPD\DOORZWKHKDQGVHWWRVDYHHYHQPRUH
SRZHUE\SXWWLQJWKHORFDWLRQSURYLGHULQDTXLHVFHQWVWDWHWKDWXVHVOHVVSRZHU
:KHQWKHFDOOHGActivity LQRXUFDVH0LFUR-REV/LVW H[LWVDQGWKHFDOOLQJActivityLV
SRSSHGRIIWKHVWDFNDQGWDNHVFRQWURORIWKHVFUHHQWKHIUDPHZRUNFDOOVWKHonResume
PHWKRGLQWKHFDOOLQJActivity,QDMapActivityZHZDQWWRWXUQRQORFDWLRQXSGDWHV
DJDLQZKHQWKLVPHWKRGLVLQYRNHG
,Q0LFUR-REVWKHonPauseDQGonResumePHWKRGVDUHVWUDLJKWIRUZDUG
/**
* @see com.google.android.maps.MapActivity#onPause()
*/
@Override
public void onPause() {
super.onPause();
mMyLocationOverlay.disableMyLocation();
}
/**
* @see com.google.android.maps.MapActivity#onResume()
*/
@Override
public void onResume() {
super.onResume();
mMyLocationOverlay.enableMyLocation();
}
1RWHWKDWLIZH¦GKDGDFRPSDVVURVHDVSDUWRIRXUMyLocationOverlayZHZRXOGKDYH
WRGLVDEOHDQGHQDEOHLWDVZHOO2WKHUZLVHWKHV\VWHPZRXOGEHZDVWLQJF\FOHVDQG
EDWWHU\ XSGDWLQJ WKH GLUHFWLRQ RI WKH FRPSDVV URVH HYHQ WKRXJK LW ZDVQ¦W YLVLEOH
RQVFUHHQ
Controlling the Map with Menu Buttons
:HZDQWWRJLYHWKHXVHUWKHDELOLW\WRWXUQRQVDWHOOLWHWUDIILFDQGVWUHHWYLHZVRIWKH
PDS,QDGGLWLRQZH¦OOWKURZLQDIHZPHQXEXWWRQVWRHQDEOH]RRPLQJDQGDQRWKHU
ZD\WRJHWWRWKH-REVOLVW
$QGURLGKDVDVRSKLVWLFDWHGVHWRIPHQXFDSDELOLWLHVWKDWLQFOXGHVWKUHHW\SHVRIPHQXV
RSWLRQVFRQWH[WDQGVXEPHQXV HDFKZLWKLWVRZQFDSDELOLWLHVLFRQPHQXEXWWRQV
DQGRWKHUDGYDQFHGIHDWXUHV:HMXVWXVHWH[WEDVHGPHQXEXWWRQV:HQHHGWRGRWZR
WKLQJV
&UHDWHWKHPHQXRIEXWWRQVWKDWZLOOEHGLVSOD\HG
&DWFKWKHPHQXHYHQWVDQGLQYRNHDSSURSULDWHDFWLRQV
7KHIROORZLQJFRGHFUHDWHVWKHPHQXLQ0LFUR-REVMDYD
/**
* Set up menus for this page
*
Controlling the Map with Menu Buttons | 379
Download from Wow! eBook <www.wowebook.com>
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean supRetVal = super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, 0, Menu.NONE, getString(R.string.map_menu_zoom_in));
menu.add(Menu.NONE, 1, Menu.NONE, getString(R.string.map_menu_zoom_out));
menu.add(Menu.NONE, 2, Menu.NONE, getString(R.string.map_menu_set_satellite));
menu.add(Menu.NONE, 3, Menu.NONE, getString(R.string.map_menu_set_map));
menu.add(Menu.NONE, 4, Menu.NONE, getString(R.string.map_menu_set_traffic));
menu.add(Menu.NONE, 5, Menu.NONE, getString(R.string.map_menu_show_list));
return supRetVal;
}
:HFUHDWHPHQXEXWWRQVE\RYHUULGLQJWKHonCreateOptionsMenuPHWKRGZKHUHZHDUH
SDVVHGDPHQXSDUDPHWHUIRUWKHActivity¦VPHQX$IWHUGXWLIXOO\DOORZLQJWKHVXSHU
FODVVDFKDQFHWRGRZKDWLWQHHGVWRGRZHVLPSO\DGGLWHPV EXWWRQV WRWKHPHQX
XVLQJmenu.add7KHYHUVLRQRImenu.addWKDWZH¦YHFKRVHQWDNHVIRXUSDUDPHWHUV
int groupid
$QGURLGDOORZV\RXWRJURXSPHQXLWHPVVRWKDW\RXFDQTXLFNO\FKDQJHWKHZKROH
PHQXDWRQFH:HGRQ¦WKDYHDQHHGIRUWKDWLQ0LFUR-REVVR Menu.NONEVD\VZH
GRQ¦WQHHGLW
int itemid
:HQHHGDXQLTXHLGHQWLILHUIRUWKLVPHQXLWHPVRWKDWZHFDQWHOOODWHUZKHWKHULW
ZDVSLFNHG
int order
7KHitemidZHGHILQHGLQWKHVHFRQGSDUDPHWHUGRHVQRWLPSO\RUGHU,IZHFDUHG
DERXWWKHRUGHULQZKLFKWKHLWHPVZHUHSUHVHQWHGZH¦GGRWKDWZLWKWKLVSDUDP
HWHU6LQFHZHGRQ¦WFDUHZHXVHMenu.NONEDJDLQ
int titleRes
7KLVLVWKH,'RIWKHVWULQJUHVRXUFHZHZDQWWRXVHIRUWKHEXWWRQWLWOH1RWHWKDW
WKLV LV DQ Integer QRW D String VR WKH PHQX VWULQJV QHHG WR EH SUHGHILQHG LQ
VWULQJ[POXQGHUWKHUHVGLUHFWRU\5HFDOOWKDW$QGURLGWDNHVFDUHRIFRPSLOLQJWKH
VWULQJVLQUHVVWULQJV[POLQWRDMDYDILOH 5MDYD WKDWDVVLJQVDQLQWHJHUWRHDFK
VWULQJ7KHgetStringPHWKRGUHWULHYHVWKDWLQWHJHUIRU\RX GHVSLWHWKHQDPHWKH
PHWKRGUHWXUQVDQLQWHJHUDQGQRWDVWULQJ 7RFDWFKWKHPHQXHYHQWVZHRYHUULGHWKHonOptionsItemSelectedPHWKRG
/**
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
// Zoom in
zoomIn();
return true;
380 | Chapter 15:ಗLocation and Mapping
case 1:
// Zoom out
zoomOut();
return true;
case 2:
// Toggle satellite views
mvMap.setSatellite(!mvMap.isSatellite());
return true;
case 3:
// Toggle street views
mvMap.setStreetView(!mvMap.isStreetView());
return true;
case 4:
// Toggle traffic views
mvMap.setTraffic(!mvMap.isTraffic());
return true;
case 5:
// Show the job list activity
startActivity(new Intent(MicroJobs.this, MicroJobsList.class));
return true;
}
}
return false;
:H XVH WKH MenuItem SDUDPHWHU DQG WKH VZLWFK KDV D FDVH IRU HDFK EXWWRQ WKDW ZH
GHILQHGIRUWKHPHQX:H¦YHDOUHDG\VHHQFRGHVLPLODUWRWKDWFRQWDLQHGLQHDFKFDVH
Controlling the Map with the Keypad
6RPHXVHUVPLJKWSUHIHUWRFRQWUROWKHPDSWKURXJKWKHNH\SDG JHQHUDOO\RQH£FOLFN¤
YHUVXVWZR£FOLFNV¤WRFDXVHDPHQXHYHQW (QDEOLQJWKLVEHKDYLRUDOVRGHPRQVWUDWHV
KRZWRUHVSRQGWR KeyPadHYHQWVLQJHQHUDOVRZH¦YHDGGHGVRPHFRGHWR]RRPLQ
]RRPRXWDQGEDFNRXWRIWKHFXUUHQWDFWLYLW\
/**
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP: // zoom in
zoomIn();
return true;
case KeyEvent.KEYCODE_DPAD_DOWN: // zoom out
zoomOut();
return true;
case KeyEvent.KEYCODE_BACK: // go back (meaning exit the app)
finish();
return true;
default:
return false;
}
}
Controlling the Map with the Keypad | 381
7RFDWFKNH\GRZQHYHQWVZHVLPSO\RYHUULGHonKeyDownDQGSURYLGHDVZLWFKIRUWKH
GLIIHUHQW NH\V WKDW DUH RI LQWHUHVW ,Q DGGLWLRQ WR WKH NH\FRGHV \RX ZRXOG H[SHFW
KEYCODE_A KEYCODE_Z DQG WKLQJV OLNH KEYCODE_SPACE KEYCODE_SHIFT_LEFT DQG
KEYCODE_SHIFT_RIGHT $QGURLGLQFOXGHVNH\FRGHVWKDWPD\RUPD\QRWDSSHDURQDQ\
SDUWLFXODUGHYLFH KEYCODE_CAMERADQGKEYCODE_VOLUME_UP $FRPSOHWHVHWRINH\FRGHV
FDQEHIRXQGDWKWWSFRGHJRRJOHFRPDQGURLGUHIHUHQFHDQGURLGYLHZ.H\(YHQWKWPO
Location Without Maps
:KDW LI \RXU DFWLYLW\ QHHGV WR DFFHVV ORFDWLRQ LQIRUPDWLRQ EXW LW GRHVQ¦W LQFOXGH D
MapView" :KHQ \RX XVH D MapView $QGURLG PDNHV HYHU\WKLQJ YHU\ HDV\ ZLWK My
LocationOverlay EXW LI \RX GRQ¦W QHHG D PDS LW VWLOO LVQ¦W WKDW KDUG WR JHW ORFDWLRQ
LQIRUPDWLRQ7KHFRGHLQWKLVVHFWLRQLVQRWSDUWRI0-$QGURLGEXWLWVKRZVKRZ\RX
REWDLQORFDWLRQLQIRUPDWLRQLQGHSHQGHQWRIMapView
/HW¦VORRNDWDYHU\VLPSOHRQHDFWLYLW\DSSOLFDWLRQWKDWGLVSOD\VWKHFXUUHQWORFDWLRQ
LQDTextView
The Manifest and Layout Files
$QDSSURSULDWH$QGURLG0DQLIHVW[POILOHIROORZV:HFUHDWHGWKLVILOHXVLQJWKH$QGURLG
6'.DQGWKH$QGURLG0DQLIHVW(GLWRUWKDWFRPHVDVSDUWRILW7KHRQO\FKDQJHZH
QHHGHG WR PDNH ZLWK WKH HGLWRU ZDV WR DGG WKH uses-permission WDJ IRU android
.permission.ACCESS_FINE_LOCATION LQWKHQH[WWRODVWOLQHRIWKHILOH :HDOZD\VQHHG
WKLVSHUPLVVLRQLQRUGHUWRJHWORFDWLRQLQIRUPDWLRQIURPD*36ORFDWLRQSURYLGHU
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.microjobsinc.dloc"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
</uses-permission>
</manifest>
:H¦OOXVHDYHU\VLPSOHOD\RXWILOHZLWKIRXUTextViewVRQHODEHODQGRQHWH[WER[HDFK
IRUODWLWXGHDQGORQJLWXGH
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
382 | Chapter 15:ಗLocation and Mapping
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/lblLatitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Latitude:"
/>
<TextView
android:id="@+id/tvLatitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/lblLongitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Longitude:"
/>
<TextView
android:id="@+id/tvLongitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Connecting to a Location Provider and Getting Location Updates
/HW¦VVWDUWZLWKDQDFWLYLW\WKDWMXVWFRQQHFWVZLWKWKH*36LocationProviderDQGJHWV
DQGGLVSOD\VRXUFXUUHQWORFDWLRQ QRXSGDWHV package com.oreilly.demo.pa.microJobs;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the TextViews
TextView tvLatitude = (TextView)findViewById(R.id.tvLatitude);
TextView tvLongitude = (TextView)findViewById(R.id.tvLongitude);
// get handle for LocationManager
LocationManager lm = (LocationManager)
Location Without Maps | 383
getSystemService(Context.LOCATION_SERVICE);
// connect to the GPS location service
Location loc = lm.getLastKnownLocation("gps");
// fill in the TextViews
tvLatitude.setText(Double.toString(loc.getLatitude()));
tvLongitude.setText(Double.toString(loc.getLongitude()));
}
}
7KHSURFHGXUHLVSUHWW\VWUDLJKWIRUZDUG+HUHDUHVRPHRIWKHKLJKOLJKWVRIWKHFRGH
&RQQHFWV WR WKH LocationManager XVLQJ getSystemService(Context.LOCATION_
SERVICE)
$VNVWKHLocationManagerZKHUHZHDUHXVLQJgetLastKnownLocation("provider")
*HWVWKHODWLWXGHDQGORQJLWXGHIURPWKHLocationUHWXUQHGDQGXVHVLWDVQHHGHG
%XWZHDOVRZDQWWRJHWSHULRGLFORFDWLRQXSGDWHVIURPWKHLocationManagerVRWKDWZH
FDQWUDFNRXUORFDWLRQDVZHPRYHDERXW)RUWKDWZHQHHGWRDGGDOLVWHQHUURXWLQHDQG
DVNWKHLocationManagerWRFDOOLWZKHQLWKDVDQXSGDWH
/RFDWLRQXSGDWHVIURPWKHLocationManagerDUHDFFHVVLEOHWRDQDSSOLFDWLRQWKURXJKD
DispLocListenerFODVVVRZHZLOOFUHDWHDQLQVWDQFHRIWKLVFODVVLQWKHonCreatePHWKRG
RI RXU PDLQ DFWLYLW\ :H DUH UHTXLUHG WR RYHUULGH D QXPEHU RI PHWKRGV LQ DispLoc
ListenerWRPHHWWKHLocationListenerLQWHUIDFHGHILQLWLRQEXWZHGRQ¦WQHHGWKHPIRU
WKLVDSSOLFDWLRQVRZH¦OOOHDYHWKHGHILQLWLRQVHPSW\7KHIXOOLPSOHPHQWDWLRQIROORZV
package com.oreilly.demo.pa.MicroJobs;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
private LocationManager lm;
private LocationListener locListenD;
public TextView tvLatitude;
public TextView tvLongitude;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the TextViews
tvLatitude = (TextView)findViewById(R.id.tvLatitude);
tvLongitude = (TextView)findViewById(R.id.tvLongitude);
384 | Chapter 15:ಗLocation and Mapping
// get handle for LocationManager
LocationManager lm =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
// connect to the GPS location service
Location loc = lm.getLastKnownLocation("gps");
// fill in the TextViews
tvLatitude.setText(Double.toString(loc.getLatitude()));
tvLongitude.setText(Double.toString(loc.getLongitude()));
// ask the Location Manager to send us location updates
locListenD = new DispLocListener();
lm.requestLocationUpdates("gps", 30000L, 10.0f, locListenD);
}
private class DispLocListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
// update TextViews
tvLatitude.setText(Double.toString(location.getLatitude()));
tvLongitude.setText(Double.toString(location.getLongitude()));
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}
2XU onCreate PHWKRG FUHDWHV DQ LQVWDQFH RI DispLocListener DQG UHTXHVWV WKDW WKH
LocationManagerXSGDWHLWDVQHHGHGXVLQJrequestLocationUpdates7KLVPHWKRGWDNHV
IRXUSDUDPHWHUV
String provider
:KLFKORFDWLRQSURYLGHUWRXVH:HDVVXPH*36LVDYDLODEOHLQWKLVFDVH
long minTime
0LQLPXPXSGDWHWLPHLQPLOOLVHFRQGV7KHLocationManagerZLOOZDLWDWOHDVWWKLV
ORQJEHWZHHQXSGDWHV+HUH¦VDQRSSRUWXQLW\WRWXQH\RXUDSSOLFDWLRQIRUEDWWHU\
OLIHPRUHIUHTXHQWXSGDWHVPHDQPRUHEDWWHU\XVDJH
Location Without Maps | 385
float minDistance
0LQLPXP GLVWDQFH LQ PHWHUV UHTXLUHG WR WULJJHU DQ XSGDWH 7KH Location
ManagerZLOOXSGDWHXVRQO\LIZH¦YHPRYHGDWOHDVWWKLVIDUVLQFHWKHODVWXSGDWH
LocationListener listener
7KH QDPH RI WKH OLVWHQHU PHWKRG WR FDOO ZKHQ WKHUH LV DQ XSGDWH 7KLV LV WKH
DispLocListenerLQVWDQFHZHMXVWFUHDWHG
)LQDOO\ZHZDQWWRDGGWKH onPauseDQG onResumeFRGHWRWXUQORFDWLRQXSGDWHVRII
ZKHQZH¦UHQRWDFWXDOO\GLVSOD\LQJRQWKHXVHU¦VVFUHHQDQGWXUQWKHPEDFNRQZKHQ
ZHDUH
/**
* Turn off location updates if we're paused
*/
@Override
public void onPause() {
super.onPause();
lm.removeUpdates(locListenD);
}
/**
* Resume location updates when we're resumed
*/
@Override
public void onResume() {
super.onResume();
lm.requestLocationUpdates("gps", 30000L, 10.0f, locListenD);
}
Updating the Emulated Location
:KLOHGHYHORSLQJDQGGHEXJJLQJDQDSSOLFDWLRQOLNHWKHRQHVKRZQLQWKHSUHFHGLQJ
VHFWLRQ\RX¦UHQRUPDOO\UXQQLQJRQWKHHPXODWRU,WZRXOGEHQLFH PD\EHHYHQHV
VHQWLDO WREHDEOHWRXSGDWHWKHFXUUHQWORFDWLRQWKDWWKHHPXODWRUXVHVDVLW¦VUXQQLQJ
\RXUFRGH6XFKDPRFNORFDWLRQSURYLGHUFDQJHWYHU\IDQF\EXW$QGURLGSURYLGHV
VRPHEXLOWLQZD\VRIXSGDWLQJWKHHPXODWHGORFDWLRQ
‡ 7KHJHRSURJUDPEXLOWLQWRWKH$QGURLGVKHOO
‡ 2QHWLPHXSGDWHVYLD''06
‡ 7UDFNVWKDWDUHVHTXHQWLDOO\XSGDWHGYLD''06
:H¦OOORRNDWHDFKRIWKHVH
Using geo to update location
7KHJHRXWLOLW\LVEXLOWLQWRWKH$QGURLGLPDJHWKDWUXQVRQWKHHPXODWRU,WKDVDQXPEHU
RIFDSDELOLWLHVWZRRIZKLFKDUHXVHIXOKHUH
386 | Chapter 15:ಗLocation and Mapping
geo fix
<RXFDQXVHWKH geo fixFRPPDQGWRVHQGDORFDWLRQWR$QGURLGE\WHOQHWLQJWR
WKHFRQVROHRIWKHHPXODWHG$QGURLG7KH LocationProviderZLOOWKHQXVHWKLVDV
WKHFXUUHQWORFDWLRQ
telnet localhost 5554
Android Console: type 'help' for a list of commands
OK
geo fix -122.842232 38.411908 0
OK
geo fixWDNHVWKUHHSDUDPHWHUV
longitude
6SHFLILHGLQGHFLPDO
latitude
$OVRVSHFLILHGLQGHFLPDO
altitude
6SHFLILHGLQPHWHUV
Using DDMS to update location
,Q&KDSWHUZHGLVFXVVHGWKH'DOYLN'HEXJ0RQLWRU6HUYLFH ''06 +HUHZHZLOO
GLVFXVVWZRIHDWXUHVRIWKLVWRROUHODWHGWRORFDWLRQXSGDWHV7KH(PXODWRU&RQWUROSDQH
RIWKH''06VFUHHQSURYLGHVVHYHUDOZD\VRIFRQWUROOLQJWKHUXQQLQJHPXODWRU$IWHU
VZLWFKLQJWRWKH''06SHUVSHFWLYH FOLFNRQ''06LQWKHXSSHUULJKWRIWKH(FOLSVH
ZLQGRZ \RXVKRXOGVHHWKH(PXODWRU&RQWUROSDQHLQWKHPLGGOHOHIWRIWKH''06
ZLQGRZ )LJXUH <RXZLOOSUREDEO\KDYHWRVFUROOGRZQLQWKDWSDQHWRVHHWKH
FRQWUROVUHODWHGWR/RFDWLRQ&RQWUROV
)LJXUH''06(PXODWRU&RQWUROSDQH
Location Without Maps | 387
7RVHQGDRQHWLPHXSGDWHRIDORFDWLRQWRWKHHPXODWRUMXVWHQWHUWKHORQJLWXGHDQG
ODWLWXGHLQWKHDSSURSULDWHER[HVDQGFOLFN6HQG
,I\RXFOLFNRQHLWKHUWKH*3;RU.0/WDE\RXZLOOEHDEOHWRORDGD*3;RU.0/ILOH
WKDW GHVFULEHV D SDWK DV VKRZQ LQ )LJXUH +HUH ZH¦YH DOUHDG\ ORDGHG WKH ILOH
25NPOZKLFKLVLQFOXGHGRQWKHZHEVLWHIRUWKLVERRN,WWUDFHVDSDWKQHDU2¦5HLOO\
KHDGTXDUWHUVLQ6HEDVWRSRO&DOLIRUQLD
)LJXUH''06HPXODWRUZLWK.0/ORFDWLRQXSGDWHV
<RXFDQFUHDWH*3;WUDFNVZLWKPDQ\*36QDYLJDWLRQVRIWZDUHWRROVDQG.0/WUDFNV
ZLWK*RRJOH(DUWKRUPDQ\RWKHUQDYLJDWLRQSURJUDPV7KH25NPOILOHZDVJHQHUDWHG
E\SORWWLQJDVHULHVRI*RRJOH(DUWKSODFHPDUNVDQGFRQFDWHQDWLQJWKHPWRJHWKHULQWR
DVLQJOHILOH+HUH¦VDQH[FHUSWRI25NPO
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>OR1.kml</name>
<StyleMap id="msn_ylw-pushpin">
<Pair>
<key>normal</key>
<styleUrl>#sn_ylw-pushpin</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#sh_ylw-pushpin</styleUrl>
</Pair>
</StyleMap>
<Style id="sh_ylw-pushpin">
<IconStyle>
<scale>1.3</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
</Icon>
388 | Chapter 15:ಗLocation and Mapping
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Style id="sn_ylw-pushpin">
<IconStyle>
<scale>1.1</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
</Icon>
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Placemark>
<name>OR1</name>
<LookAt>
<longitude>-122.7583711698369</longitude>
<latitude>38.38922415809942</latitude>
<altitude>0</altitude>
<range>14591.7166300043</range>
<tilt>0</tilt>
<heading>0.04087372005871314</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.8239277647483,38.40273084940345,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>OR2</name>
<LookAt>
<longitude>-122.7677364592949</longitude>
<latitude>38.3819544049429</latitude>
<altitude>0</altitude>
<range>11881.3330990845</range>
<tilt>0</tilt>
<heading>-8.006283077460853e-010</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.8064486052584,38.40786910573772,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>OR3</name>
<LookAt>
<longitude>-122.7677364592949</longitude>
<latitude>38.3819544049429</latitude>
<altitude>0</altitude>
<range>11881.3330990845</range>
Location Without Maps | 389
<tilt>0</tilt>
<heading>-8.006283077460853e-010</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.7911077944045,38.41500788727795,0</coordinates>
</Point>
</Placemark>
...
390 | Chapter 15:ಗLocation and Mapping
CHAPTER 16
Sensors, NFC, Speech, Gestures,
and Accessibility
7KDQNVWRDGYDQFHVLQWHFKQRORJ\ERWKWKHHQYLURQPHQWDQGWKHXVHUFDQLQWHUDFWZLWK
GHYLFHVLQDYDULHW\RIZD\VIURPH[WHUQDOVHQVRUVWKDWFDQGHWHFWZKHQDGHYLFHKDV
FKDQJHGRULHQWDWLRQZLWKLQDQHQYLURQPHQWWRWRXFKVFUHHQDGDSWDWLRQVWKDWHQDEOH
FRPSOH[ JHVWXUHV WR WULJJHU DQ HYHQW ZLWKLQ WKH GHYLFH $QGURLG SURYLGHV $3,V WKDW
HQDEOHWKHGHYHORSHUWRDFFHVVWKHVHVHQVRUVDQGWKHXVHUWRLQWHUDFWZLWKWKHVHGHYLFHV
LQDYDULHW\RIZD\V,QWKLVFKDSWHUZHZLOOH[SORUHVRPHRIWKHVH$3,V¢VHQVRUV1)&
1HDU)LHOG&RPPXQLFDWLRQ WKH*HVWXUHOLEUDULHVDQGDFFHVVLELOLW\
Sensors
7KHPRGHUQVPDUWSKRQHSURYLGHVPRUHWKDQMXVWWKHDELOLW\WRVHQGDQGUHFHLYHFRP
PXQLFDWLRQLQYDULRXVIRUPV7KHDGGLWLRQRIH[WHUQDOVHQVRUVWKDWFDQUHSRUWLQIRU
PDWLRQDERXWWKHHQYLURQPHQWWKHSKRQHLVLQKDVPDGHWKHSKRQHPRUHSRZHUIXODQG
XVHIXOIRUWKHXVHUDVZHOODVWKHGHYHORSHU6WDUWLQJZLWK$QGURLG $3,OHYHO D
VWDQGDUGVHWRIVHQVRUVDUHDYDLODEOH7KHSK\VLFDOVHQVRUVLQFOXGHEXWDUHQRWOLPLWHG
WRDFFHOHURPHWHUVWKDWPHDVXUHDFFHOHUDWLRQDORQJYDULRXVD[HVJ\URVFRSHVWKDWPHDV
XUHURWDWLRQDOFKDQJHDURXQGVRPHD[HVPDJQHWLFILHOGVHQVRUVWKDWVHQVHWKHVWUHQJWK
RIPDJQHWLFILHOGVDORQJDVHWRID[HVDOLJKWVHQVRUWKDWPHDVXUHVWKHDPRXQWRIDPELHQW
OLJKWDSUR[LPLW\VHQVRUWKDWPHDVXUHVH[WHUQDOREMHFWV¦SUR[LPLW\WRWKHGHYLFHWHP
SHUDWXUHVHQVRUVWKDWPHDVXUHDPELHQWWHPSHUDWXUHDQGSUHVVXUHVHQVRUVWKDWDFWDVD
EDURPHWHU7KHGLUHFWPHDVXUHGYDOXHRIHDFKVHQVRULVFRQVLGHUHGDUDZPHDVXUHPHQW
DQGWKXVWKHDVVRFLDWLYHVHQVRULVD£UDZVHQVRU¤:LWKVRPHRIWKHVHQVRUVWKHPHDV
XUHPHQWVFDQEHFRPELQHGRUFROOHFWHGDQGFDOFXODWLRQVFDQEHPDGHRYHUWKHFROOHFWHG
PHDVXUHPHQWVWRVKRZDPRUHFRPSOH[PHDVXUHPHQW)RUH[DPSOHE\LQWHJUDWLQJWKH
J\URVFRSH¦VPHDVXUHPHQWVRIURWDWLRQDOFKDQJHRYHUWLPH\RXFDQPHDVXUHWKHURWD
WLRQDOYHFWRU7KLVVRUWRIFRPSOH[PHDVXUHPHQWLVRIWHQGHULYHGIURPDFRPSRVLWH
VHQVRU
391
7RDFFHVVDVHQVRURUVHWRIVHQVRUV$QGURLGSURYLGHVDFRQYHQLHQWV\VWHPVHUYLFHFDOOHG
WKH6HQVRU0DQDJHU7KLVFDQEHDFFHVVHGYLDWKH getSystemService()PHWKRGRIWKH
ContextZLWKWKHDUJXPHQWRI Context.SENSOR_SERVICE:LWKWKH6HQVRU0DQDJHU\RX
WKHQFDQJHWDVSHFLILFVHQVRUYLDWKHgetDefaultSensor()PHWKRG
+RZHYHUDFRPSRVLWHVHQVRUPD\VRPHWLPHVEHUHWXUQHGVRLI\RXZLVKWRJHWDFFHVV
WRWKHUDZVHQVRUDQGLWVDVVRFLDWHGGDWD\RXVKRXOGXVHgetSensorList()
SensorManager mngr =
(SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
// getting the default accelerometer
Sensor accel = mngr.getDefaultSensor (Sensor.TYPE_ACCELEROMETER);
// getting the raw accelerometer
List<Sensor> list = mngr.getSensorList(Sensor.TYPE_ACCELEROMETER);
2QFH\RXJHWDVHQVRURUVHWRIVHQVRUV\RXFDQDFWXDOO\HQDEOHWKHPDQGVWDUWJHWWLQJ
WKHLUGDWDE\UHJLVWHULQJDOLVWHQHUDJDLQVWWKHVHQVRUV'DWDVKRXOGEHJLQWRFRPHLQDW
WKH UDWH \RX JLYH DV DQ DUJXPHQW 7KLV UDWH FDQ EH SENSOR_DELAY_NORMAL
SENSOR_DELAY_UI DUDWHDSSURSULDWHIRUEDVLF8,LQWHUDFWLRQ SENSOR_DELAY_GAME DKLJK
UDWHWKDWPDQ\JDPHVZRXOGILQGVXIILFLHQW SENSOR_DELAY_FASTEST £JLYHLWWRPHDV
IDVWDV\RXFDQ¤ RUDVSHFLILHGGHOD\EHWZHHQHYHQWVLQXQLWVRIPLOOLVHFRQGV
SensorEventListener listener = new SensorEventListener() {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
};
@Override
public void onSensorChanged(SensorEvent event) { }
// registering a listener
mngr.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
7KH WZR PHWKRGV LQ D SensorEventListener¢onAccuracyChanged() DQG onSensor
Changed()¢DUHFDOOHGZKHQGDWDIURPWKHVHQVRULQTXHVWLRQLVDYDLODEOH onAccuracy
Changed()LVFDOOHGZKHQHYHUDFKDQJHWRWKHGHJUHHRIHUURURUDFFXUDF\ZLWKWKHVHQVRU
RFFXUV7KHonSensorChanged()PHWKRGLVSHUKDSVWKHPRUHLQWHUHVWLQJPHWKRGLQWKDW
WKHGDWDWKHVHQVRULVPHDVXULQJLVSDVVHGWRLWZUDSSHGLQDSensorEventREMHFW
,WLVLQFUHGLEO\LPSRUWDQWWRXQUHJLVWHUWKHOLVWHQHUDQGWKXVGLVDEOHWKHVHQVRUZKHQ
\RX QR ORQJHU QHHG LW HJ ZKHQ DQ DFWLYLW\ LV SDXVHG RWKHUZLVH WKH GHYLFH ZLOO
FRQWLQXHWRXVHUHVRXUFHVDQGGUDLQSRZHU7KHV\VWHPZLOOQRWWDNHFDUHRIWKLVIRU
\RXHYHQZKHQWKHVFUHHQLVWXUQHGRII
mngr.unregisterListener(listener);
:KLOH WKH VHQVRU LV RQ SensorEvent LV SDVVHG WR WKH OLVWHQHU YLD WKH onSensor
Changed()PHWKRG,WLVLQWKLVSensorEvent¦VYDOXHVWKDWHDFKVHQVRUW\SHGLIIHUV
392 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
Position
7KHSKRQH¦VFRRUGLQDWHV\VWHPLVEDVHGRQWKHVFUHHQDQGGHIDXOWRULHQWDWLRQRIWKH
SKRQH7KH[\DQG]D[HVDUHDVVKRZQLQ)LJXUHDQGZRUNDVIROORZV
[D[LV
+RUL]RQWDOZLWKSRVLWLYHYDOXHVWRWKHULJKWDQGQHJDWLYHYDOXHVWRWKHOHIW
\D[LV
9HUWLFDOZLWKSRVLWLYHYDOXHVXSZDUGDQGQHJDWLYHYDOXHVGRZQZDUG
]D[LV
3RVLWLYHYDOXHVFRPLQJRXWRIWKHVFUHHQWRZDUGWKHIURQWDQGQHJDWLYHYDOXHVEH
KLQGWKHVFUHHQ WKH]]HURSRLQWUHVWVRQWKHVFUHHQ
:KHQWKHXVHUPRYHVWKHSKRQHWKHD[HVIROORZWKHSKRQH¦VPRYHPHQWDQGGRQRW
VZDSSODFHV
)LJXUH3KRQHFRRUGLQDWHV\VWHP
7KHDFFXUDF\DQGYDULDQFHRIWKHYDULRXVVHQVRUVGHSHQGRQWKHTXDOLW\RIKDUGZDUH
,QPDQ\FDVHVVLJQLILFDQWOHYHOVRIMLWWHUQRLVHZLOOQHHGWREHHOLPLQDWHG WKURXJKWKH
XVHRIORZSDVVILOWHUVIRUH[DPSOH 7KHW\SHRIILOWHUDQGLWVFRQVWUXFWLRQLVXSWRWKH
GHYHORSHUWRGHVLJQDQGFUHDWH
Sensors | 393
Accelerometer
7KHDFFHOHURPHWHUPHDVXUHVWKHDFFHOHUDWLRQDSSOLHGWRWKHGHYLFHDQGUHWXUQVYDOXHV
DORQJWKHWKUHHD[HV YDOXH>@IRUWKH[D[LVYDOXH>@IRUWKH\D[LVDQGYDOXH>@IRUWKH
]D[LV 7KHYDOXHVDUHLQ6,XQLWV PV ,WLVLPSRUWDQWWRQRWHWKDWWKHIRUFHRIJUDYLW\
LVQRWHOLPLQDWHGIURPWKHYDOXHVUHWXUQHG7KXVZKHQWKHGHYLFHLVVLWWLQJRQDWDEOH
VD\IDFHXS YDOXH>@ZLOOUHDGPV
6LQFHLWEHFDPHDIDLUO\FRPPRQQHHGWRHOLPLQDWHRUGHWHUPLQHWKHIRUFHRIJUDYLW\
DORQJWKHYDULRXVD[HV$QGURLG $3,OHYHO DOVRVXSSRUWVDOLQHDUDFFHOHUDWLRQ
VHQVRUDQGDJUDYLW\VHQVRUGLVFXVVHGODWHULQWKLVFKDSWHU
Gyroscope
7KHJ\URVFRSHPHDVXUHVWKHDQJXODUVSHHGRUUDWHRIURWDWLRQDURXQGWKHWKUHHD[HV
$OOYDOXHVDUHLQUDGLDQVVHFRQG5RWDWLRQLVSRVLWLYHLQWKHFRXQWHUFORFNZLVHGLUHFWLRQ
7KDWLVDQREVHUYHUORRNLQJDWWKHGHYLFHVFUHHQQRUPDOO\¢ORFDWHGDWLQGHYLFH
FRRUGLQDWHV¢ZRXOGUHSRUWSRVLWLYHURWDWLRQLIWKHGHYLFHDSSHDUHGWREHURWDWLQJFRXQ
WHUFORFNZLVH6LQFHWKLVLVDQJXODUVSHHGWRFDOFXODWHDQDQJOH\RXPXVWLQWHJUDWHWKH
YDOXHVRYHUDSHULRGRIWLPH
private static final float NS2S = 1.0f / 1000000000.0f;
private float timestamp;
private float[] angle;
@Override
public void onSensorChanged(SensorEvent event) {
float gyrox = event.values[0];
float gyroy = event.values[1];
float gyroz = event.values[2];
// here we integrate over time to figure out the rotational angle around each axis
if (timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
angle[0] += gyrox * dT;
angle[1] += gyroy * dT;
angle[2] += gyroz * dT;
}
}
timestamp = event.timestamp;
6LQFHWKLVLVDFRPPRQSUREOHPVHW$QGURLG $3,OHYHO VXSSRUWVDURWDWLRQYHFWRU
VHQVRUZKLFKZHGLVFXVVLQWKHIROORZLQJVHFWLRQ
Rotation vector
7KHURWDWLRQYHFWRULQ$QGURLGDQGODWHUYHUVLRQVUHSUHVHQWVWKHRULHQWDWLRQRIWKH
GHYLFHDVDFRPELQDWLRQRIDQDQJOHDQGDQD[LVLQZKLFKWKHGHYLFHKDVURWDWHGWKURXJK
DQ DQJOH Θ DURXQG DQ D[LV [ \ ]! (YHQ WKRXJK WKLV FDQ EH FDOFXODWHG YLD WKH
394 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
J\URVFRSHPDQ\GHYHORSHUVHQGHGXSGRLQJWKLVRIWHQHQRXJKWKDW*RRJOHSURYLGHG
WKHURWDWLRQYHFWRUWRKHOSVLPSOLI\WKHXVHFDVH
7KHWKUHHHOHPHQWVRIWKHURWDWLRQYHFWRUDUH[ VLQ Θ \ VLQ Θ DQG] VLQ Θ !
VXFKWKDWWKHPDJQLWXGHRIWKHURWDWLRQYHFWRULVHTXDOWRVLQ Θ DQGWKHGLUHFWLRQRI
WKHURWDWLRQYHFWRULVHTXDOWRWKHGLUHFWLRQRIWKHD[LVRIURWDWLRQ7KHWKUHHHOHPHQWV
RI WKH URWDWLRQ YHFWRU DUH HTXDO WR WKH ODVW WKUHH FRPSRQHQWV RI D XQLW TXDWHUQLRQ
FRV Θ [ VLQ Θ \ VLQ Θ DQG] VLQ Θ !(OHPHQWVRIWKHURWDWLRQYHFWRUDUH
XQLWOHVV
Linear acceleration
$QRWKHUVHQVRUW\SHLVVXSSRUWHGE\$QGURLG $3,OHYHO WRVLPSOLI\DFRPPRQ
FDOFXODWLRQZLWKWKHXVHRIWKHDFFHOHURPHWHU7KHYDOXHVHQWLVDWKUHHGLPHQVLRQDO
YHFWRULQGLFDWLQJDFFHOHUDWLRQDORQJHDFKGHYLFHD[LVQRWLQFOXGLQJJUDYLW\7KLVPHDQV
WKHYDOXHVDUHWKHUHVXOWRIOLQHDUDFFHOHUDWLRQRQHDFKD[LVPLQXVWKHHIIHFWVRIJUDYLW\
DORQJWKDWD[LV7KLVPDNHVLWHDVLHUWRILOWHURXWJUDYLW\¦VFRQVWDQWHIIHFWVIRUWKRVHRI
XVXVLQJWKHSKRQHZKLOHRQ(DUWK$OOYDOXHVKDYHXQLWVRIPV
Gravity
7KHYDOXHVUHVXOWLQJIURPWKLVVHQVRUPDNHXSDWKUHHGLPHQVLRQDOYHFWRULQGLFDWLQJ
WKHGLUHFWLRQDQGPDJQLWXGHRIJUDYLW\7KLVWRRLVDQ$QGURLG $3,OHYHO VHQVRU
WKDWSURYLGHVDFRPPRQFDOFXODWLRQ8QLWVDUHPV
Other Sensors
$QGURLGDOVRVXSSRUWVWKHIROORZLQJVHQVRUV
/LJKW
7KLVVHQVRUSURYLGHVDVLQJOHYDOXHGDUUD\ YDOXH>@ WKDWUHSUHVHQWVWKHDPELHQW
OLJKWOHYHOLQ6,OX[XQLWV O[ 0DJQHWLF
7KLVVHQVRUPHDVXUHVWKHDPELHQWPDJQHWLFILHOGVLQPLFURWHVODV μ7 DORQJWKH[
\DQG]D[HV
3UHVVXUH
1RWPDQ\GHYLFHVSURYLGHWKLVVHQVRU7KRVHWKDWGRZLOOSURYLGHWKHYDOXHVLQ
NLORSDVFDOV N3D 3UR[LPLW\
7KLVVHQVRUPHDVXUHVDVLQJOHYDOXHGDUUD\ YDOXH>@ UHSUHVHQWLQJGLVWDQFHPHDV
XUHGLQFHQWLPHWHUV FP WRWKHVHQVRU,QVRPHFDVHVWKHSUR[LPLW\VHQVRUPD\
SURYLGHRQO\D£QHDU¤ YHUVXV£IDU¤ ELQDU\PHDVXUHPHQW,QWKDWFDVHDGLV
WDQFHHTXDOWRRUJUHDWHUWKDQWKHVHQVRU¦VgetMaximumRange()YDOXHZLOOUHWXUQ£IDU¤
DQGDQ\WKLQJOHVVWKDQWKDWZLOOUHWXUQ£QHDU¤
Sensors | 395
7HPSHUDWXUH
7KLV LV DQRWKHU VHQVRU WKDW QRW PDQ\ GHYLFHV SURYLGH 7KH YDOXHV ZLOO EH LQ
FHQWLJUDGH & Near Field Communication (NFC)
1HDU)LHOG&RPPXQLFDWLRQLVDVKRUWUDQJH XSWRFP KLJKIUHTXHQF\ZLUHOHVV
FRPPXQLFDWLRQWHFKQRORJ\,WLVDVWDQGDUGWKDWH[WHQGVWKH5DGLR)UHTXHQF\,GHQWL
ILFDWLRQ 5),' VWDQGDUGE\FRPELQLQJWKHLQWHUIDFHRIDVPDUWFDUGDQGDUHDGHULQWR
D VLQJOH GHYLFH 7KLV VWDQGDUG LV SULPDULO\ EXLOW IRU PRELOH SKRQH XVH DQG WKXV LV
DWWUDFWLQJDORWRIDWWHQWLRQDPRQJYHQGRUVWKDWDUHLQWHUHVWHGLQFRQWDFWOHVVGDWDWUDQV
PLVVLRQ VXFKDVFUHGLWFDUGVDOHV 7KHVWDQGDUGHQDEOHV1)&WREHXVHGLQWKUHHVSH
FLILFZD\V
&DUGHPXODWLRQ
7KHGHYLFHLVDFRQWDFWOHVVFDUG DQGWKXVFDQEHUHDGE\RWKHUUHDGHUV 5HDGHUPRGH
7KHGHYLFHFDQUHDG5),'WDJV
33PRGH
7ZRGHYLFHVFDQFRPPXQLFDWHEDFNDQGIRUWKDQGH[FKDQJHGDWD
,Q$QGURLG $3,OHYHO *RRJOHLQWURGXFHGWKH5HDGHU0RGH1)&IXQFWLRQDOLW\
6WDUWLQJLQ$QGURLG $3,OHYHO WKHDELOLW\WRZULWHGDWDWRDQ1)&WDJDQG
H[FKDQJHGDWDYLD33PRGHLVDOVRDYDLODEOH
1)&WDJVFRQVLVWRIGDWDHQFRGHGLQ1)&'DWD([FKDQJH)RUPDW 1'() DPHVVDJH
IRUPDWVSHFLILHGE\WKH1)&)RUXP7\SH6SHFLILFDWLRQ(DFK1'()PHVVDJHFRQVLVWV
RIRQHRUPRUH1'()UHFRUGV7KHRIILFLDOWHFKQLFDOVSHFLILFDWLRQIRU1)&FDQEHIRXQG
DW KWWSZZZQIFIRUXPRUJ 7R GHYHORS DQG WHVW DQ 1)& UHDGLQJ DSSOLFDWLRQ LW LV
KLJKO\VXJJHVWHGWKDW\RXJHWDQ1)&FRPSOLDQWGHYLFH VXFKDVWKH1H[XV6DWKWWS
ZZZJRRJOHFRPSKRQHGHWDLOQH[XVV DQGDQ1)&FRPSOLDQWWDJ
7RXVH1)&IXQFWLRQDOLW\LQ\RXUDSSOLFDWLRQ\RXQHHGWRGHFODUHWKHIROORZLQJSHU
PLVVLRQLQ\RXUPDQLIHVW
<uses-permission android:name="android.permission.NFC" />
7R UHVWULFW WKH LQVWDOODWLRQ RI WKH DSSOLFDWLRQ WR GHYLFHV WKDW FDQ XVH 1)& DGG WKH
IROORZLQJWR\RXUPDQLIHVWDVZHOO
<uses-feature android:name="android.hardware.nfc" />
Reading a Tag
5HDGHUPRGHLVIRUUHFHLYLQJQRWLFHVZKHQDQ5),'1)&WDJLVVFDQQHG,Q$QGURLG
$3,OHYHO WKHRQO\PHDQVWRGRWKLVLVWRFUHDWHDQActivityWKDWOLVWHQVIRUWKH
android.nfc.action.TAG_DISCOVERED LQWHQW ZKLFK LV EURDGFDVW ZKHQ D WDJ LV UHDG
396 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
$QGURLG $3,OHYHO RIIHUVDPRUHFRPSUHKHQVLYHPHDQVWRUHFHLYHWKLVQRWLFH
IROORZLQJWKHSURFHVVVKRZQLQ)LJXUH
)LJXUH1)&WDJIORZLQ$QGURLG $3,OHYHO
,Q$QGURLG $3,OHYHO DQGODWHUZKHQDQ1)&WDJLVGLVFRYHUHGWKHWDJREMHFW
DParcelable LVSODFHGLQWRDQIntentDVDQEXTRA_TAG7KHV\VWHPWKHQEHJLQVWRIROORZ
Near Field Communication (NFC) | 397
DORJLFIORZWRGHWHUPLQHWKHEHVWActivityWRZKLFKWRVHQGWKHLQWHQW7KLVLVGHVLJQHG
WRJLYHDKLJKSUREDELOLW\RIGLVSDWFKLQJDWDJWRWKHFRUUHFWDFWLYLW\ZLWKRXWVKRZLQJ
WKHXVHUDQDFWLYLW\FKRRVHUGLDORJ LHLQDWUDQVSDUHQWPDQQHU DQGWKXVSUHYHQWWKH
FRQQHFWLRQEHWZHHQWKHWDJDQGWKHGHYLFHIURPEHLQJEURNHQE\XQQHHGHGXVHULQWHU
DFWLRQ7KHILUVWWKLQJWKDWLVFKHFNHGLVZKHWKHUWKHUHLVDQActivityLQWKHIRUHJURXQG
WKDWKDVFDOOHGWKH enableForegroundDispatch()PHWKRG,IVRWKHLQWHQWLVSDVVHGWR
WKH ActivityDQGWKLQJVVWRSWKHUH,IQRWWKHV\VWHPLQVSHFWVWKHILUVW NdefRecordLQ
WKHILUVWNdefMessageRIWKHWDJ¦VGDWD,IWKHNdefRecordLV85,6PDUW3RVWHURU0,0(
GDWD WKH V\VWHP WKHQ FKHFNV IRU DQ Activity UHJLVWHUHG IRU WKH ACTION_NDEF_
DISCOVEREDLQWHQW android.nfc.action.NDEF_DISCOVERED ZLWKWKDWW\SHRIGDWD,IWKLV
H[LVWVWKHActivityWKDWPDWFKHV WKHQDUURZHUWKHPDWFKWKHEHWWHU UHFHLYHVWKHLQWHQW
DQGWKLQJVVWRSWKHUH,IWKLVLVQRWWKHFDVHWKHV\VWHPVHHNVDQActivityWKDWLVUHJLV
WHUHGIRU ACTION_TECH_DISCOVEREDDQGWKDWPDWFKHVWKHVSHFLILFVHWRIWHFKQRORJLHVRI
WKHWDJ DJDLQWKHQDUURZHUWKHPDWFKWKHEHWWHU ,IWKHUHLVDPDWFKWKHLQWHQWLV
SDVVHGWRWKDW ActivityDQGHYHU\WKLQJLVVHWWOHG+RZHYHUVKRXOGQR ActivityH[LVW
WKDWSDVVHVWKHSULRUFKHFNVWKHLQWHQWLVILQDOO\SDVVHGDVDQ ACTION_TAG_DISCOVERED
DFWLRQPXFKDV$QGURLG $3,OHYHO KDQGOHVWKHWDJ
7RVHWXSDIRUHJURXQGActivityWREHWKHILUVWWRUHFHLYHWKHWDJ\RXPXVWUHWULHYHWKH
1)& GHYLFH DGDSWHU DQG FDOO enableForegroundDispatch ZLWK WKH Activity¦V FRQWH[W
UHIHUHQFH7KHDFWXDO1)&GHYLFHDGDSWHULVUHSUHVHQWHGE\WKH NfcAdapterFODVV7R
UHWULHYHWKHDFWXDODGDSWHURIWKHGHYLFHLVVXHgetDefaultAdapter()LQ$QGURLG $3,
OHYHO RUgetDefaultAdapter(context)LQ$QGURLG $3,OHYHO NfcAdapter adapter = NfcAdapter.getDefaultAdapter();
// --- for API 10 only
// NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
if(adapter != null) {
// true if enabled, false if not
boolean enabled = adapter.isEnabled();
}
2QFHWKH1)&GHYLFHDGDSWHULVUHWULHYHGFRQVWUXFWDPendingIntentDQGSDVVLWWRWKH
enableForegroundDispatch()PHWKRG7KLVPHWKRGPXVWEHFDOOHGIURPWKHPDLQWKUHDG
DQGRQO\ZKHQWKHActivityLVLQWKHIRUHJURXQG DIWHUonResume()KDVEHHQFDOOHG PendingIntent intent =
PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
0);
NfcAdapter.getDefaultAdapter(this).enableForegroundDispatch(this, intent,
null, null);
,W LV H[WUHPHO\ LPSRUWDQW WKDW ZKHQ WKH Activity OHDYHV WKH IRUHJURXQG ZKHQ
onPause()LVFDOOHG \RXFDOOWKHdisableForegroundDispatch()PHWKRG
@Override
protected void onPause() {
398 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
}
super.onPause();
if(NfcAdapter.getDefaultAdapter(this) != null)
NfcAdapter.getDefaultAdapter(this).disableForegroundDispatch(this);
}
,QWKHFDVHRIUHJLVWHULQJDQ ActivityIRU ACTION_NDEF_DISCOVEREDWKH ActivityPXVW
KDYH android.nfc.action.NDEF_DISCOVEREDDVDQ intent-filterDQGDQ\VSHFLILFGDWD
ILOWHUVLQWKHPDQLIHVWILOH
<activity android:name=".NFC233">
<!-- listen for android.nfc.action.NDEF_DISCOVERED -->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data android:mimeType="text/*" />
</intent-filter>
</activity>
7KLVJRHVIRUWKHTECH_DISCOVEREDFDVHDVZHOO WKHIROORZLQJH[DPSOHDOVRLQFOXGHVD
PHWDGDWDUHVRXUFHGHVFULELQJWKHVSHFLILFWHFKQRORJ\WKDWUHVLGHVLQWKH1)&WDJWKDW
ZHDUHQDUURZLQJLQRQVXFKDV1'()FRQWHQW <activity android:name=".NFC233">
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfcfilter"
/>
</activity>
<?xml version="1.0" encoding="utf-8"?>
<!-- capture anything using NfcF or with NDEF payloads-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
<tech>android.nfc.tech.MifareClassic</tech>
<tech>android.nfc.tech.Ndef</tech>
</tech-list>
</resources>
$QH[DPSOHRIUHJLVWHULQJIRUWKHACTION_TAG_DISCOVEREDLQWHQWZRXOGEHZULWWHQLQWKH
PDQLIHVWILOHOLNHWKLV
<!-- this will show up as a dialog when the nfc tag is scanned -->
<activity android:name=".NFC" android:theme="@android:style/Theme.Dialog">
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Near Field Communication (NFC) | 399
:KHQDWDJLVUHDGWKHV\VWHPEURDGFDVWVDQLQWHQWZLWKWKHSD\ORDGDVWKHDVVRFLDWHG
GDWD,Q$QGURLG $3,OHYHO DTagREMHFWLVDOVRLQFOXGHGDVDQEXTRA_TAG7KLV
TagREMHFWSURYLGHVDPHDQVWRUHWULHYHWKHVSHFLILFTagTechnologyDQGWRSHUIRUPDG
YDQFHGRSHUDWLRQV VXFKDV,2 %HDZDUHWKDWArrayVSDVVHGWRDQGUHWXUQHGE\WKLV
FODVVDUHQRWFORQHGVREHFDUHIXOQRWWRPRGLI\WKHP
Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
,Q$QGURLG $3,OHYHO DQGODWHUWKH,'RIWKHWDJLVZUDSSHGZLWKLQWKHLQWHQW
DQGNH\HGZLWKWKHWHUP£DQGURLGQIFH[WUD,'¤ NfcAdapter.EXTRA_ID DVDE\WHDUUD\
byte[] byte_id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
7KLVGDWDLVSDFNDJHGXSDVDQDUUD\RI ParcelableREMHFWV NdefMessage NH\HGZLWK
WKHWHUP£DQGURLGQIFH[WUD1'()B0(66$*(6¤ NfcAdapter.EXTRA_NDEF_MESSAGES Parcelable[] msgs =
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] nmsgs = new NdefMessage[msgs.length];
for(int i=0;i<msgs.length;i++) {
nmsgs[i] = (NdefMessage) msgs[i];
}
:LWKLQHDFKNdefMessageLVDQDUUD\RINdefRecord7KLVUHFRUGZLOODOZD\VLQFOXGHD
ELW71) W\SHQDPHIRUPDW WKHW\SHRIUHFRUGDXQLTXH,'DQGWKHSD\ORDG)RU
VSHFLILFVORRNDWWKH1GHI5HFRUGGRF KWWSGHYHORSHUDQGURLGFRPUHIHUHQFHDQGURLG
QIF1GHI5HFRUGKWPO &XUUHQWO\WKHUHDUHVHYHUDONQRZQW\SHVRIZKLFKZHFRYHUWKH
IRXUPRVWFRPPRQTEXTURISMART_POSTERDQGABSOLUTE_URI
// enum of types we are interested in
private static enum NFCType {
UNKNOWN, TEXT, URI, SMART_POSTER, ABSOLUTE_URI
}
private NFCType getTagType(final NdefMessage msg) {
if(msg == null) return null;
// we are only grabbing the first recognizable item
for (NdefRecord record : msg.getRecords()) {
if(record.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
if(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) {
return NFCType.TEXT;
}
if(Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
return NFCType.URI;
}
if(Arrays.equals(record.getType(), NdefRecord.RTD_SMART_POSTER)) {
return NFCType.SMART_POSTER;
}
} else if(record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) {
return NFCType.ABSOLUTE_URI;
}
}
return null;
}
400 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
7RUHDGWKHSD\ORDGRIDQNdefRecord.RTD_TEXTW\SHWKHILUVWE\WHRIWKHSD\ORDGZLOO
GHILQHWKHVWDWXVDQGWKXVWKHHQFRGLQJW\SHRIWKHWH[WSD\ORDG
/*
* the First Byte of the payload contains the "Status Byte Encodings" field,
* per the NFC Forum "Text Record Type Definition" section 3.2.1.
*
* Bit_7 is the Text Encoding Field.
* * if Bit_7 == 0 the the text is encoded in UTF-8
* * else if Bit_7 == 1 then the text is encoded in UTF16
* Bit_6 is currently always 0 (reserved for future use)
* Bits 5 to 0 are the length of the IANA language code.
*/
private String getText(final byte[] payload) {
if(payload == null) return null;
try {
String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
int languageCodeLength = payload[0] & 0077;
return new String(payload, languageCodeLength + 1,
payload.length - languageCodeLength - 1, textEncoding);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
:KHQUHDGLQJLQWKHSD\ORDGRIDVWDQGDUG85, NdefRecord.RTD_URI W\SHWKHILUVW
E\WHRIWKHSD\ORDGGHILQHVWKH85,¦VSUHIL[
/**
* NFC Forum "URI Record Type Definition"
*
* Conversion of prefix based on section 3.2.2 of the NFC Forum URI Record
* Type Definition document.
*/
private String convertUriPrefix(final byte prefix) {
if(prefix == (byte) 0x00) return "";
else if(prefix == (byte) 0x01) return "http://www.";
else if(prefix == (byte) 0x02) return "https://www.";
else if(prefix == (byte) 0x03) return "http://";
else if(prefix == (byte) 0x04) return "https://";
else if(prefix == (byte) 0x05) return "tel:";
else if(prefix == (byte) 0x06) return "mailto:";
else if(prefix == (byte) 0x07) return "ftp://anonymous:anonymous@";
else if(prefix == (byte) 0x08) return "ftp://ftp.";
else if(prefix == (byte) 0x09) return "ftps://";
else if(prefix == (byte) 0x0A) return "sftp://";
else if(prefix == (byte) 0x0B) return "smb://";
else if(prefix == (byte) 0x0C) return "nfs://";
else if(prefix == (byte) 0x0D) return "ftp://";
else if(prefix == (byte) 0x0E) return "dav://";
else if(prefix == (byte) 0x0F) return "news:";
else if(prefix == (byte) 0x10) return "telnet://";
else if(prefix == (byte) 0x11) return "imap:";
else if(prefix == (byte) 0x12) return "rtsp://";
else if(prefix == (byte) 0x13) return "urn:";
Near Field Communication (NFC) | 401
else if(prefix == (byte) 0x14) return "pop:";
else if(prefix == (byte) 0x15) return "sip:";
else if(prefix == (byte) 0x16) return "sips:";
else if(prefix == (byte) 0x17) return "tftp:";
else if(prefix == (byte) 0x18) return "btspp://";
else if(prefix == (byte) 0x19) return "btl2cap://";
else if(prefix == (byte) 0x1A) return "btgoep://";
else if(prefix == (byte) 0x1B) return "tcpobex://";
else if(prefix == (byte) 0x1C) return "irdaobex://";
else if(prefix == (byte) 0x1D) return "file://";
else if(prefix == (byte) 0x1E) return "urn:epc:id:";
else if(prefix == (byte) 0x1F) return "urn:epc:tag:";
else if(prefix == (byte) 0x20) return "urn:epc:pat:";
else if(prefix == (byte) 0x21) return "urn:epc:raw:";
else if(prefix == (byte) 0x22) return "urn:epc:";
else if(prefix == (byte) 0x23) return "urn:nfc:";
return null;
}
,QWKHFDVHRIDQDEVROXWH85, NdefRecord.TNF_ABSOLUTE_URI W\SHWKHZKROHSD\ORDG
LVHQFRGHGLQ87)DQGPDNHVXSWKH85,
if(record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) {
String uri = new String(record.getPayload(), Charset.forName("UTF-8");
}
7KHVSHFLDO6PDUW3RVWHU NdefRecord.RTD_SMART_POSTER W\SHFRQVLVWVRIPXOWLSOHVXE
UHFRUGVRIWH[WRU85, RUDEVROXWH85, GDWD
private void getTagData(final NdefMessage msg) {
if(Arrays.equals(record.getType(), NdefRecord.RTD_SMART_POSTER)) {
try {
// break out the subrecords
NdefMessage subrecords = new NdefMessage(record.getPayload());
// get the subrecords
String fulldata = getSubRecordData(subrecords);
System.out.println("SmartPoster: "+fulldata);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// method to get subrecord data
private String getSubRecordData(final NdefRecord[] records) {
if(records == null || records.length < 1) return null;
String data = "";
for(NdefRecord record : records) {
if(record.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
if(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) {
data += getText(record.getPayload()) + "\n";
}
if(Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
data += getURI(record.getPayload()) + "\n";
} else {
data += "OTHER KNOWN DATA\n";
402 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
Download from Wow! eBook <www.wowebook.com>
}
} else if(record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) {
data += getAbsoluteURI(record.getPayload()) + "\n";
} else data += "OTHER UNKNOWN DATA\n";
}
}
return data;
Writing to a Tag
$VRI$QGURLG $3,OHYHO WKHDELOLW\WRZULWHGDWDWRDWDJLVDYDLODEOH7RGR
WKLVWKHTagREMHFWPXVWEHXVHGWRJHWWKHDSSURSULDWHTagTechnologyZLWKLQWKHWDJ
1)&WDJVDUHEDVHGRQDQXPEHURILQGHSHQGHQWO\GHYHORSHGWHFKQRORJLHVDQGRIIHUD
ZLGHUDQJHRIFDSDELOLWLHV7KHTagTechnologyLPSOHPHQWDWLRQVSURYLGHDFFHVVWRWKHVH
GLIIHUHQWWHFKQRORJLHVDQGFDSDELOLWLHV,QWKLVFDVHWKH1'()WHFKQRORJ\LVQHHGHGWR
UHWULHYHDQGPRGLI\WKHNdefRecordVDQGNdefMessageVLQWKHWDJ
// get the tag from the Intent
Tag mytag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
// get the Ndef (TagTechnology) from the tag
Ndef ndefref = Ndef.get(mytag);
1RWH WKH IROORZLQJ UHTXLUHPHQWV ZKHQ SHUIRUPLQJ ,2 RSHUDWLRQV ZLWK D Tag
Technology
‡ connect()PXVWEHFDOOHGEHIRUHXVLQJDQ\RWKHU,2RSHUDWLRQ
‡ ,2RSHUDWLRQV PD\ EORFN DQG VKRXOGQHYHUEHFDOOHGRQWKHPDLQDSSOLFDWLRQ
WKUHDG
‡ 2QO\RQHTagTechnologyFDQEHFRQQHFWHGDWDWLPH2WKHUFDOOVWRconnect()ZLOO
UHWXUQDQIOException
‡ close()PXVWEHFDOOHGDIWHUFRPSOHWLQJ,2RSHUDWLRQVZLWKDTagTechnologyDQG
LW ZLOO FDQFHO DOO RWKHU EORFNHG ,2 RSHUDWLRQV RQ RWKHU WKUHDGV LQFOXGLQJ
connect() ZLWKDQIOException
7KHUHIRUH WR ZULWH GDWD WR D WDJ D connect() LV FDOOHG IURP ZLWKLQ D WKUHDG WKDW LV
VHSDUDWH IURP WKDW RI WKH PDLQ WKUHDG 2QFH WKLV LV GRQH isConnected() VKRXOG EH
FKHFNHGWRYHULI\WKDWWKHFRQQHFWLRQKDVEHHQHVWDEOLVKHG,IWKHFRQQHFWLRQLVHVWDE
OLVKHG writeNdefMessage() ZLWK D FRQVWUXFWHG NdefMessage FRQWDLQLQJ DW OHDVW RQH
NdefRecord PD\EHFDOOHG2QFHWKHGDWDLVZULWWHQclose()LVFDOOHGWRFOHDQO\WHUPL
QDWHWKHSURFHVV
7KHIXOOFRGHWRZULWHDWH[WUHFRUGWRDWDJXVLQJLWV1'()TagTechnologyUHIHUHQFHLV
DVIROORZV
// pass in the Ndef TagTechnology reference and the text we wish to encode
private void writeTag(final Ndef ndefref, final String text) {
if(ndefref == null || text == null || !ndefref.isWritable()) {
return;
Near Field Communication (NFC) | 403
}
}
(new Thread() {
public void run() {
try {
Message.obtain(mgsToaster, 0,
"Tag writing attempt started").sendToTarget();
int count = 0;
if(!ndefref.isConnected()) {
ndefref.connect();
}
while(!ndefref.isConnected()) {
if(count > 6000) {
throw new Exception("Unable to connect to tag");
}
count++;
sleep(10);
}
ndefref.writeNdefMessage(msg);
Message.obtain(mgsToaster, 0,
"Tag write successful!").sendToTarget();
} catch (Exception t) {
t.printStackTrace();
Message.obtain(mgsToaster, 0,
"Tag writing failed! - "+t.getMessage()).sendToTarget();
} finally {
// ignore close failure...
try { ndefref.close(); }
catch (IOException e) { }
}
}
}).start();
// create a new NdefRecord
private NdefRecord newTextRecord(String text) {
byte[] langBytes = Locale.ENGLISH.
getLanguage().
getBytes(Charset.forName("US-ASCII"));
byte[] textBytes = text.getBytes(Charset.forName("UTF-8"));
char status = (char) (langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
}
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT,
new byte[0],
data);
404 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
P2P Mode
33 PRGH LV HQDEOHG LQ $QGURLG $3, OHYHO ZKHQ RQH GHYLFH LV VHW XS WR
WUDQVPLW GDWD RYHU 1)& WR DQRWKHU GHYLFH WKDW FDQ UHFHLYH 1)& GDWD 7KH VHQGLQJ
GHYLFHPD\DOVRUHFHLYHGDWDIURPWKHUHFHLYLQJGHYLFHDQGWKXVSHHUWRSHHU 33
FRPPXQLFDWLRQ RFFXUV 7R GR WKLV WKH enableForegroundNdefPush() PHWKRG LQ WKH
NfcAdapterFODVVLVXVHG7KLVHQDEOHVWKH ActivityWRWUDQVPLWDQ NdefMessageZKHQ
LWLVLQWKHIRUHJURXQGWRDQRWKHU1)&GHYLFHWKDWVXSSRUWVWKH£FRPDQGURLGQSS¤
1'()SXVKSURWRFRO7KH enableForegroundNdefPush()PHWKRGPXVWEHFDOOHGIURP
WKHPDLQWKUHDG VXFKDVLQonResume() @Override
public void onResume() {
super.onResume();
NdefRecord[] rec = new NdefRecord[1];
rec[0] = newTextRecord("NFC Foreground Push Message");
NdefMessage msg = new NdefMessage(rec);
}
NfcAdapter.getDefaultAdapter(this).enableForegroundNdefPush(this, msg);
// create a new NdefRecord
private NdefRecord newTextRecord(String text) {
byte[] langBytes = Locale.ENGLISH.
getLanguage().
getBytes(Charset.forName("US-ASCII"));
byte[] textBytes = text.getBytes(Charset.forName("UTF-8"));
char status = (char) (langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT,
new byte[0],
data);
}
:KLOH enableForegroundNdefPush()LVDFWLYHVWDQGDUGWDJGLVSDWFKLVGLVDEOHG2QO\
WKH IRUHJURXQG DFWLYLW\ PD\ UHFHLYH WDJGLVFRYHUHG GLVSDWFKHV YLD
enableForegroundDispatch()
,W LV LPSRUWDQW WKDW ZKHQ WKH Activity LV QR ORQJHU LQ WKH IRUHJURXQG onPause()
disableForegroundNdefPush()LVFDOOHG
@Override
protected void onPause() {
super.onPause();
Near Field Communication (NFC) | 405
if(NfcAdapter.getDefaultAdapter(this) != null) {
NfcAdapter.getDefaultAdapter(this).disableForegroundNdefPush(this);
}
}
Gesture Input
,QWKHZRUOGRIWRXFKVFUHHQGHYLFHVWKHXVHRIFRPSOH[JHVWXUHV VXFKDVPXOWLSOH
VZLSHVRIWKHILQJHULQGLIIHUHQWGLUHFWLRQVRQWKHVFUHHQ LVDJUHDWZD\WRPDNHLQWHU
DFWLRQVERWKIXQDQGHDV\WRGR6WDUWLQJZLWK$QGURLG $3,OHYHO DJHVWXUHV$3,
LVDYDLODEOHIRUXVH:LWKLQWKLV$3,WKHHDVLHVWZD\WRDGGJHVWXUHLQSXWFDSDELOLW\WR
DQDSSLVWRXVHandroid.gesture.GestureOverlayView
<!-- an example usage of GestureOverlayView in a layout xml -->
<android.gesture.GestureOverlayView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gestureStrokeType="multiple"
android:eventsInterceptionEnabled="true">
</<android.gesture.GestureOverlayView>
GestureOverlayViewLVDVSHFLDOL]HGFrameLayoutWKDW\RXFDQSODFHRYHURWKHUZLGJHWV
RUWKDWFDQFRQWDLQRWKHUZLGJHWV,WFDQFDSWXUHVWURNHVRQWKHWRXFKVFUHHQDVZHOODV
GLVSOD\ D FRORUHG OLQH WKH GHIDXOW LV \HOORZ UHSUHVHQWLQJ WKH VWURNH SDWK $
GestureOverlayView.OnGesturePerformedListener LQWHUIDFH LV SURYLGHG WR HQDEOH WKH
DELOLW\WRUHDFWWRDJHVWXUHWKDWKDVEHHQSHUIRUPHG
GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
gestures.addOnGesturePerformedListener(
new GestureOverlayView.OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
// do nothing for now
}
});
2QFHWKHJHVWXUHLVSHUIRUPHG\RXFDQVHHLILWLVUHFRJQL]HGZLWKLQWKH*HVWXUHOLEUDU\
7KH*HVWXUHOLEUDU\FDQEHUHDGLQYLDYDULRXVPHDQVXVLQJWKHGestureLibrariesFODVV¦V
VWDWLF PHWKRGV 2QFH WKH OLEUDU\ LV ORDGHG ORDGLQJ D GestureStore WKH SHUIRUPHG
JHVWXUHFDQEHSDVVHGWRLWDQGWKHQDQDO\]HGXVLQJWKHrecognizePHWKRG7KLVPHWKRG
UHWXUQVDOLVWRIPredictionVHDFKKROGLQJDVFRUHDQGQDPHZLWKWKHVFRUHLQGLFDWLQJ
WKHFORVHQHVVWRWKHQDPHGJHVWXUHZLWKLQWKHOLEUDU\
final GestureLibrary library = GestureLibraries.fromFile("/Some/File/Path");
library.load();
// load library
GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
gestures.addOnGesturePerformedListener(
new GestureOverlayView.OnGesturePerformedListener() {
406 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
});
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
// do the recognize
ArrayList<Prediction> predictions = library.recognize(gesture);
if (predictions.size() > 0) {
for(Prediction prediction: predictions) {
// the score is high enough that we know it's a hit
if (prediction.score > 1.0) {
// let's show a toast telling us what the gesture is named
Toast.makeText(this,
prediction.name, Toast.LENGTH_SHORT).show();
}
}
}
}
7KHEDVLFDQDWRP\RID GestureFRQVLVWVRIPXOWLSOH GestureStrokeREMHFWVDQGHDFK
GestureStrokeREMHFWLVPDGHXSRIGesturePointREMHFWV7KHGesturePointLVPDGHXS
RI[DQG\VSDWLDOFRRUGLQDWHVDQGDVLQJOHWLPHVWDPSLQGLFDWLQJZKHQWKHSRLQWZDV
JHQHUDWHG:KHQD GestureLVVWRUHGLQD GestureStore ZLWKLQD GestureLibrary LWLV
NH\HGZLWKDQDPH String $GGLQJDGestureWRDGestureLibraryLVSUHWW\VWUDLJKWIRUZDUG<RXSURYLGHDQDPHWR
DVVRFLDWHWKHJHVWXUHDVZHOODVWKHGestureREMHFWDQGWKHQVDYHLWWRWKHOLEUDU\1RWH
WKDWDOLEUDU\PXVWEHUHDGIURPDQH[WHUQDOILOHVRXUFH VXFKDVWKH6'FDUGRUSULYDWH
ILOH IRUWKHOLEUDU\WREHPRGLILDEOHDQGWKXVDJHVWXUHVWRUH$OLEUDU\UHDGIURPDUDZ
UHVRXUFHLVUHDGRQO\ XVHRIGestureLibraries.fromRawResource(context, resId) public void saveGesture(String name, Gesture gesture) {
library.addGesture(name, gesture);
library.save();
}
Accessibility
6WDUWLQJZLWK$QGURLG $3,OHYHO DQDFFHVVLELOLW\$3,GHVLJQHGWRPDNH$QGURLG
DSSVPRUHZLGHO\XVDEOHE\EOLQGDQGORZYLVLRQXVHUVLVDYDLODEOH7KHFRUHRIWKH
DFFHVVLELOLW\ $3, LV WKH AccessibilityService DQ DEVWUDFW FODVV WKDW LV UXQ LQ WKH
EDFNJURXQG
7KLVXVHRIWKHAccessibilityServiceXOWLPDWHO\PHDQV\RXDUHH[WHQGLQJLWDQGWKXV
LWLVDVHUYLFHDQGPXVWEHGHFODUHGZLWKLQWKHPDQLIHVW1RWRQO\PXVWWKHGHFODUDWLRQ
EHPDGHEXWWKLVW\SHRIVHUYLFHDOVRKDVDVSHFLILFLQWHQWLWPXVWKDQGOH android.
accessibilityservice.AccessibilityService <service android:name=".Accessibility">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
Accessibility | 407
</intent-filter>
</service>
:KHQFUHDWLQJDQAccessibilityServiceFODVV\RXPXVWGHFODUHWKHIHHGEDFNDQGHYHQW
W\SHV<RXGRWKLVE\JHQHUDWLQJDQAccessibilityServiceInfoREMHFWVHWWLQJWKHYDUL
RXVYDULDEOHVDQGWKHQSDVVLQJLWWRWKHsetServiceInfo()PHWKRG3OHDVHQRWHWKDWWKH
V\VWHPZLOOSLFNXSWKLVLQIRUPDWLRQRQO\DIWHULWKDVERXQGWRWKHFODVVREMHFW
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
// timeout (ms) after the most recent event of a given type before notification
info.notificationTimeout = 50;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC |
AccessibilityServiceInfo.FEEDBACK_AUDIBLE |
AccessibilityServiceInfo.FEEDBACK_HAPTIC |
AccessibilityServiceInfo.FEEDBACK_SPOKEN |
AccessibilityServiceInfo.FEEDBACK_VISUAL;
info.packageNames = new String[1];
// only handle this package
info.packageNames[0] = getPackageName();
setServiceInfo(info);
2QFHWKHVHUYLFHKDVVWDUWHGDQGWKHV\VWHPKDVERXQGWRLWHYHQWVZLOOEHUHFHLYHGDQG
SDVVHGWRWKHonAccessibilityEvent()PHWKRG
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// here we check to see if it was a 'click' event
if(event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
// do something with the click event
}
}
$WWKLVSRLQW\RXKDYHYDULRXVRSWLRQVWRUHDFWWRWKHHYHQW8VXDOO\WKH9LEUDWRU6HUYLFH
LVXVHGWRSURYLGHDKDSWLFUHVSRQVHDORQJZLWKVRXQGRUVSHHFK7KH9LEUDWRULVD
V\VWHPOHYHOVHUYLFHWKDWLVUHWULHYHGYLDWKHFRQWH[WgetSystemService()PHWKRG2QFH
WKHVibratorREMHFWLVUHWULHYHGDSDWWHUQRIYLEUDWLRQVFDQEHDSSOLHGZKHQUHDFWLQJWR
DQHYHQW
// get Vibrator
Vibrator vibrate = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
// pattern to vibrate with
long[] pattern = new long[] { 0L, 100L };
// vibrate
vibrate.vibrate(pattern, -1);
$QGURLGSURYLGHVD7H[W7R6SHHFKHQJLQHWKDW\RXFDQXVHWRSURYLGHVSHHFK7RXVH
WKLV \RX LQVWDQWLDWH DQ android.speech.tts.TextToSpeech FODVV ZKLFK LQLWLDOL]HV WKH
7H[W7R6SHHFKHQJLQH2QFHLQLWLDOL]HGVSHHFKFDQEHSURGXFHGE\FDOOLQJWKHspeak
PHWKRGRQWKHFODVV$YDULHW\RIPHWKRGVDQGRSWLRQVFDQEHFDOOHGVXFKDVVHWWLQJ
ORFDOHSLWFKRUVSHHFKVSHHG%HVXUHWRFDOOWKH shutdownPHWKRGZKHQWKH TextTo
SpeechLQVWDQFHLVQRORQJHUQHHGHGVRWKDWLWVUHVRXUFHVFDQEHUHFRYHUHG
408 | Chapter 16:ಗSensors, NFC, Speech, Gestures, and Accessibility
TextToSpeech tts = new TextToSpeech(thisContext, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// notification when the TextToSpeech Engine has been initialized
}
);
// say 'click'
tts.speak("Click", 2, null);
// no longer needed and thus we shut down and release the resources
tts.shutdown();
)RUPRUHDFFHVVLELOLW\UHODWHGUHVRXUFHVFKHFNRXWWKH(\HV)UHHRSHQVRXUFHSURMHFW
KWWSFRGHJRRJOHFRPSH\HVIUHH Accessibility | 409
CHAPTER 17
Communication, Identity, Sync, and
Social Media
2QHRIWKHSULPDU\GDWDW\SHVWKDWLVVWRUHGDQGXVHG DQGUHXVHG LQ$QGURLGLVFRQWDFW
GDWD7KLVFRQVLVWVRIWKHYDULRXVSLHFHVRILQIRUPDWLRQDVVRFLDWHGZLWKDFRQWDFW¢
QDPHSKRQHQXPEHUHPDLODQGVRRQ,Q$QGURLG $3,OHYHO FRQWDFWGDWDZDV
VLJQLILFDQWO\H[SDQGHG DOORZLQJDFFHVVWRPXOWLSOHDFFRXQWVDQGVXSSRUWIRUDJJUHJD
WLRQRIVLPLODUFRQWDFWV ,QHDUOLHUFKDSWHUVZHFRYHUHGWKHXVHRIFRQWHQWSURYLGHUV
DQG$QGURLGGDWDEDVHFODVVHVVRZHZLOOQRWFRYHUWKDWSUHOLPLQDU\PDWHULDOLQWKLV
FKDSWHU,QVWHDGZHZLOOIRFXVRQWKHXVHRIWKH&RQWDFWV&RQWUDFWFRQWHQWSURYLGHU
Account Contacts
7R DFFHVV WKH DFFRXQW FRQWDFWV WKH IROORZLQJ SHUPLVVLRQV PXVW EH SURYLGHG LQ WKH
PDQLIHVW
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
:LWKLQ DQ Activity ZH FDQ XVH WKH managedQuery PHWKRG WR TXHU\ WKH Contacts
Contract.ContactsGDWDDQGUHWXUQDCursorIRURXUXVH
private Cursor getContacts() {
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME
};
String selection = null;
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME +
" COLLATE LOCALIZED ASC";
411
}
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
)RU FRPSOHWH LQIRUPDWLRQ RQ WKH FROXPQV DQG FRQVWDQWV DYDLODEOH LQ WKH Contacts
Contract.ContactsFODVVUHIHUWRWKHGHYHORSHUGRFXPHQWDWLRQDWKWWSGHYHORSHUDQ
GURLGFRPUHIHUHQFHDQGURLGSURYLGHU&RQWDFWV&RQWUDFW&RQWDFWVKWPO
2QFH ZH KDYH WKH Cursor ZH FDQ ORDG LW ZLWKLQ D SimpleCursorAdapter DQG KDYH LW
GLVSOD\WKHVSHFLILFGDWDILHOGVZHZDQWLQWKLVFDVHWKH£GLVSOD\QDPH¤RIWKHFRQWDFW
String[] fields = new String[] {
ContactsContract.Data.DISPLAY_NAME
};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.contact,
cursor,
fields,
new int[] {R.id.name});
// get the listview
ListView contactlist = (ListView) findViewById(R.id.contactlist);
// set the adapter and let it render
contactlist.setAdapter(adapter);
+HUHLVWKHOD\RXWWKDWFRQWDLQVWKHListView UHIHUHQFHGDVR.id.contactlist <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff"
>
<ListView android:id="@+id/contactlist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
+HUHLVWKHFRQWDFWOD\RXW UHIHUHQFHGDVR.layout.contact XVHGIRUWKHSimpleCursor
Adapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#fff"
>
<TextView android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="25sp"
android:padding="5dp"
412 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
/>
</LinearLayout>
+HUHZHGHOHWHDFRQWDFWE\SURYLGLQJWKHCursorDQGWKHSRVLWLRQZLWKLQWKHCursorWR
GHOHWH
private void deleteContact(Cursor cursor, int position) {
cursor.moveToPosition(position);
long id = cursor.getLong(0);
String lookupkey = cursor.getString(1);
Uri uri = ContactsContract.Contacts.getLookupUri(id, lookupkey);
}
String[] selectionArgs = null;
String where = null;
ContentResolver cr = getContentResolver();
cr.delete(uri, where, selectionArgs);
7R DGG D FRQWDFW LQ WKLV H[DPSOH ZH FRQVWUXFW D FROOHFWLRQ RI ContentProvider
OperationVDQGEDWFKDSSO\WKHP1RWHWKDWZHILUVWLQVHUWWKHQHZFRQWDFWDQGWKHQ
DGGWKHSKRQHLQIRUPDWLRQVKRXOGLWEHDYDLODEOH DVLWLVLQWKLVFDVH ,QRUGHUWRGR
WKH LQVHUWV ZH JHQHUDWH DQ LQVHUWVSHFLILF ContentProviderOperation E\ FUHDWLQJ D
ContentProviderOperation.Builder ZLWK WKH SimpleCursorContentProviderOperation
.newInsert()PHWKRGDQGWKHQEXLOGLQJZLWKWKHbuild()PHWKRG
String accountNameWeWant = "SpecialAccount";
String phone = "8885551234";
String name = "Bob";
String accountname = null;
String accounttype = null;
Account[] accounts = AccountManager.get(this).getAccounts();
// find the account we want. if we don't find it we use 'null' - the default
for(Account account : accounts) {
if(account.equals(accountNameWeWant)) {
accountname = account.name;
accounttype = account.type;
break;
}
}
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert
(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountname)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accounttype)
.build());
// create the new contact
ops.add(
Account Contacts | 413
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
name)
.build());
// if there is a phone num we add it
if(phone.getText() != null
&& phone.getText().toString().trim().length() > 0) {
ops.add(ContentProviderOperation.newInsert
(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER,
phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.TYPE_HOME)
.build());
}
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
e.printStackTrace();
}
Authentication and Synchronization
6WDUWLQJZLWK$QGURLG $3,OHYHO LWLVSRVVLEOHWRZULWHFXVWRPV\QFSURYLGHUVWR
LQWHJUDWHZLWKV\VWHPFRQWDFWVFDOHQGDUVDQGVRIRUWK6\QFKURQL]LQJZLWKDUHPRWH
VHUYLFHDWWKLVWLPHLVXQIRUWXQDWHO\DSUHFDULRXVHQGHDYRUDVDQ\PLVVWHSDWSDUWLFXODU
SRLQWVFDQOLWHUDOO\FDXVHWKH$QGURLGV\VWHPWRFUDVKDQGUHERRW ZLWKYHU\OLWWOHLQ
GLFDWLRQDVWRZKDWZDVGRQHLQFRUUHFWO\ +RSHIXOO\DV$QGURLGHYROYHVV\QFKURQL]LQJ
ZLOO EHFRPH HDVLHU DQG OHVV WULFN\ )RU QRZ WKH SURFHVV FRQVLVWV RI WZR SDUWV¢
DXWKHQWLFDWLRQ $FFRXQW$XWKHQWLFDWRU DQGV\QFKURQL]DWLRQ 6\QF3URYLGHU %HIRUHGLYLQJLQWRWKHGHWDLOVRIWKHWZRSDUWVZHZRXOGOLNHWRQRWHWKDWWKHH[DPSOHV
ZHSURYLGHKHUHKDYHWZRFRPSRQHQWV¢DVHUYHUVLGHDQGWKH$QGURLGFOLHQWVLGH7KH
VHUYHUVLGHWKDWZHXVHLVDEDVLFZHEVHUYLFHWKDWDFFHSWVVSHFLILF GETUHTXHVWVDQG
UHVSRQGVEDFNZLWKD-621IRUPDWWHGUHVSRQVH7KHUHOHYDQW GET85,DVZHOODVWKH
H[DPSOHUHVSRQVHDUHSURYLGHGZLWKLQHDFKVHFWLRQ7KHVRXUFHWKDWFRPHVZLWKWKLV
ERRNLQFOXGHVWKHIXOOVHUYHUVLGHVRXUFHIRUFRPSOHWHQHVV
7KHRWKHUWKLQJWRQRWHLVWKDWLQWKHH[DPSOHZHSURYLGHZHFKRRVHWRV\QFZLWKWKH
DFFRXQWFRQWDFWV7KLVLVQRWWKHRQO\WKLQJWKDW\RXFDQV\QFXS<RXFDQV\QFXSZLWK
DQ\FRQWHQWSURYLGHU\RXKDYHDFFHVVWRRUHYHQWRDSSOLFDWLRQVSHFLILFVWRUHGGDWD
414 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
Authentication
7RJHWWKHFOLHQWWRDXWKHQWLFDWHZLWKDUHPRWHVHUYHUXVLQJWKH$QGURLG$FFRXQW$X
WKHQWLFDWRUV\VWHPWKUHHSLHFHVPXVWEHSXWLQWRSODFH
‡ $VHUYLFHWKDWLVWULJJHUHGE\WKH android.accounts.AccountAuthenticatorLQWHQW
DQGWKDWLQLWVonBindPHWKRGUHWXUQVDVXEFODVVRIAbstractAccountAuthenticator
‡ $QDFWLYLW\WKDWSURPSWVWKHXVHUWRHQWHUKHUFUHGHQWLDOV
‡ $Q;0/ILOHGHVFULELQJKRZ\RXUDFFRXQWVKRXOGORRNZKHQGLVSOD\HGWRWKHXVHU
/HW¦V DGGUHVV WKH VHUYLFH ILUVW ,Q WKH PDQLIHVW ZH QHHG android.permission.
AUTHENTICATE_ACCOUNTSWREHHQDEOHG
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
7KHQ WKH VHUYLFH QHHGV WR EH GHVFULEHG LQ WKH PDQLIHVW 1RWH WKDW WKH
android.accounts.AccountAuthenticator LQWHQW LV LQFOXGHG ZLWKLQ WKH intent-filter
GHVFULSWRU7KHPDQLIHVWDOVRGHVFULEHVDUHVRXUFHIRUWKHAccountAuthenticator
<service android:name=".sync.authsync.AuthenticationService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
7KH UHVRXUFH ZH LQGLFDWHG LQ WKH PDQLIHVW IROORZV ,Q SDUWLFXODU LW GHVFULEHV WKH
accountTypeWKDWZLOOGLVWLQJXLVKWKLVDXWKHQWLFDWRUIURPRWKHUDXWKHQWLFDWRUVXVLQJWKH
DFFRXQW¦VGHILQLWLRQ%HYHU\FDUHIXOZLWKWKLV;0/GRFXPHQW HJGRQRWGLUHFWO\
DVVLJQDVWULQJWRWKHandroid:labelRUKDYHDPLVVLQJGUDZDEOHLQGLFDWHG DV$QGURLG
ZLOOFUDVKDQGEXUQWKHPRPHQW\RXDWWHPSWWRDGGDQHZDFFRXQW IURPZLWKLQWKH
$FFRXQW 6\QFVHWWLQJV <?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.oreilly.demo.pa.ch17.sync"
android:icon="@drawable/icon"
android:smallIcon="@drawable/icon"
android:label="@string/authlabel"
/>
1RZWKDWWKHVHUYLFHLVGHVFULEHGZLWKLQWKHPDQLIHVWZHFDQWXUQWRWKHVHUYLFHLWVHOI
1RWHWKDWWKHonBind()PHWKRGUHWXUQVDQAuthenticatorFODVV7KLVFODVVH[WHQGVWKH
AbstractAccountAuthenticatorFODVV
package com.oreilly.demo.pa.ch17.sync.authsync;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
Authentication and Synchronization | 415
public class AuthenticationService extends Service {
private static final Object lock = new Object();
private Authenticator auth;
@Override
public void onCreate() {
synchronized (lock) {
if (auth == null) {
auth = new Authenticator(this);
}
}
}
}
@Override
public IBinder onBind(Intent intent) {
return auth.getIBinder();
}
%HIRUHZHJHWWRWKHIXOOVRXUFHRIWKHAuthenticatorFODVVWKHUHLVDPHWKRGZLWKLQWKH
AbstractAccountAuthenticator WKDW LV LPSRUWDQW¢addAccount() 7KLV PHWKRG XOWL
PDWHO\LVFDOOHGZKHQWKHEXWWRQLQGLFDWLQJRXUFXVWRPDFFRXQWLVVHOHFWHGIURPWKH
$GG$FFRXQWVFUHHQ$ LoginActivity RXUFXVWRP ActivityZKLFKZLOODVNWKHXVHU
WRVLJQLQ LVGHVFULEHGZLWKLQWKHIntentWKDWLVSODFHGZLWKLQWKHBundleWKDWLVUHWXUQHG
7KHAccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSENH\LQFOXGHGLQWKHLQWHQWLV
YLWDODVLWLQFOXGHVWKHAccountAuthenticatorResponseREMHFWWKDWLVQHHGHGWRVKLSEDFN
WKHDFFRXQWNH\VRQFHWKHXVHUKDVVXFFHVVIXOO\FHUWLILHGDJDLQVWWKHUHPRWHVHUYLFH
public class Authenticator extends AbstractAccountAuthenticator {
public Bundle addAccount(AccountAuthenticatorResponse response,
String accountType, String authTokenType,
String[] requiredFeatures, Bundle options) {
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
}
1RZIRUWKHIXOOAuthenticatorDFWLYLW\WKDWH[WHQGVWKHAbstractAccountAuthenticator
package com.oreilly.demo.pa.ch17.sync.authsync;
import com.oreilly.demo.pa.ch17.sync.LoginActivity;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
416 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
public class Authenticator extends AbstractAccountAuthenticator {
public static final String AUTHTOKEN_TYPE
= "com.oreilly.demo.pa.ch17.sync";
public static final String ACCOUNT_TYPE
= "com.oreilly.demo.pa.ch17.sync";
private final Context context;
public Authenticator(Context context) {
super(context);
this.context = context;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response,
String accountType, String authTokenType,
String[] requiredFeatures, Bundle options) {
}
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response,
Account account, Bundle options) {
return null;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response,
String accountType) {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle loginOptions) {
}
return null;
@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response,
Account account, String[] features) {
return null;
Authentication and Synchronization | 417
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle loginOptions) {
return null;
}
}
)RUWKLVH[HUFLVHWKHUHPRWHVHUYHUKDVDORJLQ$3,FDOO DFFHVVHGYLDDQ+77385,
WKDWWDNHVWKHXVHUQDPHDQGSDVVZRUGDVYDULDEOHV6KRXOGWKHORJLQVXFFHHGWKHUH
VSRQVHFRPHVEDFNZLWKD-621VWULQJFRQWDLQLQJDWRNHQ
uri: http://<serverBaseUrl>:<port>/login?username=<name>&password=<pass>
response: { "token" : "someAuthenticationToken" }
7KHLoginActivityWKDWUHTXHVWVWKHXVHUWRLQSXWWKHXVHUQDPHDQGSDVVZRUGIRUWKH
DFFRXQWWKHQSURFHHGVWRFRQWDFWWKHUHPRWHVHUYHU2QFHWKHH[SHFWHG-621VWULQJLV
UHWXUQHGWKH handleLoginResponse()PHWKRGLVFDOOHGDQGSDVVHVWKHUHOHYDQWLQIRU
PDWLRQDERXWWKHDFFRXQWEDFNWRWKHAccountManager
package com.oreilly.demo.pa.ch17.sync;
import org.json.JSONObject;
import com.oreilly.demo.pa.ch17.R;
import com.oreilly.demo.pa.ch17.sync.authsync.Authenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorActivity;
import android.accounts.AccountManager;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;
public class LoginActivity extends AccountAuthenticatorActivity {
public static final String PARAM_AUTHTOKEN_TYPE
= "authtokenType";
public static final String PARAM_USERNAME
= "username";
public static final String PARAM_PASSWORD
= "password";
private String username;
private String password;
@Override
public void onCreate(Bundle savedInstanceState) {
418 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
super.onCreate(savedInstanceState);
getVars();
setupView();
}
@Override
protected Dialog onCreateDialog(int id) {
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage("Attemping to login");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
return dialog;
}
private void getVars() {
username = getIntent().getStringExtra(PARAM_USERNAME);
}
private void setupView() {
setContentView(R.layout.login);
findViewById(R.id.login).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
login();
}
});
if(username != null) {
((EditText) findViewById(R.id.username)).setText(username);
}
}
private void login() {
if(((EditText) findViewById(R.id.username)).getText() == null ||
((EditText) findViewById(R.id.username)).getText().toString().
trim().length()
< 1) {
Toast.makeText(this, "Please enter a Username",
Toast.LENGTH_SHORT).show();
return;
}
if(((EditText) findViewById(R.id.password)).getText() == null ||
((EditText) findViewById(R.id.password)).getText().toString().
trim().length()
< 1) {
Toast.makeText(this, "Please enter a Password",
Toast.LENGTH_SHORT).show();
return;
}
username = ((EditText) findViewById(R.id.username)).getText().toString();
password = ((EditText) findViewById(R.id.password)).getText().toString();
showDialog(0);
Authentication and Synchronization | 419
Handler loginHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == NetworkUtil.ERR) {
dismissDialog(0);
Toast.makeText(LoginActivity.this, "Login Failed: "+
msg.obj, Toast.LENGTH_SHORT).show();
} else if(msg.what == NetworkUtil.OK) {
handleLoginResponse((JSONObject) msg.obj);
}
}
};
}
NetworkUtil.login(getString(R.string.baseurl),
username, password, loginHandler);
private void handleLoginResponse(JSONObject resp) {
dismissDialog(0);
final Account account = new Account(username, Authenticator.ACCOUNT_TYPE);
if (getIntent().getStringExtra(PARAM_USERNAME) == null) {
AccountManager.get(this).addAccountExplicitly(account, password, null);
ContentResolver.setSyncAutomatically(account,
ContactsContract.AUTHORITY, true);
} else {
AccountManager.get(this).setPassword(account, password);
}
}
Intent intent = new Intent();
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, username);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
Authenticator.ACCOUNT_TYPE);
if (resp.has("token")) {
intent.putExtra(AccountManager.KEY_AUTHTOKEN, resp.optString("token"));
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(RESULT_OK, intent);
finish();
}
7KHLoginActivity¦VOD\RXW;0/LV
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#fff">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="0dip"
420 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
android:layout_weight="1">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="5dip"
android:paddingBottom="13dip"
android:paddingLeft="20dip"
android:paddingRight="20dip">
<EditText
android:id="@+id/username"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minWidth="250dip"
android:scrollHorizontally="true"
android:capitalize="none"
android:hint="Username"
android:autoText="false" />
<EditText
android:id="@+id/password"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minWidth="250dip"
android:scrollHorizontally="true"
android:capitalize="none"
android:autoText="false"
android:password="true"
android:hint="Password"
android:inputType="textPassword" />
</LinearLayout>
</ScrollView>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:minHeight="54dip"
android:paddingTop="4dip"
android:paddingLeft="2dip"
android:paddingRight="2dip">
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:minWidth="100dip"
android:text="Login" />
</FrameLayout>
</LinearLayout>
$WWKLVSRLQWWKHDFFRXQWLVHVWDEOLVKHGDQGLVUHDG\WREHXVHGWRV\QFKURQL]HGDWD
Authentication and Synchronization | 421
Download from Wow! eBook <www.wowebook.com>
Synchronization
7RV\QFKURQL]HDQDFFRXQW¦VGDWDZHRQFHDJDLQDUHGHDOLQJZLWKWKUHHSLHFHV¢DVHUYLFH
WKDWLVUHJLVWHUHGWROLVWHQIRUDQandroid.content.SyncAdapterLQWHQWDQGWKDWUHWXUQV
DQAbstractThreadedSyncAdapterH[WHQGHGFODVVRQWKHonBind()PHWKRGDQ;0/GH
VFULSWRUGHVFULELQJWKHVWUXFWXUHRIWKHGDWDWKDWLVWREHYLHZHGDQGV\QFHGDQGDFODVV
H[WHQGLQJWKHAbstractThreadedSyncAdapterWKDWKDQGOHVWKHDFWXDOV\QF
)RU RXU H[DPSOH ZH ZLVK WR V\QF XS FRQWDFW LQIRUPDWLRQ IRU WKH DFFRXQW WKDW ZH
GHVFULEHGLQWKHSUHFHGLQJVHFWLRQ'RQRWHWKDWFRQWDFWLQIRUPDWLRQLVQRWWKHRQO\
LQIRUPDWLRQ\RXFDQV\QFXS<RXFDQV\QFXSZLWKDQ\FRQWHQWSURYLGHU\RXKDYH
DFFHVVWRRUHYHQWRDSSOLFDWLRQVSHFLILFVWRUHGGDWD
7KHIROORZLQJSHUPLVVLRQVDUHLQGLFDWHGLQWKHPDQLIHVW
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
1RZZHGHVFULEH WKH VHUYLFH ZH LQWHQG WRXVH1RWHWKDWWKH android.content.Sync
Adapter LQWHQW LV LQFOXGHG DQG ERWK D VWUXFWXUH IRU WKH FRQWDFW GDWD DQG WKH
SyncAdapterDUHGHVFULEHG
<service android:name=".sync.authsync.SyncService">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
<meta-data android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
,QWKH sync-adapter;0/UHVRXUFHQRWHWKH accountTypeGHVFULSWRU7KHFRQWHQWZH
LQWHQGWRZRUNZLWKLVWKH$QGURLGFRQWDFWVGDWD
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.oreilly.demo.pa.ch17.sync"
/>
+HUH LV WKH FRQWDFWV GHVFULSWRU ;0/ 1RWH WKH QDPHV RI WKH YDULRXV FROXPQV ZH
GHVFULEHG
422 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
<?xml version="1.0" encoding="utf-8"?>
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
<ContactsDataKind
android:mimeType=
"vnd.android.cursor.item/vnd.com.oreilly.demo.pa.ch17.sync.profile"
android:icon="@drawable/icon"
android:summaryColumn="data2"
android:detailColumn="data3"
android:detailSocialSummary="true" />
</ContactsSource>
7KHSyncServiceZHFUHDWHGUHWXUQVWKHSyncAdapterFODVV7KLVLVRXUFXVWRPFODVVWKDW
H[WHQGVAbstractThreadedSyncAdapter
package com.oreilly.demo.pa.ch17.sync.authsync;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class SyncService extends Service {
private static final Object lock = new Object();
private static SyncAdapter adapter = null;
@Override
public void onCreate() {
synchronized (lock) {
if (adapter == null) {
adapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
@Override
public void onDestroy() {
adapter = null;
}
@Override
public IBinder onBind(Intent intent) {
return adapter.getSyncAdapterBinder();
}
}
&RQWLQXLQJZLWKWKLVH[HUFLVHZHFUHDWHDgetfriendsPHWKRGRQWKHUHPRWHVHUYHUVLGH
7KLVWDNHVWKHWRNHQWKDWZDVSDVVHGEDFNDQGVWRUHGE\WKHVXFFHVVIXOORJLQFRGHGXS
LQWKHSUHYLRXVVHFWLRQDQGDWLPHLQGLFDWLQJWKHODVWWLPHWKHFDOOZDVPDGH LILWLVWKH
ILUVWWLPH0LVSDVVHG 7KHUHVSRQVHLVDQRWKHU-621VWULQJGHVFULELQJWKHIULHQGV ZLWK
,'QDPHDQGSKRQH WKHWLPHWKHFDOOZDVPDGH LQ8QL[WLPHRQWKHVHUYHU DQGD
KLVWRU\GHVFULELQJDGGLWLRQVDQGGHOHWLRQVRIIULHQGVIRUWKLVDFFRXQW,QWKHKLVWRU\
WKHtypeILHOGLV0WRDGGDQG1WRGHOHWH7KHwhoILHOGLVWKH,'RIWKHIULHQGDQGWKH
timeVKRZVZKHQWKHRSHUDWLRQRFFXUUHG
Authentication and Synchronization | 423
uri: http://<serverBaseUrl>:<port>/getfriends?token=<token>&time=<lasttime>
response:
{
"time" : 1295817666232,
"history" : [
{
"time" : 1295817655342,
"type" : 0,
"who" : 1
}
],
"friend" : [
{
"id" : 1,
"name" : "Mary",
"phone" : "8285552334"
}
]
}
7KHAbstractThreadedSyncAdapterFODVVH[WHQGLQJSyncAdapterIROORZV
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private final Context context;
private static long lastsynctime = 0;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
this.context = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
String authtoken = null;
try {
authtoken = AccountManager.get(context).blockingGetAuthToken(account,
Authenticator.AUTHTOKEN_TYPE, true);
ListFriends friendsdata =
ListFriends.fromJSON(
NetworkUtil.getFriends(context.getString(R.string.baseurl),
authtoken, lastsynctime, null));
lastsynctime = friendsdata.time;
sync(account, friendsdata);
} catch (Exception e) {
e.printStackTrace();
}
}
private void sync(Account account, ListFriends data) {
424 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
}
}
// MAGIC HAPPENS
7KHIXOOSyncAdapterFODVVIROORZVZLWKWKHYDULRXVDFWLRQVWKDWRFFXUZKHQWKHV\QF
PHWKRGUHFHLYHVGDWD7KHYDULRXVDGGLWLRQVDQGGHOHWLRQVRIWKHFRQWDFWLQIRUPDWLRQ
DUHLQFOXGHG ContactDQGContentProviderRSHUDWLRQVDUHFRYHUHGLQSUHYLRXVFKDSWHUV
DQGVHFWLRQV
package com.oreilly.demo.pa.ch17.sync.authsync;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentUris;
import android.content.Context;
import android.content.SyncResult;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import com.oreilly.demo.pa.ch17.R;
import com.oreilly.demo.pa.ch17.sync.NetworkUtil;
import com.oreilly.demo.pa.ch17.sync.dataobjects.Change;
import com.oreilly.demo.pa.ch17.sync.dataobjects.ListFriends;
import com.oreilly.demo.pa.ch17.sync.dataobjects.User;
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private final Context context;
private static long lastsynctime = 0;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
this.context = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
String authtoken = null;
try {
// get accounttoken. this eventually calls our Authenticator
// getAuthToken()
authtoken = AccountManager.get(context).blockingGetAuthToken(account,
Authenticator.AUTHTOKEN_TYPE, true);
ListFriends friendsdata =
ListFriends.fromJSON(
NetworkUtil.getFriends(context.getString(R.string.baseurl),
Authentication and Synchronization | 425
authtoken, lastsynctime, null));
lastsynctime = friendsdata.time;
sync(account, friendsdata);
} catch (Exception e) {
e.printStackTrace();
}
}
// where the magic happens
private void sync(Account account, ListFriends data) {
User self = new User();
self.username = account.name;
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
// cycle through the history to find the deletes
if(data.history != null && !data.history.isEmpty()) {
for(Change change : data.history) {
if(change.type == Change.ChangeType.DELETE) {
ContentProviderOperation op = delete(account, change.who);
if(op != null) ops.add(op);
}
}
}
// cycle through the friends to find ones we do not already have and add them
if(data.friends != null && !data.friends.isEmpty()) {
for(User f : data.friends) {
ArrayList<ContentProviderOperation> op = add(account, f);
if(op != null) ops.addAll(op);
}
}
}
if(!ops.isEmpty()) {
try {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY,
ops);
} catch (Exception e) {
e.printStackTrace();
}
}
// adding a contact. note we are storing the id referenced in the response
// from the server in the SYNC1 field - this way we can find it with this
// server based id
private ArrayList<ContentProviderOperation> add(Account account, User f) {
long rawid = lookupRawContact(f.id);
if(rawid != 0) return null;
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
426 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
ops.add(ContentProviderOperation.newInsert(
ContactsContract.RawContacts.CONTENT_URI)
.withValue(RawContacts.SOURCE_ID, 0)
.withValue(RawContacts.SYNC1, f.id)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE,
Authenticator.ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME,
account.name)
.build());
if(f.name != null && f.name.trim().length() > 0) {
ops.add(ContentProviderOperation.newInsert(
ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,
0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.
StructuredName.DISPLAY_NAME, f.name)
.build());
}
if(f.phone != null && f.phone.trim().length() > 0) {
ops.add(ContentProviderOperation.newInsert
(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, f.phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.TYPE_HOME)
.build());
}
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
"vnd.android.cursor.item/vnd.com.oreilly.demo.pa.ch17.sync.profile")
.withValue(ContactsContract.Data.DATA2, "Ch15 Profile")
.withValue(ContactsContract.Data.DATA3, "View profile")
.build()
);
return ops;
}
// delete contact via the server based id
private ContentProviderOperation delete(Account account, long id) {
long rawid = lookupRawContact(id);
if(rawid == 0) return null;
return ContentProviderOperation.newDelete(
ContentUris.withAppendedId(
ContactsContract.RawContacts.CONTENT_URI,
rawid))
.build();
}
Authentication and Synchronization | 427
// look up the actual raw id via the id we have stored in the SYNC1 field
private long lookupRawContact(long id) {
long rawid = 0;
Cursor c = context.getContentResolver().query(
RawContacts.CONTENT_URI, new String[] {RawContacts._ID},
RawContacts.ACCOUNT_TYPE + "='" +
Authenticator.ACCOUNT_TYPE + "' AND "+
RawContacts.SYNC1 + "=?",
new String[] {String.valueOf(id)},
null);
try {
if(c.moveToFirst()) {
rawid = c.getLong(0);
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
return rawid;
}
}
$Q LPSRUWDQW GHWDLO PLJKW EH PLVVHG LQ WKH SUHYLRXV SyncAdapter FODVV GXULQJ WKH
onPerformSync()FDOOZHDWWHPSWWRJHWWKHauthtokenIURPWKHAccountManagerE\XVLQJ
WKH blockingGetAuthToken() PHWKRG 7KLV HYHQWXDOO\ FDOOV WKH AbstractAccount
AuthenticatorWKDWLVDVVRFLDWHGZLWKWKLVDFFRXQW,QWKLVFDVHLWFDOOVWKHAuthentica
tor FODVV ZH SURYLGHG LQ WKH SUHYLRXV VHFWLRQ :LWKLQ WKH Authenticator FODVV WKH
PHWKRGgetAuthToken()LVFDOOHG$QH[DPSOHIROORZV
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
String authTokenType, Bundle loginOptions) {
// check and make sure it is the right token type we want
if (!authTokenType.equals(AUTHTOKEN_TYPE)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ERROR_MESSAGE,
"invalid authTokenType");
return result;
}
// if we have the password, let's try and get the current
// authtoken from the server
String password = AccountManager.get(context).getPassword(account);
if (password != null) {
JSONObject json = NetworkUtil.login(context.getString(R.string.baseurl),
account.name, password, true, null);
if(json != null) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
result.putString(AccountManager.KEY_AUTHTOKEN,
json.optString("token"));
428 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
}
}
return result;
}
// if all else fails let's see about getting the user to log in
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(LoginActivity.PARAM_USERNAME, account.name);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
Bluetooth
%OXHWRRWKZDVWKHQLFNQDPHIRU.LQJ+DUDOGRI'HQPDUN7KHIROORZLQJDUWLFOHRQ
6XQ¦VGHYHORSHUVLWH KWWSGHYHORSHUVVXQFRPPRELOLW\PLGSDUWLFOHVEOXHWRRWK FRQ
WDLQVDYDULHW\RILQIRUPDWLRQDERXW%OXHWRRWKLQFOXGLQJWKHSRVVLEO\DSRFU\SKDODV
VHUWLRQWKDWDUXQLFVWRQHHUHFWHGLQKRQRURI+DUDOGVWDWHV
+DUDOG&KULVWLDQL]HGWKH'DQHV
+DUDOGFRQWUROOHG'HQPDUNDQG1RUZD\
+DUDOGWKLQNVQRWHERRNVDQGFHOOXODUSKRQHVVKRXOGFRPPXQLFDWHVHDPOHVVO\
7RVKRZ\RXKRZWRXVH$QGURLG¦V%OXHWRRWKFODVVHVLQ\RXUDSSOLFDWLRQVZHZLOOFUHDWH
DXWLOLW\IRUFRQQHFWLQJWRDQGWUDQVIHUULQJGDWDWRDQGIURP%OXHWRRWKGHYLFHV7KLV
FRGHLVEDVHGRQWKH%OXHWRRWK&KDWH[DPSOHLQWKH$QGURLG6'.,WKDVEHHQJHQHUDO
L]HGWRFRYHUPRUHDSSOLFDWLRQVRI%OXHWRRWKDQGLWKDVEHHQPRGLILHGWRPDNHLWHDVLHU
WRDGDSWWR\RXUSXUSRVHV
$VZHH[SORUH$QGURLG¦V%OXHWRRWK$3,VZHZLOOVHHKRZWKLVFRGHPDNHVXVHRIWKHVH
$3,VDQGKRZ\RXFDQXVHWKHFRGHIRUDSSOLFDWLRQVSHFLILFSXUSRVHVLQFOXGLQJDVD
GLDJQRVWLFWRROIRU%OXHWRRWKGHYHORSPHQW
)LUVWZHZLOOOHDUQPRUHDERXWKRZ%OXHWRRWKZRUNVDQGKRZLWLVLPSOHPHQWHGLQ
$QGURLG
The Bluetooth Protocol Stack
7KLVVHFWLRQWDNHVDORRNDWWKHVWDQGDUGVDQGSURWRFROVWKDWPDNHXSWKH%OXHWRRWK
SURWRFROVWDFN VHH)LJXUH 7KHVHSURWRFROVDQGVWDQGDUGVDUHZKDWFKDUDFWHUL]H
%OXHWRRWKWKHNLQGVRIGDWD%OXHWRRWKLVGHVLJQHGWRPRYHKRZPDQ\GHYLFHVFDQEH
FRQQHFWHGDWWKHVDPHWLPHODWHQF\DQGVRRQ
%OXHWRRWKKDVHPHUJHGDVDVHSDUDWHIRUPRIQHWZRUNLQJEHFDXVHLWLVD£SHUVRQDODUHD
QHWZRUN¤RU3$1DOVRUHIHUUHGWRDVDSLFRQHW%OXHWRRWKLVGHVLJQHGWRFRQQHFWXS
WRHLJKWGHYLFHVDQGWRFDUU\GDWDDWDPD[LPXPRIDSSUR[LPDWHO\WKUHHPHJDELWVSHU
VHFRQG7KHFRQQHFWHGGHYLFHVPXVWEHFORVHWRRQHDQRWKHUZLWKLQDERXWPHWHUV
%OXHWRRWK RSHUDWHV DW YHU\ ORZ SRZHU OHYHOV LQ PLOOLZDWWV 7KDW PHDQV YHU\ VPDOO
Bluetooth | 429
)LJXUH7KH$QGURLG%OXHWRRWKSURWRFROVWDFN
EDWWHULHVFDQODVWDORQJWLPHD%OXHWRRWKKHDGVHWZLWKDWLQ\OLJKWZHLJKWEDWWHU\FDQ
ODVW IRU KRXUV RI WDONLQJ¢DERXW DV ORQJ DV WKH PXFK ODUJHU EDWWHU\ LQ \RXU PRELOH
KDQGVHWFDQODVWEHFDXVHWKHPRELOHUDGLRVLJQDOPXVWEHDEOHWRUHDFKDUHODWLYHO\
GLVWDQWDQWHQQD
7KHNLQGVRIGHYLFHVIRUZKLFK%OXHWRRWKLVXVHIXOLQFOXGHORZDQGPHGLXPGDWDUDWH
GHYLFHVVXFKDVNH\ERDUGVPLFHWDEOHWVSULQWHUVVSHDNHUVKHDGSKRQHVDQGKHDGVHWV
DQGWKHPRELOHDQGSHUVRQDOFRPSXWLQJGHYLFHVWKRVHSHULSKHUDOGHYLFHVPD\ZDQWWR
WDONWR%OXHWRRWKDOVRVXSSRUWVFRQQHFWLRQVDPRQJ3&VDQGPRELOHKDQGVHWV
Bluetooth-specific protocols and adopted protocols
2QHXVHIXOZD\RIWKLQNLQJDERXWWKH%OXHWRRWKSURWRFROVWDFNLVWRVHSDUDWHLWLQWR
%OXHWRRWKVSHFLILFSURWRFROVDQG£DGRSWHG¤SURWRFROVWKDWUXQRQWRSRI%OXHWRRWK
7DNHQWRJHWKHU%OXHWRRWKDQGWKHDGRSWHGSURWRFROVFDQEHGDXQWLQJO\FRPSOH[EXW
LI\RXVHWDVLGHIRUDZKLOHWKHIDFWWKDWODUJHFRPSOH[SURWRFROVVXFKDV2%(;DQG
7&3,3UXQRQWRSRI%OXHWRRWKLW¦VPRUHXQGHUVWDQGDEOH7KHUHIRUHZHZLOOVWDUWZLWK
WKHORZHUOD\HUVRI%OXHWRRWKDQGHPSKDVL]HKRZWKHVHOD\HUVVKDSHKRZ\RXFDQPDNH
XVHRI%OXHWRRWK
$QRWKHUXVHIXOPHQWDOPRGHORI%OXHWRRWKLVWKDWLWUHSODFHVVHULDOSRUWV7KLVPHDQV
WKHORZHUOD\HUVRI%OXHWRRWKHPXODWHDQGHQDEOH\RXWRPDQDJHDYLUWXDOVHWRIVHULDO
FDEOHVEHWZHHQSHULSKHUDOV7KLVLVWKHW\SHRI%OXHWRRWKSURWRFROZHZLOOEHXVLQJ
7KLV LQ WXUQ HQDEOHV XV WR XVH WKH VLPSOH java.io FODVVHV InputStream DQG Output
StreamWRUHDGDQGZULWHGDWD
430 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
Bluez: The Linux Bluetooth Implementation
$PRELOHKDQGVHWPD\ZDQWWRFRQQHFWWRDOONLQGVRI%OXHWRRWKGHYLFHVXQOLNHSH
ULSKHUDOGHYLFHVWKDWQHHGWREHFRQQHFWDEOHRQO\WRDFRPSXWHURUKDQGVHW7KDWPHDQV
DPRELOHKDQGVHWZDQWVWRKDYHDIDLUO\FRPSOHWHLPSOHPHQWDWLRQRI%OXHWRRWKDQGWKH
DGRSWHGSURWRFROVDVZHOODVDXVHULQWHUIDFHWKDWHQDEOHVWKHQHFHVVDU\LQWHUDFWLRQVIRU
PDNLQJDQGPDQDJLQJFRQQHFWLRQVDQGIRUXVLQJDSSOLFDWLRQVWKDWFRPPXQLFDWHRYHU
%OXHWRRWK
$QGURLGXVHVWKH%OXH]%OXHWRRWKVWDFNZKLFKLVWKHPRVWFRPPRQO\XVHG%OXHWRRWK
VWDFNIRU/LQX[,WVXSHUVHGHGDSURMHFWFDOOHG2SHQ%7,QIRUPDWLRQRQ%OXH]FDQEH
IRXQGDWWKH%OXH]SURMHFWVLWHKWWSZZZEOXH]RUJ
%OXH]ZDVGHYHORSHGDW4XDOFRPPDQGKDVEHHQDGRSWHGLQWRWKH/LQX[NHUQHO7KH
SURMHFWZDVEHJXQLQDQGKDVEHHQDQDFWLYHDQGZHOOVXSSRUWHGSURMHFWHYHUVLQFH
%OXH]LVWKHUHIRUHDVWDEOHDQGFRPSDWLEOHLPSOHPHQWDWLRQ¢DQRWKHUUHDVRQ/LQX[LV
DJRRGFKRLFHIRUKDQGVHWRSHUDWLQJV\VWHPV
Using Bluetooth in Android Applications
8VLQJ%OXHWRRWKLQ$QGURLGPHDQVXVLQJFODVVHVWKDWZHUHGHVLJQHGWRHQFDSVXODWHWKH
ZD\%OXHWRRWKZRUNVLQWKH$QGURLGRSHUDWLQJV\VWHPWKH%OXH]VWDFNSURYLGHVZD\V
WRHQXPHUDWHGHYLFHVOLVWHQIRUFRQQHFWLRQVDQGXVHFRQQHFWLRQVWKHjava.ioSDFNDJH
SURYLGHVFODVVHVIRUUHDGLQJDQGZULWLQJGDWDDQGWKHHandlerDQGMessageFODVVHVSUR
YLGHDZD\WREULGJHEHWZHHQWKHWKUHDGVWKDWPDQDJH%OXHWRRWKLQSXWDQGRXWSXWDQG
WKHXVHULQWHUIDFH/HW¦VWDNHDORRNDWWKHFRGHDQGKRZWKHVHFODVVHVDUHXVHG
&RPSLOLQJDQGUXQQLQJWKLVFRGHZLOOJLYH\RXDQLGHDRIZKDW$QGURLG¦V%OXHWRRWK
FODVVHVFDQGRIRUDSSOLFDWLRQVWKDWQHHGWREXLOGVLPSOHFRQQHFWLRQVWRQHDUE\GHYLFHV
7KHILUVWVWHSLQWU\LQJRXWWKLV%OXHWRRWKDSSOLFDWLRQLVWRSDLU\RXUKDQGVHWZLWKD3&
7KHQ\RXQHHGDSURJUDPWKDWPRQLWRUVZKDWWKH3&KDVUHFHLYHGYLD%OXHWRRWKWRVHH
WKDWZKDW\RXVHQGIURPWKLVDSSOLFDWLRQJRWWR\RXU3&,QWKLVFDVHZH¦OOXVHWKH/LQX[
XWLOLW\hcidump
6WDUWWKHSURJUDPXQGHUWKHGHEXJJHULI\RXZDQWWRVHWVRPHEUHDNSRLQWVDQGVWHS
WKURXJKLWHVSHFLDOO\WKHSDUWVRIWKHDSSOLFDWLRQWKDWRSHQDQGDFFHSWFRQQHFWLRQV
<RXFDQFUHDWHWKHFRQQHFWLRQIURP\RXU3&XVLQJWKH%OXHPDQDSSOHWLQ/LQX[RU
IURPWKHDSS2QFHWKHFRQQHFWLRQLVFUHDWHGVWDUW hcidumpLQDWHUPLQDOWRVHHWKDW
ZKDW\RXW\SHGLQWRWKHDSSLVUHFHLYHGE\WKH3&8VHWKHIODJVVKRZQEHORZWRVKRZ
RQO\WKHFRQWHQWRIWKH%OXHWRRWKFRQQHFWLRQ
sudo hcidump -a -R
1RZZKDW\RXVHQGIURP\RXUGHYLFHVKRXOGVKRZXSDVWKHRXWSXWRIKFLGXPSRQ
\RXU3&
Bluetooth | 431
Bluetooth and related I/O classes
7KLVSURJUDPUHOLHVRQWKH BluetoothAdapterFODVVWRFRQWUROWKHGHYLFH¦V%OXHWRRWK
DGDSWHUWKHBluetoothDeviceFODVVWRUHSUHVHQWWKHVWDWHRIWKHFRQQHFWHGGHYLFHDQG
WKHBluetoothSocketFODVVWRUHSUHVHQWVRFNHWVIRUOLVWHQLQJIRUDQGPDNLQJFRQQHFWLRQV
package com.finchframework.bluetooth;
import android.os.Handler;
import android.os.Message;
public class BtHelperHandler extends Handler {
public enum MessageType {
STATE,
READ,
WRITE,
DEVICE,
NOTIFY;
}
public Message obtainMessage(MessageType message, int count, Object obj) {
return obtainMessage(message.ordinal(), count, -1, obj);
}
public MessageType getMessageType(int ordinal) {
return MessageType.values()[ordinal];
}
}
7KHBtHelperHandlerFODVVGHILQHVVRPHFRQVWDQWVDQGSURYLGHVDOLWWOHELWRIZUDSSHU
FRGHWKDWPDNHVPHVVDJHUHODWHGPHWKRGVFOHDQHU
BtSPPHelper.javaLVZKDWHQFDSVXODWHVRXUXVHRIWKH%OXHWRRWK6HULDO3RUW3URWRFRO
633 package com.finchframework.bluetooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import com.finchframework.finch.R;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
432 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
/**
* Helper class that runs AsyncTask objects for communicating with a Bluetooth
* device. This code is derived from the Bluetoothchat example, but modified in
* several ways to increase modularity and generality: The Handler is in a
* separate class to make it easier to drop into other components.
*
* Currently this only does Bluetooth SPP. This can be generalized to other
* services.
*/
public class BtSPPHelper {
// Debugging
private final String TAG = getClass().getSimpleName();
private static final boolean D = true;
public enum State {
NONE,
LISTEN,
CONNECTING,
CONNECTED;
}
// Name for the SDP record when creating server socket
private static final String NAME = "BluetoothTest";
// Unique UUID for this application
private static final UUID SPP_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final BtHelperHandler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private State mState;
private Context mContext;
/**
* Constructor. Prepares a new Bluetooth SPP session.
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public BtSPPHelper(Context context, BtHelperHandler handler) {
mContext = context;
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = State.NONE;
mHandler = handler;
}
/**
* Set the current state of the chat connection
* @param state The current connection state
*/
private synchronized void setState(State state) {
Bluetooth | 433
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
}
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(BtHelperHandler.MessageType.STATE,
-1, state).sendToTarget();
/**
* Return the current connection state.
*/
public synchronized State getState() {
return mState;
}
/**
* Start the session. Start AcceptThread to begin a
* session in listening (server) mode.
*
* Typically, call this in onResume()
*/
public synchronized void start() {
if (D) Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
}
// Start the thread to listen on a BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(State.LISTEN);
/**
* Start the ConnectThread to initiate a connection to a remote device.
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == State.CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
434 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(State.CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket
*
The BluetoothSocket on which the connection was made
* @param device
*
The BluetoothDevice that has been connected
*/
private synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
if (D)
Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one
// device
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
}
// Send the name of the connected device back to the UI Activity
mHandler.obtainMessage(BtHelperHandler.MessageType.DEVICE, -1,
device.getName()).sendToTarget();
setState(State.CONNECTED);
Bluetooth | 435
/**
* Stop all threads
*/
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
setState(State.NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != State.CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
private void sendErrorMessage(int messageId) {
setState(State.LISTEN);
mHandler.obtainMessage(BtHelperHandler.MessageType.NOTIFY, -1,
mContext.getResources().getString(messageId)).sendToTarget();
}
/**
* This thread listens for incoming connections.
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
436 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
}
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, SPP_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
Download from Wow! eBook <www.wowebook.com>
// Listen to the server socket if we're not connected
while (mState != BtSPPHelper.State.CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BtSPPHelper.this) {
switch (mState) {
case LISTEN:
case CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case NONE:
case CONNECTED:
// Either not ready or already connected.
// Terminate new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread");
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
Bluetooth | 437
}
}
}
/**
* This thread runs while attempting to make an outgoing connection
* with a device. It runs straight through; the connection either
* succeeds or fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
sendErrorMessage(R.string.bt_unable);
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure",
e2);
}
// Start the service over to restart listening mode
BtSPPHelper.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BtSPPHelper.this) {
438 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
}
}
}
mConnectThread = null;
// Start the connected thread
connected(mmSocket, mmDevice);
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
Bluetooth | 439
mHandler.obtainMessage(BtHelperHandler.MessageType.READ,
bytes, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
sendErrorMessage(R.string.bt_connection_lost);
break;
}
}
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
}
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BtHelperHandler.MessageType.WRITE, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
7KH BtSPPHelperFODVVEULQJVWKHXVHRIWKHVHFODVVHVWRJHWKHUDQGDOVRFRQWDLQVWKH
GHILQLWLRQRISULYDWHThreadVXEFODVVHVWKDWOLVWHQIRUFRQQHFWDQGUXQFRQQHFWLRQV
7KLV LV DOVR ZKHUH WKH java.io SDFNDJH PHHWV $QGURLG %OXHWRRWK WKH Bluetooth
Socket REMHFWV FRQWDLQ PHWKRGV WKDW UHWXUQ UHIHUHQFHV WR InputStream DQG Output
StreamREMHFWVWREHXVHGWRUHDGDQGZULWHGDWDRQWKHVRFNHWFRQQHFWLRQ
package com.finchframework.bluetooth;
import java.util.Set;
import com.finchframework.finch.R;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
440 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
/**
* Derived from the Bluetooth Chat example, an activity that enables
* picking a paired or discovered Bluetooth device
*/
public class DeviceListActivity extends Activity {
// Debugging
private static final String TAG = "DeviceListActivity";
private static final boolean D = true;
// Return Intent extra
public static String EXTRA_DEVICE_ADDRESS = "device_address";
// Member fields
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up the window
setContentView(R.layout.device_list);
// Set result CANCELED in case the user backs out
setResult(Activity.RESULT_CANCELED);
// Initialize the button to perform device discovery
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
});
// Initialize array adapters. One for already paired devices and
// one for newly discovered devices
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this,
R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this,
R.layout.device_name);
Bluetooth | 441
// Find and set up the ListView for paired devices
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// Find and set up the ListView for newly discovered devices
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// Get the local Bluetooth adapter
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
// Get a set of currently paired devices
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() +
"\n" + device.getAddress());
}
} else {
String noDevices =
getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// Make sure we're not doing discovery anymore
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
// Unregister broadcast listeners
this.unregisterReceiver(mReceiver);
}
/**
* Start device discover with the BluetoothAdapter
*/
442 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
private void doDiscovery() {
if (D) Log.d(TAG, "doDiscovery()");
// Indicate scanning in the title
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// Turn on sub-title for new devices
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// If we're already discovering, stop it
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBtAdapter.startDiscovery();
}
// The on-click listener for all devices in the ListViews
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// Cancel discovery because it's costly and we're about to connect
mBtAdapter.cancelDiscovery();
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
}
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
finish();
};
// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(
device.getName() + "\n" + device.getAddress());
Bluetooth | 443
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices =
getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}
The DeviceListActivity class
7KLVDFWLYLW\GLVSOD\VDGLDORJWKDWOLVWVNQRZQGHYLFHVDQGHQDEOHVWKHXVHUWRUHTXHVW
DVFDQIRUGHYLFHV8QOLNHWKRVHSDUWVRIWKHDSSZKHUH ThreadVXEFODVVHVDUHXVHGWR
LPSOHPHQWDV\QFKURQRXV,2DQGHandlerVXEFODVVHVSDVVWKHUHVXOWVWRWKH8,WKUHDG
WKH startDiscoveryPHWKRGRIWKH BluetoothAdapterFODVVNLFNVRIIDVHSDUDWHWKUHDG
DQGFRPPXQLFDWHVUHVXOWVXVLQJEURDGFDVWLQWHQWV$ BroadcastReceiverLVXVHGKHUH
WRSURFHVVWKRVHUHVXOWV
The BtConsoleActivity class
7KHBtConsoleActivityFODVVFUHDWHVDFKDWOLNHDFWLYLW\IRULQWHUDFWLQJZLWKD%OXHWRRWK
GHYLFH7KHPHQXVLQWKLVDFWLYLW\HQDEOHFRQQHFWLQJWRDGHYLFHDQGWKHPDLQYLHZLQ
WKLVDFWLYLW\LVDVFUROOLQJOLVWRIGDWDVHQWDQGUHFHLYHG$WWKHERWWRPRIWKHVFUHHQ
WKHUH LV DQ (GLW7H[W YLHZ IRU HQWHULQJ WH[W WR EH VHQW WR WKH RWKHU HQG RI WKH 633
FRQQHFWLRQ
+DQGOHUFODVVHVDUHXVHGWRJOXHWKHVLQJOHWKUHDGHG8,WRWKHWKUHDGVWKDWOLVWHQFRQ
QHFWDQGSHUIRUP,2RQVRFNHWFRQQHFWLRQV
444 | Chapter 17:ಗCommunication, Identity, Sync, and Social Media
CHAPTER 18
The Android Native Development
Kit (NDK)
-DYD1DWLYH,QWHUIDFH -1, LVDSDUWRIWKH-DYDVWDQGDUGWKDWHQDEOHVGHYHORSHUVWRZULWH
QDWLYHPHWKRGVLQRWKHUODQJXDJHVVXFKDV&DQG&DQGFDOOWKRVHPHWKRGVIURP
-DYDFRGH7KLVLVHVSHFLDOO\XVHIXOZKHQ\RXZDQWWRXVHSODWIRUPVSHFLILFIHDWXUHVRU
WDNH DGYDQWDJH RI KDUGZDUH LQ WKH SODWIRUP VXFK DV DFKLHYLQJ IDVWHU QXPHULFDO
FRPSXWDWLRQE\WDNLQJDGYDQWDJHRI)38LQVWUXFWLRQVHWH[WHQVLRQVRUOHWWLQJJUDSKLFV
LQWHQVLYHFRGHH[SORLWWKH2SHQ*/$3,7KLVFKDSWHUFRYHUV-1,EDVLFVIRUSURJUDP
PHUV XVLQJ WKH $QGURLG 1'. )RU IXUWKHU GHWDLOV VHH WKH -DYD 1DWLYH ,QWHUIDFH
6SHFLILFDWLRQ
7\SLFDO JRRG FDQGLGDWHV IRU LPSOHPHQWDWLRQ LQ & RU & XVLQJ WKH 1'. DUH VHOI
FRQWDLQHG&38LQWHQVLYHRSHUDWLRQVWKDWGRQ¦WDOORFDWHPXFKPHPRU\VXFKDVVLJQDO
SURFHVVLQJSK\VLFVVLPXODWLRQDQGVRRQ6LPSO\UHFRGLQJDUDQGRPPHWKRGWRUXQ
LQ&XVXDOO\GRHVQRWUHVXOWLQDODUJHSHUIRUPDQFHLQFUHDVH:KHQH[DPLQLQJZKHWKHU
\RXVKRXOGGHYHORSLQQDWLYHFRGHWKLQNDERXW\RXUUHTXLUHPHQWVDQGVHHZKHWKHUWKH
$QGURLG6'.DOUHDG\SURYLGHVWKHIXQFWLRQDOLW\\RXQHHG<RX¦OOILQGWKDWLQPRVWFDVHV
WKH$QGURLG6'.ZLOOIXOILOO\RXUQHHGV,WLVZRUWKUHPHPEHULQJWKDWDOWKRXJKPRVW
$QGURLGSODWIRUPVDUH$50ULJKWQRZWKHUHDUHOLNHO\WREHRWKHUV VXFKDV$WRP LQ
WKHIXWXUH8VLQJ1'.PDNHV\RXUFRGHQRQSRUWDEOH
-1,LVZKDW$QGURLGXVHVWRDFFHVVFRGHLPSOHPHQWHGLQ&RU&DQGWKH$QGURLG
1'.LVDQRSWLRQDOH[WHQVLRQWRWKH$QGURLG6'.WKDWVXSSRUWVWKHXVHRI&RU&
FRGHLQ$QGURLGDSSOLFDWLRQV7RPDNHWKLQJVDVHDV\DVSRVVLEOHIRUWKH-DYDGHYHORSHU
-1,OHWVDQDWLYHPHWKRGXVH-DYDREMHFWVLQWKHVDPHZD\WKDW-DYDFRGHXVHVWKHVH
REMHFWV:LWKLQWKHQDWLYHPHWKRG-DYDREMHFWVFDQEHFUHDWHGLQVSHFWHGDQGXVHGWR
SHUIRUPLWVWDVNV7KLVVDPHDELOLW\WRLQVSHFWDQGXVH-DYDREMHFWVHQDEOHVWKHQDWLYH
PHWKRGWRXVHRWKHU-DYDREMHFWVSDVVHGWRLWIURPWKH-DYDDSSOLFDWLRQ DQGWKXVWKH
$QGURLGDSSOLFDWLRQ 445
Native Methods and JNI Calls
-1,FUHDWHGFHUWDLQFRQYHQWLRQVWRDOORZFDOOVWRPHWKRGVIURPRWKHUODQJXDJHV7KH
FKDQJHVRQWKHVLGHRIWKHQDWLYHPHWKRGV HVVHQWLDOO\&RU&OLEUDULHV DUHJUHDWHU
WKDQWKHFKDQJHVUHTXLUHGRQWKH-DYDVLGH
Conventions on the Native Method Side
:KHQDYLUWXDOPDFKLQH 90 ¢LQ$QGURLG¦VFDVH'DOYLN¢LQYRNHVDIXQFWLRQLPSOH
PHQWHGLQ&RU&LWSDVVHVWZRVSHFLDOSDUDPHWHUV
‡ $JNIEnvSRLQWHUZKLFKLVDNLQGRIKDQGOHIRUWKHWKUHDGLQWKH90WKDWFDOOHGWKH
QDWLYHPHWKRG
‡ $jobjectSRLQWHUZKLFKLVDUHIHUHQFHWRWKHFDOOLQJFODVV
7KHVHSDUDPHWHUVDUHSDVVHGWUDQVSDUHQWO\WR-DYDFRGH7KDWLVWKH\GRQRWDSSHDULQ
WKHPHWKRGVLJQDWXUHGHFODUHGLQWKHFDOOLQJ-DYDFRGH7KH-DYDFDOOMXVWH[SOLFLWO\
SDVVHVDQ\RWKHUSDUDPHWHUVQHHGHGE\WKHFDOOHGIXQFWLRQ
$-1,IXQFWLRQPD\ORRNOLNHWKLV
/* sample method where the Java call passed no parameters */
void Java_ClassName_MethodName (JNIEnv *env, jobject obj) {
/* do something */
}
/* another sample method with two parameters passed, returning a double */
jdouble Java_ClassName_MethodName ( JNIEnv* env, jobject obj,
jdouble x, jdouble y) {
return x + y;
}
7KHVHH[DPSOHVVKRZWKHWZRSDUDPHWHUVSDVVHGDXWRPDWLFDOO\WRHYHU\QDWLYHPHWKRG
DQGWZRSDUDPHWHUVZLWKW\SHVWKDWPDSWR-DYDW\SHV
:KHQDQDWLYHPHWKRGLVFDOOHGLWUXQVLQWKHVDPHSURFHVVDQGWKHVDPHWKUHDGDVWKH
-DYDFRGHWKDWFDOOVLW$VZHZLOOVHHODWHULQWKLVFKDSWHULWFDQDOORFDWHPHPRU\IURP
WKH-DYDKHDSWRWDNHDGYDQWDJHRIJDUEDJHFROOHFWLRQRURXWVLGHWKH-DYDKHDSWRFLU
FXPYHQW-DYDPHPRU\PDQDJHPHQW9DULDEOHVDOORFDWHGRQWKHVWDFNLQ&RU&FRGH
KDYHWKHVDPHVHPDQWLFVDVLQQDWLYHH[HFXWDEOHVLQWKRVHODQJXDJHV7KH\DUHDOORFDWHG
IURPWKHVWDFNVSDFHIRUWKHSURFHVVWKH\UXQLQ
-1,SURYLGHVW\SHVWKDWFRUUHVSRQGWR-DYDW\SHVDVVKRZQLQ7DEOH
446 | Chapter 18:ಗThe Android Native Development Kit (NDK)
7DEOH'DWDPDSSLQJ
Native type
Java type
Description
boolean
jboolean
Unsigned 8 bits
byte
jbyte
Signed 8 bits
char
jchar
Unsigned 16 bits
short
jshort
Signed 16 bits
int
jint
Signed 32 bits
long
jlong
Signed 64 bits
float
jfloat
32 bits
double
jdouble
64 bits
void
void
N/A
,QFRPSRXQGW\SHVVXFKDVREMHFWVDUUD\VDQGVWULQJVWKHQDWLYHFRGHPXVWH[SOLFLWO\
FRQYHUW WKH GDWD E\ FDOOLQJ FRQYHUVLRQ PHWKRGV ZKLFK DUH DFFHVVLEOH WKURXJK WKH
JNIEnvSRLQWHU
Conventions on the Java Side
%HIRUHQDWLYHPHWKRGVFDQEHXVHGZLWKLQD-DYDFODVVWKHOLEUDU\FRQWDLQLQJQDWLYH
PHWKRGVPXVWEHORDGHGE\FDOOLQJSystem.loadLibrary7\SLFDOO\WKHFODVVWKDWQHHGV
WKHQDWLYHPHWKRGZRXOGVWDWLFDOO\ORDGWKLV1DWLYHPHWKRGVDFFHVVHGE\DFODVVDUH
GHFODUHGLQWKHFODVVXVLQJWKHnativeNH\ZRUG
public class ClassWithNativeMethod {
public native double nativeMethod();
static {
System.loadLibrary("sample");
}
// native method
// load lib called 'sample'
public static void main(String[] args) {
ClassWithNativeMethod cwnm = new ClassWithNativeMethod();
double answer = cwnm.nativeMethod();
// call native method
System.out.println("Answer is : "+answer);
}
}
Native Methods and JNI Calls | 447
The Android NDK
7KH$QGURLG1DWLYH'HYHORSPHQW.LW 1'. LVDFRPSDQLRQWRROWRWKH$QGURLG6'.
,I \RX XVH WKH 1'. WR FUHDWH QDWLYH FRGH \RXU DSSOLFDWLRQV DUH VWLOO SDFNDJHG LQWR
DQDSNILOHDQGUXQLQVLGHD90RQWKHGHYLFH7KHIXQGDPHQWDO$QGURLGDSSOLFDWLRQ
PRGHOGRHVQRWFKDQJH
Setting Up the NDK Environment
,QRUGHUWRXVHWKH1'.\RXPXVWILUVWLQVWDOODQGVHWXSWKH6'.7KHV\VWHPUH
TXLUHPHQWVIRULQVWDOOLQJDQGXVLQJWKH1'.DUHDVIROORZV
‡ :LQGRZV;3 ELW RU9LVWD RUELW ZLWK&\JZLQRUODWHU
‡ 0DF26;RUODWHU
‡ /LQX[ RUELW
1HFHVVDU\GHYHORSPHQWWRROVWKDWDUHQRWSURYLGHGLQWKH1'.DUHDVIROORZV
‡ *180DNHRUODWHU
‡ $UHFHQWYHUVLRQRI$ZN HLWKHU*18$ZNRU1DZN
)LUVW GRZQORDG DQG LQVWDOO WKH 1'. KWWSGHYHORSHUDQGURLGFRPVGNQGNLQGH[
KWPO ,QVWDOODWLRQLVVLPSOHXQ]LSWKH1'.LQWRDQ\GLUHFWRU\+HUHZHZLOOUHIHUWR
WKDWGLUHFWRU\DVQGN
2QFHWKH1'.LVGRZQORDGHGDQGLQVWDOOHG\RXZLOOILQGTXLWHDELWRIGRFXPHQWDWLRQ
ORFDWHGLQWKHQGNGRFVGLUHFWRU\ :HKLJKO\UHFRPPHQGWKDW\RXUHDGWKHGRFXPHQ
WDWLRQVWDUWLQJZLWK29(59,(:KWPO$OVRLQFOXGHGLQWKH1'.DUHVDPSOHV ORFDWHG
LQQGNVDPSOHV 7KHVDPSOHVFRYHUTXLWHDELWPRUHWKDQWKLVFKDSWHUZLOOVRDIWHU\RX
KDYHXVHGWKH1'.DELWZHUHFRPPHQGWKDW\RXJRWKURXJKWKHVDPSOHV
Compiling with the NDK
,QRUGHUWRGHYHORSQDWLYHFRGHZLWKWKH1'.\RXZLOOQHHGWRGRWKHIROORZLQJ
&UHDWHDMQLGLUHFWRU\ZLWKLQ\RXUSURMHFW
3ODFH\RXUQDWLYHVRXUFHLQWKHMQLGLUHFWRU\
&UHDWH DQ $QGURLGPN ILOH DQG RSWLRQDOO\ DQ $SSOLFDWLRQPN ILOH LQ WKH MQL
GLUHFWRU\
5XQWKHndk/ndk-buildFRPPDQGIURPZLWKLQWKHMQLGLUHFWRU\
7KHRSWLRQDO$SSOLFDWLRQPNILOHGHVFULEHVZKDWQDWLYHPRGXOHVDUHQHHGHGIRU\RXU
DSSOLFDWLRQ DV ZHOO DV VSHFLILF $%, W\SHV WR EXLOG DJDLQVW )RU PRUH GHWDLOV FKHFN
$33/,&$7,210.KWPOLQWKHGRFXPHQWDWLRQ$VDPSOH$SSOLFDWLRQPNILOHIROORZV
# Build both ARMv5TE and ARMv7-A machine code.
APP_ABI := armeabi armeabi-v7a
448 | Chapter 18:ಗThe Android Native Development Kit (NDK)
# What platform to build against (android-3 (1.5) - android-9 (2.3))
APP_PLATFORM := android-9
7KH$QGURLGPNILOHGHVFULEHV\RXUVRXUFHWRWKHEXLOGV\VWHP,WLVUHDOO\DWLQ\*18
0DNHILOHIUDJPHQWWKDWLVSDUVHGE\WKHEXLOGV\VWHPZKHQEXLOGLQJ\RXUDSS)RUPRUH
GHWDLOV UHDG WKH $1'52,'0.KWPO GRFXPHQWDWLRQ ILOH $ VDPSOH $QGURLGPN
IROORZV
# Must define the LOCAL_PATH and return the current dir
LOCAL_PATH := $(call my-dir)
# Cleans various variables... making a clean build
include $(CLEAR_VARS)
# Identify the module/library's name
LOCAL_MODULE
:= sample
# Specify the source files
LOCAL_SRC_FILES := sample.c
# Load local libraries (here we load the log library)
LOCAL_LDLIBS
:= -llog
# Build the shared library defined above
include $(BUILD_SHARED_LIBRARY)
2QFH \RX KDYH ZULWWHQ $QGURLGPN DQG RSWLRQDOO\ $SSOLFDWLRQPN DQG WKH QDWLYH
VRXUFHILOHVWKHPVHOYHVUXQ ndk/ndk-buildZLWKLQWKHSURMHFWGLUHFWRU\WREXLOG\RXU
OLEUDULHV6KRXOGWKHEXLOGEHVXFFHVVIXOWKHVKDUHGOLEUDULHVZLOOEHFRSLHGLQWR\RXU
DSSOLFDWLRQ¦VURRWSURMHFWGLUHFWRU\DQGDGGHGWRLWVEXLOG
JNI, NDK, and SDK: A Sample App
7R KHOS \RX XQGHUVWDQG KRZ WKH 6'. DQG QDWLYH VRXUFH FDQ EH SXW WRJHWKHU ZH
SURYLGHWKHIROORZLQJVDPSOHDSS,WGHVFULEHVDQDFWLYLW\FDOOHGSampleActivityWithNa
tiveMethods7KH$QGURLGPDQLIHVWIUDJPHQWLV
<activity android:name=".SampleActivityWithNativeMethods"
android:label="Sample Activity With Native Methods"
android:debuggable="true" />
7KHSampleActivityWithNativeMethodsDFWLYLW\XVHVWKHIROORZLQJOD\RXW
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="@+id/whatami"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="What CPU am I?"
The Android NDK | 449
/>
</LinearLayout>
7KHVDPSOH&OLEUDU\VRXUFHKDVDPHWKRGFDOOHGwhatAmIZKLFKRXU-DYDDFWLYLW\ZLOO
KRRNWRWKHEXWWRQZLWKWKH whatami,':HDOVRGHILQHDIXQFWLRQQDPHG LOGINFO
UHVROYLQJWRDQ__android_log_printFDOO7KLVLVKRZWKH$QGURLGORJLVZULWWHQ
// the jni library MUST be included
#include <jni.h>
// the log lib is included
#include <android/log.h>
// usage of log
#define LOGINFO(x...)
__android_log_print(ANDROID_LOG_INFO,"SampleJNI",x)
jstring Java_com_oreilly_demo_pa_ch18_SampleActivityWithNativeMethods_whatAmI(
JNIEnv* env,jobject thisobject) {
LOGINFO("SampleJNI","Sample Info Log Output");
return (*env)->NewStringUTF(env, "Unknown");
}
2XU$QGURLGPNILOHIROORZV1RWHWKDWLWFDXVHVWKHlogOLEUDU\WREHORDGHG
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample
LOCAL_SRC_FILES := sample.c
LOCAL_LDLIBS
:= -llog
include $(BUILD_SHARED_LIBRARY)
)LQDOO\KHUHLVWKH SampleActivityWithNativeMethods-DYDDFWLYLW\¦VVRXUFHFRGH7KH
FODVVORDGVWKHVDPSOHOLEUDU\DQGGHFODUHVWKH whatAmI()QDWLYHPHWKRG:KHQWKH
EXWWRQ LV FOLFNHG WKH whatAmI() PHWKRG LV FDOOHG DQG UHWXUQV "Unknown" 7KLV WKHQ
VKRZVD ToastZLWKWKHVWULQJ "CPU: Unknown",I\RXILQGWKHRXWSXWXQLQIRUPDWLYH
UHVWDVVXUHGWKDWZHZLOOLQFOXGHWKH&38LQIRUPDWLRQLQDODWHUVHFWLRQ
package com.oreilly.pa.ch18;
import com.oreilly.pa.ch18.R;
import android.widget.Toast;
public class SampleActivityWithNativeMethods extends Activity {
static {
System.loadLibrary("sample");
}
// load our sample lib
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample);
450 | Chapter 18:ಗThe Android Native Development Kit (NDK)
}
setupview();
public native String whatAmI();
// sample lib native method
private void setupview() {
findViewById(R.id.whatami).setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
String whatami = whatAmI();
Toast.makeText(getBaseContext(), "CPU: "+whatami,
Toast.LENGTH_SHORT).show();
}
}
});
Android-Provided Native Libraries
7KH1'.FRPHVZLWKWKHIROORZLQJVHWRIKHDGHUVIRUVWDEOHQDWLYH$3,V
‡ libc &OLEUDU\ KHDGHUV
‡ libm PDWKOLEUDU\ KHDGHUV
‡ -1,LQWHUIDFHKHDGHUV
‡ libz =OLEFRPSUHVVLRQ KHDGHUV
‡ liblog $QGURLGORJJLQJ KHDGHU
‡ 2SHQ*/(6DQG2SHQ*/(6 'JUDSKLFVOLEUDULHV KHDGHUV
‡ libjnigraphics SL[HOEXIIHUDFFHVV KHDGHU IRU$QGURLGDQGODWHU
‡ $PLQLPDOVHWRIKHDGHUVIRU&VXSSRUW
‡ 2SHQ6/(6QDWLYHDXGLROLEUDULHV
‡ $QGURLGQDWLYHDSSOLFDWLRQ$3,V
([FHSWIRUWKHOLEUDULHVMXVWOLVWHGQDWLYHV\VWHPOLEUDULHVLQWKH$QGURLG
SODWIRUP DUH QRW VWDEOH DQG PD\ FKDQJH LQ IXWXUH SODWIRUP YHUVLRQV
<RXUDSSOLFDWLRQVVKRXOGXVHRQO\WKHVWDEOHQDWLYHV\VWHPOLEUDULHVSUR
YLGHGLQWKH1'.
6RPHOLEUDULHVVXFKDV libcDQG libmDUHDXWRPDWLFDOO\UHIHUHQFHGLQWKHEXLOGDQG
WKXVQHHGWREHUHIHUHQFHGRQO\LQWKHVRXUFHFRGHDVLQFOXGHV+RZHYHUVRPHOLEUDULHV
DUH QRW DXWRPDWLFDOO\ UHIHUHQFHG DQG WKXV UHTXLUH VSHFLILF VWDWHPHQWV ZLWKLQ WKH
$QGURLGPNEXLOGILOH
+HUHLVDVDPSOH$QGURLGPNILOHWKDWLPSRUWVWKHcpufeaturesPRGXOHZKLFKZLOOJLYH
XVWKHLQIRUPDWLRQPLVVLQJIURPRXUHDUOLHUwhatAmIH[DPSOH
Android-Provided Native Libraries | 451
Download from Wow! eBook <www.wowebook.com>
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample
LOCAL_SRC_FILES := sample.c
LOCAL_LDLIBS
:= -llog
# Here we reference the cpufeatures module
LOCAL_STATIC_LIBRARIES := cpufeatures
include $(BUILD_SHARED_LIBRARY)
# Here we import the cpufeatures modules
$(call import-module,cpufeatures)
7KHIROORZLQJVRXUFH H[WHQGLQJWKHwhatAmIIXQFWLRQZHVKRZHGLQWKHSUHYLRXVVHF
WLRQ XWLOL]HVWKHcpufeaturesPRGXOHZHKDYHLQFOXGHG
// Include the cpu-features module
#include <cpu-features.h>
#include <jni.h>
#include <android/log.h>
#define
LOGINFO(x...)
__android_log_print(ANDROID_LOG_INFO,"SampleJNI",x)
jstring Java_com_oreilly_demo_pa_ch18_SampleActivityWithNativeMethods_whatAmI(
JNIEnv* env, jobject thisobject) {
LOGINFO("SampleJNI","Sample Info Log Output");
// -- Here we use the cpufeatures -- //
uint64_t cpu_features;
if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) {
return (*env)->NewStringUTF(env, "Not ARM");
}
cpu_features = android_getCpuFeatures();
if ((cpu_features & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0) {
return (*env)->NewStringUTF(env, "ARMv7");
} else if ((cpu_features & ANDROID_CPU_ARM_FEATURE_VFPv3) != 0) {
return (*env)->NewStringUTF(env, "ARM w VFPv3 support");
} else if ((cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0) {
return (*env)->NewStringUTF(env, "ARM w NEON support");
}
// -- End cpufeatures usage -- //
}
return (*env)->NewStringUTF(env, "Unknown");
452 | Chapter 18:ಗThe Android Native Development Kit (NDK)
Building Your Own Custom Library Modules
7KLVVHFWLRQSXWVWRJHWKHUVHYHUDOWHFKQLTXHVVKRZQWKURXJKRXWWKHFKDSWHUWRFUHDWH
DQGXVHDVLPSOH&PRGXOHWKDWXVHVWKHPDWKOLEUDU\WRFDOFXODWHDSRZHU:H¦OOVWDUW
ZLWKWKH$QGURLGPNILOH1RWLFHWKDWZHQHHGWREXLOGWKHOLEUDU\ sample_lib DQG
H[SRUWWKHLQFOXGHV7KLVOLEUDU\LVWKHQUHIHUHQFHGLQWKHVDPSOH
LOCAL_PATH := $(call my-dir)
# this is our sample library
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample_lib
LOCAL_SRC_FILES := samplelib/sample_lib.c
# we need to make sure everything knows where everything is
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/samplelib
include $(BUILD_STATIC_LIBRARY)
# sample uses the sample lib we created
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample
LOCAL_SRC_FILES := sample.c
LOCAL_LDLIBS
:= -llog
# We load our sample lib
LOCAL_STATIC_LIBRARIES := sample_lib
include $(BUILD_SHARED_LIBRARY)
:HKDYHDVKRUWKHDGHUILOHVDPSOHBOLEK
#ifndef SAMPLE_LIB_H
#define SAMPLE_LIB_H
extern double calculatePower(double
x, double
y);
#endif
7KHVRXUFHFRGHIRURXUIXQFWLRQVDPSOHBOLEFLV
#include "sample_lib.h"
// we include the math lib
#include "math.h"
// we use the math lib
double calculatePower(double
return pow(x, y);
}
x, double
y) {
)ROORZLQJLVWKHVDPSOHFILOHWKDWJOXHVRXUsample_libOLEUDU\WRWKH-DYDFRGH
// we include the sample_lib
#include "sample_lib.h"
#include <jni.h>
#include <android/log.h>
Building Your Own Custom Library Modules | 453
#define
LOGINFO(x...)
__android_log_print(ANDROID_LOG_INFO,"SampleJNI",x)
jdouble
Java_com_oreilly_demo_pa_ch18_SampleActivityWithNativeMethods_calculatePower(
JNIEnv* env, jobject thisobject, jdouble x, jdouble y) {
LOGINFO("Sample Info Log Output");
// we call sample-lib's calculate method
return calculatePower(x, y);
}
7KHOD\RXWWKHActivityZLOOXVHLV
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<EditText
android:id="@+id/x"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textColor="#000"
android:hint="X Value"
/>
<EditText
android:id="@+id/y"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textColor="#000"
android:hint="Y Value"
/>
<Button
android:id="@+id/calculate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="Calculate X^Y"
/>
</LinearLayout>
)ROORZLQJLVWKH SampleActivityWithNativeMethodsDFWLYLW\WKDWZHKDYHPRGLILHGWR
XVH ZLWK WKLV QHZ OLEUDU\ 7KH VDPSOH OLEUDU\ LV ORDGHG DQG WKH calculatePower()
PHWKRGLVGHFODUHG:KHQWKH£FDOFXODWH¤EXWWRQLVFOLFNHGZHWKHQWDNHWKHQXPEHUV
SURYLGHGIURPWKHWZRHGLWWH[WER[HV XVLQJDGHIDXOWRILIWKHWH[WLVPLVVLQJRULV
454 | Chapter 18:ಗThe Android Native Development Kit (NDK)
QRWDQXPEHU DQGSDVVWKHPWRWKHcalculatePower()PHWKRG7KHUHWXUQHGGRXEOHLV
WKHQSRSSHGXSDVSDUWRIDToast
package com.oreilly.pa.ch18;
import com.oreilly.pa.ch18.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class SampleActivityWithNativeMethods extends Activity {
static {
System.loadLibrary("sample");
}
// load our sample lib
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample);
}
setupview();
// sample lib native method
public native double calculatePower(double x, double y);
private void setupview() {
findViewById(R.id.calculate).setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
String answer = "";
double x = 2;
double y = 2;
String sx = ((EditText) findViewById(R.id.x)).getText().toString();
String sy = ((EditText) findViewById(R.id.y)).getText().toString();
if(sx == null) {
answer = "X defaults to 2\n";
} else {
try {
x = Double.parseDouble(sx);
} catch (Exception e) {
answer = "X is not a number, defaulting to 2\n";
x = 2;
}
}
if(sy == null) {
answer += "Y defaults to 2\n";
Building Your Own Custom Library Modules | 455
} else {
try {
y = Double.parseDouble(sy);
} catch (Exception e) {
answer = "Y is not a number, defaulting to 2\n";
y = 2;
}
}
double z = calculatePower(x, y);
answer += x+"^"+y+" = "+z;
Toast.makeText(SampleActivityWithNativeMethods.this, answer,
Toast.LENGTH_SHORT).show();
});
}
}
}
Native Activities
$QGURLG $3,OHYHO DQG$QGURLG1'.UHYLVLRQOHW\RXZULWHHQWLUHDFWLYLWLHV
DQGDSSOLFDWLRQVDVQDWLYHVRXUFHE\XVLQJWKH NativeActivityFODVVWRDFFHVVWKH$Q
GURLGDSSOLFDWLRQOLIHF\FOH
7RXWLOL]HWKLVPHWKRGWKHandroid.app.NativeActivityQHHGVWREHUHIHUHQFHGLQWKH
$QGURLGPDQLIHVWILOH1RWHWKDWWKHDSSOLFDWLRQUHIHUHQFHKDVDhasCodeDWWULEXWH7KLV
DWWULEXWH VKRXOG EH VHW WR false LI WKHUH LV QR -DYD LQ WKH DSSOLFDWLRQ RQO\ WKH
NativeActivity ,QWKLVFDVHKRZHYHUVLQFHZHGRKDYH-DYDFRGHZHVHWWKHYDOXHWR
true
<!-- This .apk has Java code, so set hasCode to true which is the default. -->
<!-- if this only had a native app (only the activity
called 'android.app.NativeActivity') -->
<!-- then set to false -->
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:hasCode="true" >
<activity android:name=".NDKApp" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="android.app.NativeActivity"
android:label="SampleNativeActivity"
android:debuggable="true" >
<!-- here we declare what lib to reference -->
<meta-data android:name="android.app.lib_name"
456 | Chapter 18:ಗThe Android Native Development Kit (NDK)
</activity>
android:value="sample_native_activity" />
</application>
,QWKLVH[DPSOHZHXVHWKHDQGURLGBQDWLYHBDSSBJOXHKKHDGHUILOHLQVWHDGRIQDWLYHB
DFWLYLW\K7KHQDWLYHBDFWLYLW\KLQWHUIDFHLVEDVHGRQDVHWRIDSSOLFDWLRQSURYLGHGFDOO
EDFNVWKDWZLOOEHFDOOHGE\WKHActivity¦VPDLQWKUHDGZKHQFHUWDLQHYHQWVRFFXU7KLV
PHDQV FDOOEDFNV VKRXOG QRW EORFN DQG WKHUHE\ LV FRQVWUDLQLQJ 7KH DQGURLGB
QDWLYHBDSSBJOXHKILOHH[SRVHVDKHOSHUOLEUDU\ZLWKDGLIIHUHQWH[HFXWLRQPRGHOWKDW
SURYLGHVDPHDQVIRUWKHDSSOLFDWLRQWRLPSOHPHQWLWVRZQPDLQIXQFWLRQLQDGLIIHUHQW
WKUHDG7KHIXQFWLRQPXVWEHQDPHGandroid_main()DQGLVFDOOHGZKHQWKHDSSOLFDWLRQ
LVFUHDWHGDQGDQandroid_appREMHFWLVSDVVHGWRLW7KLVSURYLGHVDPHDQVWRUHIHUHQFH
WKHDSSOLFDWLRQRUDFWLYLW\DQGOLVWHQLQRQYDULRXVOLIHF\FOHHYHQWV
7KHIROORZLQJVLPSOHnativeactivityH[DPSOHFRQVWUXFWVDQActivityDQGOLVWHQVLQRQ
MotionHYHQWV7KHMotionHYHQWV¦[DQG\VFUHHQFRRUGLQDWHVDUHWKHQVHQWWRWKH/RJ&DW
#include <jni.h>
#include <android/log.h>
#include <android_native_app_glue.h>
// usage of log
#define LOGINFO(x...) __android_log_print(ANDROID_LOG_INFO,"SampleNativeActivity",x)
// handle commands
static void custom_handle_cmd(struct android_app* app, int32_t cmd) {
switch(cmd) {
case APP_CMD_INIT_WINDOW:
LOGINFO("App Init Window");
break;
}
}
// handle input
static int32_t custom_handle_input(struct android_app* app, AInputEvent* event) {
// we see a motion event and we log it
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
LOGINFO("Motion Event: x %f / y %f", AMotionEvent_getX(event, 0),
AMotionEvent_getY(event, 0));
return 1;
}
return 0;
}
// This is the function that application code must implement,
// representing the main entry to the app.
void android_main(struct android_app* state) {
// Make sure glue isn't stripped.
app_dummy();
int events;
// set up so when commands happen we call our custom handler
state->onAppCmd = custom_handle_cmd;
Native Activities | 457
// set up so when input happens we call our custom handler
state->onInputEvent = custom_handle_input;
while (1) {
struct android_poll_source* source;
// we block for events
while (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) {
// Process this event.
if (source != NULL) {
source->process(state, source);
}
}
}
// Check if we are exiting.
if (state->destroyRequested != 0) {
LOGINFO("We are exiting");
return;
}
}
7KLVLVWKH$QGURLGPNILOHIRUWKHVDPSOHnativeactivity1RWHWKDWLWORDGVDQGUHIHUV
WRWKHandroid_native_app_gluePRGXOH
LOCAL_PATH := $(call my-dir)
# this is our sample native activity
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample_native_activity
LOCAL_SRC_FILES := sample_nativeactivity.c
LOCAL_LDLIBS
:= -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
)ROORZLQJLVWKHPDLQ-DYD$QGURLGDFWLYLW\WKDWLVFDOOHGZKHQWKHXVHUODXQFKHVWKH
DSSOLFDWLRQ&OLFNLQJRQWKHEXWWRQODXQFKHVWKHNativeActivityWKDWZHKDYHSURYLGHG
package com.oreilly.pa.ch18;
import com.oreilly.pa.ch18.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class NDKApp extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
458 | Chapter 18:ಗThe Android Native Development Kit (NDK)
findViewById(R.id.nativeactivity).setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(getBaseContext(),
android.app.NativeActivity.class));
}
}
// call nativeactivity
});
}
,I \RX FRPSLOH DQG UXQ WKLV H[DPSOH \RX ZLOO QRWH WKDW ZKHQ WKH QDWLYH DFWLYLW\ LV
ODXQFKHGWKHVFUHHQLVEODQNDQGLI\RXDUHYLHZLQJWKH/RJ&DW\RXZLOOVHHYDULRXV
ORJ PHVVDJHV DSSHDU HVSHFLDOO\ ZKHQ PRYLQJ \RXU ILQJHU DFURVV WKH VFUHHQ 7KLV
KRZHYHULVQRWPXFKIXQ6RWRVSUXFHWKLQJVXSZHZLVKWRGRVRPHWKLQJZLWKWKH
VFUHHQ7KHIROORZLQJH[DPSOHDGGVWKHXVHRI2SHQ*/(6WRFKDQJHWKHVFUHHQ¦VFRORU
+HUHLVWKHQDWLYHVRXUFHZLWKWKHDGGLWLRQDO2SHQ*/(6PDWHULDO,WVLPSO\WXUQVWKH
VFUHHQEULJKWUHGZKHQWKHDFWLYLW\LVGLVSOD\HG
#include <jni.h>
#include <android/log.h>
#include <android_native_app_glue.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
// usage of log
#define LOGINFO(x...)
__android_log_print(ANDROID_LOG_INFO,"NativeWOpenGL",x)
struct eglengine {
EGLDisplay display;
EGLSurface surface;
EGLContext context;
};
// initialize the egl engine
static int engine_init_display(struct android_app* app, struct eglengine* engine) {
const EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLint w, h, dummy, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
Native Activities | 459
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(app->window, 0, 0, format);
surface = eglCreateWindowSurface(display, config, app->window, NULL);
context = eglCreateContext(display, config, NULL, NULL);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
LOGINFO("eglMakeCurrent FAIL");
return -1;
}
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
engine->display = display;
engine->context = context;
engine->surface = surface;
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
}
return 0;
// draw to the screen
static void engine_color_screen(struct eglengine* engine) {
if (engine->display == NULL) {
return;
}
glClearColor(255, 0, 0, 1); // let's make the screen all red
glClear(GL_COLOR_BUFFER_BIT);
}
eglSwapBuffers(engine->display, engine->surface);
// when things need to be terminated
static void engine_terminate(struct eglengine* engine) {
if (engine->display != EGL_NO_DISPLAY) {
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
if (engine->context != EGL_NO_CONTEXT) {
eglDestroyContext(engine->display, engine->context);
}
if (engine->surface != EGL_NO_SURFACE) {
eglDestroySurface(engine->display, engine->surface);
}
eglTerminate(engine->display);
}
engine->display = EGL_NO_DISPLAY;
460 | Chapter 18:ಗThe Android Native Development Kit (NDK)
}
engine->context = EGL_NO_CONTEXT;
engine->surface = EGL_NO_SURFACE;
// handle commands
static void custom_handle_cmd(struct android_app* app, int32_t cmd) {
struct eglengine* engine = (struct eglengine*)app->userData;
switch(cmd) {
// things are starting up... let's initialize the engine and color the screen
case APP_CMD_INIT_WINDOW:
if (app->window != NULL) {
engine_init_display(app, engine);
engine_color_screen(engine);
}
break;
case APP_CMD_TERM_WINDOW: // things are ending...let's clean up the engine
engine_terminate(engine);
break;
}
}
// handle input
static int32_t custom_handle_input(struct android_app* app, AInputEvent* event) {
// we see a motion event and we log it
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
LOGINFO("Motion Event: x %f / y %f", AMotionEvent_getX(event, 0),
AMotionEvent_getY(event, 0));
return 1;
}
return 0;
}
// This is the function that application code must implement,
// representing the main entry to the app.
void android_main(struct android_app* state) {
// Make sure glue isn't stripped.
app_dummy();
// here we add the eglengine to the app
struct eglengine engine;
memset(&engine, 0, sizeof(engine));
// set engine as userdata so we can reference
state->userData = &engine;
int events;
// set up so when commands happen we call our custom handler
state->onAppCmd = custom_handle_cmd;
// set up so when input happens we call our custom handler
state->onInputEvent = custom_handle_input;
while (1) {
struct android_poll_source* source;
// we block for events
while (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) {
Native Activities | 461
// Process this event.
if (source != NULL) {
source->process(state, source);
}
// Check if we are exiting.
if (state->destroyRequested != 0) {
LOGINFO("We are exiting");
return;
}
}
}
}
7KH$QGURLGPNILOHIRUWKHsample_native_activity_openglDFWLYLW\ORDGVWKH(*/DQG
*/(6YB&0OLEUDULHV
LOCAL_PATH := $(call my-dir)
# this is our sample native activity with opengl
include $(CLEAR_VARS)
LOCAL_MODULE
:= sample_native_activity_opengl
LOCAL_SRC_FILES := sample_nativeactivity_opengl.c
# loading the log , android, egl, gles libraries
LOCAL_LDLIBS
:= -llog -landroid -lEGL -lGLESv1_CM
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
462 | Chapter 18:ಗThe Android Native Development Kit (NDK)
Index
Symbols
TXRWDWLRQPDUNV >SHUFHQWVLJQ SHULRG VHPLFRORQ DVVLJQPHQWRSHUDWRU ^` FXUO\EUDFHV _ SLSHFKDUDFWHU A
DEVWUDFWFODVVHV
DERXW
DGGLWLRQDOLQIRUPDWLRQ
$EVWUDFW$FFRXQW$XWKHQWLFDWRUFODVV
DGG$FFRXQWPHWKRG
DXWKHQWLFDWLRQH[DPSOH¡
$EVWUDFW7KUHDGHG6\QF$GDSWHUFODVV
RQ3HUIRUP6\QFPHWKRG
V\QFKURQL]DWLRQH[DPSOH¡
$FFHOHUDWH,QWHUSRODWRUFODVV
DFFHOHURPHWHUV
DFFHVVPRGLILHUV
GHILQHG
HQFDSVXODWLRQDQG
JHWWHUVDQGVHWWHUV
DFFHVVLELOLW\$3,
$FFHVVLELOLW\6HUYLFHFODVV
DERXW
RQ$FFHVVLELOLW\(YHQWPHWKRG
VHW6HUYLFH,QIRPHWKRG
$FFHVVLELOLW\6HUYLFH,QIRFODVV
$&&(66B),1(B/2&$7,21SHUPLVVLRQ
$FFRXQW$XWKHQWLFDWRUV\VWHP¡
DFFRXQWFRQWDFWV
DERXW¡
DXWKHQWLFDWLQJ¡
V\QFKURQL]LQJ
$FFRXQW$XWKHQWLFDWRU5HVSRQVHFODVV
$FFRXQW0DQDJHUFODVV
EORFNLQJ*HW$XWK7RNHQPHWKRG
JHW$XWK7RNHQPHWKRG
.(<B$&&2817B$87+(17,&$725B5
(63216(FRQVWDQW
$&,'WUDQVDFWLRQSURSHUWLHV
$&3 $QGURLG&RPSDWLELOLW\3DFNDJH DFWLYLW\
DQGURLGDOZD\V5HWDLQ7DVN6WDWHDWWULEXWH
DQGURLGILQLVK2Q7DVN/DXQFKDWWULEXWH
DQGURLGODXQFK0RGHDWWULEXWH
DQGURLGQDPHDWWULEXWH
DQGURLGQR+LVWRU\DWWULEXWH
DQGURLGSURFHVVDWWULEXWH
DQGURLGWDVN$IILQLW\DWWULEXWH
DWWULEXWHVDIIHFWLQJWDVNEHKDYLRU
FRQWHQWSURYLGHUVDQG
GHILQHG
ODXQFKPRGH
OLIHF\FOHRYHUYLHZ¡
QDWLYH¡
WDVNDIILQLW\
XVHUH[SHULHQFHDFURVV¡
$FWLYLW\FODVV
DERXW
DFWLYLW\OLIHF\FOH
FRQILJXUDWLRQFKDQJHVDQGOLIHF\FOHV¡
:H¦GOLNHWRKHDU\RXUVXJJHVWLRQVIRULPSURYLQJRXULQGH[HV6HQGHPDLOWRLQGH[#RUHLOO\FRP
463
&RQWH[WFODVVDQG
ILQG9LHZ%\,GPHWKRG
JHW)UDJPHQW0DQDJHUPHWKRG
JHW/DVW1RQ&RQILJXUDWLRQ,QVWDQFHPHWKRG
JHW6WULQJPHWKRG
LV)LQLVKLQJPHWKRG
OLIHF\FOHPHWKRGVDQG
PDQDJHG4XHU\PHWKRG
PDQLIHVWILOHVDQG
PHPRU\UHFRYHU\DQGOLIHF\FOHV¡
QDWLYHDFWLYLWLHVDQG
RQ$FWLYLW\5HVXOWPHWKRG
RQ&RQWH[W,WHP6HOHFWHGPHWKRG
RQ&UHDWHPHWKRG
RQ&UHDWH&RQWH[W0HQXPHWKRG
RQ&UHDWH2SWLRQV0HQXPHWKRG
RQ'HVWUR\PHWKRG
RQ.H\'RZQPHWKRG
RQ1HZ,QWHQWPHWKRG
RQ2SWLRQV,WHP6HOHFWHGPHWKRG
RQ3DXVHPHWKRG
RQ3RVW&UHDWHPHWKRG
RQ3RVW5HVXPHPHWKRG
RQ5HVWDUWPHWKRG
RQ5HVWRUH,QVWDQFH6WDWHPHWKRG
RQ5HVXPHPHWKRG
RQ5HWDLQ1RQ&RQILJXUDWLRQ,QVWDQFH
PHWKRG
RQ6DYH,QVWDQFH6WDWHPHWKRG
RQ6WDUWPHWKRG
RQ6WRSPHWKRG
RQ8VHU/HDYH+LQWPHWKRG
UHDGLQJWDJV
5(67IXODSSOLFDWLRQVDQG
UXQ2Q8L7KUHDGPHWKRG
VDYLQJUHVWRULQJLQVWDQFHVWDWH
VWDUW$FWLYLW\PHWKRG
VWDUW$FWLYLW\)RU5HVXOWPHWKRG
YLVXDOL]LQJOLIHF\FOHV¡
ZHOOEHKDYHGDSSOLFDWLRQVDQG¡
DGE $QGURLG'HEXJ%ULGJH DGEFRPPDQG
$'7(FOLSVHSOXJLQ
DERXW
FRPSRQHQWVVXSSRUWHG¡
FRQILJXULQJ
LQVWDOOLQJ
NHHSLQJXSWRGDWH
464 | Index
WRROVVXSSRUWHG
$,'/ $QGURLG,QWHUIDFH'HILQLWLRQ/DQJXDJH
$'7SOXJLQVXSSRUW
JHQGLUHFWRU\DQG
UHPRWHSURFHGXUHFDOOVDQG
$OSKD$QLPDWLRQFODVV
$QGURLGDSSOLFDWLRQV
VHHDOVRDSSOLFDWLRQGHYHORSPHQWVNHOHWRQ
DSSOLFDWLRQV
DFWLYLWLHVDQGLQWHQWV
$3,VXSSRUW
DSSO\LQJVWDWLFDQDO\VLV¡
%OXHWRRWKLQ¡
EXLOGLQJ
FRPSRQHQWOLIHF\FOHV¡
&RQWH[WFODVVKLHUDUFK\
FUHDWLQJ$QGURLGSURMHFWV¡
GDWDEDVHGHVLJQIRU¡
GHEXJJLQJ
GHYHORSLQJ5(67IXO
H[SRUWLQJ
PDQLIHVWILOHVDQG¡
0-$QGURLGDSSOLFDWLRQH[DPSOH¡
SDFNDJLQJ
SRUWLQJVRIWZDUHWR
SXEOLVKLQJ
UHVGLUHFWRU\
UXQQLQJ
UXQWLPHHQYLURQPHQW¡
VHFXULW\FRQVLGHUDWLRQV
6LPSOH9LGHR'E+HOSHUFODVVH[DPSOH¡
64/DQG
WUDGLWLRQDOSURJUDPPLQJPRGHOV
XQSXEOLVKLQJ
XSORDGLQJLQ$QGURLG0DUNHW¡
DQGURLGFRPPDQG
$QGURLG&RPSDWLELOLW\3DFNDJH $&3 $QGURLG'HEXJ%ULGJH DGE $QGURLG'HYHORSHUVVLWH
DERXW
LQVWDOOLQJ$'7SOXJLQ
6\VWHP5HTXLUHPHQWVSDJH
7RROV2YHUYLHZDUWLFOH
$QGURLG'HYHORSPHQW7RROVSOXJLQ VHH$'7
(FOLSVHSOXJLQ
$QGURLG'HYLFH&KRRVHUGLDORJ
$QGURLGGHYLFHV
Download from Wow! eBook <www.wowebook.com>
DXGLRDQGYLGHRIRUPDWV
UXQQLQJSURJUDPVRQ
VRFLDOQHWZRUNLQJDQG
$QGURLG)UDPHZRUN
VHHDOVR$QGURLG*8,IUDPHZRUN
DERXW
$QGURLGOLEUDULHV¡
FRQFXUUHQWSURJUDPPLQJ¡
H[WHQGLQJFODVVHV¡
IUDJPHQWV¡
OD\RXWPHFKDQLVP¡
PRQLWRULQJWKUHDGV
RUJDQL]LQJ-DYDVRXUFH¡
RYHUULGHVDQGFDOOEDFNV¡
SRO\PRUSKLVPDQGFRPSRVLWLRQ¡
VHULDOL]DWLRQ¡
WKUHDGFRQILQHPHQW
$QGURLG*8,IUDPHZRUN
DUFKLWHFWXUDORYHUYLHZ¡
DVVHPEOLQJ¡
$V\QF7DVNDQG¡
FOLSUHFWDQJOH
GUDZLQJFODVVHV
LPSOHPHQWLQJPHQXV¡
UROOLQJ\RXURZQZLGJHWV¡
WRROVVXSSRUWHG¡
ZLULQJXSFRQWUROOHU¡
$QGURLG,QWHUIDFH'HILQLWLRQ/DQJXDJH VHH
$,'/
$QGURLG/D\RXW(GLWRU
$QGURLGOLEUDULHV
VHHDOVRVSHFLILFOLEUDULHV
DERXW¡
FRQFXUUHQWSURJUDPPLQJDQG
H[WHQGLQJ$QGURLG¡
1'.VXSSRUWHG
$QGURLG0DQLIHVW(GLWRU
$QGURLG0DSV$3,.H\6LJQXSSDJH
$QGURLG0DUNHW
DERXW
EHFRPLQJRIILFLDO$QGURLGGHYHORSHU
JHWWLQJSDLG
ORVLQJVLJQLQJFHUWLILFDWHDQG
SODFLQJDSSOLFDWLRQVLQ¡
$QGURLG0HQX(GLWRU
$QGURLG1'. VHH1'.
$QGURLG3DFNDJH%XLOGHU
DQGURLGSDFNDJHWUHH
$QGURLG3UH&RPSLOHU
$QGURLGSURMHFWV VHHSURMHFWV
$QGURLG5HVRXUFH(GLWRU
$QGURLG5HVRXUFH0DQDJHU
$QGURLG6'.
DERXW
DGGLQJEXLOGWDUJHWV
FRPSRQHQWVVXSSRUWHG¡
FRQILUPLQJLQVWDOODWLRQ¡
GRZQORDGLQJSDFNDJH
H[DPSOHFRGH
IROGHUVIRUWRROV
LQVWDOOLQJ¡
NHHSLQJXSWRGDWH
RUJDQL]LQJ-DYDVRXUFH¡
SUHUHTXLVLWHV¡
VDPSOHDSSOLFDWLRQ¡
WRROVVXSSRUWHG¡
WURXEOHVKRRWLQJSUREOHPV
$QGURLG9LUWXDO'HYLFH VHH$9'
$QGURLG;0/5HVRXUFHV(GLWRU
DQGURLGDSSOLEUDU\
DQGURLGFRQWHQWOLEUDU\
DQGURLGGDWDEDVHOLEUDU\
DQGURLGJUDSKLFVOLEUDU\
DQGURLGWHOHSKRQ\OLEUDU\
DQGURLGWH[WOLEUDU\
DQGURLGYLHZOLEUDU\
DQGURLGZHENLWOLEUDU\
DQGURLGZLGJHWOLEUDU\
DQGURLGZLGJHWVSDFNDJH
DQGURLGDOZD\V5HWDLQ7DVN6WDWHDWWULEXWH
DQGURLGILQLVK2Q7DVN/DXQFKDWWULEXWH
DQGURLGODXQFK0RGHDWWULEXWH
DQGURLGQDPHDWWULEXWH
DQGURLGQR+LVWRU\DWWULEXWH
DQGURLGSURFHVVDWWULEXWH
DQGURLGWDVN$IILQLW\DWWULEXWH
$QGURLG0DQLIHVW[POILOH
DERXW
GHFODUDWLRQVLQ
LQLWLDOL]DWLRQSDUDPHWHUVLQ¡
DQGURLGBQDWLYHBDSSBJOXHPRGXOH
DQLPDWLRQ
EDFNJURXQG¡
IUDPHE\IUDPH¡
2SHQ*/H[DPSOH
VXUIDFHYLHZ
WUDQVLWLRQ¡
WZHHQHG
Index | 465
$QLPDWLRQFODVV
DERXW
$QLPDWLRQ/LVWHQHULQWHUIDFH
DSSO\7UDQVIRUPDWLRQPHWKRG
$QLPDWLRQ'UDZDEOHFODVV
DERXW
VWDUWPHWKRG
$QLPDWLRQ/LVWHQHULQWHUIDFH
DERXW
RQ$QLPDWLRQ(QGPHWKRG
$QLPDWLRQ6HWFODVV
DQRQ\PRXVFODVVHV¡
$SDFKH+WWS&RUHSURMHFW
$3,V DSSOLFDWLRQSURJUDPPLQJLQWHUIDFHV
DFFHVVLELOLW\¡
$QGURLGDSSOLFDWLRQVDQG
DSSOLFDWLRQGLVWULEXWLRQDQG
H[WHUQDOVHQVRUV¡
JHVWXUHLQSXW¡
1HDU)LHOG&RPPXQLFDWLRQ¡
6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU
H[DPSOH¡¡
DSNILOHV
DERXW
EXLOGLQJ
XSORDGLQJ
DSNEXLOGHUDSSOLFDWLRQ
$SSOLFDWLRQFODVV
DERXW
OLIHF\FOHPHWKRGV¡
DSSOLFDWLRQGHYHORSPHQW
VHHDOVR$QGURLGDSSOLFDWLRQVVNHOHWRQ
DSSOLFDWLRQV
DGGLWLRQDOLQIRUPDWLRQ
DSSO\LQJVWDWLFDQDO\VLV¡
FRQWHQWDVVLVW
GDWDEDVHGHVLJQ¡
'HVLJQIRU([WHQVLRQFRGLQJUXOH
JUDSKLFVHIIHFWV¡
-DYDFRGLQJLQ(FOLSVH¡
0-$QGURLGDSSOLFDWLRQH[DPSOH¡
PRGXODUSURJUDPPLQJ¡
UHIDFWRULQJ
UROOLQJ\RXURZQZLGJHWV¡
6LPSOH9LGHR'E+HOSHUFODVVH[DPSOH¡
64/DQG
WUDGLWLRQDOSURJUDPPLQJPRGHOV
DSSOLFDWLRQGLVWULEXWLRQ
466 | Index
DSSOLFDWLRQVLJQLQJ¡
H[SRUWLQJ$QGURLGDSSOLFDWLRQV
*RRJOH0DSV$3,NH\V
SODFLQJLQ$QGURLG0DUNHW¡
VFUHHQFRPSDWLELOLW\DQG
VSHFLI\LQJ$3,OHYHOFRPSDWLELOLW\
DSSOLFDWLRQSURJUDPPLQJLQWHUIDFHV VHH$3,V
DSSOLFDWLRQVLJQLQJ
DERXW
FU\SWRJUDSKLF¡
SURFHVVRYHUYLHZ¡
SURWHFWLRQDQG¡
VHOIVLJQHGFHUWLILFDWHV
DSSOLFDWLRQWHPSODWH VHHVNHOHWRQDSSOLFDWLRQV
DSSOLFDWLRQV VHH$QGURLGDSSOLFDWLRQV
$UUD\/LVWFODVV
$UUD\VFODVV
DUWLIDFWV
GHILQHG
SURMHFWVDQG
DVVLJQPHQWRSHUDWRU DVVRFLDWLRQVGHILQHG
DV\QFKURQRXV,2PHFKDQLVPV
$V\QF7DVNFODVV
GR,Q%DFNJURXQGPHWKRG
RQ&OLFN/LVWHQHUPHWKRG
RQ3RVW([HFXWHPHWKRG
RQ3UH([HFXWHPHWKRG
RQ3URJUHVV8SGDWHPHWKRG
SXEOLVK3URJUHVVPHWKRG
VXEFODVVLQJDQG
8,WKUHDGDQG¡
DXGLR
$QGURLGVXSSRUWHGIRUPDWV
$XGLR5HFRUGHUUHFRUGLQJ
$XGLR7UDFNSOD\EDFN
,QWHQWUHFRUGLQJ
0HGLD3OD\HUSOD\EDFN
0HGLD5HFRUGHUUHFRUGLQJ
SOD\EDFNPHWKRGV¡
UHFRUGLQJPHWKRGV¡
$XGLR5HFRUGHUFODVV
DXGLRUHFRUGLQJ
VWDUW5HFRUGLQJPHWKRG
$XGLR7UDFNFODVV
DXGLRSOD\EDFN
SDXVHPHWKRG
SOD\PHWKRG
UHOHDVHPHWKRG
VWRSPHWKRG
$87+(17,&$7(B$&&28176SHUPLVVLRQ
DXWKHQWLFDWLQJFRQWDFWGDWD¡
$872,1&5(0(17FRQVWUDLQW
$9' $QGURLG9LUWXDO'HYLFH
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FUHDWLQJ¡
UXQQLQJSURJUDPVRQ
VHWWLQJSDUDPHWHUV
DYGPJUWRRO
B
EDFNJURXQGDQLPDWLRQ¡
%DVH$GDSWHUFODVV
%HDXOLHX$ODQ
ELQGLUHFWRU\
ELQDU\GDWD
%LWPDSFODVV
%LWPDS'UDZDEOHFODVV
%/2%W\SH 64/LWH %ORFK-RVKXD
EORFNGHILQHG
%OXHWRRWKVWDQGDUG
DERXW
$QGURLGDSSOLFDWLRQVDQG¡
/LQX[LPSOHPHQWDWLRQ
SURWRFROVWDFNDQG
633VXSSRUW
%OXHWRRWK$GDSWHUFODVV
%OXHWRRWK'HYLFHFODVV
%OXHWRRWK6RFNHWFODVV
%OXH]%OXHWRRWKVWDFN
ERROHDQW\SH
%URDGFDVW5HFHLYHUFODVV
DERXW
PDQLIHVWILOHVDQG
ZHOOEHKDYHGDSSOLFDWLRQVDQG
EXLOGHUVGHILQHG
%XQGOHFODVV
IUDJPHQWOLIHF\FOHDQG
JHW6HULDOL]DEOHPHWKRG
SXW6HULDOL]DEOHPHWKRG
VHULDOL]DWLRQDQG
%XWWRQFODVV
DERXW
VHW2Q&OLFN/LVWHQHUPHWKRG
ZLGJHWVDQG
E\WHW\SH
C
&DOOEDFNLQWHUIDFH 'UDZDEOH &DOOEDFNLQWHUIDFH 6XUIDFH+ROGHU
DERXW
VXUIDFH&UHDWHGPHWKRG
VXUIDFH'HVWUR\HGPHWKRG
FDOOEDFNVGHILQHG¡
&DPHUDFODVV
DERXW
URWDWHPHWKRG
WUDQVODWHPHWKRG
&$0(5$SHUPLVVLRQ
&DQYDVFODVV
DERXW
FRQFDW0DWUL[PHWKRG
FRRUGLQDWHWUDQVIRUPDWLRQ
GUDZ&LUFOHPHWKRG
GUDZLQJWH[W¡
GUDZ3RV7H[WPHWKRG
GUDZ7H[WPHWKRG
GUDZ7H[W2Q3DWKPHWKRG
JHW0DWUL[PHWKRG
UHVWRUHPHWKRG
URWDWHPHWKRG
VDYHPHWKRG
VFDOHPHWKRG
VHW0DWUL[PHWKRG
VNHZPHWKRG
WUDQVODWHPHWKRG
FDQYDVGUDZLQJ
DERXW¡
GUDZLQJWH[W¡
PDWUL[WUDQVIRUPDWLRQV¡
FDVFDGLQJPHWKRGV
&HOO,'
FHUWLILFDWHDXWKRULW\
FHUWLILFDWHILQJHUSULQW
FHUWLILFDWHV
GHEXJ
VHOIVLJQHG¡
FKDUW\SH
&+(&.FRQVWUDLQW
FODVVDWWULEXWH
FODVVILOHV
FODVVHV
VHHDOVRVSHFLILFFODVVHV
DERXW
Index | 467
DEVWUDFW
DQRQ\PRXV¡
H[WHQGLQJ¡
ILQDODQGVWDWLFGHFODUDWLRQV¡
REMHFWFUHDWLRQ¡
VHULDOL]DWLRQVXSSRUW
FOLSUHFWDQJOH
&OLS'UDZDEOHFODVV
&ORQHDEOHLQWHUIDFH
FRGHVLJQLQJ VHHDSSOLFDWLRQVLJQLQJ
&ROOHFWLRQLQWHUIDFH
&ROOHFWLRQV/LEUDU\
&RORU)LOWHUFODVV
FRPDQGURLGLGHHFOLSVHDGWSOXJLQ
FRPDQGURLGLGHHFOLSVHGGPVSOXJLQ
&RPSDUDEOHLQWHUIDFH
DERXW
FRPSDUH7RPHWKRG
FRPSRVLWLRQGHILQHG¡
FRPSRXQGTXHULHV
FRQFXUUHQWSURJUDPPLQJ
$QGURLGOLEUDULHVDQG
$V\QF7DVNDQG8,WKUHDG¡
PXOWLWKUHDGHG
WKUHDGVLQ$QGURLGSURFHVVHV
FRQVWUXFWRUV
GHILQHG
)UDJPHQWFODVVDQG
FRQWDFWGDWD
DERXW¡
DXWKHQWLFDWLQJ¡
V\QFKURQL]LQJ
&RQWDFWVFODVV
DGGLWLRQDOLQIRUPDWLRQ
TXHU\LQJ
&RQWDFWV&RQWUDFWFRQWHQWSURYLGHU¡
FRQWDLQHUYLHZV
FRQWHQWDVVLVW
FRQWHQWSURYLGHUV
DERXW¡
DFWLYLWLHVDQG
ELQDU\GDWD
EXLOGLQJ¡
&RQWDFWV&RQWUDFW¡
&217(17B85,FRQVWDQW¡
GHFODULQJ
GHYHORSLQJ5(67IXODSSOLFDWLRQV
ILOHPDQDJHPHQW
LPSOHPHQWLQJ
468 | Index
0HGLD6WRUH
09&DUFKLWHFWXUHDQG¡
QHWZRUN09&DQG¡
5(67DQG
6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU
H[DPSOH¡
XVDJHFRQVLGHUDWLRQV¡
ZULWLQJLQWHJUDWLQJ
<RX7XEHYLGHRH[DPSOH¡
FRQWHQW85,
&RQWHQW2EVHUYHURQ&KDQJHPHWKRG
&RQWHQW3URYLGHUFODVV
DERXW
GHOHWHPHWKRG
H[WHQGLQJ¡
JHW7\SHPHWKRG
LQVHUWPHWKRG
PDQLIHVWILOHVDQG
RQ&UHDWHPHWKRG
RSHQ)LOHPHWKRG
RSHQ6WUHDPPHWKRG
TXHU\PHWKRG
5(67IXODSSOLFDWLRQVDQG
VHULDOL]DWLRQDQG
XSGDWHPHWKRG
ZHOOEHKDYHGDSSOLFDWLRQVDQG
&RQWHQW3URYLGHU2SHUDWLRQFODVV
DERXW
QHZ,QVHUWPHWKRG
&RQWHQW3URYLGHU2SHUDWLRQ%XLOGHUFODVV
&RQWHQW5HVROYHUFODVV
DERXW
GHOHWHPHWKRG
LQVHUWPHWKRG
QRWLI\&KDQJHPHWKRG
RSHQ,QSXW6WUHDPPHWKRG
RSHQ2XWSXW6WUHDPPHWKRG
UHJLVWHU&RQWHQW2EVHUYHUPHWKRG
&RQWHQW8ULVZLWK$SSHQGHG,GPHWKRG
&RQWHQW9DOXHVFODVV
DERXW
FUHDWLQJ
VWRUHGPHGLDFRQWHQW
&RQWH[WFODVV
DERXW
JHW5HVRXUFHVPHWKRG
JHW6\VWHP6HUYLFHPHWKRG
&RQWH[W0HQXFODVV
FRQWH[WXDOPHQXV
&RQWUROOHUFRPSRQHQW 09&
DERXW
IRFXVDQGWKUHDGLQJ¡
OLVWHQLQJIRUNH\HYHQWV
OLVWHQLQJIRUWRXFKHYHQWV¡
OLVWHQLQJWRWKH0RGHO¡
ZLULQJXS¡
FSXIHDWXUHVPRGXOH
&UHDWH1HZ$QGURLG9LUWXDO'HYLFH $9'
GLDORJ
&5($7(7$%/(VWDWHPHQW 64/ &58'PHWKRGRORJ\
&WUO)
&WUOVSDFHEDU
FXUO\EUDFHV^`
&XUUHQF\FODVV
&XUVRULQWHUIDFH
DERXW
DFFRXQWFRQWDFWVH[DPSOH
PRYH7R)LUVWPHWKRG
PRYH7R1H[WPHWKRG
PRYH7R3UHYLRXVPHWKRG
UHJLVWHU&RQWHQW2EVHUYHUPHWKRG
UHTXHU\PHWKRG
VHW1RWLILFDWLRQ8ULPHWKRG
&\FOH,QWHUSRODWRUFODVV
D
'SDGV
'DOYLN'HEXJ0RQLWRU6HUYHU VHH''06
GDOYLNSDFNDJHWUHH
'DOYLNYLUWXDOPDFKLQHV 90V
DERXW
$QGURLGUXQWLPHHQYLURQPHQW
=\JRWHSURFHVVDQG
GDWDVWUXFWXUHVV\QFKURQL]DWLRQDQG
GDWDW\SHV
FRQWDFWGDWD¡
-DYDVXSSRUWHG
-1,FDOOVDQG
64/LWHVXSSRUWHG
GDWDEDVHVFKHPDV
GHILQHG
IRUHLJQNH\FRQVWUDLQWV
GDWDEDVHWULJJHUV
GDWDEDVHV VHHUHODWLRQDOGDWDEDVHV
'DWHFODVV
'DWH3LFNHUFODVV
'DWH7LPHFODVV
''06 'DOYLN'HEXJ0RQLWRU6HUYHU
DERXW¡
(PXODWRU&RQWUROSDQH
-1,FRQYHQWLRQV
ORFDWLRQXSGDWHV
GHEXJFHUWLILFDWH
GHEXJJDEOHDWWULEXWH
GHEXJJLQJ
$QGURLGDSSOLFDWLRQV
$QGURLGGHYLFHV
'HFHOHUDWH,QWHUSRODWRUFODVV
GHIDXOWFRQVWUXFWRUV
'(/(7(RSHUDWLRQ 5(67 '(/(7(VWDWHPHQW 64/ GHSHQGHQF\LQMHFWLRQ
GHVHULDOL]LQJGDWD
'HVLJQIRU([WHQVLRQFRGLQJUXOH
GHYHORSLQJDSSOLFDWLRQV VHHDSSOLFDWLRQ
GHYHORSPHQW
GH[ILOHV
'LFWLRQDU\FODVV
GLVWULEXWLQJDSSOLFDWLRQV VHHDSSOLFDWLRQ
GLVWULEXWLRQ
GRXEOHW\SH
'UDZSDWFKGUDZLQJSURJUDP
'UDZDEOHFODVV
DERXW¡
&DOOEDFNLQWHUIDFH
XVDJHFRQVLGHUDWLRQV
ZUDSSHUVVXSSRUWLQJ
GUDZDEOHGLUHFWRU\
GUDZLQJJUDSKLFV
DQLPDWLRQV¡
%LWPDSFODVVVXSSRUW
&DQYDVFODVVVXSSRUW¡
'UDZDEOHFODVVVXSSRUW¡
JUDSKLFVHIIHFWVH[DPSOHV¡
OD\RXWFRQVLGHUDWLRQV¡
2SHQ*/VXSSRUW¡
UROOLQJ\RXURZQZLGJHWV
VKDGRZVJUDGLHQWVILOWHUV
'5237$%/(VWDWHPHQW 64/ G\QDPLFGHFODUDWLRQV
E
(FOLSVH,'(
VHHDOVR$'7(FOLSVHSOXJLQ
DERXW
DGGLWLRQDOLQIRUPDWLRQ
Index | 469
FRQFHSWVDQGWHUPLQRORJ\¡
FRQILUPLQJLQVWDOODWLRQ
GRZQORDGLQJ
([WHQVLRQVYLHZ
)LOH([SORUHUYLHZ
+HDSYLHZ
LGLRV\QFUDVLHVDQGDOWHUQDWLYHV¡
LQVWDOOLQJ
-DYDFRGLQJLQ¡
-5(UHTXLUHPHQWV
NHHSLQJXSWRGDWH
/D\RXWYLHZ
/RJ&DWYLHZ¡
2XWOLQHYLHZ
3DFNDJH([SORUHUYLHZ
3L[HO3HUIHFWYLHZ
3OXJLQVYLHZ
3UREOHPVYLHZ
6'.DQG$9'0DQDJHUVXSSRUW
VWDWLFDQDO\]HUV¡
7DVN/LVWYLHZ
7KUHDGVYLHZ
YLHZVDQGSHUVSHFWLYHV¡
HFOLSVHLQLILOH
(GLW7H[WFODVV
DGG7H[W&KDQJHG/LVWHQHUPHWKRG
KDQGOLQJHYHQWV
LQYDOLGDWHPHWKRG
HQFDSVXODWLRQ
DERXW
DFFHVVPRGLILHUVDQG
JHWWHUDQGVHWWHUPHWKRGV
HQFU\SWLRQSXEOLFNH\¡
(QXPHUDWLRQLQWHUIDFH
(TXLQR[IUDPHZRUN
HYHQWTXHXHV
HYHQWV
DOWHUQDWLYHZD\VWRKDQGOH
OLVWHQLQJIRUNH\HYHQWV
OLVWHQLQJIRUWRXFKHYHQWV¡
([FHSWLRQFODVV
H[FHSWLRQV¡
VHHDOVRVSHFLILFH[FHSWLRQV
H[LWFRPPDQG 64/LWH H[SRUWLQJ$QGURLGDSSOLFDWLRQV
H[WHQGVNH\ZRUG
H[WHQVLRQVGHILQHG¡
H[WHUQDOVHQVRUV VHHVHQVRUV
(\HV)UHHRSHQVRXUFHSURMHFW
470 | Index
F
)LOH([SORUHUYLHZ (FOLSVH ILOHPDQDJHPHQW
)LOH+DQGOHUFODVV
ILOWHUV GUDZLQJJUDSKLFV ILQDOGHFODUDWLRQV
ILQDONH\ZRUG
)LQG%XJVWRRO
DERXW¡
DSSO\LQJVWDWLFDQDO\VLV¡
W\SHVDIHW\LQ-DYD
IORDWW\SH
IRFXVDEOHDWWULEXWH
)25(,*1.(<FRQVWUDLQW
IRUNLQJSURFHVVHV
)UDJPHQWFODVV
DERXW
FUHDWLQJIUDJPHQWV
JHW$UJXPHQWVPHWKRG
RQ$FWLYLW\&UHDWHGPHWKRG
RQ$WWDFKPHWKRG
RQ&UHDWHPHWKRG
RQ&UHDWH9LHZPHWKRG
RQ3DXVHPHWKRG
RQ5HVXPHPHWKRG
RQ6DYH,QVWDQFH6WDWHPHWKRG
RQ6WDUWPHWKRG
RQ6WRSPHWKRG
VHW$UJXPHQWVPHWKRG
YLVXDOL]LQJOLIHF\FOHV¡
)UDJPHQW0DQDJHUFODVV
DERXW
ILQG)UDJPHQW%\7DJPHWKRG
IUDJPHQWV
DERXW
$QGURLG&RPSDWLELOLW\3DFNDJHDQG
FUHDWLQJ¡
OLIHF\FOHVRI¡¡
PDQLSXODWLQJ
WUDQVDFWLRQVLQYROYLQJ¡
IUDPHE\IUDPHDQLPDWLRQ¡
)UDPH/D\RXWFODVV
IUDPHZRUNDSSOLFDWLRQV VHHVNHOHWRQ
DSSOLFDWLRQV
G
JDUEDJHFROOHFWLRQ
JHQGLUHFWRU\
JHQHULFV
*HQQLFN-RQDWKDQ
JHRXWLOLW\
*HVWXUHFODVV
JHVWXUHLQSXW
DERXW
OLVWHQLQJIRU¡
*HVWXUH/LEUDULHVFODVV
DERXW
IURP5DZ5HVRXUFHPHWKRG
*HVWXUH/LEUDU\FODVV
*HVWXUH2YHUOD\9LHZFODVV
DERXW
2Q*HVWXUH3HUIRUPHG/LVWHQHULQWHUIDFH
*HVWXUH3RLQWFODVV
*HVWXUH6WRUHFODVV
*HVWXUH6WURNHFODVV
*(7RSHUDWLRQ 5(67 JHWWHUPHWKRGV
*OREDO3RVLWLRQLQJ6\VWHP *36 ¡
*/6XUIDFH9LHZFODVV
DERXW
5HQGHUHULQWHUIDFH
VL]H&KDQJHGPHWKRG
VXUIDFH&UHDWHGPHWKRG
*RHW]%ULDQ
*RRJOH&KHFNRXW
*RRJOH(DUWK
*RRJOH,2FRQIHUHQFH
*RRJOH0DSV
DERXW
$3,NH\V
0DS9LHZFODVVDQG
VWDUWLQJ
*36 *OREDO3RVLWLRQLQJ6\VWHP ¡
*38 *UDSKLFV3URFHVVLQJ8QLW JUDGLHQWV GUDZLQJJUDSKLFV *UDSKLFV3URFHVVLQJ8QLW *38 JUDSKLFVGUDZLQJ VHHGUDZLQJJUDSKLFV
JUDYLW\
*8,IUDPHZRUN VHH$QGURLG*8,IUDPHZRUN
J\URVFRSHV
H
+DQGOHUFODVV
DERXW
/RRSHUFODVVDQG
+DVK0DSFODVV
DERXW
$QGURLGOLEUDULHVDQG
&RQWHQW3URYLGHUFODVVDQG
&RQWHQW9DOXHVFODVVDQG
+DVK6HWFODVV
+DVKWDEOHFODVV
KFLGXPSXWLOLW\
+HDSYLHZ (FOLSVH KHOSFRPPDQG 64/LWH +LEHUQDWHIUDPHZRUN
+LHUDUFK\9LHZHUWRRO
+WWS(QWLW\LQWHUIDFH
I
LDOLEVSDFNDJH
L%$7,6IUDPHZRUN
,OOHJDO6WDWH([FHSWLRQ
LQKHULWDQFH
LQWHUIDFHVDQG
-DYDVXSSRUW
-DYDW\SHVDQG
LQQHUMRLQV
,QSXW6WUHDPFODVV
,16(57VWDWHPHQW 64/ ,QVWDOO1HZ6RIWZDUH:L]DUG
LQVWDQFHYDULDEOHV¡
LQWW\SH
,17(*(5W\SH 64/LWH ,QWHOOL-,'($
,QWHQWFODVV
DERXW
DQGURLGODXQFK0RGHDWWULEXWHDQG
DXGLRUHFRUGLQJ
)/$*B$&7,9,7<B%528*+7B72B)52
17FRQVWDQW
)/$*B$&7,9,7<B&/($5B7$6.
FRQVWDQW
)/$*B$&7,9,7<B&/($5B723FRQVWDQW
)/$*B$&7,9,7<B&/($5B:+(1B7$6
.B5(6(7FRQVWDQW
)/$*B$&7,9,7<B(;&/8'(B)520B5(
&(176FRQVWDQW
)/$*B$&7,9,7<B)25:$5'B5(68/7
FRQVWDQW
)/$*B$&7,9,7<B/$81&+('B)520B
+,6725<FRQVWDQW
Index | 471
)/$*B$&7,9,7<B08/7,3/(B7$6.
FRQVWDQW
)/$*B$&7,9,7<B1(:B7$6.FRQVWDQW
)/$*B$&7,9,7<B12B$1,0$7,21
FRQVWDQW
)/$*B$&7,9,7<B12B+,6725<
FRQVWDQW
)/$*B$&7,9,7<B12B86(5B$&7,21
FRQVWDQW
)/$*B$&7,9,7<B35(9,286B,6B723
FRQVWDQW
)/$*B$&7,9,7<B5(25'(5B72B)52
17FRQVWDQW
VHWWLQJIODJV¡
VWDUWLQJ*RRJOH0DSV
YLGHRUHFRUGLQJ
LQWHUIDFHV
VHHDOVRVSHFLILFLQWHUIDFHV
DERXW¡
DGGLWLRQDOLQIRUPDWLRQ
,QWHUSRODWRUFODVV
,2([FHSWLRQ
,62 ,QWHUQDWLRQDO2UJDQL]DWLRQIRU
6WDQGDUGL]DWLRQ ,WHUDWRULQWHUIDFH
J
-DYD&ROOHFWLRQV)UDPHZRUN
DERXW
FROOHFWLRQLQWHUIDFHW\SHV
MDYDXWLOSDFNDJHDQG
-DYD&ROOHFWLRQV/LEUDU\
-DYDFRPSLOHU
-DYD&U\SWRJUDSK\$UFKLWHFWXUH
-DYD'HYHORSPHQW.LW VHH-'.
MDYDILOHVRUJDQL]LQJ¡
-DYDODQJXDJH
DEVWUDFWFODVVHV
DGGLWLRQDOLQIRUPDWLRQ
DQRQ\PRXVFODVVHV¡
FRGLQJLQ(FOLSVH¡
H[FHSWLRQVVXSSRUW¡
ILQDODQGVWDWLFGHFODUDWLRQV¡
JDUEDJHFROOHFWLRQ
JHQHULFV
LQKHULWDQFHVXSSRUW
LQWHUIDFHVXSSRUW¡
PRGXODUSURJUDPPLQJLQ¡
472 | Index
PXOWLWKUHDGHGFRQFXUUHQWSURJUDPPLQJ
2EMHFWFODVVDQGLWVPHWKRGV¡
REMHFWFUHDWLRQ¡
REMHFWVDQGFODVVHV
SDVVLQJSDUDPHWHUVE\YDOXH
SRO\PRUSKLVPVXSSRUW¡
SULPLWLYHW\SHV
VHULDOL]DWLRQVXSSRUW
V\QFKURQL]DWLRQDQGGDWDVWUXFWXUHV
V\QFKURQL]DWLRQDQGWKUHDGVDIHW\¡
WKUHDGFRQWURO
W\SHV\VWHP¡
-DYD1DWLYH,QWHUIDFH VHH-1,
-DYDSDFNDJHV
VHHDOVRVSHFLILFSDFNDJHV
DERXW
QDPHVSDFHVDQG
VFRSHDQG
-DYD5XQWLPH(QYLURQPHQW -5(
DERXW
(FOLSVHUHTXLUHPHQWV
-DYD9LUWXDO0DFKLQH -90
''06VXSSRUW
SURFHVVRYHUYLHZ
MDYDDZWSDFNDJH
MDYDLRSDFNDJH
MDYDODQJSDFNDJH
MDYDUPLSDFNDJH
MDYDXWLOSDFNDJH
MDYDXWLOFRQFXUUHQWSDFNDJH
MDYDFFRPPDQG
MDYD[SDFNDJH
MDYD[VRXQGSDFNDJH
MDYD[VZLQJSDFNDJH
-'. -DYD'HYHORSPHQW.LW
FRQILUPLQJLQVWDOODWLRQ
GRZQORDGLQJ
LQVWDOOLQJ
NHHSLQJXSWRGDWH
-1, -DYD1DWLYH,QWHUIDFH
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FRQYHQWLRQVIRUPHWKRGFDOOV
VDPSOHDSSOLFDWLRQ¡
-5( -DYD5XQWLPH(QYLURQPHQW
DERXW
(FOLSVHUHTXLUHPHQWV
-90 -DYD9LUWXDO0DFKLQH
''06VXSSRUW
SURFHVVRYHUYLHZ
K
NH\FRGHV.H\(YHQWFODVV
.H\(YHQWFODVV
IRFXVDQGWKUHDGLQJ
JHW5HSHDW&RXQWPHWKRG
KDQGOLQJHYHQWV
NH\FRGHV
.H\+DQGOHUKDQGOH.H\PHWKRG
NH\VWRUH
DERXW
UHPHPEHULQJSDVVZRUG
NH\VWURNHV
FRQWUROOLQJPDSZLWK
OLVWHQLQJIRU
NH\WRROFRPPDQG
DERXW
FUHDWLQJSULYDWHNH\V
OLVWRSWLRQ
L
OD\RXWGLUHFWRU\
OD\RXWSURFHVV
DERXW¡
DUUDQJHPHQWSKDVH
PHDVXUHPHQWSKDVH¡
/D\RXWYLHZ (FOLSVH /D\RXWRSWVWDWLFDQDO\]HU
/%6 ORFDWLRQEDVHGVHUYLFHV
DERXW
&HOO,'
*36
WULDQJXODWLRQ
OLEUDULHV$QGURLG VHH$QGURLGOLEUDULHV
OLIHF\FOHV
$FWLYLW\FODVVDQG¡
$QGURLGFRPSRQHQWV¡
$SSOLFDWLRQFODVVDQG¡
FRQILJXUDWLRQFKDQJHVDQG¡
IUDJPHQW¡
)UDJPHQWFODVVDQG
PDQDJLQJ
PHPRU\UHFRYHU\DQG¡
VHULDOL]DWLRQDQG
XVHUH[SHULHQFHDQG
ZHOOEHKDYHGDSSOLFDWLRQVDQG¡
OLJKWVHQVRUV
/,.(NH\ZRUG
OLQHDUDFFHOHUDWLRQ
/LQHDU*UDGLHQWFODVV
/LQHDU,QWHUSRODWRUFODVV
/LQHDU/D\RXWFODVV
DERXW
PHDVXUHPHQWSURFHVV
RQ0HDVXUHPHWKRG
VHW*UDYLW\PHWKRG
/LQNHG/LVWFODVV
/LQX[HQYLURQPHQW
%OXHWRRWKLPSOHPHQWDWLRQ
KFLGXPSXWLOLW\
LQVWDOOLQJ$QGURLG6'.
LQVWDOOLQJ(FOLSVH
LQVWDOOLQJ-'.
1'.UHTXLUHPHQWV
UXQQLQJSURJUDPVRQ$QGURLGGHYLFHV
VDQGER[LQJDQG
/LVWLQWHUIDFH
/LVW9LHZFODVV
DERXW
DFFRXQWFRQWDFWVH[DPSOH
QRWLILFDWLRQVDQG
VHW$GDSWHUPHWKRG
ORFDWLRQDQGPDSSLQJ
DERXW
DFFHVVLQJZLWKRXWPDSV¡
FRQWUROOLQJZLWKNH\SDG
FRQWUROOLQJZLWKPHQXEXWWRQV¡
*RRJOH0DSV
ORFDWLRQEDVHGVHUYLFHV
0DS$FWLYLW\FODVV
0DS9LHZFODVV¡
PRELOHSKRQHVDQG
0\/RFDWLRQ2YHUOD\FODVV¡
]RRPLQJLQ
ORFDWLRQEDVHGVHUYLFHV VHH/%6
/RFDWLRQ/LVWHQHULQWHUIDFH
/RFDWLRQ0DQDJHUFODVV
JHW/DVW.QRZQ/RFDWLRQPHWKRG
UHTXHVW/RFDWLRQ8SGDWHVPHWKRG
/RFDWLRQ3URYLGHUFODVV¡
/RJ&DWYLHZ (FOLSVH ¡
ORQJW\SH
/RRSHUFODVV
OVFRPPDQG
Index | 473
M
0DFLQWRVKHQYLURQPHQW
LQVWDOOLQJ$QGURLG6'.
LQVWDOOLQJ-'.
1'.UHTXLUHPHQWV
UXQQLQJSURJUDPVRQ$QGURLGGHYLFHV
PDJQHWLFVHQVRUV
PDQLIHVWILOHV
DERXW
$QGURLG0DQLIHVW[PO¡
DXWKHQWLFDWLRQH[DPSOH
ORFDWLRQZLWKRXWPDSVH[DPSOH
0DSLQWHUIDFH
0DS$FWLYLW\FODVV
DERXW
JUDSKLFDOLQWHUIDFHVDQG
LV5RXWH'LVSOD\HGPHWKRG
RQ3DXVHPHWKRG
RQ5HVXPHPHWKRG
0DS&RQWUROOHUFODVV
DERXW
VHW=RRPPHWKRG
]RRP,QPHWKRG
]RRP,Q)L[LQJPHWKRG
]RRP2XWPHWKRG
]RRP7R6SDQPHWKRG
PDSSLQJ VHHORFDWLRQDQGPDSSLQJ
0DS9LHZFODVV
DERXW
LQLWLDOL]LQJ¡
SUHUHTXLVLWHV
VHW&OLFNDEOHDWWULEXWH
VHW(QDEOHGDWWULEXWH
VHW6DWHOOLWHDWWULEXWH
VHW6WUHHW9LHZDWWULEXWH
VHW7UDIILFDWWULEXWH
XVDJHVXJJHVWLRQV
PDUVKDOLQJGDWD
0DVN)LOWHUFODVV
0DWUL[FODVV
&DQYDVFODVVDQG
SRVW7UDQVODWHPHWKRG
SUH7UDQVODWHPHWKRG
0HDVXUH6SHFFODVV
$7B0267FRQVWDQW
(;$&7/<FRQVWDQW
JHW0RGHPHWKRG
JHW6L]HPHWKRG
8163(&,),('FRQVWDQW
474 | Index
0HGLD6WRUHFRQWHQWSURYLGHU
0HGLD3OD\HUFODVV
DGGLWLRQDOLQIRUPDWLRQ
DXGLRSOD\EDFN
FUHDWHPHWKRG
JHW&XUUHQW3RVLWLRQPHWKRG
OLIHF\FOHVWDWHV
SDXVHPHWKRG
SUHSDUHPHWKRG
UHOHDVHPHWKRG
UHVHWPHWKRG
VHW'DWD6RXUFHPHWKRG
VWDUWPHWKRG
VWRSPHWKRG
YLGHRSOD\EDFN
0HGLD5HFRUGHUFODVV
DXGLRUHFRUGLQJ
OLIHF\FOHVWDWHV
SHUPLVVLRQVVXSSRUWHG
SUHSDUHPHWKRG
UHOHDVHPHWKRG
UHVHWPHWKRG
VWDUWPHWKRG
VWRSPHWKRG
YLGHRUHFRUGLQJ
0HGLD6WRUHFRQWHQWSURYLGHU
PHPRU\UHFRYHU\DQGOLIHF\FOHV¡
0HQXLQWHUIDFH
DGGPHWKRG
121(FRQVWDQW
0HQX,WHPLQWHUIDFH
PHQXV
FRQWUROOLQJPDSVZLWK¡
LPSOHPHQWLQJ¡
W\SHVRI
PHUFKDQWDFFRXQWV
PHWKRGV
FDVFDGLQJ
ILQDODQGVWDWLFGHFODUDWLRQV¡
JHWWHUVDQGVHWWHUV
-1,FRQYHQWLRQV
WKURZLQJH[FHSWLRQV
0-$QGURLGVDPSOHDSSOLFDWLRQ
DERXW¡
FRQWUROOLQJPDSZLWKNH\SDG
FRQWUROOLQJPDSZLWKPHQXEXWWRQV¡
GDWDEDVHTXHULHV¡
ORDGLQJDQGVWDUWLQJ
Download from Wow! eBook <www.wowebook.com>
0DS$FWLYLW\FODVV
0DS9LHZFODVV¡
PRGLI\LQJGDWDEDVH¡
0\/RFDWLRQ2YHUOD\FODVV¡
UHDGLQJGDWDIURPGDWDEDVH¡
VRXUFHIROGHU
0RGHOFRPSRQHQW 09& ¡
0RGHO9LHZ&RQWUROOHUDUFKLWHFWXUH VHH09&
DUFKLWHFWXUH
PRGXODUSURJUDPPLQJ¡
0RQNH\WHVWDXWRPDWLRQWRRO
0RWLRQ(YHQWFODVV
$&7,21B029(FRQVWDQW
FUHDWLQJ
IRFXVDQGWKUHDGLQJ
JHW+LVWRULFDO;PHWKRG
JHW+LVWRULFDO<PHWKRG
JHW+LVWRU\6L]HPHWKRG
QDWLYHDFWLYLWLHVDQG
PXOWLPHGLD
DXGLRDQGYLGHRIRUPDWV
SOD\LQJDXGLRDQGYLGHR
UHFRUGLQJDXGLRDQGYLGHR¡
VWRUHGFRQWHQW
09& 0RGHO9LHZ&RQWUROOHU DUFKLWHFWXUH
DGGLWLRQDOLQIRUPDWLRQ
$QGURLG*8,DQG¡
FRQWHQWSURYLGHUVDQG¡
&RQWUROOHUFRPSRQHQW¡
HVVHQWLDOGHVLJQUXOHV
0RGHOFRPSRQHQW¡
5(67IXODSSOLFDWLRQVDQG¡
64/VXSSRUW¡
WKUHDGVLQ$QGURLGSURFHVVDQG
W\LQJFRQFHSWVWRJHWKHU¡
9LHZFRPSRQHQW
0\/RFDWLRQ2YHUOD\FODVV
JHW0\/RFDWLRQPHWKRG
JUDSKLFDOLQWHUIDFHVDQG
LQLWLDOL]LQJ¡
UXQ2Q)LUVW)L[PHWKRG
N
QDPHVSDFHV-DYDSDFNDJHVDQG
1DWLYH'HYHORSPHQW.LW VHH1'.
QDWLYHNH\ZRUG
1DWLYH$FWLYLW\FODVV¡
1'() 1)&'DWD([FKDQJH)RUPDW 1GHIZULWH1GHI0HVVDJHPHWKRG
1GHI0HVVDJHFODVV
1GHI5HFRUGFODVV
UHDGLQJWDJV
57'B60$57B3267(5FRQVWDQW
57'B7(;7FRQVWDQW
57'B85,FRQVWDQW
71)B$%62/87(B85,FRQVWDQW
ZULWLQJWDJV
1'. 1DWLYH'HYHORSPHQW.LW
DERXW
EXLOGLQJFXVWRPOLEUDU\PRGXOHV
FRPSLOLQJZLWK
QDWLYHDFWLYLWLHV¡
QDWLYHOLEUDULHV
VDPSOHDSSOLFDWLRQ¡
VHWWLQJXSHQYLURQPHQW
1HDU)LHOG&RPPXQLFDWLRQ VHH1)&
1HWZRUN([FHSWLRQ
1HZ$QGURLG3URMHFWGLDORJ
1HZ$QGURLG3URMHFW:L]DUG
QHZNH\ZRUG
1)& 1HDU)LHOG&RPPXQLFDWLRQ
DERXW
33PRGH
UHDGLQJWDJV¡
ZULWLQJWDJV
1)&'DWD([FKDQJH)RUPDW 1'() 1IF$GDSWHUFODVV
$&7,21B1'()B',6&29(5('FRQVWDQW
$&7,21B7$*B',6&29(5('FRQVWDQW
$&7,21B7(&+B',6&29(5('FRQVWDQW
GLVDEOH)RUHJURXQG'LVSDWFKPHWKRG
HQDEOH)RUHJURXQG'LVSDWFKPHWKRG
HQDEOH)RUHJURXQG1GHI3XVKPHWKRG
(;75$B,'FRQVWDQW
(;75$B1'()B0(66$*(6FRQVWDQW
JHW'HIDXOW$GDSWHUPHWKRG
SDWFK $QGURLGUHVRXUFH 1,67 1DWLRQDO,QVWLWXWHRI6WDQGDUGVDQG
7HFKQRORJ\ QRDUJFRQVWUXFWRUV
12718//FRQVWUDLQW
Index | 475
O
P
2EMHFWFODVV
DERXW
FORQHPHWKRG
HTXDOVPHWKRG
ILQDOL]HPHWKRG
KDVK&RGHPHWKRG
MDYDODQJSDFNDJHDQG
QRWLI\PHWKRG
QRWLI\$OOPHWKRG
WR6WULQJPHWKRG
ZDLWPHWKRG
REMHFWUHODWLRQDOPDSSLQJ 250 2EMHFW,QSXW6WUHDPFODVV
2EMHFW2XWSXW6WUHDPFODVV
REMHFWV
DERXW
FUHDWLQJ¡
2Q&OLFN/LVWHQHURQ&OLFNPHWKRG
2Q&UHDWH&RQWH[W0HQX/LVWHQHULQWHUIDFH
2Q)RFXV&KDQJH/LVWHQHULQWHUIDFH
2Q*HVWXUH3HUIRUPHG/LVWHQHULQWHUIDFH
2Q.H\/LVWHQHULQWHUIDFH
KDQGOLQJHYHQWV
RQ.H\PHWKRG
WURXEOHVKRRWLQJ
2Q7RXFK/LVWHQHULQWHUIDFH
KDQGOLQJHYHQWV
RQ7RXFKPHWKRG
2SHQ:LWKFRPPDQG
2SHQ*/
DERXW
DQLPDWLRQH[DPSOH
JUDSKLFVVXSSRUW¡
MDYD[SDFNDJHVXSSRUW
RUJDSDFKHKWWSSDFNDJHWUHH
RUJMVRQSDFNDJH
RUJZFGRPSDFNDJH
RUJ[POVD[SDFNDJH
RUJ[POSXOOSDFNDJH
250 REMHFWUHODWLRQDOPDSSLQJ 26*LEXQGOHV
2XW2I0HPRU\([FHSWLRQ
2XWSXW6WUHDPFODVV
RYHUULGHVGHILQHG¡
33 SHHUWRSHHU FRPPXQLFDWLRQ
SDFNDJLQJ$QGURLGDSSOLFDWLRQV
3DLQWFODVV
DERXW
DWWULEXWHVRI
VHW6KDGRZ/D\HUPHWKRG
3$1 SHUVRQDODUHDQHWZRUN SDUDPHWHUV
$QGURLG0DQLIHVW[POILOH¡
SDVVLQJE\YDOXH
3DUFHODEOHLQWHUIDFH
VHULDOL]DWLRQVXSSRUW¡
ZULWH7R3DUFHOPHWKRG
SDVVZRUGUHPHPEHULQJIRUNH\VWRUH
3$7+HQYLURQPHQWYDULDEOH
3DWK(IIHFWFODVV
SHHUWRSHHU 33 FRPPXQLFDWLRQ
3HQGLQJ,QWHQWFODVV
SHUFHQWVLJQ SHULRG SHUPLVVLRQV
DFFRXQWFRQWDFWV
DXWKHQWLFDWLRQ
*36ORFDWLRQSURYLGHUV
0HGLD5HFRUGHUFODVV
V\QFKURQL]DWLRQ
SHUVLVWHQFHDSSOLFDWLRQVDQG
SHUVRQDODUHDQHWZRUN 3$1 SKRQHFRRUGLQDWHV\VWHPV
DERXW
DFFHOHURPHWHUV
JUDYLW\
J\URVFRSHV
OLQHDUDFFHOHUDWLRQ
URWDWLRQYHFWRU
SLFRQHW
SLSHFKDUDFWHU _ 3L[HO3HUIHFWYLHZ (FOLSVH SOD\EDFN
DXGLRPHWKRGV
OLIHF\FOHVWDWHV
YLGHRPHWKRGV
SOXJLQV
VHHDOVR$'7(FOLSVHSOXJLQ
GHILQHG
H[WHQVLRQVDQG¡
SRO\PRUSKLVP¡¡
SRUWLQJVRIWZDUHWR$QGURLG
476 | Index
3267RSHUDWLRQ 5(67 3UHGLFWLRQFODVV
3UHIHUHQFHVGLDORJ
SUHRUGHUWUDYHUVDO
SUHVVXUHVHQVRUV
35,0$5<.(<FRQVWUDLQW
SULPLWLYHW\SHVGHILQHG
SULYDWHNH\V
FUHDWLQJ
ORVLQJ
DVVLJQLQJFHUWLILFDWHV
SULYDWHNH\ZRUG
SURMHFWV
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FUHDWLQJ¡
PDQLIHVWILOHV
SURWHFWHGNH\ZRUG
SUR[LPLW\VHQVRUV
SXEOLFNH\HQFU\SWLRQ¡
SXEOLFNH\ZRUG
SXEOLVKLQJ
$QGURLGDSSOLFDWLRQV
UHIHUHQFHV
Q
4(08
TXHULHV
DFFRXQWFRQWDFWV
FRPSRXQG
0-$QGURLGDSSOLFDWLRQH[DPSOH¡
QHWZRUNHGPHWKRG¡
TXRWDWLRQPDUNV R
5FODVV
5DGLR)UHTXHQF\,GHQWLILFDWLRQ VHH5),'
UDZGLUHFWRU\
5&3 5LFK&OLHQW3ODWIRUP 5'%06V UHODWLRQDOGDWDEDVHPDQDJHPHQW
V\VWHPV 5($/W\SH 64/LWH UHFRUGLQJPXOWLPHGLD
DXGLRPHWKRGV¡
OLIHF\FOHVWDWHV
YLGHRPHWKRGV
5(&25'B$8',2SHUPLVVLRQ
5(&25'B9,'(2SHUPLVVLRQ
UHIDFWRULQJ
UHODWLRQDOGDWDEDVHPDQDJHPHQWV\VWHPV
5'%06V UHODWLRQDOGDWDEDVHV
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FRPSRXQGTXHULHV
GDWDEDVHFRQVWUDLQWV¡
GDWDEDVHPDQLSXODWLRQH[DPSOH¡
GDWDEDVHWUDQVDFWLRQV
GHVLJQIRU$QGURLGDSSOLFDWLRQV¡
LQQHUMRLQV
0-$QGURLGDSSOLFDWLRQH[DPSOH¡
6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU
H[DPSOH
6LPSOH9LGHR'E+HOSHUFODVVH[DPSOH¡
64/LWHVXSSRUWHGFODVVHV
WULJJHUV
<RX7XEHYLGHRH[DPSOH
5HODWLYH/D\RXWFODVV
UHPRWHSURFHGXUHFDOOV$,'/DQG
5HQGHUHULQWHUIDFH
UHVGLUHFWRU\
UHVRXUFHTXDOLILHUV
5HVRXUFHVJHW'UDZDEOHPHWKRG
5HVSRQVH+DQGOHULQWHUIDFH
DERXW
KDQGOH5HVSRQVHPHWKRG
5(67 5HSUHVHQWDWLRQDO6WDWH7UDQVIHU
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FRQVWDQWVDQGLQLWLDOL]DWLRQ
FRQWHQWSURYLGHUVDQG
FUHDWLQJGDWDEDVH
'(/(7(RSHUDWLRQ
GHYHORSLQJ$QGURLGDSSOLFDWLRQV
ILOHPDQDJHPHQW
*(7RSHUDWLRQ
LQVHUWDQG5HVSRQVH+DQGOHUV¡
QHWZRUN09&DQG¡
QHWZRUNHGTXHU\PHWKRG¡
3267RSHUDWLRQ
83'$7(RSHUDWLRQ
5),' 5DGLR)UHTXHQF\,GHQWLILFDWLRQ
DERXW
UHDGLQJWDJV¡
5LFK&OLHQW3ODWIRUP 5&3 Index | 477
5RWDWH$QLPDWLRQFODVV
5RWDWH'UDZDEOHFODVV
URWDWLRQYHFWRU
5XQQDEOHLQWHUIDFH
UXQWLPHHQYLURQPHQW
DERXW¡
$QGURLGOLEUDULHVDQG¡
5XQWLPH([FHSWLRQ
S
VDQGER[LQJ
6FDOH$QLPDWLRQFODVV
6FDOH'UDZDEOHFODVV
6FKHGXOHG7KUHDG3RRO([HFXWRUFODVV
VFRSH
DERXW
DFFHVVPRGLILHUVDQGHQFDSVXODWLRQ
-DYDSDFNDJHVDQG
6'.DQG$9'0DQDJHU
DERXW
FRQILJXULQJ$9'V
FUHDWLQJ$9'V
LQYRNLQJ
VFUHHQFRQILJXUDWLRQV
VHDUFKDSSOLFDWLRQH[DPSOH
FRQWUROOHUFROOHFWLQJXVHULQSXW
LPSOHPHQWLQJ5(67IXOUHTXHVW¡
8,FROOHFWLQJXVHULQSXW
VHFXULW\
DGGLWLRQDOLQIRUPDWLRQ
VHOIVLJQHGFHUWLILFDWHVDQG
6(/(&7VWDWHPHQW 64/
DERXW
&RQWHQW3URYLGHUFODVVDQG
)520FODXVH
*5283%<FODXVH
+$9,1*FODXVH
/,0,7FODXVH
25'(5%<FODXVH
:+(5(FODXVH
VHOIVLJQHGFHUWLILFDWHV
DERXW
FUHDWLQJ
VLJQLQJDSSOLFDWLRQV¡
VHPLFRORQ 6HQVRUJHW0D[LPXP5DQJHPHWKRG
6HQVRU(YHQWFODVV
6HQVRU(YHQW/LVWHQHULQWHUIDFH
RQ$FFXUDF\&KDQJHGPHWKRG
478 | Index
RQ6HQVRU&KDQJHGPHWKRG
6HQVRU0DQDJHUFODVV
DERXW
JHW'HIDXOW6HQVRUPHWKRG
JHW6HQVRU/LVWPHWKRG
6(1625B'(/$<B)$67(67FRQVWDQW
6(1625B'(/$<B*$0(FRQVWDQW
6(1625B'(/$<B1250$/FRQVWDQW
6(1625B'(/$<B8,FRQVWDQW
VHQVRUV
DERXW¡
DFFHOHURPHWHUV
JUDYLW\
J\URVFRSHV
OLJKW
OLQHDUDFFHOHUDWLRQ
PDJQHWLF
SKRQHFRRUGLQDWHV\VWHPV¡
SUHVVXUH
SUR[LPLW\
URWDWLRQYHFWRU
WHPSHUDWXUH
6HULDO3RUW3URWRFRO 633 6HULDOL]DEOHLQWHUIDFH
VHULDOL]DWLRQ
DSSOLFDWLRQOLIHF\FOHDQG
FODVVHVVXSSRUWLQJ
FRPPRQXVHVIRU
GHILQHG
-DYDVXSSRUW
3DUFHODEOHLQWHUIDFH¡
6HUYLFHFODVV
DERXW
&RQWH[WFODVVDQG
PDQLIHVWILOHVDQG
5(67IXODSSOLFDWLRQVDQG
ZHOOEHKDYHGDSSOLFDWLRQVDQG
6HWLQWHUIDFH
VHW&OLFNDEOHDWWULEXWH
VHW(QDEOHGDWWULEXWH
VHW6DWHOOLWHDWWULEXWH
VHW6WUHHW9LHZDWWULEXWH
VHWWHUPHWKRGV
VHW7UDIILFDWWULEXWH
6KDGHUFODVV
VKDGHUV GUDZLQJJUDSKLFV 6KDGRZ/D\HUFODVV
VKDGRZV GUDZLQJJUDSKLFV VKRUWW\SH
6KRZ9LHZGLDORJ
VLJQLQJDSSOLFDWLRQ VHHDSSOLFDWLRQVLJQLQJ
6LPSOH&XUVRU$GDSWHUFODVV
6LPSOH)LQFK9LGHR&RQWHQW3URYLGHUH[DPSOH
DERXW
FROXPQQDPHV
FROXPQVSHFLILFDWLRQVWULQJV¡
FUHDWLQJGDWDEDVH
GHILQLQJSURYLGHUSXEOLF$3,¡
H[WHQGLQJ&RQWHQW3URYLGHUFODVV¡
LPSOHPHQWLQJGHOHWHPHWKRG
LPSOHPHQWLQJJHW7\SHPHWKRG
LPSOHPHQWLQJLQVHUWPHWKRG
LPSOHPHQWLQJRQ&UHDWHPHWKRG
LPSOHPHQWLQJTXHU\PHWKRG¡
LPSOHPHQWLQJXSGDWHPHWKRG
LQVWDQFHYDULDEOHVDQG¡
QRWLI\LQJREVHUYHUV
VRXUFHFRGHVWUXFWXUH
6LPSOH9LGHR'E+HOSHUFODVV H[DPSOH ¡
VNHOHWRQDSSOLFDWLRQV
DERXW
$FWLYLW\FODVVOLIHF\FOHV¡
$SSOLFDWLRQFODVVOLIHF\FOHV¡
ELQDU\GDWD
EXLOGLQJFRQWHQWSURYLGHUV¡
FRQWHQWSURYLGHUVDQG5(67
GHFODULQJFRQWHQWSURYLGHUV
GHYHORSLQJ5(67IXO
ILOHPDQDJHPHQW
IORZLQJLQWXLWLYHXVHUH[SHULHQFH¡
)UDJPHQWFODVVOLIHF\FOHV¡
09&DQGFRQWHQWREVHUYDWLRQ¡
QHWZRUN09&DQG¡
6LPSOH)LQFK9LGHR&RQWHQW3URYLGHU
H[DPSOH¡
ZHOOEHKDYHG¡
ZULWLQJLQWHJUDWLQJFRQWHQWSURYLGHUV
<RX7XEHYLGHRH[DPSOH¡
6PDOO7DONODQJXDJH
VRFLDOQHWZRUNLQJ
VRIWZDUHGHYHORSPHQW VHHDSSOLFDWLRQ
GHYHORSPHQW
633 6HULDO3RUW3URWRFRO 64/ 6WDQGDUG4XHU\/DQJXDJH
DERXW
DGGLWLRQDOLQIRUPDWLRQ
$QGURLGDSSOLFDWLRQVDQG
GDWDGHILQLWLRQFRPPDQGV¡
GDWDPDQLSXODWLRQFRPPDQGV¡
GDWDEDVHFRQVWUDLQWV¡
09&PRGHODQG
64/LWHGDWDEDVHV\VWHP
DERXW
DGGLWLRQDOLQIRUPDWLRQ
FRPSRXQGTXHULHV
GDWDW\SHVVXSSRUWHG
GDWDEDVHFODVVHV
GDWDEDVHFRQVWUDLQWV¡
GDWDEDVHWUDQVDFWLRQV
SHUVLVWHQFHDQG
VTOLWHFRPPDQG
VTOLWHFRPPDQG
DERXW
EDODQFLQJTXRWHV
GDWDEDVHPDQLSXODWLRQH[DPSOH¡
SHUFHQWVLJQLQ
SHULRGLQ
SLSHFKDUDFWHULQ
VHPLFRORQLQ
64/LWH'DWDEDVHFODVV
DERXW
GHOHWHPHWKRG
H[HF64/PHWKRG
LQVHUWPHWKRG
TXHU\PHWKRG
UDZ4XHU\PHWKRG
UDZ4XHU\:LWK)DFWRU\PHWKRG
XSGDWHPHWKRG
64/LWH2SHQ+HOSHUFODVV
DERXW
H[WHQGLQJ
RQ&UHDWHPHWKRG
RQ8SJUDGHPHWKRG
64/LWH4XHU\%XLOGHUFODVV
VUFGLUHFWRU\
6WDQGDUG4XHU\/DQJXDJH VHH64/
VWDWLFDQDO\VLV
DERXW¡
DSSO\LQJWR$QGURLGFRGH¡
)LQG%XJVWRRODQG¡
OLPLWDWLRQVRI
VWDWLFGHFODUDWLRQV
6WULQJFODVV
&DQYDVFODVVDQG
DVILQDOGHFODUDWLRQ
Index | 479
VXEFODVVHV
GHILQHG
SURJUDPPLQJFRQVLGHUDWLRQV
VXSHUFODVVHVGHILQHG
6XUIDFH+ROGHUFODVV
&DOOEDFNLQWHUIDFH
XQORFN&DQYDV$QG3RVWPHWKRG
6XUIDFH9LHZFODVV
DERXW
DQLPDWLRQVXSSRUW
6\QDSWLF3DFNDJH0DQDJHUXWLOLW\
V\QFKURQL]DWLRQ
DFFRXQWGDWD
GDWDVWUXFWXUHVDQG
WKUHDGVDIHW\DQG¡
V\QFKURQL]HGNH\ZRUG¡
6\VWHPORDG/LEUDU\PHWKRG
T
WDEOHFRPPDQG 64/LWH WDEOHV
GDWDEDVHFRQVWUDLQWV¡
GHILQHG
64/GDWDGHILQLWLRQFRPPDQGV¡
64/GDWDPDQLSXODWLRQFRPPDQGV¡
7DJ7HFKQRORJ\LQWHUIDFH
FORVHPHWKRG
FRQQHFWPHWKRG
LV&RQQHFWHGPHWKRG
UHDGLQJWDJV
ZULWLQJWDJV
WDVNV
DSSOLFDWLRQVDQG
VSHFLI\LQJEHKDYLRU¡
WUDFNLQJ
WHPSHUDWXUHVHQVRUV
7(;7W\SH 64/LWH WH[WGUDZLQJ¡
7H[W7R6SHHFKFODVV
DERXW
VKXWGRZQPHWKRG
VSHDNPHWKRG
7H[W9LHZFODVV
ORFDWLRQZLWKRXWPDSVH[DPSOH¡
ZLGJHWVDQG
7H[W:DWFKHULQWHUIDFH
DIWHU7H[W&KDQJHGPHWKRG
EHIRUH7H[W&KDQJHGPHWKRG
480 | Index
RQ7H[W&KDQJHGPHWKRG
7KUHDGFODVV
WKUHDGFRQILQHPHQW
WKUHDGVDIHW\YLRODWLRQV
WKUHDGV
$QGURLG*8,DQG¡
LQ$QGURLGSURFHVVHV
FRQFXUUHQW
PRQLWRULQJ
2EMHFWFODVVVXSSRUW
VSDZQLQJ
V\QFKURQL]DWLRQDQG¡
7KUHDGVYLHZ (FOLSVH 7KURZDEOHFODVV
7LPHU7DVNFODVV
7LPH=RQHFODVV
WRXFKHYHQWV
JHVWXUHLQSXW
OLVWHQLQJIRU¡
WUDFNEDOOV
WUDQVDFWLRQV
GDWDEDVH
IUDJPHQW¡
WUDQVIRUPDWLRQVPDWUL[¡
WUDQVLWLRQDQLPDWLRQV¡
7UDQVODWH$QLPDWLRQFODVV
7UHH0DSFODVV
WULDQJXODWLRQ
WULJJHUVGDWDEDVH
WURXEOHVKRRWLQJ
2Q.H\/LVWHQHULQWHUIDFH
6'.SUREOHPV
WU\FDWFKEORFN
WZHHQHGDQLPDWLRQV
U
8EXQWX/LQX[HQYLURQPHQW
LQVWDOOLQJ(FOLSVH
LQVWDOOLQJ-'.
XQFKHFNHGH[FHSWLRQV
81,48(FRQVWUDLQW
XQPDUVKDOLQJGDWD
XQSXEOLVKLQJ$QGURLGDSSOLFDWLRQV
83'$7(RSHUDWLRQ 5(67 83'$7(VWDWHPHQW 64/
DERXW
&RQWHQW3URYLGHUFODVVDQG
:+(5(FODXVH
Download from Wow! eBook <www.wowebook.com>
XSORDGLQJDSSOLFDWLRQVLQ$QGURLG0DUNHW
¡
8UL0DWFKHUFODVV
DERXW
DGG85,PHWKRG
LQLWLDOL]LQJ
12B0$7&+FRQVWDQW
85/(QFRGHUHQFRGHPHWKRG
86%
DFFHVVLQJ$QGURLGGHYLFHV
GHEXJJLQJ$QGURLGGHYLFHV
XVHUH[SHULHQFH
$FWLYLW\OLIHF\FOHDQG
IORZLQJDQGLQWXLWLYH¡
XVHVVGNDWWULEXWH
88,'FODVV
V
YDOXHVGLUHFWRU\
9HFWRUFODVV
9LEUDWRUFODVV
YLGHR
$QGURLGVXSSRUWHGIRUPDWV
,QWHQWUHFRUGLQJ
0HGLD3OD\HUSOD\EDFN
0HGLD5HFRUGHUUHFRUGLQJ
SOD\EDFNPHWKRGV
UHFRUGLQJPHWKRGV
9LGHR9LHZFODVV
9LHZFODVV
VHHDOVRZLGJHWV
DERXW
DVVHPEOLQJ*8,
EDFNJURXQGDQLPDWLRQ
GLVSDWFK.H\(YHQWPHWKRG
'LVSDWFK.H\(YHQWPHWKRG
GLVSDWFK7UDFNEDOO(YHQWPHWKRG
GUDZPHWKRG
ILQG9LHZ%\,GPHWKRG
JHW%DFNJURXQGPHWKRG
JHW0HDVXUHG+HLJKWPHWKRG
JHW0HDVXUHG:LGWKPHWKRG
JHW6XJJHVWHG0LQLPXP+HLJKWPHWKRG
JHW6XJJHVWHG0LQLPXP:LGWKPHWKRG
KDQGOLQJHYHQWV
LQYDOLGDWHPHWKRG
LV)RFXVDEOH,Q7RXFK0RGHPHWKRG
LV,Q7RXFK0RGHPHWKRG
PHDVXUHPHWKRG
2Q&OLFN/LVWHQHULQWHUIDFH
2Q&UHDWH&RQWH[W0HQX/LVWHQHULQWHUIDFH
RQ'UDZPHWKRG
2Q)RFXV&KDQJH/LVWHQHULQWHUIDFH
RQ.H\'RZQPHWKRG
2Q.H\/LVWHQHULQWHUIDFH
RQ/D\RXWPHWKRG
RQ0HDVXUHPHWKRG
RQ7RXFK(YHQWPHWKRG
2Q7RXFK/LVWHQHULQWHUIDFH
RQ7UDFNEDOO(YHQWPHWKRG
SRVWPHWKRG
SRVW'HOD\HGPHWKRG
UHTXHVW)RFXVPHWKRG
UHTXHVW/D\RXWPHWKRG
VHW%DFNJURXQG'UDZDEOHPHWKRG
VHW%DFNJURXQG5HVRXUFHPHWKRG
VHW)RFXVDEOHPHWKRG
VHW0HDVXUHG'LPHQVLRQVPHWKRG
VHW2Q&UHDWH&RQWH[W0HQX/LVWHQHU
PHWKRG
VHW2Q.H\/LVWHQHUPHWKRG
VWDUW$QLPDWLRQPHWKRG
ZLGJHWVDQG
9LHZFRPSRQHQW 09& VHHDOVRGUDZLQJJUDSKLFV
YLHZPRGHO
9LHZ*URXSFODVV
FRQWDLQHUYLHZVDQG
GLVSDWFK'UDZPHWKRG
)UDJPHQWFODVVDQG
PHDVXUH&KLOGPHWKRG
PHDVXUH&KLOGUHQPHWKRG
PHDVXUH&KLOG:LWK0DUJLQVPHWKRG
UHTXHVW&KLOG)RFXVPHWKRG
UHTXHVW)RFXVPHWKRG
ZLGJHWVDQG
YLUWXDOPDFKLQHV VHH'DOYLNYLUWXDOPDFKLQHV
90V
9LVXDO$JHWRRO
90V YLUWXDOPDFKLQHV VHH'DOYLNYLUWXDO
PDFKLQHV 90V
W
ZKDWDPLH[DPSOH
ZLGJHWV
VHHDOVR9LHZFODVV
%LWPDSFODVV
Index | 481
FDQYDVGUDZLQJ¡
GHILQHG
'UDZDEOHFODVV¡
IRFXVDEOHDWWULEXWH
IXOO\IXQFWLRQDOH[DPSOH
JUDSKLFVHIIHFWVH[DPSOHV¡
OD\RXWSURFHVV¡
RQ'UDZPHWKRG
RQ/D\RXWPHWKRG
RQ0HDVXUHPHWKRG
:LQGRZVHQYLURQPHQW
LQVWDOOLQJ-'.
1'.UHTXLUHPHQWV
UXQQLQJSURJUDPVRQ$QGURLGGHYLFHV
VDQGER[LQJDQG
ZRUNVSDFHV
GHILQHG
GHSLFWHG
SURMHFWVDQG
X
;0/HGLWRUV
Y
<RX7XEHYLGHRH[DPSOH
DERXW
FRQVWDQWVDQGLQLWLDOL]DWLRQ
FRQWUROOHUFROOHFWLQJXVHULQSXW
FUHDWLQJGDWDEDVH
ILOHPDQDJHPHQW
LQVHUWDQG5HVSRQVH+DQGOHUV¡
QHWZRUNHGTXHU\PHWKRG¡
VWUXFWXUHRIVRXUFHFRGH
8,FROOHFWLQJXVHULQSXW
Z
=LSDOLJQWRRO
]RRPLQJLQ$QGURLGPDSV
=\JRWHSURFHVV
482 | Index
About the Authors
=LJXUG0HGQLHNVLVDFRQVXOWDQWWROHDGLQJ2(0VHQWHUSULVHVDQGHQWUHSUHQHXULDO
YHQWXUHVFUHDWLQJ$QGURLGEDVHGV\VWHPVDQGVRIWZDUH3UHYLRXVO\KHZDVFKLHIDUFKL
WHFW DW ' 7HFKQRORJLHV D 9RLFH RYHU ,3 9R,3 WHFKQRORJ\ SURYLGHU 7KHUH KH OHG
HQJLQHHULQJDQGSURGXFWGHILQLWLRQZRUNIRUSURGXFWVWKDWEOHQGHGFRPPXQLFDWLRQ
DQGVRFLDOPHGLDLQSXUSRVHEXLOWHPEHGGHGV\VWHPVDQGRQWKH$QGURLGSODWIRUP
/DLUG'RUQLQLVDPRELOHGHYHORSPHQWDUFKLWHFWZLWKH[WHQVLYHH[SHULHQFHLQ-DYD
$QGURLG-0(6DYD-HDQGWKH:HE.LWEURZVHUOLEUDU\+HZDVDPHPEHURIWKH-6(
GHYHORSPHQWWHDPDW6XQ0LFURV\VWHPVVSHFLDOL]LQJLQ-DYD50,DQG-LQLWHFKQRORJ\
+HLVFXUUHQWO\DVHQLRUHQJLQHHUDWDPDMRUZLUHOHVVFDUULHUZKHUHKHSURYLGHV$QGURLG
DUFKLWHFWXUDOJXLGDQFHDQG1HWZRUN$3,VXSSRUWWRPHPEHUVRIWKHFDUULHU¦VGHYHORSHU
FRPPXQLW\
*%ODNH0HLNHLVDYHWHUDQGHYHORSHUZLWKZLGHH[SHULHQFHEXLOGLQJ-DYDDSSOLFDWLRQV
IRUDUDQJHRIPRELOHDQGVHUYHUVLGHSODWIRUPV
:LWKPRUHWKDQDGHFDGHRIVRIWZDUHHQJLQHHULQJH[SHULHQFH0DVXPL1DNDPXUDKDV
ZRUNHGLQYDULRXVSRVLWLRQVZLWKLQWKHPRELOHWHFKQRORJ\DUHQDIURPEXLOGLQJRXW
PRELOHLQIUDVWUXFWXUHWRIRXQGLQJKLVRZQPRELOHFRPSDQ\+HZDVRQHRIWKHSULPDU\
$QGURLGGHYHORSHUVRIWKH:+(5($QGURLGDSSDQGLVQRZSULQFLSDODUFKLWHFWIRUWKH
%LJ'DWDDQG5HFRPPHQGDWLRQVJURXSDW:+(5(,QF2XWVLGHRIFRGLQJKHVSHQGV
KLVWLPHSUDFWLFLQJ%D*XD=KDQJDQGFDULQJIRUKLVWZRFDWV
Colophon
7KHDQLPDORQWKHFRYHURI3URJUDPPLQJ$QGURLGLVDSLQHJURVEHDN 3LQLFRODHQXFOHD
WRU $PHPEHURIWKHILQFKIDPLO\WKHVHODUJHVWRIWKHVRFDOOHG£ZLQWHUILQFKHV¤FDQ
EH IRXQG WKURXJKRXW WKH FRQLIHURXV IRUHVWV RI WKH QRUWKHUQ KHPLVSKHUH LQ $ODVND
&DQDGD6FDQGLQDYLDDQG6LEHULD0RUHUDUHO\GXULQJWKHZLQWHUVRPHLQGLYLGXDOVVWUD\
DVIDUVRXWKDVWKHXSSHU0LGZHVWDQG1HZ(QJODQGSRUWLRQVRIWKH8QLWHG6WDWHVDQG
RQRFFDVLRQHYHQLQWRWHPSHUDWH(XURSH
$GXOWSLQHJURVEHDNVDUHUDWKHUGLVWLQFWLYHORRNLQJ%RWKPDOHVDQGIHPDOHVKDYHORQJ
IRUNHGEODFNWDLOVDQGEODFNZLQJVZLWKZKLWHZLQJEDUV7KHUHPDLQGHURIDPDOH¦V
SOXPDJHLVSUHGRPLQDQWO\UHGZKLOHIHPDOHVGLVSOD\DQROLYHFRORURQWKHKHDGDQG
UXPSDQGJUD\RQWKHEDFNDQGXQGHUVLGH&RQYHUVHO\FRORUVRQ\RXQJSLQHJURVEHDNV
DUHQRWLFHDEO\PRUHVXEGXHG
3LQHJURVEHDNVIHHGPRVWO\RQYHJHWDEOHPDWWHULQFOXGLQJWKHEXGVVHHGVDQGIUXLWRI
YDULRXVYDULHWLHVRIWUHHWKRXJKWKH\ZLOODOVRHDWLQVHFWVDQGLQIDFWSUHIHUWRIHHGVXFK
WRWKHLU\RXQJ,QWHUHVWLQJO\EUHHGLQJDGXOWVZLOOGHYHORSSRXFKHVLQWKHIORRURILWV
PRXWKVSHFLILFDOO\GHVLJQHGWRFDUU\WKLVIRRGEDFNWRWKHQHVW
Download from Wow! eBook <www.wowebook.com>
7KHFRYHULPDJHLVIURP-RKQVRQ¦V1DWXUDO+LVWRU\7KHFRYHUIRQWLV$GREH,7&*D
UDPRQG7KHWH[WIRQWLV/LQRW\SH%LUNDWKHKHDGLQJIRQWLV$GREH0\ULDG&RQGHQVHG
DQGWKHFRGHIRQWLV/XFDV)RQW¦V7KH6DQV0RQR&RQGHQVHG
Download