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)URP0DUNHUFRPPDQG'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 $GGEXWWRQLQWKH,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ൺ2WKHUDQGH[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