813

Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Embed Size (px)

Citation preview

Page 1: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment
Page 2: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ProAndroid5

DaveMacLean

SatyaKomatineni

GrantAllen

Page 3: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ProAndroid5

Copyright©2015byDaveMacLean,SatyaKomatineni,andGrantAllen

Thisworkissubjecttocopyright.AllrightsarereservedbythePublisher,whetherthewholeorpartofthematerialisconcerned,specificallytherightsoftranslation,reprinting,reuseofillustrations,recitation,broadcasting,reproductiononmicrofilmsorinanyotherphysicalway,andtransmissionorinformationstorageandretrieval,electronicadaptation,computersoftware,orbysimilarordissimilarmethodologynowknownorhereafterdeveloped.Exemptedfromthislegalreservationarebriefexcerptsinconnectionwithreviewsorscholarlyanalysisormaterialsuppliedspecificallyforthepurposeofbeingenteredandexecutedonacomputersystem,forexclusiveusebythepurchaserofthework.DuplicationofthispublicationorpartsthereofispermittedonlyundertheprovisionsoftheCopyrightLawofthePublisher’slocation,initscurrentversion,andpermissionforusemustalwaysbeobtainedfromSpringer.PermissionsforusemaybeobtainedthroughRightsLinkattheCopyrightClearanceCenter.ViolationsareliabletoprosecutionundertherespectiveCopyrightLaw.

ISBN-13(pbk):978-1-4302-4680-0

ISBN-13(electronic):978-1-4302-4681-7

Trademarkednames,logos,andimagesmayappearinthisbook.Ratherthanuseatrademarksymbolwitheveryoccurrenceofatrademarkedname,logo,orimageweusethenames,logos,andimagesonlyinaneditorialfashionandtothebenefitofthetrademarkowner,withnointentionofinfringementofthetrademark.

TheimagesoftheAndroidRobot(01/AndroidRobot)arereproducedfromworkcreatedandsharedbyGoogleandusedaccordingtotermsdescribedintheCreativeCommons3.0AttributionLicense.AndroidandallAndroidandGoogle-basedmarksaretrademarksorregisteredtrademarksofGoogleInc.intheUnitedStatesandothercountries.ApressMediaLLCisnotaffiliatedwithGoogleInc.,andthisbookwaswrittenwithoutendorsementfromGoogleInc.

Theuseinthispublicationoftradenames,trademarks,servicemarks,andsimilarterms,eveniftheyarenotidentifiedassuch,isnottobetakenasanexpressionofopinionastowhetherornottheyaresubjecttoproprietaryrights.

Whiletheadviceandinformationinthisbookarebelievedtobetrueandaccurateatthedateofpublication,neithertheauthorsnortheeditorsnorthepublishercanacceptanylegalresponsibilityforanyerrorsoromissionsthatmaybemade.Thepublishermakesnowarranty,expressorimplied,withrespecttothematerialcontainedherein.

ManagingDirector:WelmoedSpahr

LeadEditor:SteveAnglin

TechnicalReviewer:ShaneKirk

EditorialBoard:SteveAnglin,LouiseCorrigan,JonathanGennick,RobertHutchinson,MichelleLowman,JamesMarkham,Susan

Page 4: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

McDermott,MatthewMoodie,JeffreyPepper,DouglasPundick,BenRenow-Clarke,GwenanSpearing,SteveWeiss

CoordinatingEditor:MarkPowers

CopyEditor:BrendanFrost

Compositor:SPiGlobal

Indexer:SPiGlobal

Artist:SPiGlobal

CoverDesigner:AnnaIshchenko

DistributedtothebooktradeworldwidebySpringerScience+BusinessMediaNewYork,233SpringStreet,6thFloor,NewYork,NY10013.Phone1-800-SPRINGER,fax(201)348-4505,[email protected],orvisitwww.springeronline.com.ApressMedia,LLCisaCaliforniaLLCandthesolemember(owner)isSpringerScience+BusinessMediaFinanceInc(SSBMFinanceInc).SSBMFinanceIncisaDelawarecorporation.

Forinformationontranslations,[email protected],orvisitwww.apress.com.

ApressandfriendsofEDbooksmaybepurchasedinbulkforacademic,corporate,orpromotionaluse.eBookversionsandlicensesarealsoavailableformosttitles.Formoreinformation,referenceourSpecialBulkSales–eBookLicensingwebpageatwww.apress.com/bulk-sales.

Anysourcecodeorothersupplementarymaterialreferencedbytheauthorinthistextisavailabletoreadersatwww.apress.com/9781430246800.Fordetailedinformationabouthowtolocateyourbook’ssourcecode,gotowww.apress.com/source-code/.

Page 5: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TomywifeRosie,Ineverwouldhavemadeitthisfarwithoutyourloveandsupport.Thankyou,youarewonderful,andIloveyou.

—DaveMacLean

TomylateyoungerbrotherSankarKomatineniwhoseindustry,hardship,andzestforlifefillsmewithsadnessandjoy.

—SatyaKomatineni

ToalltheAndroiddevelopersouttheredreamingofthenextgreatAndroidapp!Youareanamazingcommunity,andIcan’twaittoseewhatyou

developnext.

—GrantAllen

Page 6: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContentsataGlanceAbouttheAuthors

AbouttheTechnicalReviewer

Acknowledgments

Foreword

Introduction

Chapter1:HelloAndroid

Chapter2:IntroductiontoAndroidApplicationArchitecture

Chapter3:BuildingBasicUserInterfacesandUsingControls

Chapter4:AdaptersandListControls

Chapter5:BuildingMoreAdvancedUILayouts

Chapter6:WorkingwithMenusandActionBars

Chapter7:StylesandThemes

Chapter8:Fragments

Chapter9:RespondingtoConfigurationChanges

Chapter10:WorkingwithDialogs

Chapter11:WorkingwithPreferencesandSavingState

Chapter12:UsingtheCompatibilityLibraryforOlderDevices

Chapter13:ExploringPackages,Processes,Threads,andHandlers

Chapter14:BuildingandConsumingServices

Chapter15:AdvancedAsyncTaskandProgressDialogs

Chapter16:BroadcastReceiversandLong-RunningServices

Chapter17:ExploringtheAlarmManager

Chapter18:Exploring2DAnimation

Chapter19:ExploringMapsandLocation-BasedServices

Chapter20:UnderstandingtheMediaFrameworks

Chapter21:HomeScreenWidgets

Page 7: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter22:TouchScreens

Chapter23:ImplementingDragandDrop

Chapter24:UsingSensors

Chapter25:ExploringAndroidPersistenceandContentProviders

Chapter26:UnderstandingLoaders

Chapter27:ExploringtheContactsAPI

Chapter28:ExploringSecurityandPermissions

Chapter29:UsingGoogleCloudMessagingwithAndroid

Chapter30:DeployingYourApplication:GooglePlayStoreandBeyond

Index

Page 8: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContentsAbouttheAuthors

AbouttheTechnicalReviewer

Acknowledgments

Foreword

Introduction

Chapter1:HelloAndroid

PrerequisitesforAndroidDevelopment

SettingUpYourEclipseEnvironmentDownloadingJDK6

DownloadingEclipse4.2

DownloadingtheAndroidSDK

TheToolsWindow

InstallingADT

SettingUpYourAndroidStudioEnvironmentJavarequirementsforAndroidStudio

DownloadingandInstallingAndroidStudio

LearningAndroid’sFundamentalComponentsView

Activity

Fragment

Intent

ContentProvider

Service

AndroidManifest.xml

AVDs

HelloWorld!

AVDs

RunningonaRealDevice

ExploringtheStructureofanAndroidApplication

ExaminingtheApplicationLifeCycle

SimpleDebugging

Page 9: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

LaunchingtheEmulator

References

Summary

Chapter2:IntroductiontoAndroidApplicationArchitecture

ExploringaSimpleAndroidApplication

DefiningUIthroughLayoutFilesSpecifyingCommentsinLayoutFiles

AddingViewsandViewGroupsinLayoutFiles

SpecifyingControlPropertiesinLayoutFiles

IndicatingViewGroupProperties

ControllingWidthandHeightofaControl

IntroducingResourcesandBackgrounds

WorkingwithTextControlsintheLayoutFile

WorkingwithAutogeneratedIDsforControls

ImplementingProgrammingLogicLoadingtheLayoutFileintoanActivity

GatheringControls

SettingUpButtons

RespondingtoButtonClicks:TyingItAllTogether

UpdatingtheAndroidManifest.XML

PlacingtheFilesintheAndroidProject

TestingtheCalculatorApponaRealDevice

AndroidActivityLifeCyclevoidonCreate(BundlesavedInstanceState)

voidonStart()

voidonRestoreInstanceState(BundlesavedInstanceState)

voidonResume()

voidonPause()

voidonStop()

voidonSaveInstanceState(BundlesaveStateBundle)

voidonRestart()

ObjectonRetainNonConfigurationInstance()

voidonDestroy()

GeneralNotesonActivityCallbacks

MoreonResourcesDirectoryStructureofResources

Page 10: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReadingResourcesfromJavaCode

RuntimeBehaviorofDrawableResources

UsingArbitraryXMLFilesasResources

WorkingwithRawResourceFiles

ReadingFilesfromtheAssetsDirectory

ReadingResourcesandAssetsWithoutanActivityReference

UnderstandingResourceDirectories,Language,andLocale

MoreonIntentsStartingActivitiesforResults

ExercisingtheGET_CONTENTAction

RelatingIntentsandActivities

UnderstandingExplicitandImplicitIntents

SavingStateinAndroid

RoadmapforLearningAndroidandtheRestoftheBookTrack1:UIEssentialsforYourAndroidApplications

Track2:SavingState

Track3:Preparing/TakingYourApplicationtotheMarket

Track4:MakingYourApplicationRobust

Track5:BringingFinessetoYourApps

Track6:IntegratingwithOtherDevicesandtheCloud

FinalTrack:GettingaHelpingHandfromExpertAndroid

AsWeLeaveYouNowwiththeRestoftheBook

References

Summary

Chapter3:BuildingBasicUserInterfacesandUsingControls

UIDevelopmentinAndroidBuildingaUICompletelyinCode

BuildingaUICompletelyinXML

BuildingaUIinXMLwithCode

UnderstandingAndroid’sCommonControlsTextControls

ButtonControls

TheImageViewControl

DateandTimeControls

TheMapViewControl

References

Page 11: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Summary

Chapter4:AdaptersandListControls

UnderstandingAdaptersGettingtoKnowSimpleCursorAdapter

GettingtoKnowArrayAdapter

UsingAdapterswithAdapterViewsTheBasicListControl:ListView

TheGridViewControl

TheSpinnerControl

TheGalleryControl

Summary

Chapter5:BuildingMoreAdvancedUILayouts

CreatingCustomAdaptersOtherControlsinAndroid

StylesandThemesUsingStyles

UsingThemes

UnderstandingLayoutManagersTheLinearLayoutLayoutManager

TheTableLayoutLayoutManager

TheRelativeLayoutLayoutManager

TheFrameLayoutLayoutManager

TheGridLayoutLayoutManager

CustomizingtheLayoutforVariousDeviceConfigurations

Summary

Chapter6:WorkingwithMenusandActionBars

WorkingwithMenusThroughXMLFilesCreatingXMLMenuResourceFiles

PopulatingActivityMenufromMenuXMLFiles

RespondingtoXML-BasedMenuItems

WorkingwithMenusinJavaCodeWorkingwithMenuGroups

UnderstandingExpandedMenus

Page 12: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WorkingwithIconMenus

WorkingwithSubmenus

WorkingwithContextMenusRegisteringaViewforaContextMenu

PopulatingaContextMenu

RespondingtoContextMenuItems

IncorporatingDynamicMenusWorkingwithPop-upMenus

ExploringActionBars

ImplementingaStandardActionBar

ImplementingaTabbedActionBar

ImplementingaList-BasedActionBar

ExploringActionBarandSearchViewDefiningaSearchViewWidgetasaMenuItem

CreatingaSearchResultsActivity

SpecifyingaSearchableXMLFile

DefiningtheSearchResultsActivityintheManifestFile

IdentifyingtheSearchTargetfortheSearchViewWidget

Resources

Summary

Chapter7:StylesandThemes

UsingStyles

UsingThemes

References

Summary

Chapter8:Fragments

WhatIsaFragment?WhentoUseFragments

TheStructureofaFragment

AFragment’sLifeCycle

SampleFragmentAppShowingtheLifeCycle

FragmentTransactionsandtheFragmentBackStack

Page 13: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

FragmentTransactionTransitionsandAnimations

TheFragmentManagerCautionWhenReferencingFragments

SavingFragmentState

ListFragmentsand<fragment>

InvokingaSeparateActivityWhenNeeded

PersistenceofFragments

CommunicationswithFragmentsUsingstartActivity()andsetTargetFragment()

References

Summary

Chapter9:RespondingtoConfigurationChanges

TheDefaultConfigurationChangeProcessTheDestroy/CreateCycleofActivities

TheDestroy/CreateCycleofFragments

UsingFragmentManagertoSaveFragmentState

UsingsetRetainInstanceonaFragment

DeprecatedConfigurationChangeMethods

HandlingConfigurationChangesYourself

References

Summary

Chapter10:WorkingwithDialogs

UsingDialogsinAndroid

UnderstandingDialogFragmentsDialogFragmentBasics

DialogFragmentSampleApplication

WorkingwithToast

References

Summary

Chapter11:WorkingwithPreferencesandSavingState

ExploringthePreferencesFrameworkUnderstandingCheckBoxPreferenceandSwitchPreference

Page 14: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AccessingaPreferenceValueinCode

UnderstandingListPreference

UnderstandingEditTextPreference

UnderstandingMultiSelectListPreference

UpdatingAndroidManifest.xml

UsingPreferenceCategory

CreatingChildPreferenceswithDependency

PreferenceswithHeaders

PreferenceScreens

DynamicPreferenceSummaryTextSavingStatewithPreferences

UsingDialogPreference

Reference

Summary

Chapter12:UsingtheCompatibilityLibraryforOlderDevices

ItAllStartedwithTablets

AddingtheLibrarytoYourProjectIncludingthev7SupportLibrary

Includingthev8SupportLibrary

Includingthev13SupportLibrary

Includingthev17SupportLibrary

IncludingJustthev4SupportLibrary

RetrofittinganAppwiththeAndroidSupportLibrary

References

Summary

Chapter13:ExploringPackages,Processes,Threads,andHandlers

UnderstandingPackagesandProcesses

ACodePatternforSharingData

UnderstandingLibraryProjects

UnderstandingComponentsandThreads

UnderstandingHandlers

UsingWorkerThreads

References

Page 15: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Summary

Chapter14:BuildingandConsumingServices

ConsumingHTTPServicesUsingtheHttpClientforHTTPGETRequests

UsingtheHttpClientforHTTPPOSTRequests(aMultipartExample)

SOAP,JSON,andXMLParsers

DealingwithExceptions

AddressingMultithreadingIssues

FunwithTimeouts

UsingtheHttpURLConnection

UsingtheAndroidHttpClient

UsingAndroidServicesUnderstandingServicesinAndroid

UnderstandingLocalServices

UnderstandingAIDLServices

DefiningaServiceInterfaceinAIDL

ImplementinganAIDLInterface

CallingtheServicefromaClientApplication

PassingComplexTypestoServices

MessengersandHandlers

References

Summary

Chapter15:AdvancedAsyncTaskandProgressDialogs

EssentialsofaSimpleAsyncTaskImplementingYourFirstAsyncTask

CallinganAsyncTask

UnderstandingtheonPreExecute()CallbackandProgressDialog

UnderstandingthedoInBackground()Method

TriggeringonProgressUpdate()throughpublishProgress()

UnderstandingtheonPostExecute()Method

UpgradingtoaDeterministicProgressDialog

AsyncTaskandThreadPools

IssuesandSolutionsforCorrectlyShowingtheProgressofanAsyncTaskDealingwithActivityPointersandDeviceRotation

DealingwithManagedDialogs

UsingRetainedObjectsandFragmentDialogs

Page 16: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UsingRetainedFragmentsandFragmentDialogs

UsingRetainedFragmentsandProgressBars

References

Summary

Chapter16:BroadcastReceiversandLong-RunningServices

SendingaBroadcastCodingaSimpleReceiver

RegisteringaReceiverintheManifestFile

AccommodatingMultipleReceivers

WorkingwithOut-of-ProcessReceivers

UsingNotificationsfromaReceiverMonitoringNotificationsThroughtheNotificationManager

SendingaNotification

StartinganActivityinaBroadcastReceiver

ExploringLong-RunningReceiversandServicesUnderstandingLong-RunningBroadcastReceiverProtocol

UnderstandingIntentService

ExtendingIntentServiceforaBroadcastReceiverExploringLong-RunningBroadcastServiceAbstraction

DesigningALong-RunningReceiver

AbstractingaWakeLockwithLightedGreenRoom

ImplementingaLong-RunningServiceUnderstandingaNonstickyService

UnderstandingaStickyService

UnderstandingRedeliverIntentsOption

CodingaLong-RunningService

AdditionalTopicsinBroadcastReceivers

References

Summary

Chapter17:ExploringtheAlarmManager

SettingUpaSimpleAlarmSettingOffanAlarmRepeatedly

CancellinganAlarm

UnderstandingExactnessofAlarms

Page 17: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UnderstandingPersistenceofAlarms

References

Summary

Chapter18:Exploring2DAnimation

ExploringFrame-by-FrameAnimation

ExploringLayoutAnimationUnderstandingInterpolators

ExploringViewAnimationUsingCameratoProvideDepthPerceptionin2D

ExploringtheAnimationListenerClass

NotesonTransformationMatrices

ExploringPropertyAnimations:TheNewAnimationAPIUnderstandingPropertyAnimation

PlanningaTestBedforPropertyAnimation

AnimatingViewswithObjectAnimators

AchievingSequentialAnimationwithAnimatorSet

SettingAnimationRelationshipswithAnimatorSet.Builder

UsingXMLtoLoadAnimators

UsingPropertyValuesHolder

UnderstandingViewPropertiesAnimation

UnderstandingTypeEvaluators

UnderstandingKeyFrames

UnderstandingLayoutTransitions

Resources

Summary

Chapter19:ExploringMapsandLocation-BasedServices

UnderstandingtheMappingPackageObtainingaMapsAPIKeyfromGoogle

AddingtheMapsAPIKeytoYourApplication

UnderstandingMapFragment

AddingMarkerstoMaps

UnderstandingtheLocationPackageGeocodingwithAndroid

UnderstandingLocationServices

UsingProximityAlertsandGeofencing

Page 18: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

References

Summary

Chapter20:UnderstandingtheMediaFrameworks

UsingtheMediaAPIsWhitherSDCards?

PlayingMediaPlayingAudioContent

PlayingVideoContent

BonusOnlineChapteronRecordingandAdvancedMediaReferences

Summary

Chapter21:HomeScreenWidgets

UserExperiencewithHomeScreenWidgets

UnderstandingWidgetConfigurationActivity

UnderstandingtheLifeCycleofaWidgetUnderstandingWidgetDefinitionPhase

ImplementingASampleWidgetApplicationDefiningtheWidgetProvider

ImplementingWidgetConfigurationActivity

ImplementingaWidgetProvider

Collection-BasedWidgets

Resources

Summary

Chapter22:TouchScreens

UnderstandingMotionEventsTheMotionEventObject

RecyclingMotionEvents

UsingVelocityTracker

MultitouchTheBasicsofMultitouch

Gestures

Page 19: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThePinchGesture

GestureDetectorandOnGestureListeners

References

Summary

Chapter23:ImplementingDragandDrop

ExploringDragandDrop

BasicsofDragandDropin3.0+

Drag-and-DropExampleApplicationListofFiles

LayingOuttheExampleDrag-and-DropApplication

RespondingtoonDragintheDropzone

SettingUptheDragSourceViews

TestingtheExampleDrag-and-DropApplication

References

Summary

Chapter24:UsingSensors

WhatIsaSensor?DetectingSensors

WhatCanWeKnowAboutaSensor?

GettingSensorEventsIssueswithGettingSensorData

InterpretingSensorDataLightSensors

ProximitySensors

TemperatureSensors

PressureSensors

GyroscopeSensors

Accelerometers

MagneticFieldSensors

UsingAccelerometersandMagneticFieldSensorsTogether

MagneticDeclinationandGeomagneticField

GravitySensors

LinearAccelerationSensors

RotationVectorSensors

Page 20: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

References

Summary

Chapter25:ExploringAndroidPersistenceandContentProvidersSavingStateUsingSharedPreferences

SavingStateUsingInternalFiles

SavingStateUsingExternalFiles

SavingStateUsingSQLite

SavingStateUsingO/RMappingLibraries

SavingStateUsingContentProviders

SavingStateUsingNetworkStorage

StoringDataDirectlyUsingSQLiteSummarizingKeySQLitePackagesandClasses

CreatinganSQLiteDatabase

DefiningaDatabaseThroughDDLs

MigratingaDatabase

InsertingRows

UpdatingRows

DeletingRows

ReadingRows

ApplyingTransactions

SummarizingSQLite

DoingTransactionsThroughDynamicProxies

ExploringDatabasesontheEmulatorandAvailableDevices

ExploringContentProvidersExploringAndroid’sBuilt-inProviders

UnderstandingtheStructureofContentProviderURIs

ImplementingContentProvidersPlanningaDatabase

ExtendingContentProvider

UsingUriMatchertoFigureOuttheURIs

UsingProjectionMaps

FulfillingMIME-TypeContracts

ImplementingtheQueryMethod

ImplementingtheInsertMethod

ImplementingtheUpdateMethod

ImplementingtheDeleteMethod

RegisteringtheProvider

ExercisingtheBookProvider

Page 21: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AddingaBook

RemovingaBook

DisplayingtheListofBooks

Resources

Summary

Chapter26:UnderstandingLoaders

UnderstandingtheArchitectureofLoaders

ListingBasicLoaderAPIClasses

DemonstratingtheLoaders

Step1:PreparingtheActivitytoLoadData

Step2:InitializingtheLoaderDelvingintotheStructureofListActivity

WorkingwithAsynchronousLoadingofData

Step3:ImplementingonCreateLoader()

Step4:ImplementingonLoadFinished()

Step5:ImplementingonLoaderReset()

UsingSearchwithLoaders

UnderstandingtheOrderofLoaderManagerCallbacks

WritingCustomLoaders

Resources

Summary

Chapter27:ExploringtheContactsAPI

UnderstandingAccountsEnumeratingAccounts

UnderstandingContactsExaminingtheContactsSQLiteDatabase

UnderstandingRawContacts

UnderstandingtheContactsDataTable

UnderstandingAggregatedContacts

Exploringview_contacts

Exploringcontact_entities_view

Page 22: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WorkingwiththeContactsAPIExploringAccounts

ExploringAggregatedContacts

ExploringRawContacts

ExploringRawContactData

AddingaContactwithItsDetails

ControllingAggregationofContacts

UnderstandingPersonalProfileReadingProfileRawContacts

ReadingProfileContactData

AddingDatatothePersonalProfile

RoleofSyncAdapters

UsingBatchOperationstoOptimizeContentProviderUpdatesIdeaofBatchingContentProviderUpdates

BatchingCommitsbyYielding

UsingBackReferences

OptimisticLocking

ReusingtheContactProviderUI

UsingGroupFeatures

UsingPhotoFeatures

References

Summary

Chapter28:ExploringSecurityandPermissions

UnderstandingtheAndroidSecurityModelOverviewofSecurityConcepts

SigningApplicationsforDeployment

PerformingRuntimeSecurityChecksUnderstandingSecurityattheProcessBoundary

DeclaringandUsingPermissions

UnderstandingandUsingURIPermissions

References

Summary

Chapter29:UsingGoogleCloudMessagingwithAndroid

Page 23: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WhatIsGoogleCloudMessaging?UnderstandingtheKeyBuildingBlocksofGCM

PreparingtoUseGCMinYourApplication

AuthenticatingGCMCommunication

BuildinganAndroidGCM-EnabledApplicationCodingtheClientComponentforGCM

CodingtheServerComponentforGCM

MovingBeyondtheGCMIntroduction

Chapter30:DeployingYourApplication:GooglePlayStoreandBeyond

BecomingaPublisherFollowingtheRules

DeveloperConsole

PreparingYourApplicationforSaleTestingforDifferentDevices

SupportingDifferentScreenSizes

PreparingAndroidManifest.xmlforUploading

LocalizingYourApplication

PreparingYourApplicationIcon

DirectingUsersBacktothePlayStore

TheAndroidLicensingService

UsingProGuardforOptimization,FightingPiracy

PreparingYour.apkFileforUploading

UploadingYourApplicationGraphics

ListingDetails

PublishingOptions

ContactInformation

Consent

UserExperienceonGooglePlayStore

BeyondGooglePlayStore

References

Summary

Index

Page 24: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AbouttheAuthorsDaveMacLeanisasoftwareengineerandarchitectlivingandworkinginOrlando,Florida.Since1980,hehasprogrammedinmanylanguages,developingsolutionsrangingfromrobotautomationsystemstodatawarehousing,fromwebself-serviceapplicationstoelectronicdatainterchangetransactionprocessors.DavehasworkedforSunMicrosystems,IBM,TrimbleNavigation,GeneralMotors,BlueCrossBlueShieldofFlorida,andseveralsmallcompanies.HehaswrittenseveralbooksonAndroidandafewmagazinearticles.HegraduatedfromtheUniversityofWaterlooinCanadawithaSystemsDesignEngineeringdegree.Visithisblogathttp://[email protected].

SatyaKomatinenihasbeenprogrammingformorethan20yearsintheITandWebspace.HehashadtheopportunitytoworkwithAssembly,C,C++,Rexx,Java,C#,Lisp,HTML,JavaScript,CSS,SVG,relationaldatabases,objectdatabases,andrelatedtechnologies.Hehaspublishedmorethan30articlestouchingmanyoftheseareas,bothinprintandonline.HehasbeenafrequentspeakeratO’ReillyOpenSourceConference,speakingoninnovationsaroundJavaandWeb.SatyahasdoneaconsiderableamountoforiginalworkincreatingAspire,acomprehensiveopen-sourceJava-basedwebframework,andhasexploredpersonalwebproductivityandcollaborationtoolsthroughhisopen-sourceworkforKnowledgeFolders.com.Satyaholdsamaster’sdegreeinelectricalengineeringfromIndianInstituteofTechnologyandabachelor’sdegreeinelectricalengineeringfromAndhraUniversity,India.YoucanfindhiswebsiteatSatyaKomatineni.com.

GrantAllenhasworkedintheITfieldforover20years,asaCTO,enterprisearchitect,anddatabaseadministrator.Grant’sroleshavecoveredprivateenterprise,academia,andthegovernmentsectoraroundtheworld,specializinginglobal-scalesystemsdesign,development,andperformance.Heisafrequentspeakeratindustryandacademicconferences,ontopicsrangingfromdataminingtocompliance,andtechnologiessuchasdatabases(DB2,Oracle,SQLServer,MySQL),contentmanagement,collaboration,disruptiveinnovation,andmobileecosystemslikeAndroid.HisfirstAndroidapplicationwasatasklisttoremindhimtofinishallhisotherunfinishedAndroidprojects.GrantworksforGoogle,andinhissparetimeiscompletingaPhDonbuildinginnovativehigh-technologyenvironments.GrantistheauthorofBeginningAndroidandleadauthorofOracleSQLRecipesandTheDefinitiveGuidetoSQLite.

Page 25: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AbouttheTechincalreviewerShaneKirkearnedaB.S.inComputerSciencefromtheUniversityofKentuckyin2000.He’scurrentlyaSeniorSoftwareEngineerforIDEXXLaboratoriesinWestbrook,Maine,wherehespendshisdaysworkingoncommunicationsolutionsforembeddedsystems.Shane’sforayintomobiledevelopmentbeganin2010,shortlyafterpurchasinghisfirstsmartphone—aDroidXrunningEclair(Android2.1).He’sbeenhookedonAndroideversince.

Page 26: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AcknowledgmentsWritingthisbooktookeffortnotonlyonthepartoftheauthors,butalsofromsomeoftheverytalentedstaffatApress,aswellasthetechnicalreviewer.Therefore,wewouldliketothankSteveAnglin,MatthewMoodie,DouglasPundick,MarkPowers,BrendanFrost,AnaPanchoo,andJillBalzano.

Wewouldalsoliketoextendourdeepestappreciationtothetechnicalreviewer—ShaneKirk—forhisexpertappraisalsandattentiontodetail.Thisbookissomuchbetterbecauseofhisefforts.

Writingatechnicalbookaboutasubjectthatfrequentlychangesisadauntingtask.Whenthedocumentationdidn’tsay,andthesourcecodedidn’treveal,wewouldsearchtheInternetforanswers.Andwe’deventuallyfindwhatwewerelookingfor,buriedhereandthere.ToalltheotherAndroiddevelopersouttherewhoareworkingalongwithustoprovideanswers,wethankyou.

Finally,theauthorsaredeeplygratefultotheirfamiliesforlettingustoilawayonnights,earlymornings,andweekends.Ittakesgreatdedicationtowriteabook,andperhapsevenmoretoputupwithauthorswhiletheywrite.

Page 27: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ForewordWaybackin2008,IwasgivenmyfirstAndroiddevice.ItwastheDream,alsoknownastheG1,andIimmediatelystartedtinkeringwithit.Afterall,herewasasmartphonewiththepromiseofthousandsofapplications,andwhoknewhowmanyhundredsofpossiblehandsets.ThatshowshowmuchIknewatthetime!Ireallyshouldhavebeenthinkingintheorderofmillionsofapplications,andtensofthousandsofdevices,becausethatiswhereAndroidisheadingtoday.

Whetheritistraditionalphones,tablets,cars,in-flightentertainmentsystems,robots,oranyotherofthemyriadAndroiddevicesoutthere,whatmakesthemgreataretheapplicationswrittenbypeoplelikeyou,dearreader!Everyday,Androiddeveloperspushthepossibilitiesofwhatapplications—andAndroid—cando,anditisthatenergythatdrawsmetothecommunity,andtohelpinginmyownsmallwaywithbookslikeProAndroid.

OneofthebestobservationsabouttechnologyandinnovationIhaveheardisthatinnovationhappenswhenyoucreatesomethingandshareitwithanotherperson,whichtheythenadaptanduseinatotallyunexpectedway.Soletmecommendthisbooktoyouinthatspirit.EnjoyeverythingProAndroidhastoofferyou,andtakeittocreatesomethingtotallyunexpected!We’llbefirstinlinetotryitout,whateveritis.

—GrantAllenNewYorkMay2015

Page 28: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IntroductionWelcometothewonderfulworldofAndroid.Aworldwhere,withabitofknowledgeandeffort,youtoocanwriteAndroidapplications.Towritegoodapplications,however,youwillneedtodigdeeper,tounderstandthefundamentalsoftheAndroidarchitecture,tounderstandhowapplicationscanworktogether,tounderstandhowmobileapplicationsaredifferentfromallpreviousformsofprogramming.TheonlinedocumentationonAndroidisfair,butitdoesnotgofarenough.Youcanreadthesourcecode,butthat’snotatalleasy.

Thisbookistheculminationofsevenyearsofresearching,developing,testing,refining,andwritingaboutAndroid.We’vereadalltheonlinedocumentation,scouredthroughsourcecode,exploredthefarreachesoftheInternet,andhavecompiledthisbook.We’vefilledinthegaps,anticipatedthequestionsyouhave,andprovidedanswers.Alongthewaywe’veseenAPIscomeandgoandberevised.We’veseenmajorchangesinhowapplicationsareconstructed.AtfirstweallusedActivities,butwhentabletscamealongwestartedusingFragments.We’vetakeneverythingwe’velearnedandfilledthisbookwithpracticalguidancetousingthelatestAndroidAPIstowriteinterestingapplications.

Youwillstillfindcoverageofthebeginningtopics,tohelpthenewlearnergetstarteddevelopingforAndroid.Youwillalsofindcoverageofthemoreadvancedtopics,suchasGoogleMapsAndroidAPIv2,whichisverydifferentfromv1.We’veupdatedthiseditionwiththelatestinformationontheavailableAPIs.Youwillfindin-depthcoverageofintents,services,broadcastreceivers,communication,fragments,widgets,sensors,animation,security,GoogleCloudMessaging,audioandvideo,andmore.AndforeverytopictherearesampleprogramsthatillustrateeachAPIinmeaningfulways.Allsourcecodeisdownloadable,soyoucancopyandpasteitintoyourapplicationstogetagreatheadstart.

Page 29: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter1

HelloAndroidWelcometothebook,andwelcometotheworldofAndroiddevelopment.Inalittleundertenyears,Androidhashelpedchangethefaceofmodernmobilecomputingandtelephonyandlaunchedarevolutioninhowapplicationsaredeveloped,andbywhom.Withthisbookinyourhands,youarenowpartofthegreatAndroidexplosion!We’regoingtoassumethatyouwanttogetstraightatworkingwithAndroid,sowe'renotgoingtoboreyouwithafiresidechataboutAndroid'shistory,majorcharacters,plaudits,oranyotherprose.We'regoingtogetstraighttoit!

Inthischapter,you’llstartbyseeingwhatyouneedtobeginbuildingapplicationswiththeAndroidsoftwaredevelopmentkit(SDK)andsetupyourchoiceofdevelopmentenvironment.Next,youstepthrougha“HelloWorld!”application.ThenthechapterexplainstheAndroidapplicationlifecycleandendswithadiscussionaboutrunningyourapplicationswithAndroidVirtualDevices(AVDs)andonrealdevices.Solet’sgetstarted.

PrerequisitesforAndroidDevelopmentTobuildapplicationsforAndroid,youneedtheJavaSEDevelopmentKit(JDK),theAndroidSDK,andadevelopmentenvironment.Strictlyspeaking,youcandevelopyourapplicationsusingnothingmorethanaprimitivetexteditorandahandfulofcommand-linetoolslikeAnt.Forthepurposesofthisbook,we’llusethecommonlyavailableEclipseIDE,thoughyouarefreetoadoptAndroidStudioanditsIntelliJunderpinnings—we’llevenwalkthroughAndroidStudioforthosewhohavenotseenit.Withtheexceptionofafewadd-ontools,theexamplesweshareinthebookwillworkequallywellbetweenthesetwoIDEs.

TheAndroidSDKrequiresJDK6or7(thefullJDK,notjusttheJavaRuntimeEnvironment[JRE])andoptionallyasupportedIDE.Currently,GoogledirectlysupportstwoalternativeIDEs,providingsomechoice.Historically,EclipsewasthefirstIDEsupportedbyGoogleforAndroiddevelopment,anddevelopingforAndroid4.4KitKator5.0LollipoprequiresEclipse3.6.2orhigher(thisbookusesEclipse4.2or4.4,alsoknownasJunoandLuna,respectively,andotherversions).ThealternativeenvironmentreleasedandsupportedbyGoogleforAndroidisnowknownasAndroidStudio.ThisisapackagedversionofIDEAIntelliJwithbuilt-inAndroidSDKanddevelopertools.

NoteAtthetimeofthiswriting,Java8wasavailablebutnotyetsupportedbytheAndroidSDK.InpreviousversionsoftheAndroidSDK,Java5wasalsosupported,butthisisnolongerthecase.ThelatestversionofEclipse(4.4,a.k.a.Juno)wasalsoavailable,butAndroidhashistoricallynotbeenreliableonthelatestEclipserightaway.Checkthesystemrequirementsheretofindthelatest:http://developer.android.com/sdk/index.html.

Page 30: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheAndroidSDKiscompatiblewithWindows(WindowsXP,WindowsVista,andWindows7),MacOSX(Intelonly),andLinux(Intelonly).Intermsofhardware,youneedanIntelmachine,themorepowerfulthebetter.

Tomakeyourlifeeasier,ifyouchooseEclipseasyourIDE,youwillwanttouseAndroiddevelopmenttools(ADT).ADTisanEclipseplug-inthatsupportsbuildingAndroidapplicationswiththeEclipseIDE.

TheAndroidSDKismadeupoftwomainparts:thetoolsandthepackages.WhenyoufirstinstalltheSDK,allyougetarethebasetools.Theseareexecutablesandsupportingfilestohelpyoudevelopapplications.ThepackagesarethefilesspecifictoaparticularversionofAndroid(calledaplatform)oraparticularadd-ontoaplatform.TheplatformsincludeAndroid1.5through4.4.2.Theadd-onsincludetheGoogleMapsAPI,theMarketLicenseValidator,andevenvendor-suppliedonessuchasSamsung’sGalaxyTabadd-on.AfteryouinstalltheSDK,youthenuseoneofthetoolstodownloadandsetuptheplatformsandadd-ons.

Remember,youonlyneedtosetupandconfigureoneofEclipseorAndroidStudio.Youcanusebothifyouaresoinclined,butit’scertainlynotrequired.Let’sgetstarted!

SettingUpYourEclipseEnvironmentInthissection,youwalkthroughdownloadingJDK6,theEclipseIDE,theAndroidSDK(toolsandpackages),andADT.YoualsoconfigureEclipsetobuildAndroidapplications.Googleprovidesapagetodescribetheinstallationprocess(http://developer.android.com/sdk/installing.html)butleavesoutsomecrucialsteps,asyouwillsee.

DownloadingJDKThefirstthingyouneedistheJDK.TheAndroidSDKrequiresJDK6orhigher;we’vedevelopedourexamplesusingJDK6and7,dependingontheversionofEclipseorAndroidStudioinuse.ForWindowsandMacOSX,downloadJDK7fromtheOraclewebsite(www.oracle.com/technetwork/java/javase/downloads/index.html)andinstallit.YouonlyneedtheJDK,notthebundles.ToinstalltheJDKforLinux,openaTerminalwindowandinstructyourpackagemanagertoinstallit.Forexample,inDebianorUbuntutrythefollowing:

sudoapt-getinstallsun-java7-jdk

ThisshouldinstalltheJDKplusanydependenciessuchastheJRE.Ifitdoesn’t,itprobablymeansyouneedtoaddanewsoftwaresourceandthentrythatcommandagain.Thewebpagehttps://help.ubuntu.com/community/Repositories/Ubuntuexplainssoftwaresourcesandhowtoaddtheconnectiontothird-partysoftware.TheprocessisdifferentdependingonwhichversionofLinuxyouhave.Afteryou’vedonethat,retrythecommand.

Page 31: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WiththeintroductionofUbuntu10.04(LucidLynx),UbunturecommendsusingOpenJDKinsteadoftheOracle/SunJDK.ToinstallOpenJDK,trythefollowing:

sudoapt-getinstallopenjdk-7-jdk

Ifthisisnotfound,setupthethird-partysoftwareasoutlinedpreviouslyandrunthecommandagain.AllpackagesonwhichtheJDKdependsareautomaticallyaddedforyou.ItispossibletohavebothOpenJDKandtheOracle/SunJDKinstalledatthesametime.ToswitchactiveJavabetweentheinstalledversionsofJavaonUbuntu,runthiscommandatashellprompt

sudoupdate-alternatives--configjava

andthenchoosewhichJavayouwantasthedefault.

NowthatyouhaveaJavaJDKinstalled,it’stimetosettheJAVA_HOMEenvironmentvariabletopointtotheJDKinstallfolder.TodothisonaWindowsXPmachine,chooseStart MyComputer,right-click,selectProperties,choosetheAdvancedtab,andclickEnvironmentVariables.ClickNewtoaddthevariableorEdittomodifyitifitalreadyexists.ThevalueofJAVA_HOMEissomethinglikeC:\ProgramFiles\Java\jdk1.7.0_79.

ForWindowsVistaandWindows7,thestepstogettotheEnvironmentVariablesscreenarealittledifferent.ChooseStart Computer,right-click,chooseProperties,clickthelinkforAdvancedSystemSettings,andclickEnvironmentVariables.Afterthat,followthesameinstructionsasforWindowsXPtochangetheJAVA_HOMEenvironmentvariable.

ForMacOSX,yousetJAVA_HOMEinthe.bashrcfileinyourhomedirectory.Editorcreatethe.bashrcfile,andaddalinethatlookslikethis

exportJAVA_HOME=path_to_JDK_directory

wherepath_to_JDK_directoryisprobably/Library/Java/Home.ForLinux,edityour.bashrcfileandaddalineliketheoneforMacOSX,exceptthatyourpathtoJavaisprobablysomethinglike/usr/lib/jvm/java-6-sunor/usr/lib/jvm/java-6-openjdk.

DownloadingEclipseAftertheJDKisinstalled,youcandownloadtheEclipseIDEforJavaDevelopers.(Youdon’tneedtheeditionforJavaEE;itworks,butit’smuchlargerandincludesthingsyoudon’tneedforthisbook.)TheexamplesinthisbookuseEclipse4.2or4.4(onbothLinuxandWindowsenvironments).YoucandownloadallversionsofEclipsefromwww.eclipse.org/downloads/.

NoteAsanalternativetotheindividualstepspresentedhere,youcanalsodownloadtheADTBundlefromtheAndroiddevelopersite.ThisincludesEclipsewithbuilt-indevelopertoolsandtheAndroidSDKinonepackage.It’s

Page 32: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

agreatwaytogetstartedquickly,butifyouhaveanexistingenvironment,orjustwanttoknowhowallthecomponentsarestitchedtogether,thenfollowingthestep-by-stepinstructionsisthewaytogo.

TheEclipsedistributionisa.zipfilethatcanbeextractedjustaboutanywhere.ThesimplestplacetoextracttoonWindowsisC:\,whichresultsinaC:\eclipsefolderwhereyoufindeclipse.exe.Dependingonyoursecurityconfiguration,WindowsmayinsistonenforcingUACwhenrunningfromC:.ForMacOSX,youcanextracttoApplications.ForLinux,youcanextracttoyourhomedirectoryorhaveyouradministratorputEclipseintoacommonplacewhereyoucangettoit.TheEclipseexecutableisintheeclipsefolderforallplatforms.YoumayalsofindandinstallEclipseusingLinux’sSoftwareCenterforaddingnewapplications,althoughthismaynotprovideyouwiththelatestversion.

WhenyoufirststartupEclipse,itasksyouforalocationfortheworkspace.Tomakethingseasy,youcanchooseasimplelocationsuchasC:\androidoradirectoryunderyourhomedirectory.Ifyousharethecomputerwithothers,youshouldputyourworkspacefoldersomewhereunderneathyourhomedirectory.

DownloadingtheAndroidSDKTobuildapplicationsforAndroid,youneedtheAndroidSDK.Asstatedbefore,theSDKcomeswiththebasetools;thenyoudownloadthepackagepartsthatyouneedand/orwanttouse.ThetoolspartoftheSDKincludesanemulatorsoyoudon’tneedamobiledevicewiththeAndroidOStodevelopAndroidapplications.Italsohasasetuputilitytoallowyoutoinstallthepackagesthatyouwanttodownload.

YoucandownloadtheAndroidSDKfromhttp://developer.android.com/sdk.Itshipsasa.zipfile,similartothewayEclipseisdistributed,soyouneedtounzipittoanappropriatelocation.ForWindows,unzipthefiletoaconvenientlocation(weusedtheC:drive),afterwhichyoushouldhaveafoldercalledsomethinglikeC:\android-sdk-windowsthatcontainsthefilesasshowninFigure1-1.ForMacOSXandLinux,youcanunzipthefiletoyourhomedirectory.NoticethatMacOSXandLinuxdonothaveanSDKManagerexecutable;theequivalentoftheSDKManagerinMacOSXandLinuxistorunthetools/androidprogram.

Figure1-1.BasecontentsoftheAndroidSDK

Page 33: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Analternativeapproach(forWindowsonly)istodownloadaninstallerEXEinsteadofthezipfileandthenruntheinstallerexecutable.ThisexecutablechecksfortheJavaJDK,unpackstheembeddedfilesforyou,andrunstheSDKManagerprogramtohelpyousetuptherestofthedownloads.

WhetherthroughusingtheWindowsinstallerorbyexecutingtheSDKManager,youshouldinstallsomepackagesnext.WhenyoufirstinstalltheAndroidSDK,itdoesnotcomewithanyplatformversions(thatis,versionsofAndroid).Installingplatformsisprettyeasy.Afteryou’velaunchedtheSDKManager,youseewhatisinstalledandwhat’savailabletoinstall,asshowninFigure1-2.YoumustaddAndroidSDKtoolsandplatform-toolsinorderforyourenvironmenttowork.Becauseyouuseitshortly,addatleasttheAndroid1.6SDKplatform,aswellasthelatestplatformshowninyourinstaller.

Figure1-2.AddingpackagestotheAndroidSDK

ClicktheInstallbutton.YouneedtoclickAcceptforeachitemyou’reinstalling(orAcceptAll)andthenclickInstall.Androidthendownloadsyourpackagesandplatformstomakethemavailabletoyou.TheGoogleAPIsareadd-onsfordevelopingapplicationsusingGoogleMaps.Youcanalwayscomebacktoaddmorepackageslater.

UpdatingYourPATHEnvironmentVariableTheAndroidSDKcomeswithatoolsdirectorythatyouwanttohaveinyourPATH.

Page 34: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

YoualsoneedinyourPATHtheplatform-toolsdirectoryyoujustinstalled.Let’saddthemnowor,ifyou’reupgrading,makesurethey’recorrect.Whileyou’rethere,youcanalsoaddaJDKbindirectory,whichwillmakelifeeasierlater.

ForWindows,getbacktotheEnvironmentVariableswindow.EditthePATHvariableandaddasemicolon(;)ontheend,followedbythepathtotheAndroidSDKtoolsfolder,followedbyanothersemicolon,followedbythepathtotheAndroidSDKplatform-toolsfolder,followedbyanothersemicolon,andthen%JAVA_HOME%\bin.ClickOKwhenyou’redone.ForMacOSXandLinux,edityour.bashrcfileandaddtheAndroidSDKtoolsdirectorypathtoyourPATHvariable,aswellastheAndroidSDKplatform-toolsdirectoryandthe$JAVA_HOME/bindirectory.SomethinglikethefollowingworksforLinux:

exportPATH=$PATH:$HOME/android-sdk-linux_x86/tools:$HOME/android-sdk-linux_x86/platform-tools:$JAVA_HOME/bin

JustmakesurethatthePATHcomponentthat’spointingtotheAndroidSDKtoolsdirectoriesiscorrectforyourparticularsetup.

TheToolsWindowLaterinthisbook,therearetimeswhenyouneedtoexecuteacommand-lineutilityprogram.TheseprogramsarepartoftheJDKorpartoftheAndroidSDK.ByhavingthesedirectoriesinyourPATH,youdon’tneedtospecifythefullpathnamesinordertoexecutethem,butyouneedtostartupatoolswindowinordertorunthem(laterchaptersrefertothistoolswindow).TheeasiestwaytocreateatoolswindowinWindowsistochooseStart Run,typeincmd,andclickOK.ForMacOSX,chooseTerminalfromyourApplicationsfolderinFinderorfromtheDockifit’sthere.ForLinux,runyourfavoriteterminal.

YoumayneedtoknowtheIPaddressofyourworkstationlater.TofindthisinWindows,launchatoolswindowandenterthecommandipconfig.TheresultscontainanentryforIPv4(orsomethinglikethat)withyourIPaddresslistednexttoit.AnIPaddresslookssomethinglikethis:192.168.1.25.ForMacOSXandLinux,launchatoolswindowandusethecommandifconfig.YoufindyourIPaddressnexttothelabelinetaddr.

Youmayseeanetworkconnectioncalledlocalhostorlo;theIPaddressforthisnetworkconnectionis127.0.0.1.Thisisaspecialnetworkconnectionusedbytheoperatingsystemandisnotthesameasyourworkstation’sIPaddress.Lookforadifferentnumberforyourworkstation’sIPaddress.

InstallingADTNowyouneedtoinstallADT(veryrecentlyrenamedtoGDT,theGoogleDeveloperTools),anEclipseplug-inthathelpsyoubuildAndroidapplications.Specifically,ADTintegrateswithEclipsetoprovidefacilitiesforyoutocreate,test,anddebugAndroid

Page 35: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

applications.YouneedtousetheInstallNewSoftwarefacilityinEclipsetoperformtheinstallation.(TheinstructionsforupgradingADTappearlaterinthissection.)Togetstarted,launchtheEclipseIDEandfollowthesesteps:

1. SelectHelp InstallNewSoftware.

2. SelecttheWorkWithfield,typein

https://dl-ssl.google.com/android/eclipse/,

andpressEnter.EclipsecontactsthesiteandpopulatesthelistasshowninFigure1-3.

Figure1-3.InstallingADTusingtheInstallNewSoftwarefeatureinEclipse

3. YoushouldseeanentrynamedDeveloperToolswithfourchildnodes:AndroidDDMS,AndroidDevelopmentTools,AndroidHierarchyViewer,andAndroidTraceview.Justbeforepublishingthisbook,GoogleupdatedtheADTtobepartofthemoregenericGoogleDeveloperToolspluginforEclipse,orGDT.LookforthesameoptionsintheGDT.SelecttheparentnodeDeveloperTools,makesurethechildnodesarealsoselected,andclicktheNextbutton.Theversionsyouseemaybenewerthanthese,andthat’sokay.Youmayalsoseeadditionaltools.Thesetoolsareexplained

Page 36: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

furtherinChapter11.

4. Eclipseasksyoutoverifythetoolstoinstall.ClickNext.

5. You’reaskedtoreviewthelicensesforADTaswellasforthetoolsrequiredtoinstallADT.Reviewthelicenses,click“Iaccept,”andthenclicktheFinishbutton.

Eclipsedownloadsthedevelopertoolsandinstallsthem.YouneedtorestartEclipseforthenewplug-intoshowupintheIDE.

IfyoualreadyhaveanolderversionofADTinEclipse,gototheEclipseHelpmenuandchooseCheckforUpdates.YoushouldseethenewversionofADTandbeabletofollowtheinstallationinstructions,pickingupatstep3.

NoteIfyou’redoinganupgradeofADT,youmaynotseesomeofthesetoolsinthelistoftoolstobeupgraded.Ifyoudon’tseethem,thenafteryou’veupgradedtherestoftheADT,gotoInstallNewSoftwareandselecthttps://dl-ssl.google.com/android/eclipse/fromtheWorksWithmenu.Themiddlewindowshouldshowyouothertoolsthatareavailabletobeinstalled.

ThefinalsteptomakeADTfunctionalinEclipseistopointittotheAndroidSDK.InEclipse,selectWindow Preferences.(OnMacOSX,PreferencesisundertheEclipsemenu.)InthePreferencesdialogbox,selecttheAndroidnodeandsettheSDKLocationfieldtothepathoftheAndroidSDK(seeFigure1-4)andthenclicktheApplybutton.NotethatyoumayseeadialogboxaskingifyouwanttosendusagestatisticstoGoogleconcerningtheAndroidSDK;thatdecisionisuptoyou.

Page 37: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure1-4.PointingADTtotheAndroidSDK

YoumaywanttomakeonemorePreferenceschangeontheAndroid Buildpage.TheSkipPackagingoptionshouldbecheckedifyou’dliketomakeyourfilesavesfaster.Bydefault,theADTreadiesyourapplicationforlauncheverytimeitbuildsit.Bycheckingthisoption,packagingandindexingoccuronlywhentrulyneeded.

FromEclipse,youcanlaunchtheSDKManager.Todoso,chooseWindow AndroidSDKManager.YoushouldseethesamewindowasinFigure1-2.

Ifyou’vechosenEclipseasyourIDE,youarealmostreadyforyourfirstAndroidapplication—youcanskipthefollowingsectiononAndroidStudioandheadstraighttothe“LearningAndroid’sFundamentalComponents”section.

SettingUpYourAndroidStudioEnvironmentIn2013,Googleintroducedasecondsupporteddevelopmentenvironment,knownasAndroidStudio(orAndroidDeveloperStudioatthetimeoflaunch).ThisisbasedaroundapopularJavaIDE:IDEAIntelliJ.ThemostimportantthingtoknowaboutAndroidStudioisthatitisstillaworkinprogress.Asofthisbook’swriting,thelatestversionis1.2.Anyonefamiliarwiththevagariesofversionnumbersknowsthatstartingwithalow

Page 38: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

numberusuallymeans“beware!”

ThesecondmostimportantthingtorememberisthatAndroidStudiocurrentlyassumesa64-bitdevelopmentenvironment.ThatmeansdependencieslikeJavaalsoneedtobe64-bit.

ThenextsectionsbrieflycoverthesetupofAndroidStudioforthoseinterestedorgung-hoenoughtouseit.BemindfulthattherestofthebookpredominantlyshowsexamplesandoptionsusingEclipse.

JavarequirementsforAndroidStudioLikeEclipse,AndroidStudioreliesonaworkingJavainstallation.AndroidStudiowillattempttoautomaticallydiscoveryourJavaenvironmentduringinstallation,soitpaystohaveJavainstalledandconfigured.

ForJavainstallation,rememberthatAndroidStudiois64-bit.Inallotherrespects,youcanfollowtheprecedingsectiontitled“DownloadingJDK”—wewon’trepeatthatword-for-wordheretosavesometrees.Ensureyoufollowalltheinstructionsthere,includingsettingtheJAVA_HOMEenvironmentvariable,asthisisthemainindicatorusedbytheAndroidStudioinstallertofindyourJavainstallation.

DownloadingandInstallingAndroidStudioGooglemakesAndroidStudioavailablefromthemainAndroiddevelopmentsite,currentlyattheURLhttp://developer.android.com/sdk/installing/studio.html.Thatmaychangeatanytime,butaquicksearchonthedeveloper.android.comsiteshouldfindit.AndroidStudioispackagedasamonolithicbundle,withnearlyallthecomponentsyouneed.TheJavaSDKistheexception—we’llcoverthatshortly.ThepackagedownloadedfromtheprecedingURLwillbenamedsomethinglikeandroid-studio-bundle-132.893413-windows.exeforwindows,orasimilarnamewithadifferentextensionforOSXandLinux,andincludesthefollowing:

CurrentlatestbuildoftheAndroidStudiobundleofIntelliJIDEA

Built-inAndroidSDK

AllrelatedAndroidbuildtools

AndroidVirtualDeviceimages

We’lltalkmoreaboutthesecomponentsinlaterchapters.ForaWindowsinstallationruntheexecutableandfollowthepromptstochooseaninstallationpath,anddecidewhetherAndroidStudioismadeavailabletoallusersontheWindowsmachine,orjustthecurrentuser.ForOSX,openthe.dmgfileandcopytheAndroidStudioentrytoyourApplicationsfolder.UnderLinux,extractthecontentsofthe.tgzfiletoyourdesiredlocation.

Onceinstalled,youcanstartAndroidStudiounderWindowsfromthestartmenufolder

Page 39: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

youchosewhenprompted;underOSXfromtheApplicationsfolder;andunderLinuxbyrunningthe./android-studio/bin/studio.shfileunderyourinstallationdirectory.Whatevertheoperatingsystem,youshouldseetheAndroidStudiohomescreenasdepictedinFigure1-5.

Figure1-5.AndroidStudiowhenfirstlaunched

LearningAndroid’sFundamentalComponentsEveryapplicationframeworkhassomekeycomponentsthatdevelopersneedtounderstandbeforetheycanbegintowriteapplicationsbasedontheframework.Forexample,youneedtounderstandJavaServerPages(JSP)andservletsinordertowriteJava2Platform,EnterpriseEdition(J2EE)applications.Similarly,youneedtounderstandviews,activities,fragments,intents,contentproviders,services,andtheAndroidManifest.xmlfilewhenyoubuildapplicationsforAndroid.Youbrieflycoverthesefundamentalconceptshereandexploretheminmoredetailthroughoutthebook.

Page 40: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ViewViewsareuserinterface(UI)elementsthatformthebasicbuildingblocksofauserinterface.Aviewcanbeabutton,alabel,atextfield,ormanyotherUIelements.Ifyou’refamiliarwithviewsinJ2EEandSwing,thenyouunderstandviewsinAndroid.Viewsarealsousedascontainersforviews,whichmeansthere’susuallyahierarchyofviewsintheUI.Intheend,everythingyouseeisaview.

ActivityAnactivityisaUIconceptthatusuallyrepresentsasinglescreeninyourapplication.Itgenerallycontainsoneormoreviews,butitdoesn’thaveto.Anactivityisprettymuchlikeitsounds—somethingthathelpstheuserdoonething,whichcouldbeviewingdata,creatingdata,oreditingdata.MostAndroidapplicationshaveseveralactivitieswithinthem.

FragmentWhenascreenislarge,itbecomesdifficulttomanageallofitsfunctionalityinasingleactivity.Fragmentsarelikesub-activities,andanactivitycandisplayoneormorefragmentsonthescreenatthesametime.Whenascreenissmall,anactivityismorelikelytocontainjustonefragment,andthatfragmentcanbethesameoneusedwithinlargerscreens.

IntentAnintentgenericallydefinesan“intention”todosomework.Intentsencapsulateseveralconcepts,sothebestapproachtounderstandingthemistoseeexamplesoftheiruse.Youcanuseintentstoperformthefollowingtasks:

Broadcastamessage

Startaservice

Launchanactivity

Displayawebpageoralistofcontacts

Dialaphonenumberoransweraphonecall

Intentsarenotalwaysinitiatedbyyourapplication—they’realsousedbythesystemtonotifyyourapplicationofspecificevents(suchasthearrivalofatextmessage).

Intentscanbeexplicitorimplicit.IfyousimplysaythatyouwanttodisplayaURL,thesystemdecideswhatcomponentwillfulfilltheintention.Youcanalsoprovidespecificinformationaboutwhatshouldhandletheintention.Intentslooselycoupletheactionandactionhandler.

Page 41: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContentProviderDatasharingamongmobileapplicationsonadeviceiscommon.Therefore,Androiddefinesastandardmechanismforapplicationstosharedata(suchasalistofcontacts)withoutexposingtheunderlyingstorage,structure,andimplementation.Throughcontentproviders,youcanexposeyourdataandhaveyourapplicationsusedatafromotherapplications.

ServiceServicesinAndroidresembleservicesyouseeinWindowsorotherplatforms—they’rebackgroundprocessesthatcanpotentiallyrunforalongtime.Androiddefinestwotypesofservices:localservicesandremoteservices.Localservicesarecomponentsthatareonlyaccessiblebytheapplicationthatishostingtheservice.Conversely,remoteservicesareservicesthataremeanttobeaccessedremotelybyotherapplicationsrunningonthedevice.

Anexampleofaserviceisacomponentthatisusedbyane-mailapplicationtopollfornewmessages.Thiskindofservicemaybealocalserviceiftheserviceisnotusedbyotherapplicationsrunningonthedevice.Ifseveralapplicationsusetheservice,thenit’simplementedasaremoteservice.

AndroidManifest.xmlAndroidManifest.xml,whichissimilartotheweb.xmlfileintheJ2EEworld,definesthecontentsandbehaviorofyourapplication.Forexample,itlistsyourapplication’sactivitiesandservices,alongwiththepermissionsandfeaturestheapplicationneedstorun.

AVDsAnAVDallowsdeveloperstotesttheirapplicationswithouthookingupanactualAndroiddevice(typicallyaphoneoratablet).AVDscanbecreatedinvariousconfigurationstoemulatedifferenttypesofrealdevices.

HelloWorld!Nowyou’rereadytobuildyourfirstAndroidapplication.Youstartbybuildingasimple“HelloWorld!”program.Createtheskeletonoftheapplicationbyfollowingthesesteps:

1. LaunchEclipse,andselectFile New Project.IntheNewProjectdialogbox,selectAndroidApplicationProjectandthenclickNext.YouseetheNewAndroidProjectdialogbox,asshowninFigure1-6.(EclipsemayhaveaddedAndroidProjecttotheNewmenu,soyoucanuseitifit’sthere.)There’salsoaNewAndroid

Page 42: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Projectbuttononthetoolbar.

Figure1-6.UsingtheNewProjectWizardtocreateanAndroidapplication

2. AsshowninFigure1-6,enterHelloAndroidastheprojectname.YouneedtodistinguishthisprojectfromotherprojectsyoucreateinEclipse,sochooseanamethatwillmakesensetoyouwhenyouarelookingatalltheprojectsinyourEclipseenvironment.YouwillalsoseetheavailableBuildTargets.SelectAndroid2.2.ThisistheversionofAndroidyouuseasyourbasefortheapplication.YoucanrunyourapplicationonlaterversionsofAndroid,suchas4.3and4.4;butAndroid2.2hasallthefunctionalityyouneedforthisexample,sochooseitasyourtarget.Ingeneral,it’sbesttochoosethelowestversionnumberyoucan,becausethatmaximizesthenumberofdevicesthatcanrunyourapplication.

3. LeavetheProjectNametoauto-completeitselfbasedonyourApplicationName.

4. Usecom.androidbook.helloasthepackagename.LikeallJavaapplications,yourapplicationmusthaveabasepackagename,andthisisit.Thispackagenamewillbeusedasanidentifierforyourapplicationandmustbeuniqueacrossallapplications.Forthisreason,it’sbesttostartthepackagenamewithadomainnamethatyouown.Ifyoudon’townone,becreativetoensurethatyourpackagenamewon’tlikelybeusedbyanyoneelse.ClickNext.

Page 43: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

5. Thenextwindowprovidesoptionsforcustomerlaunchericons,theactualdirectoryfortheworkspaceinwhichyousourcecodeandotherfilesarestored,andseveralotheroptions.Leavealloftheseatthedefault,andclickNext.

6. ThenextwindowshowsyoutheConfigureLauncherIconoptionsandsettings,asshowninFigure1-7.Feelfreetoplaywiththeoptionshere,thoughanychangesyoumakearecosmeticandaffectthelookofthelaunchericonwhenyourapplicationisdeployed,andnotitsactuallogic.ClickNextwhenready.

Figure1-7.TheAndroidlauncherconfigurationoptionsforanewAndroidproject

7. You’llnextseetheCreateActivityscreen.ChooseBlankActivityastheactivitytype,andclickNexttomovetothelastscreenofthewizard.

8. ThefinalscreenoftheNewAndroidApplicationwizardwillbetheBlankActivitydetailspage.TypeHelloActivityastheActivityName.You’retellingAndroidthatthisactivityistheonetolaunchwhenyourapplicationstartsup.Youmayhaveotheractivitiesinyourapplication,butthisisthefirstonetheusersees.AllowtheLayoutNametoauto-populatewiththevalueactivity_hello.

9. ClicktheFinishbutton,whichtellsADTtogeneratetheprojectskeletonforyou.Fornow,opentheHelloActivity.javafileunderthesrcfolderandmodifytheonCreate()methodasfollows:

Page 44: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);/**createaTextViewandwriteHelloWorld!*/TextViewtv=newTextView(this);tv.setText("HelloWorld!");/**setthecontentviewtotheTextView*/setContentView(tv);}

Youwillneedtoaddanimportandroid.widget.TextView;statementatthetopofthefilewiththeotherimportstogetridoftheerrorreportedbyEclipse.SavetheHelloActivity.javafile.

Toruntheapplication,youneedtocreateanEclipselaunchconfiguration,andyouneedavirtualdeviceonwhichtorunit.We’llrunquicklythroughthesestepsandcomebacklatertomoredetailsaboutAVDs.CreatetheEclipselaunchconfigurationbyfollowingthesesteps:

1. SelectRun RunConfigurations.

2. IntheRunConfigurationsdialogbox,double-clickAndroidApplicationintheleftpane.ThewizardinsertsanewconfigurationnamedNewConfiguration.

3. RenametheconfigurationRunHelloWorld.

4. ClicktheBrowsebutton,andselecttheHelloAndroidproject.

5. LeaveLaunchActionsettoLaunchDefaultActivity.ThedialogshouldappearasshowninFigure1-8.

Page 45: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure1-8.ConfiguringanEclipserunconfigurationtorunthe“HelloWorld!”application

6. ClickApplyandthenRun.You’realmostthere!Eclipseisreadytorunyourapplication,butitneedsadeviceonwhichtorunit.AsshowninFigure1-9,you’rewarnedthatnocompatibletargetswerefoundandaskedifyou’dliketocreateone.ClickYes.

Figure1-9.ErrormessagewarningabouttargetsandaskingforanewAVD

7. You’representedwithawindowthatshowstheexistingAVDs(seeFigure1-10).YouneedtoaddanAVDsuitableforyournewapplication.ClicktheNewbutton.

Page 46: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure1-10.TheexistingAVDs

8. FillintheCreateAVDformasshowninFigure1-11.SetNametoKitKat,chooseAndroid4.4-APILevel19(orsomeotherversion)fortheTarget,setSDCardSizeto64(for64MB),andchooseothervaluesasshown.ClickCreateAVD.TheManagermayconfirmthesuccessfulcreationofyourAVD.ClosetheAVDManagerwindowbyclickingXintheupper-rightcorner.

Figure1-11.ConfiguringanAVD

NoteYou’rechoosinganewerversionoftheSDKforyourAVD,butyourapplicationcanalsorunonanolderone.ThisisokaybecauseAVDswithnewerSDKscanrunapplicationsthatrequireolderSDKs.Theopposite,ofcourse,isnottrue:anapplicationthatrequiresfeaturesof

Page 47: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

anewerSDKwon’trunonanAVDwithanolderSDK.

9. SelectyournewAVDfromthebottomlist.NotethatyoumayneedtoclicktheRefreshbuttontomakeanynewAVDstoshowupinthelist.ClicktheOKbutton.

10. EclipselaunchestheemulatorwithyourveryfirstAndroidapp(seeFigure1-12)!

Figure1-12.HelloAndroidApprunningintheemulator

NoteItmaytaketheemulatorawhiletoemulatethedevicebootupprocess.Oncethebootupprocesshascompleted,youtypicallyseealockedscreen.ClicktheMenubuttonordragtheunlockimagetounlocktheAVD.Afterunlocking,youshouldseeHelloAndroidApprunningintheemulator,asshowninFigure1-11.Beawarethattheemulatorstartsotherapplicationsinthebackgroundduringthestartupprocess,soyoumayseeawarningorerrormessagefromtimetotime.Ifyoudo,youcangenerallydismissittoallowtheemulatortogotothenextstepinthestartupprocess.Forexample,ifyouruntheemulatorandseeamessagelike“applicationabcisnotresponding,”youcaneitherwaitfortheapplicationtostartorsimplyasktheemulatortoforcefullyclosetheapplication.Generally,youshouldwaitandlettheemulatorstartupcleanly.

NowyouknowhowtocreateanewAndroidapplicationandrunitintheemulator.Next,

Page 48: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

we’lllookmorecloselyatAVDs,andalsohowtodeploytoarealdevice.

AVDsAnAVDrepresentsadeviceanditsconfiguration.Forexample,youcouldhaveanAVDrepresentingareallyoldAndroiddevicerunningversion1.5oftheSDKwitha32MBSDcard.TheideaisthatyoucreateAVDsyouaregoingtosupportandthenpointtheemulatortooneofthoseAVDswhendevelopingandtestingyourapplication.Specifying(andchanging)whichAVDtouseisveryeasyandmakestestingwithvariousconfigurationsasnap.Earlier,yousawhowtocreateanAVDusingEclipse.YoucanmakemoreAVDsinEclipsebychoosingWindow AndroidVirtualDeviceManager.YoucanalsocreateAVDsusingthecommandlinewiththeutilitynamedandroidunderthetoolsdirectory(e.g.,c:\android-sdk-windows\tools\).androidallowsyoutocreateanewAVDandmanageexistingAVDs.Forexample,youcanviewexistingAVDs,moveAVDs,andsoonbyinvokingandroidwiththe“avd”option.Youcanseetheoptionsavailableforusingandroidbyrunningandroid-help.Fornow,let’sjustcreateanAVD.

RunningonaRealDeviceThebestwaytotestanAndroidappistorunitonarealdevice.AnycommercialAndroiddeviceshouldworkwhenconnectedtoyourworkstation,butyoumayneedtodoalittleworktosetitup.IfyouhaveaMac,youdon’tneedtodoanythingexceptplugitinusingtheUSBcable.Then,onthedeviceitself,chooseSettings Applications Development(thoughthismayvarybyphoneandversion)andenableUSBdebugging.OnLinux,youprobablyneedtocreateormodifythisfile:/etc/udev/rules.d/51-android.rules.Weputacopyofthisfileonourwebsitewiththeprojectfiles;copyittotheproperdirectory,andmodifytheusernameandgroupvaluesappropriatelyforyourmachine.Then,whenyoupluginanAndroiddevice,itwillberecognized.Next,enableUSBdebuggingonthedevice.

ForWindows,youhavetodealwithUSBdrivers.GooglesuppliessomewiththeAndroidpackages,whichareplacedundertheusb_driversubdirectoryoftheAndroidSDKdirectory.Otherdevicevendorsprovidedriversforyou,solookforthemontheirwebsites.YoucanalsovisittheXDAforums,forum.xda-developers.com,whereadviceonsourcingandconfiguringdriversforavarietyofphonesanddevicesisdiscussed.Whenyouhavethedriverssetup,enableUSBdebuggingonthedevice,andyou’reready.

Nowthatyourdeviceisconnectedtoyourworkstation,whenyoutrytolaunchanapp,eitheritlaunchesdirectlyonthedeviceor(ifyouhaveanemulatorrunningorotherdevicesattached)awindowopensinwhichyouchoosewhichdeviceoremulatortolaunchinto.Ifnot,tryeditingyourRunConfigurationtomanuallyselectthetarget.

Page 49: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ExploringtheStructureofanAndroidApplicationAlthoughthesizeandcomplexityofAndroidapplicationscanvarygreatly,theirstructuresaresimilar.Figure1-13showsthestructureofthe“HelloWorld!”appyoujustbuilt.

Figure1-13.Thestructureofthe“HelloWorld!”application

Androidapplicationshavesomeartifactsthatarerequiredandsomethatareoptional.Table1-1summarizestheelementsofanAndroidapplication.

Page 50: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Table1-1.TheArtifactsofanAndroidApplication

Artifact Description Required?

AndroidManifest.xml

TheAndroidapplicationdescriptorfile.Thisfiledefinestheactivities,contentproviders,services,andintentreceiversoftheapplication.Youcanalsousethisfiletodeclarativelydefinepermissionsrequiredbytheapplication,aswellasinstrumentationandtestingoptions.

Yes

src Afoldercontainingallofthesourcecodeoftheapplication. Yes

assets Anarbitrarycollectionoffoldersandfiles. No

resAfoldercontainingtheresourcesoftheapplication.Thisistheparentfolderofdrawable,animator,layout,menu,values,xml,andraw.

Yes

drawable Afoldercontainingtheimagesorimage-descriptorfilesusedbytheapplication. No

animator AfoldercontainingtheXML-descriptorfilesthatdescribetheanimationsusedbytheapplication. No

layout Afoldercontainingviewsoftheapplication. No

menu AfoldercontainingXML-descriptorfilesformenusintheapplication. No

values Afoldercontainingotherresourcesusedbytheapplication.Examplesofresourcesfoundinthisfolderincludestrings,arrays,styles,andcolors. No

xml AfoldercontainingadditionalXMLfilesusedbytheapplication. No

raw Afoldercontainingadditionaldata—possiblynon-XMLdata—thatisrequiredbytheapplication. No

AsyoucanseefromTable1-1,anAndroidapplicationisprimarilymadeupofthreemandatorypieces:theapplicationdescriptor,acollectionofvariousresources,andtheapplication’ssourcecode.IfyouputasidetheAndroidManifest.xmlfileforamoment,youcanviewanAndroidappinthissimpleway:youhavesomebusinesslogicimplementedincode,andeverythingelseisaresource.

AndroidhasalsoadoptedtheapproachofdefiningviewsviamarkupinXML.Youbenefitfromthisapproachbecauseyoudon’thavetohard-codeyourapplication’sviews;youcanmodifythelookandfeeloftheapplicationbyeditingthemarkup.

Itisalsoworthnotingafewconstraintsregardingresources.First,Androidsupportsonlyasingle-levellistoffileswithinthepredefinedfoldersunderres.Forexample,therearesomesimilaritiesbetweentheassetsfolderandtherawfolderunderres.Bothfolderscancontainrawfiles,butthefilesinrawareconsideredresources,andthefilesinassetsarenot.Sothefilesinrawarelocalized,accessiblethroughresourceIDs,andsoon.Butthecontentsoftheassetsfolderareconsideredgeneral-purposecontenttobeusedwithoutresourceconstraintsandsupport.Notethatbecausethecontentsofthe

Page 51: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

assetsfolderarenotconsideredresources,youcanputanarbitraryhierarchyoffoldersandfilesinthisfolder.(Chapter3talksalotmoreaboutresources.)

NoteYoumayhavenoticedthatXMLisusedquiteheavilywithAndroid.YouknowthatXMLcanbeabloateddataformat,sodoesitmakesensetorelyonXMLwhenyouknowyourtargetisadevicewithlimitedresources?ItturnsoutthattheXMLyoucreateduringdevelopmentisactuallycompileddowntobinaryusingtheAndroidAssetPackagingTool(AAPT).Therefore,whenyourapplicationisinstalledonadevice,thefilesonthedevicearestoredasbinary.Whenthefileisneededatruntime,thefileisreadinitsbinaryformandisnottransformedbackintoXML.Thisgivesyouthebenefitsofbothworlds—yougettoworkwithXML,andyoudon’thavetoworryabouttakingupvaluableresourcesonthedevice.

ExaminingtheApplicationLifeCycleThelifecycleofanAndroidapplicationisstrictlymanagedbythesystem,basedontheuser’sneeds,availableresources,andsoon.Ausermaywanttolaunchawebbrowser,forexample,butthesystemultimatelydecideswhethertostarttheapplication.Althoughthesystemistheultimatemanager,itadherestosomedefinedandlogicalguidelinestodeterminewhetheranapplicationcanbeloaded,paused,orstopped.Iftheuseriscurrentlyworkingwithanactivity,thesystemgiveshighprioritytothatapplication.Conversely,ifanactivityisnotvisibleandthesystemdeterminesthatanapplicationmustbeshutdowntofreeupresources,itshutsdownthelower-priorityapplication.

Theconceptofapplicationlifecycleislogical,butafundamentalaspectofAndroidapplicationscomplicatesmatters.Specifically,theAndroidapplicationarchitectureiscomponent-andintegration-oriented.Thisallowsarichuserexperience,seamlessreuse,andeasyapplicationintegrationbutcreatesacomplextaskfortheapplicationlife-cyclemanager.

Let’sconsideratypicalscenario.Auseristalkingtosomeoneonthephoneandneedstoopenane-mailmessagetoansweraquestion.Theusergoestothehomescreen,opensthemailapplication,opensthee-mailmessage,clicksalinkinthee-mail,andanswersthefriend’squestionbyreadingastockquotefromawebpage.Thisscenariorequiresfourapplications:thehomeapplication,atalkapplication,ane-mailapplication,andabrowserapplication.Astheusernavigatesfromoneapplicationtothenext,theexperienceisseamless.Inthebackground,however,thesystemissavingandrestoringapplicationstate.Forinstance,whentheuserclicksthelinkinthee-mailmessage,thesystemsavesmetadataontherunninge-mailmessageactivitybeforestartingthebrowser-applicationactivitytolaunchaURL.Infact,thesystemsavesmetadataonanyactivitybeforestartinganothersothatitcancomebacktotheactivity(whentheuserbacktracks,forexample).Ifmemorybecomesanissue,thesystemhastoshutdownaprocessrunninganactivityandresumeitasnecessary.

Androidissensitivetothelifecycleofanapplicationanditscomponents.Therefore,you

Page 52: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

needtounderstandandhandlelife-cycleeventsinordertobuildastableapplication.TheprocessesrunningyourAndroidapplicationanditscomponentsgothroughvariouslife-cycleevents,andAndroidprovidescallbacksthatyoucanimplementtohandlestatechanges.Forstarters,youshouldbecomefamiliarwiththevariouslife-cyclecallbacksforanactivity(seeListing1-1).

Listing1-1.Life-CycleMethodsofanActivity

protectedvoidonCreate(BundlesavedInstanceState);protectedvoidonStart();protectedvoidonRestart();protectedvoidonResume();protectedvoidonPause();protectedvoidonStop();protectedvoidonDestroy();

Listing1-1showsthelistoflife-cyclemethodsthatAndroidcallsduringthelifeofanactivity.It’simportanttounderstandwheneachofthemethodsiscalledbythesysteminordertoensurethatyouimplementastableapplication.Notethatyoudonotneedtoreacttoallofthesemethods.Ifyoudo,however,besuretocallthesuperclassversionsaswell.Figure1-14showsthetransitionsbetweenstates.

Figure1-14.Statetransitionsofanactivity

Thesystemcanstartandstopyouractivitiesbasedonwhatelseishappening.AndroidcallstheonCreate()methodwhentheactivityisfreshlycreated.onCreate()isalwaysfollowedbyacalltoonStart(),butonStart()isnotalwaysprecededbyacalltoonCreate()becauseonStart()canbecalledifyourapplicationwasstopped.WhenonStart()iscalled,youractivityisnotvisibletotheuser,butit’sabouttobe.onResume()iscalledafteronStart(),justwhentheactivityisintheforegroundandaccessibletotheuser.Atthispoint,theusercaninteractwithyouractivity.

Whentheuserdecidestomovetoanotheractivity,thesystemcallsyouractivity’sonPause()method.FromonPause(),youcanexpecteitheronResume()oronStop()tobecalled.onResume()iscalled,forexample,iftheuserbringsyouractivitybacktotheforeground.onStop()iscalledifyouractivitybecomesinvisibleto

Page 53: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theuser.IfyouractivityisbroughtbacktotheforegroundafteracalltoonStop(),thenonRestart()iscalled.Ifyouractivitysitsontheactivitystackbutisnotvisibletotheuser,andthesystemdecidestokillyouractivity,onDestroy()iscalled.

Asadeveloper,youneedn’tdealwitheverypossiblescenario;youmostlyhandleonCreate(),onResume(),andonPause().YouhandleonCreate()tocreatetheuserinterfaceforyouractivity.Inthismethod,youbinddatatoyourwidgetsandwireupanyeventhandlersforyourUIcomponents.InonPause(),youwanttopersistcriticaldatatoyourapplication’sdatastore:it’sthelastsafemethodthatiscalledbeforethesystemkillsyourapplication.onStop()andonDestroy()arenotguaranteedtobecalled,sodon’trelyonthesemethodsforcriticallogic.

Thetakeawayfromthisdiscussion?Thesystemmanagesyourapplication,anditcanstart,stop,orresumeanapplicationcomponentatanytime.Althoughthesystemcontrolsyourcomponents,theydon’trunincompleteisolationwithrespecttoyourapplication.Inotherwords,ifthesystemstartsanactivityinyourapplication,youcancountonanapplicationcontextinyouractivity.

SimpleDebuggingTheAndroidSDKincludesahostoftoolsthatyoucanusefordebuggingpurposes.ThesetoolsareintegratedwiththeEclipseIDE(seeFigure1-15forasmallsample).

Figure1-15.DebuggingtoolsthatyoucanusewhilebuildingAndroidapplications

OneofthetoolsthatyouusethroughoutAndroiddevelopmentisLogCat.Thistooldisplaysthelogmessagesyouemitusingandroid.util.Log,exceptions,System.out.println,andsoon.AlthoughSystem.out.printlnworks,andthemessagesappearintheLogCatwindow,tologmessagesfromyourapplicationyoushouldusetheandroid.util.Logclass.Thisclassdefinesthefamiliarinformational,warning,anderrormethodsthatyoucanfilterintheLogCatwindowtoseejustwhatyouwanttosee.HereisasampleLogcommand:

Log.v("stringTAG","Thisismyverbosemessagetowritetothelog");

Thisexampleshowsthestaticv()methodoftheLogclass,butthereareothersfordifferentlevelsofseverity.It’sbesttousetheappropriatecalllevelforthemessageyouwanttolog,anditgenerallyisn’tagoodideatoleaveaverbosecallinanappthatyou

Page 54: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

wanttodeploytoproduction.KeepinmindthatloggingusesmemoryandtakesCPUresources.What’sparticularlyniceaboutLogCatisthatyoucanviewlogmessageswhenyou’rerunningyourapplicationintheemulator,butyoucanalsoviewlogmessageswhenyou’veconnectedarealdevicetoyourworkstationandit’sindebugmode.Infact,logmessagesarestoredsuchthatyoucanevenretrievethemostrecentmessagesfromadevicethatwasdisconnectedwhenthelogmessageswererecorded.WhenyouconnectadevicetoyourworkstationandyouhavetheLogCatviewopen,youseethelastseveralhundredmessages.

LaunchingtheEmulatorEarlieryousawhowtolaunchtheemulatorfromyourprojectinEclipse.Inmostcases,youwanttolaunchtheemulatorfirstandthendeployandtestyourapplicationsinarunningemulator.Tolaunchanemulatoranytime,firstgototheAVDManagerbyrunningtheAndroidprogramwiththeavdoptionfromthetoolsdirectoryoftheAndroidSDKorfromtheWindowmenuinEclipse.OnceintheManager,choosethedesiredAVDfromthelist,andclickStart.

WhenyouclicktheStartbutton,theLaunchOptionsdialogopens(seeFigure1-16).Thisallowsyoutoscalethesizeoftheemulator’swindowtosuityourdisplayandchangethestartupandshutdownoptions.Thescalingresultscansometimesbeunexpectedlylargeorsmall,sopickthevaluethatworksforyoubasedonyourscreensizeandscreendensity.

Figure1-16.TheLaunchOptionsdialog

Page 55: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

YoucanalsoworkwithsnapshotsintheLaunchOptionsdialog.Savingtoasnapshotcausesasomewhatlongerdelaywhenyouexittheemulator.Asthenamesuggests,youarewritingoutthecurrentstateoftheemulatortoasnapshotimagefile,whichcanthenbeusedthenexttimeyoulaunchtoavoidgoingthroughanentireAndroidbootupsequence.Launchinggoesmuchfasterifasnapshotispresent,makingthedelayatsavetimewellworthit—youbasicallypickupwhereyouleftoff.

Ifyouwanttostartcompletelyfresh,youcanchooseWipeUserData.YoucanalsodeselectLaunchfromSnapshottokeeptheuserdataandgothroughthebootupsequence.OryoucancreateasnapshotthatyoulikeandenableonlytheLaunchfromSnapshotoption;thisreusesthesnapshotoverandoversoyourstartupisfastandtheshutdownisfasttoo,becauseitdoesn’tcreateanewsnapshotimagefileeverytimeitexits.ThesnapshotimagefileisstoredinthesamedirectoryastherestoftheAVDimagefiles.Ifyoudidn’tenablesnapshotswhenyoucreatedtheAVD,youcanalwaysedittheAVDandenablethemthere.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://developer.samsung.com/:Samsung’sdevelopersite,withmanyAndroid-relateddevelopmenttools.

http://developer.htc.com/:HTCsiteforAndroiddevelopers.

http://developer.android.com/guide/developing/tools/index.htmlDeveloperdocumentationfortheAndroiddebuggingtools.

www.droiddraw.org/:DroidDrawsite.ThisisaUIdesignerforAndroidapplicationsthatusesdrag-and-droptobuildlayouts.

SummaryThischaptercoveredthefollowingtopicstogetyousetupforAndroiddevelopment:

DownloadingandinstallingtheJDK,EclipseorAndroidStudio,andtheAndroidSDK

HowtomodifyyourPATHvariableandlaunchatoolswindow

InstallingandupgradingtheADTfundamentalconceptsofviews,activities,fragments,intents,contentproviders,services,andtheAndroidManifest.xmlfile

AndroidVirtualDevices(AVDs),whichcanbeusedtotestappswhenyoudon’thaveadevice(ortheparticulardeviceyouwanttotestwith)

Page 56: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Buildinga“HelloWorld!”appanddeployingittoanemulator

Thebasicrequirementstoinitializeanyapplication(projectname,Androidtarget,applicationname,packagename,mainactivity,minimumSDKversion)

Wheretherunconfigurationsareandhowtochangethem

Connectingarealdevicetoyourworkstationandrunningyournewappsonit

TheinnerstructureofanAndroidapp,andthelifecycleofanactivity

LogCat,andwheretolookfortheinternalmessagesfromapps

Optionsavailablewhenlaunchinganemulator,suchassnapshotsandadjustingthescreendisplaysize

Page 57: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter2

IntroductiontoAndroidApplicationArchitectureThefirstchaptercoveredtheenvironmentandtoolsnecessarytodevelopAndroidapplications.ThischapterwillbeabroadintroductorytourofAndroid’sapplicationarchitecture.Wewilldothatbydoingthreethings.First,wewillpresentthearchitectureofanAndroidappbybuildingone.WewillthenpresenttheessentialcomponentsofAndroidarchitecture,namely,activities,resources,intents,activitylifecycle,andsavingstate.Wewillconcludethechapterwithalearningroadmaponhowtousetherestofthebooktocreatesimpletosophisticatedmobileapps.

Inthefirstsectionofthischapter,aone-pagecalculatorappwillgiveyouabird’seyeviewofwritingapplicationsusingtheAndroidSDK.CreatingthisappwilldemonstratehowtocreatetheUI,writeJavacodetocontroltheUI,andbuildanddeploytheapp.

InadditiontodemonstratingtheUI,thiscalculatorappwillintroduceyoutoactivities,resources,andintents.TheseconceptsgototheheartofAndroidapplicationarchitecture.WewillcoverthesetopicsindetailinthesecondsectionofthechapterinordertogiveyouastrongfootingforunderstandingtherestoftheAndroidSDK.Wewillalsocovertheactivitylifecycleandabriefoverviewofthepersistenceoptionsforyourapplication.

InthethirdsectionwewillgiveyouaroadmapfortherestofthebookthataddressesbasicandadvancedaspectsofbuildingAndroidapplications.Thisfinalsectionbreaksthechaptersintoasetoflearningtracks.ThissectionisabroadintroductiontotheentiresetofAndroidAPIs.

Furthermore,inthischapteryouwillfindanswerstothefollowing:HowcanIcreateUIwitharichsetofcontrols?HowcanIstorestatepersistently?HowcanIreadstaticfilesthatareinputstotheapp?HowcanIreachoutandreadfromorwritetotheweb?WhatotherAPIsdoesAndroidprovidetomakemyappfunctionalandrich?

Withoutfurtherado,let’sdropyouintothesimplecalculatorapplicationtoopenuptheworldofAndroid.

ExploringaSimpleAndroidApplicationThecalculatorapplicationwewanttodemonstrateforthischapterisshowninFigure2-1.

Page 58: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure2-1.ACalculatorApp

DisplayinFigure2-1iscalledanactivityinAndroid.Thisactivityhastwoeditcontrolsatthetoprepresentingtwonumbers.Youcanenternumbersintheseeditboxesandusetheoperatorbuttonsatthebottomofthefiguretoperformarithmeticaloperations.Theresultofanoperationwillbeshowninthetopeditcontrol.ThesetwoeditboxesarelabeledOperand1andOperand2.TocreatethistypeofacalculatorapplicationusingtheAndroidSDK,youneedtoperformthefollowingsteps:

1. CreateaUserInterface(UI)definitioninatext/xmlfile(calledalayoutoralayoutfileinAndroid).

2. WriteprogramminglogicinaJavafile(usuallyinaclassextendingthebaseactivityclass).

3. Createaconfigurationfiledescribingyourapplication(thisfileisalwayscalledAndroidManifest.xml).

4. Createaprojectandadirectorystructuretoplacethefilesfromsteps1,2,and3.

5. Buildadeployablepackageusingtheprojectinstep4(itiscalledan.apkfile).

BygoingthroughthedetailsofthesestepsyouwillgetafeelforhowAndroidapplicationsaremade.Wewillgothroughthesestepsnow.

DefiningUIthroughLayoutFilesAnAndroidapplicationresemblesawebapplicationinlotsofways.Inawebapplication

Page 59: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theUIisyourwebpage.UIofawebpageisdefinedthroughHTML.AnHTMLwebpageisaseriesofcontrolslikeparagraphs,divisions,forms,buttons,etc.UIisconstructedsimilarlyinAndroid.AlayoutfileinAndroidislikeanHTMLpage,albeitthecontrolsaredrawnfromtheAndroidSDKinsteadofHTML.InAndroidthisfileiscalledalayoutfile.Listing2-1showsthelayoutfilethatproducedtheUIofFigure2-1.Listing2-1.AnAndroidLayoutFilethatDefinesUIforanActivity

<?xmlversion="1.0"encoding="utf-8"?><!--**********************************************calculator_layout.xml*correspondingactivity:CalculatorMainActivity.java*prefix:cl_(Usedforprefixinguniqueidentifiers)**Use:*Demonstrateasimplecalculator*Demonstratetextviews,edittext,buttons,businesslogic*********************************************--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="5dp"android:padding="5dp"android:background="@android:color/darker_gray"><!--Operand1--><TextViewandroid:layout_width="match_parent"

android:layout_height="wrap_content"android:text="Operand1,(AndResult)"/><EditTextandroid:layout_width="match_parent"

android:layout_height="wrap_content"android:id="@+id/editText1"android:text="0"android:inputType="numberDecimal"/><!--Operand2--><TextViewandroid:layout_width="match_parent"

android:layout_height="wrap_content"android:text="Operand2"android:layout_marginTop="10dp"/><EditTextandroid:layout_width="match_parent"

android:layout_height="wrap_content"android:text="0"android:id="@+id/editText2"android:inputType="numberDecimal">

Page 60: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

</EditText><!--ButtonsforVariousOperators--><TextViewandroid:layout_width="match_parent"

android:layout_height="wrap_content"android:text="Operand1=Operand1OperatorOperand2"android:layout_marginTop="10dp"/><LinearLayoutandroid:orientation="horizontal"android:layout_marginTop="10dp"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:text="+"android:id="@+id/plusButton"

android:layout_weight="1"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><Buttonandroid:text="-"android:id="@+id/minusButton"

android:layout_weight="1"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><Buttonandroid:text="*"android:id="@+id/multiplyButton"

android:layout_weight="1"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><Buttonandroid:text="/"android:id="@+id/divideButton"

android:layout_weight="1"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button></LinearLayout></LinearLayout>

Let’sgothroughthiscalculatorXMLlayoutfileofListing2-1linebyline.ThisfilelookscomplicatedcomparedtoFigure2-1.Yes,itisverbose,butyouwillseeshortlyitissimpleinitsarchitecture.

SpecifyingCommentsinLayoutFilesAsagoodpracticethecommentsatthetopofthelayoutXMLfileinListing2-1indicatewhatthisfilenameis,whatUIactivitywillbeusedtodisplaythisfile,whatthepurposeofthisfileis,andbrieflywhatcontrolsareinthislayoutfile.

AddingViewsandViewGroupsinLayoutFiles

Page 61: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

EachXMLnodeinalayoutfilerepresentsaUIcontrol.Thesecontrolscanbeeitherviewsorcontainersofotherviews.AcontainerofotherviewsiscalledaViewGroup.Forexample,abuttonisaview.ALinearLayoutinListing2-1isaViewGroupthatplacesallitschildviewseitherverticallydownorhorizontallyacross.So,aLinearLayoutislikeanHTMLdivthatlaysoutitschildreneitheracrossordown.

SpecifyingControlPropertiesinLayoutFilesTheUIcontrolsinthecalculatorlayoutfileareLinearLayout,TextView,EditText,andabutton.EachofthesecontrolsrepresentsaJavaobjectwhenpaintedonthescreen.Beinganobject,eachofthesecontrolshasproperties.IfthecontrolsbelongtothecoreAndroidSDK,theirpropertiesareprefixedwith“android:”asin“android:orientation”fortheLinearLayoutcontrol.Themajority,ifnotall,ofthecontrolsthatyounormallyuseinyourappsarefromthecoreAndroidSDK.Whenyouwriteyourowncontrolstheyarecalledcustomcontrols.Thesecustomcontrolsallowyoutodefinecustomproperties.Seethe“Roadmap”sectionofthischapterformoreoncustomcontrols.

IndicatingViewGroupPropertiesSomeofthecontrolpropertiesarelabeledas“android:layout_,”suchasandroid:layout_width.Theseproperties,althoughmentionedinagivenXMLnode,likeabutton,arereadandusedbyparentnode,likeLinearLayout,toplacethechildren.ParentnodesareviewgroupsliketheLinearLayout.YoucanseethisdifferenceinhowpaddingandmarginsaredefinedforthefirstLinearLayoutnodeinthelayoutfileofListing2-1.ThepropertypaddingbelongstothetopmostLinearLayoutobjectinthisexample,whereasthepropertyformarginsofthatsametopmostLinearLayout,thelayout_marginproperty,belongstotheparentoftheLinearLayout,whichisanimplicitviewgroupprovidedbytheAndroidframework.Soforpaddingyousayandroid:padding,andformarginsyousayandroid:layout_margin.Noticethepresenceorlackof“layout_”prefix.Ifyouwanttoknowwhatpropertiesanobject(orcontrol)supports,youcanuseCtrl-Spaceineclipsetoseeasetofsuggestionsforthepropertiesforthatobject.Dependingonyourdevelopmentenvironmentyoucaneasilyfindanequivalentsetofkeycombinationstodothesame.

ControllingWidthandHeightofaControlTwooften-usedpropertiesforacontrolareitslayoutwidthandlayoutheight.Thelayoutparentofacontrolmanagesthesevalues.Valuesforthesepropertiesaretypicallymatch_parentandwrap_content.IfyousayyourTextViewissettomatch_parentforitswidth,thewidthofthecontrolmatchesupwiththeparentwidth.WhenaTextViewissetforitsheightwrap_content,thenitsheightwillbejustsufficienttocontainallitstextintheverticaldirection.Ofcourse,thesetwopropertiesare

Page 62: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

availabletoallchildcontrolsofalayout,notjustthetextcontrol.Thesetwolayoutcontrolproperties,match_parentandwrap_content,alsoapplytotheheightofacontrolaswell.

IntroducingResourcesandBackgroundsAlthoughweareinthemiddleofexplainingthecontrolsinthelayoutfile,thisisagoodplacetointroduceresources.Layoutfilesare,andaremadeupof,resources.Inthecalculatorlayoutfile,wehavesetthebackgroundoftheentireviewbysettingthebackgroundontherootLinearLayoutcontrol.Thisinstructionlookedlikethefollowing:

android:background="@android:color/darker_gray"

EveryvieworcontrolinAndroidsupportsthebackgroundproperty.Backgroundsareusuallyidentifiedasresources.Inthisexample,thebackgroundispointingtoaresource,comingfromtheAndroidpackage,whichisoftypecolorwhosereferencedvalueisdarkergray.

AnumberofinputstoyourapplicationarerepresentedasresourcesinAndroid.Someexampleresourcesareimagefiles,entirelayoutfiles,colors,strings,XMLfiles,menus,andmanyotherthingsaslistedintheAndroidSDK.Forinstance,theentirecalculatorlayoutfilewearetalkingaboutisitselfaresource.

Asyoucanseefromthecalculatorlayoutfile,resourcesareofdifferenttypes.InAndroidtheyarefurtherbroadlyclassifiedas“valuebased”or“filebased.”Examplesofresourcesthatarevaluesarestringsandcolors.Examplesofresourcesthatarefilesareimagesorlayoutfiles.Listing2-2showsanexampleofcreatingvalue-basedresourcesthatarestringsandcolors.

Listing2-2.ExampleofValue-BasedResources

<?xmlversion="1.0"encoding="utf-8"?><!--thisfilewillbein/res/valuessubdirectory--><resources><stringname="hello">HelloWorld,CalculatorMainActivity!</string><stringname="app_name">ADemoCalculator</string><colorname="red">#FF0000</color><colorname="blue">#0000FF</color></resources>

Youcanhaveanynumberofvalue-basedfilesaslongastheyareallunderthe/res/valuessubdirectory.Eachfilewillstartwiththeresourcesrootnode.YoucanuseCtrl-Spacetodiscoverwhatotherpossiblevalue-basedresourcesareavailable.

Turningtofile-basedresources,Listing2-3showsanexampleofplacinganumberoffile-basedresourcesundertheirrespectiveresourcesubdirectories.

Page 63: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing2-3.ExampleofFile-BasedResources

/res/layout/page1_layout.xml(Alayoutfileforsaypage1)/res/drawable/page1_background.jpg(Anexampleimagefile)/res/drawable-hdpi/page1_background.jpg(Sameimagefileforadifferentdensity)/res/xml/some_preferences.xml(exampleofaninputfileforyourapp)

Anyoftheseresources,beitfilebasedorvaluebased,canbereferencedinthelayoutfilesusingthe“@”resourcereferencesyntax.Forexample,inthecalculatorlayoutfileinListing2-1thebackgroundcanbesetliterallyandexplicitlyasacolorvaluebetweenthequotes,suchas“#FFFFFF,”orpointtoaresourcereference(indicatedbyastarting@color/red)thatisalreadydefinedasacolorresource(asinListing2-2).Inthissyntaxledby“@,”thetypeofreferencedresourceis“color.”Someofthekeywordsforothertypesofresourcesarestring(forstrings),drawable(forimages),etc.

InListing2-1,thewaytoreadthevalueofthebackgroundpropertyoftheLinearLayout,namely,@android:color/darker_gray,isasfollows:Usethevalueoftheresourceidentifiedasdarker_grayintheAndroidcoreframeworkandwhoseresourcetypeiscolor.Withthisknowledgeofresourcereferencesyntax,takealookatthecalculatorlayoutfilelistingonemoretimeandyouwillbeabletoreaditwhereeachcontrolhaspropertiesandeachpropertyhasavaluethatiseitherdirectlyspecifiedorreferencesaresourcethatiselsewheredefinedinaresourcefile.

Theindirectionofacontrolpropertyvaluedefinedasaresourcereferencehasanadvantage.Aresourcecanbecustomizedforlanguages,devicedensityvariation,andavarietyoffactorswithoutalteringthecompiledJavasourcecode.ForexamplewhenyousupplybackgroundimagesyoucanplaceanumberoftheseimagesindifferentdirectoriesandnamethemusingtheconventionspecifiedbyAndroid.ThenAndroidknowshowtolocatetherightimage,givenitsname,dependingonthedeviceyourappisrunningon.

WorkingwithTextControlsintheLayoutFileInthecalculatorlayoutexamplewehaveusedtwotext-basedcontrols.OneisaTextViewcontrol,whichisusedasalabel;theotherisanEditTextcontrol,whichisusedfortakinginputtext.Wehavealreadyshownyouhowtosetthewidthandheightofanyviewbyusingtheattributesthatstartwith“layout_”.Everytext-basedcontrolalsohasanattributecalledtext.Inourexampleswehavedirectlyspecifiedtheliteraltextasavalueforthisproperty.Therecommendationistouseinsteadaresourcereference.Forexample:

android:text="Literaltext"//whatwedidforclarityorandroid:text="@string/LiteralTextId"//doingitproperly

ThelatterresourceID,LiteralTextId,thencanbedefinedinafileinthe

Page 64: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/res/valuessubdirectorymuchlikeinListing2-2.

EditTextcontrolinthecalculatorlayouthasanattributeinputTypetoprovidethenecessaryconstraintsandvalidationsthatneedtotakeplacewhendataistypedintotheeditablefield.Refertothedocumentationtoseealargenumberofconstraintsthatareavailableforeditablefields.Alternatively,youcanuseeclipseADTtodiscovertheavailableinputtypesontheflyduringcoding.

WorkingwithAutogeneratedIDsforControlsTomanipulatethecontrolsthatareinthecalculatorlayoutofListing2-1,weneedawaytoturnthemintoJavaobjects.ThisisdonebylocatingthesecontrolsusingauniqueIDinthecurrentlyloadedlayoutfileofanactivity.Let’slookatoneexampleinthelayoutfilewhereanEditTextcontrolisgivenanIDofeditText2asfollows:

android:id="@+id/editText2"

ThisformattellsAndroidthatIDofthisEditTextcontrolisaresourceoftypeIDanditsintegervalueshouldbeknowninJavaaseditText2.The+isaconveniencetoallocateanewuniqueintegerforeditText2.Ifyoudon’thavethe+sign,thenAndroidlooksforaninteger-valuedresourcedefinedwithanIDthatiscallededitText2.Withtheconvenienceof+wecanavoidseparatelydefiningaresourcefirstandthenuseit.Insomecases,youmayhaveaneedforawell-knownIDthatissharedbymultiplepiecesofcode,inwhichcaseyouwillremovethe+andtakethemultiplestepsofdefiningtheIDfirstandthenusingitsnameinmultipleplaces.Youwillseeintheprogramminglogicsection(soontofollow)howthesecontrolIDsareusedtolocatethecontrolsandmanipulatethem.

ImplementingProgrammingLogicToseethecalculatorlayoutonthescreenofyourdevice,youneedaJavaclassderivedfromtheAndroidSDKsclassactivity.Suchanactivityrepresentsawindowinyourmobileapplication.SoyouneedtocraftacalculatoractivitybyextendingtheAndroidbaseactivityclassasshowninListing2-4.

Listing2-4.ProgrammingLogic:ImplementinganActivityClass

/***Activityname:CalculatorMainActivity*Layoutfile:calculator_layout.xml*Layoutshortcutprefixforids:cl_*Menufile:none*PurposeandLogic********************1.Demonstratebusinesslogicforasimplecalculator*2.Loadthecalculator_layout.xmlaslayout

Page 65: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

*3.Setupbuttoncallbacks*4.Respondtobuttonclicks*5.Readvaluesfromedittextcontrols*6.Performoperationandupdateresulteditcontrol*/publicclassCalculatorMainActivityextendsActivity

implementsOnClickListener{privateEditTextnumber1EditText;privateEditTextnumber2EditText;

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);setContentView(R.layout.calculator_layout);gatherControls();setupButtons();}privatevoidgatherControls(){

number1EditText=(EditText)this.findViewById(R.id.editText1);number2EditText=(EditText)this.findViewById(R.id.editText2);number2EditText.requestFocus();}privatevoidsetupButtons(){

Buttonb=(Button)this.findViewById(R.id.plusButton);b.setOnClickListener(this);

b=(Button)this.findViewById(R.id.minusButton);b.setOnClickListener(this);

b=(Button)this.findViewById(R.id.multiplyButton);b.setOnClickListener(this);

b=(Button)this.findViewById(R.id.divideButton);b.setOnClickListener(this);}@OverridepublicvoidonClick(Viewv){

StringsNum1=number1EditText.getText().toString();StringsNum2=number2EditText.getText().toString();doublenum1=getDouble(sNum1);doublenum2=getDouble(sNum2);Buttonb=(Button)v;

doublevalue=0;

Page 66: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

if(b.getId()==R.id.plusButton){value=plus(num1,num2);}elseif(b.getId()==R.id.minusButton){value=minus(num1,num2);}elseif(b.getId()==R.id.multiplyButton){value=multiply(num1,num2);}elseif(b.getId()==R.id.divideButton){value=divide(num1,num2);}number1EditText.setText(Double.toString(value));}

privatedoubleplus(doublen1,doublen2){

returnn1+n2;}privatedoubleminus(doublen1,doublen2){

returnn1-n2;}privatedoublemultiply(doublen1,doublen2){

returnn1*n2;}privatedoubledivide(doublen1,doublen2){

if(n2==0){return0;}returnn1/n2;}privatedoublegetDouble(Strings){

if(validString(s)){returnDouble.parseDouble(s);}return0;}privatebooleaninvalidString(Strings){return!validString(s);}privatebooleanvalidString(Strings){if(s==null){returnfalse;}if(s.trim().equalsIgnoreCase("")){returnfalse;}returntrue;

Page 67: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}}

Inthislisting,thecalculatoractivityiscalledCalculatorMainActivity.Onceyouhavethisactivity,youcanloadthecalculatorlayoutintoitinordertoseethecalculatorscreenofFigure2-1.

Let’slearnabitaboutanactivityinAndroid.Aprogrammerdoesnotneedtoinstantiateanactivitydirectly.AnactivitycanbeinstantiatedbytheAndroidframeworkbasedonuser’sactions.Inthatsense,anactivityisa“managedcomponent”managedbyAndroid.

AnactivitycangetpartiallyhiddenorcompletelyhiddenwhenanotherUIwithhigherprioritysitsontopofit(forexample,duetoaphonecall).Or,anactivitythatisinthebackgroundcanbetemporarilyremovedduetomemoryconstraint.Inthesecircumstances,theactivitycanbeautomaticallybroughtbackwhenauserrevisitstheapplication.

LoadingtheLayoutFileintoanActivityAstheactivityiseventdriven,anactivityreliesoncallbacks.ThefirstcallbackofimportanceistheonCreate()callback.InthecalculatoractivitygiveninListing2-4,youcaneasilylocatethismethod.Thisiswherewewillloadthecalculatorlayoutintothecalculatoractivity.ThisisdonethroughthemethodsetContentView().Theinputtothismethodisanidentifierforthecalculatorlayoutfile.

AnicefeatureofAndroidiswhatitdoeswiththevariousresourcesincludingthelayoutfiles.ItautogeneratesajavaclasscalledR.javawhereitdefinesintegerIDsforalltheresourcesbetheyvaluebasedorfilebased.IntheactivitygiveninListing2-4,thevariableR.layout.calculator_layoutpointstothecalculatorlayoutfile(whichitselfisinListing2-1).

WhenyouaredippingyourtoesintotheAndroidframework,theothermysteriousthinginonCreate()isthesavedInstanceBundle.AstheAndroidframeworkmaystopandrestart(evenre-create)activities,itneedsawaytopassthelaststateoftheactivitytotheonCreate()method.ThatiswhatthesavedInstanceBundleis.Itisacollectionofkeyvaluepairsholdingthepreviousstateoftheactivity.Youwilllearnaboutthisaspectofstatemanagementinmoredetaillaterinthechapter,andalsoinChapter9,wherewecoverwhathappenswhenadeviceisrotated.Fortheimplementationofthecalculatorexamplewesimplycallthesuperclass’smethodtopassonthatstatebundle.

GatheringControlsThenexttwomethods,gatherControls()andsetupButtons(),setuptheinteractionmodelforthecalculator.InthegatherControls()methodyouobtainjavareferencesfortheeditcontrolsthatyouneedtomanipulate(readorwriteto)andsavethemlocallyinthecalculatoractivityclass.YoudothisbyusingthefindViewById()methodonthebaseactivityclass.ThefindViewById()methodtakesasinputtheID

Page 68: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ofthecontrolthatisinthelayoutfile.HerealsoAndroidautogeneratestheseIDsandplacesthemintotheR.javaclass.Inyoureclipseprojectyoucanseethisfileinthe/gensubdirectory.Listing2-5showsthegeneratedR.javafileforthiscalculatorproject.(Ifyouweretotrythisprojectyourself,theseIDsmaydiffer.Sousethislistingprimarilytounderstandconcepts.)

Listing2-5.AutogeneratedResourceIDs:R.java

publicfinalclassR{publicstaticfinalclassattr{}publicstaticfinalclassdrawable{publicstaticfinalintbackground=0x7f020000;publicstaticfinalinticon=0x7f020001;}publicstaticfinalclassid{publicstaticfinalintdivideButton=0x7f050005;publicstaticfinalinteditText1=0x7f050000;publicstaticfinalinteditText2=0x7f050001;publicstaticfinalintminusButton=0x7f050003;publicstaticfinalintmultiplyButton=0x7f050004;publicstaticfinalintplusButton=0x7f050002;}publicstaticfinalclasslayout{publicstaticfinalintcalculator_layout=0x7f030000;}publicstaticfinalclassstring{publicstaticfinalintapp_name=0x7f040001;publicstaticfinalinthello=0x7f040000;}}

NoticehowR.javausesadifferentclassprefixforeachresourcetype.ThisallowstheprogrammerineclipsetoquicklyseparatetheIDsbywhattheirtypeis.So,forexample,allIDsforlayoutfilesareprefixedwithR.layout,andallimageIDsareprefixedwithR.drawable,andallstringswithR.string,etc.However,thereisacautionwhileworkingtheseIDs.EvenifyouhavetenlayoutfilestheIDsforallthecontrolsaregeneratedintoasinglenamespacesuchasR.id.*(where“id”isanexampleofaresourcetype).Soyoumaywanttogetintothehabitofnamingcontrolsinthelayoutfileswithsomeprefixindicatingwhichlayoutfilestheybelongto.

SettingUpButtonsSomeofthecontrolsinthecalculatorlayoutofListing2-1arethecalculatorbuttons.Theyarethebuttonsrepresentingoperators:+,-,x,and/.Weneedcodetobeinvokedwhenthesebuttonsarepressed.Thewaytodothatisbyregisteringacallbackobjectonthebuttoncontrols.Thesecallbackobjectsmustimplementthe

Page 69: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

View.OnClickListenerinterface.ThecalculatoractivityinadditiontoextendingtheactivityclassalsoimplementstheView.OnClickListenerinterface,allowingustoregisterouractivityastheonethatneedstobecalledbackwheneachbuttonispressed.Asyoucanseeinthecodeoftheactivity(Listing2-4),thisisdonebycallingthesetOnClickListeneroneachbutton.

RespondingtoButtonClicks:TyingItAllTogetherWhenanyoftheoperatorbuttonsisclicked,theonClick()methodinthecalculatoractivitygiveninListing2-4getscalled.InthismethodwewillinvestigatetheIDoftheviewthatcalledback.Thiscallingviewshouldbeoneofthebuttons.InthismethodwewillreadthevaluesfromboththeEditTextcontrols(theoperandvalues)andtheninvokeamethodthatisspecifictoeachoperator.TheoperatormethodwillcalculatetheresultandupdatetheEditText,whichislabeledResult.

UpdatingtheAndroidManifest.XMLSofarwehavetheUI(intermsofthelayoutfile)andwehavethebusinesslogicintermsofthecalculatoractivity.EveryAndroidappmusthaveitsconfigurationfile.ThisfileiscalledtheAndroidManifest.xml.Thisisavailableintherootdirectoryoftheproject.Listing2-6showstheAndroidManifest.xmlforthisproject.

Listing2-6.ApplicationConfigurationFile:AndroidManifest.xml

<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.calculator"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="14"/><applicationandroid:icon="@drawable/icon"

android:label="@string/app_name">

<activityandroid:name=".CalculatorMainActivity"android:theme="@android:style/Theme.Light"android:label="@string/app_name"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity>

</application></manifest>

Page 70: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thepackageattributeofthismanifestfilefollowsanamingstructuresimilartothejavanamespaces.Inthecalculatorapp,thepackageissettocom.androidbook.calculator.Thisislikegivinganameandauniqueidentifiertoyourapp.OnceyousignthisappandinstallitonanapppublisherliketheGooglePlayStore,onlyyouwillbeabletoupdateitorreleasesubsequentversionsofit.Theuses-sdkdirectiveindicatestheAPIforwhichthisappisbackwardcompatible.TheapplicationnodehasanumberofpropertiesincludingitslabelandaniconthatwillshowupintheAndroiddeviceappsmenu.Insideanapplicationnodeweneedtodefinealloftheactivitiesthatmakeupthisapplication.Eachactivityisidentifiedbyitsrespectivejavaclassname.Iftheactivityclassnameisnotfullyqualified,thenthejavapackageisassumedtobethesameastheapplicationpackageidentified.Themefortheactivityindicatesasetofpropertiesthattheviewsbelongingtothatactivitywillinherit.ItislikesettingaCSSstyleontheHTMLUI.Androidcomeswithafewdefaultstyles.Choosingalightthemeisgoodforcontrastwhiletakingscreenshots(asshowninFigure2-1).Chapter7isdedicatedtousingstylesandthemesinyourapps.

IntheAndroidapplicationmanifestfileanactivitycanspecifyaseriesofintentfilters.IntentisaprogrammingconceptthatisuniquetoAndroid.Androidreliesheavilyontheseintents.Androidusesintentobjectstoinvokeapplicationcomponentsincludingactivities.Anintentobjectcancontainanexplicitactivityclassnamesothatwhenyouinvokethatintentyouendupinvokingtheactivity.Orinsteadofhavinganexplicitclassname,anintentcanindicateagenericactionlikeVIEWtoviewawebpage.WhenyouinvokesuchanintentwithagenericactionAndroidwillpresentallpossibleactivitiesthatcansatisfythataction.ActivitiesregisterwithAndroidthroughthemanifestfilethattheycanrespondtosomeactionsthroughanintentfilter.Listing2-7showshowyoucaninvokeanactivitythroughanintentobject.

Listing2-7.UsinganIntentObjecttoInvokeanActivity

//currentActivityreferstotheactivityinwhichthiscoderunsIntenti=newIntent(currentActivity,SomeTargetActivity.class);currentActivity.startActivity(i);//startthetargetactivity

AlthoughweusedcurrentActivityasthevalueofthefirstargumenttocreateanintent,allitneedsisabaseclassreferencecalledContext.Acontextreferencerepresentstheapplicationcontextinwhichacomponentlikeanactivityruns.Comingbacktotheintentobject,ithasanumberofflagsandextradataelementsthatyoucanusetocontrolthebehaviorofthetargetactivitythattheintentisinvoking.Listing2-8showsanexample.

Listing2-8.UsingExtrasonanIntentObject

//currentActivityreferstotheactivityinwhichthiscoderunsIntentintent=new

Page 71: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Intent(currentActivity,SomeTargetActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);intent.putExtra("some-key","some-value");currentActivity.startActivity(intent);

Inthisexample,wewantthetargetactivitytobebroughttothetopofthewindoworactivitystackandcloseanyotheractivitiesthatwereontopofitbefore.Asoneinvokesactivitiesfromotheractivitiestheysitontopofeachother.Thisstackallowsthebackbuttontonavigatebacktothepreviousactivityinthestack.Whenyougoback,thecurrenttopactivityisfinishedandthepreviousactivityisshownintheforeground.ThecodeinListing2-8islikegoingbacktothelastpositionofthetargetactivity,makingthatthetopinstance,andremoving/finishingallrecentactivitiesabovethat.Extrasonintentareasetofkeyvaluepairsthatyoucanpasstothetargetactivityfromthesourceactivity.Activitiesareprettyisolatedfromeachother.Theydon’tsharetheirlocalvariablesbetweeneachother.Instead,theyshouldpasstheirdatathroughobjectsthatcanbeserializedanddeserialized.AndroidusesaninterfacesimilartoSerializablecalledParcelablethatallowsgreaterflexibilityandefficiency.

Ultimately,everyactivityisalmostalwaysstartedbyanintentobject.YoucangettheintentobjectanywhereinyourtargetactivitybycallinggetIntent().Onceyougettheintentobject,youcangetitsextrasandseeifthereisanypertinentdatathatyouneed.

Completestudyofintentsandtheirvariationsisalargetopic.Wewillreturntotalkmoreaboutintentslaterinthischapterafterconcludingourdiscussiononthecalculatorapp.WehavealsoincludedaURLforthefreededicatedchapteronintentsfromourpreviouseditionsattheendofthischapter.

PlacingtheFilesintheAndroidProjectLet’sreturntoourmainlineofthought,thecalculatorapp.Bynowyouhavethethreefilesyouneedtocreatethecalculatorapplication.UsewhatyouhavelearnedinthefirstchaptertocreateanemptyAndroidprojectandadjustthatprojecttoplacethesethreefiles.ThesefilesaregiveninListing2-9alongwiththeirparentdirectories.

Listing2-9.PlacementofFilesfortheCalculatorApp

/res/layout/calculator_layout.xml/src/com/androidbook/calculator/CalculatorActivity.java/AndroidManifest.xml

Figure2-2showsthestructureofyourAndroidprojectineclipse.YoucanseetherelativelocationsofthefilesofListing2-9.

Page 72: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure2-2.Acalculatorappdirectorystructure

ThedirectorystructureinFigure2-1alsoshowsyouwhereotherresourceslikeimagesandstringsareplaced.Youcanalsoseethedirectorystructureforthedevice-dependentimagefilesinFigure2-2.ThisishowAndroidsolvesthelocalizationmultilingualsupportaswellbyusingdifferentresourcesubdirectorysuffixes.YouwilllearnabouttheothersubdirectoriesofanAndroidprojectasyougothroughthisbook.

TestingtheCalculatorApponaRealDeviceAllthatisleftnowistobuildtheAPKfile,signit,andbereadytodeploy.ThesimplestwaytotestyourprojectistohaveeclipsedeploytheAPKtotheemulatorandtestit.The

Page 73: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

simplestwaytotestthisfile(onceitissigned)onadeviceistoe-mailittoyourselfandopenthee-mailonyourdevice.ThereisasecuritysettingonthedevicetoallowAPKsfromunverifiedsources.Aslongasthisisallowed,youwillbeabletoinstalltheAPKfileandrunitonyourdevice.OryoucanalsoconnectthedevicetotheUSBportandhaveeclipsedeploytheAPKdirectlytothedevice.Youcanevendebugitonthedevicethrougheclipse.YoucanalsocopytheAPKfilefromyourPCorMactothedeviceSDcardandinstallitfromthere.Thisconcludesoursectiononthecalculatorapp,whichillustratedthenatureofAndroidapps.Wewillmovetothesecondsectionofthechapternowwherewewilltalkaboutactivitiesinalotmoredepthandalsorevisitresources,intents,andsavingstate.Let’sstartwithactivities.

AndroidActivityLifeCycleAnAndroidactivityisaself-standingcomponentofanAndroidapplicationthatcanbestarted,stopped,paused,restarted,orreclaimeddependingonvariouseventsincludinguser-initiatedandsystem-initiatedones.Soitisreallyimportanttoreviewthearchitectureofthelifecycleofanactivitybylookingatallofitscallbacks.Figure2-3showsthelifecycleofanactivitybydocumentingtheorderofitscallbacksandthecircumstancesunderwhichthosecallbacksareexecuted.Let’sconsiderthesecallbackmethodsonebyone.

Page 74: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment
Page 75: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure2-3.AnnotatedAndroidactivitylifecycle

voidonCreate(BundlesavedInstanceState)Theactivity’slifecyclestartswiththismethod.Inthismethodyoushouldloadyourviewhierarchiesbyloadingthelayoutsintothecontentviewoftheactivity.Youalsoinitializeanyactivitylevelvariablesthatmaybeusedduringthelifetimeoftheactivity.Likemanyofthecallbacksyoualsocalltheparent’sonCreate()methodfirst.

WhenonCreateiscalled,anactivitymaybeinoneofthreestates.Theactivitymayhavebeenabrand-newactivitystartingoutitslifeforthefirsttime.Oritmaybeanactivitythatisautomaticallyrestartedbecauseofaconfigurationchangesuchadevicerotatingfromoneorientationtoanother.Oritisanactivitythatisrestartedfollowingapreviousprocessshutdownduetolow-memoryconditionsandbeinginthebackground.IntheonCreatecallback,youshouldtakethesescenariosintoaccountifwhatyouneedtodoineachscenarioisdifferent.

NowwecanunderstandtheargumenttothismethodinvolvingthesavedInstanceBundle.Youcanusethisbundletolookintothepreviousstateoftheactivity.Thisbundlemayhavebeenoriginallyusedtosavethestateoftheactivityduringaconfigurationchangeorwhentheactivityanditsprocessshutdownduetolow-memoryconditions.Thestatethatissavedintothisbundleargumentisusuallycalledtheinstancestateoftheactivity.Theinstancestateissomewhattemporaryinnature;specifically,itistiedtothisinstanceoftheapplicationduringthisinvocation.Thistypeofstateisnotexpectedtobewrittentopermanentstoragelikefiles.Theuserwillnotbetoodisconcertedifthisstateistoreverttoaninitialstatewhentheapplicationisrevived.InthecallbackwewillexplainsooncalledonPause()youcansavethestatethatmustbepersistedtolong-termstorage.Ifthathappens,youcanusetheonCreate()methodtoloadthatstateaswellaspartofthestart-up.

Thereisanotherconsiderationthatthismethodcantakeintoaccount.Whenanactivityisrestartedorre-createdbecauseofanorientationchange,theoldactivityisdestroyedandanewactivityiscreatedinitsplace.Thismeansthenewactivityhasanewreferenceinmemory.Theoldactivityreferenceisnolongervalid.Itwouldbewrongtohaveanexternalthreadoraglobalobjectthatisholdingontotheoldactivity.Sothereneedstobeamechanismwhentheactivityisre-createdtotelltheexternalobjectthatthereisanewactivityreference.Todothat,there-createdactivityneedstoknowthereferenceofthatexternalobject.Thisexternalobjectreferenceiscalled“non-configurationinstancereference.”ThereisacallbackmethodcalledonRetainNonConfigurationInstance()thatcanreturnareferencetothisexternalobject;weshallcoverthisshortly.AndroidSDKthenkeepsthisreferenceandmakesitavailabletothere-createdactivitythroughamethodcalledgetLastNonConfigurationInstance().NotethatinChapter8,wewillshowyouhowtodothisbetterthroughwhatarecalledheadlessretainedfragments.WewillreturntothistopicalsoinChapter15onAsyncTask.

ThereisanothernuancetotheonCreatemethod.Youmaywanttoensurethatinthe

Page 76: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

layoutsyouhaverightviewsandfragments(whichyouwilllearninChapter8)tomatchwhenthestatewassaved.BecauseasubsequentonRestoreInstanceState()(whichiscalledafteronStart())assumesthatalltheviewandfragmenthierarchiesarepresenttorestoretheirrespectivestates,themerepresenceofthepreviousstatewillnotre-createtheviews.Soitisuptothismethodtoloadtherightlayoutstobeshown.Thisisusuallynotanissueifyoudon’tdeleteoraddviewsduringtheinteractionwiththeactivity.

voidonStart()Afterbeingcreated,thismethodpushestheactivityintoavisiblestate.Inotherwordsthismethodstartsthe“visiblelifecycle”oftheactivity.ThismethodiscalledrightafteronCreate().ThismethodassumesthattheviewhierarchiesareloadedandavailablefromtheonCreate().Younormallydon’tneedtodooverridethismethodandifyoudo,makesureyoucalltheparent’sonStart()first.InFigure2-2notethatthismethodcanalsobecalledfromanothercallbackcalledonRestart.

YoumustbeawarethattheonRestoreInstanceStatemethodiscalledafterthismethod.Soyoushouldn’tmakeassumptionsaboutthestateoftheviewsinthismethod.Sotrynottomanipulatethestateoftheviewsinthismethod.DothatrefinementinthesubsequentonRestoreInstanceStateortheonResumemethod.BecausethisisacounterpartoftheonStop(),dothereverseshouldyouhavestoppedsomethinginonStop()orinonPause().Ifyouseesomethingisbeingdoneinthismethod,lookatitwithcautionandmakesureitiswhatyouwant.Alsoknowthatthestart-and-stopcyclecanhappenmultipletimesduringtheoverallcurrentcycleoftheactivity.

Thismethodcanalsobecalledwhentheactivityisshownafterbeinghiddenfirst,becauseanotheractivityhascometothetopofthevisibilitystack.InthosecasesthismethodiscalledaftertheonRestart(),whichitselfistriggeredaftertheonStop().Sotherearetwopathsintothismethod:eitheronCreate()oronRestart().Inbothcasestheviewhierarchiesareexpectedtobeestablishedandavailablepriortothiscallback.

voidonRestoreInstanceState(BundlesavedInstanceState)Ifanactivityistobelegitimatelyclosedbyauser,thenthestatethatuseriswillingtodiscardistheinstancestate.Forexample,whentheuserchoosesabackbutton,thenhe/sheisinformingAndroidthathe/shenolongerisinterestedinthisactivityandthattheactivitycanbeclosed,discardingallitsstatethatisnotyetsaved.Sothisstate,whichistransitoryandonlyvalidforthelifeoftheactivitywhileitisinmemory,istheinstancestate.

Ifthesystemchosestoclosetheactivity,becausethereisachangeinorientation,thentheuserwillexpectthattransitory(instance)staterightbackwhentheactivityisrestarted.Tofacilitatethis,AndroidcallsthisonRestoreInstanceStatemethodwithabundlethatcontainsthesavedinstancestate.(SeetheonSavedInstanceStatemethod

Page 77: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

explanation.)

Incontrasttoinstancestate,thepersistentstateofanactivityissomethingtheuserexpectstoseeevenaftertheactivityfinishesandisnolongerinplay.Thispersistencestatemayhavebeencreatedduringtheactivityormayevenexistbeforetheactivityiscreated.Thistypeofstate,especiallywhenitiscreatedwiththehelpoftheactivity,mustbeexplicitlysavedtoanexternalpersistentstorelikeafile.Iftheactivitydoesn’tuseanexplicit“save”buttonforsuchneeds,thenthe“onPause”methodneedstobeusedtosavesuchimplicitpersistentstates.ThisisbecausenomethodafteronPauseisguaranteedtobecalledincaseoflow-memoryconditions.Youshouldn’trelyontheinstancestateiftheinformationistooimportanttolose.

voidonResume()ThecallbackmethodonResumeistheprecursortohavingtheactivityfullyvisible.Thisisalsothestartoftheforegroundcyclefortheactivity.InthisforegroundcycletheactivitycanmovebetweenonResume()andonPause()multipletimesasotheractivities,notifications,ordialogswithmoreurgencycomeontopandgo.

Bythetimethismethodiscalled,wecanexpecttheviewsandtheirstatefullyrestored.Youcantakethisopportunitytotweakfinalstatechanges.Asthismethoddoesn’thaveabundle,youneedtorelyontheinformationfromonCreateoronRestoreInstanceStatemethodstofine-tunestateiffurtherneeded.

IfyouhadstoppedanycountersoranimationsduringonPauseyoucanrestartthemhere.Youcanalsokeeptrackofthecaseiftheviewsarereallydestroyedornotbyfollowingthepreviouscallbackmethods(whetheronResumeisaresultofonCreate,onRestart,oronPause)anddotheminimumpossibletoadjusttheviewstate.Typicallyyouwillnotdostatemanagementherebutonlythosetasksthatneedtobeturnedonoroffbasedonvisibility.

voidonPause()Thiscallbackindicatesthattheactivityisabouttogointobackground.Youshouldstopanycountersoranimationsthatwererunningwhentheactivitywasfullyvisible.TheactivitymaygotoonResumeorproceedtoonStop.GoingtoonResumewillbringtheactivitytotheforeground.GoingtoonStopwilltaketheactivityintoabackgroundstate.

AspertheSDK,itisalsothelastmethodthatisguaranteedtobecalledbeforetheactivityandtheprocessiscompletelyreclaimed.Soitisthelastopportunitythatadeveloperhastosaveanynon-instanceandpersistentdatatoafile.

AndroidSDKalsowaitsforthismethodtoreturnbeforemakingtheforegroundactivityfullyactive.Soyouwanttobebriefinthismethod.Alsonoticethatthismethodhasnobundlethatispassed.Thisisanindicationthatthismethodisforstoringpersistentdataandalsoinanexternalstoragemediumsuchasafileoranetwork.

Page 78: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Youcanalsousethismethodtostopanycounters,animations,orstatusdisplaysofabackgroundtask.YoucanresumetheminonResume.

voidonStop()ThecallbackmethodonStop()movestheactivityfrompartiallyvisibletothebackgroundstatewhilekeepingalloftheviewhierarchiesintact.ThisisthecounterpartofonStart.TheactivitycanbetakenbacktothevisiblecyclebycallingonStart.ThisstatetransitionofgoingfromonStoptoonStartduringthesameactivitylifecyclegoesthroughtheonRestart()method.

Afterthiscall,theactivityisnolongervisible.ButkeepinmindthatthismaynotbecalledafteronPauseunderlow-memoryconditions.Becauseofthisuncertaintydonotusethismethodtostartorstopservicesthatareoutsideofthisprocess.DothatinonPauseinsteadandresumetheminonResume.However,youcanusethismethodtocontrolservicesorworkthatisinsideyourprocess.Thisisbecause,aslongastheprocessisactive,thismethodisgoingtogetcalled.Ifthewholeprocessistakendownthenthosedependenttasksorglobalvariableswillgoawayanyway.

voidonSaveInstanceState(BundlesaveStateBundle)ThecontrolgoestoonDestroy()comingoutofonStopiftheprocessisstillinmemory.However,ifAndroidrealizesthatactivityisbeingclosedwithouttheuser’sexpectationthenitwouldcalltheonSaveInstanceState()beforecallingonDestroy().Orientationchangeisaveryconcreteexampleofthis.TheSDKwarnsthatthetimingofonSaveInstanceState()isnotpredictablewhetherbeforeorafteronStop().

Thedefaultimplementationofthismethodalreadysavesthestateofviews.HoweverifthereissomeexplicitstatethatisnotknowntotheviewsyouneedtosaveitinthebundleobjectandretrieveitbackintheonRestoreInstanceStatemethod.Youdoneedtocalltheparent’sonSaveInstanceState()methodfirstsothatviewshaveanopportunitytosavetheirstatethemselves.Therearesomerestrictionsandrulesfortheviewstobeabletosavetheirstate.ThechaptersonUIcontrols(Chapters3,4,and5)andconfigurationchange(Chapter9)gointomoredetailonthissubject.

voidonRestart()Thismethodiscalledwhentheactivitytransitionsfrombackgroundstatetopartiallyvisiblestate,i.e.,goingfromonStoptoonStart.YoucanusethisknowledgeinonStartifyouwanttooptimizecodetherebasedonwhetheritisafreshstartorarestart.Whenitisarestarttheviewandtheirstatearefairlyintact.

YoucandothingsinthismethodthatwouldhavebeendoneinonStart,butoptimizedwhentheactivityisnotvisible,buttooexpensivetobedonemultipletimesinonResume.

Page 79: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ObjectonRetainNonConfigurationInstance()Thiscallbackmethodisinplacetodealwithactivityre-creationduetoconfigurationchanges.Thismethodreturnsanobjectreferenceinyourprocessmemorythatneedstoberetiedtotheactivityonceitisre-created.WeexplainedthisinmoredetailpreviouslywhenwedescribedtheonCreatemethod.

Whentheactivityisre-created,theobjectthatisreturnedfromthismethodismadeavailablethroughthemethodgetLastNonConfigurationInstance().NowinonCreate()thenewactivitycanusethepreviouslyestablishedresourcesandobjectreferences.Importantly,ifthosepreviousresourcesareholdingtotheoldactivityreference,thentheresourcescanbetoldtousethenewone.

ThisdilemmaexistsbecauseduringanorientationchangeAndroiddoesn’tkilltheprocess,butjustdiscardstheoldactivity,re-createstheactivityintheneworientation,andexpectstheprogrammertosupplynewlayouts,etc.,tosuitthenewconfiguration.Sotheworkingobjectsarestillthereholdingontoanoldactivity.Thisisthemethodinassociationwithits“get”counterparttoovercomethisobstacle.

WhenyoureadChapter8,youwilllearnthatthismethodisdeprecatedandyouwilluseinitsplacewhatarecalledheadlessretainedfragments.Theseheadlessretainedfragmentshavetheadditionalbenefitofbeingabletotracktheactivitylifecycleandnotjustthereferencetotheactivity.

voidonDestroy()onDestroy()isthecounterpartofonCreate().TheactivityisgoingtofinishafteronDestroy.Anactivitycanfinishfortwoprimaryreasons.

Oneisanexplicitclose.Thiscanhappenwhentheuserhasexplicitlycausedtheactivitytofinisheitherbyclickingabuttonthatisprovidedtoindicatethattheuserisdoneorbyusingabackbuttonleavingtheactivitytogotothepreviousactivity.Undersuchcircumstancestheactivitywillnotbebroughtbackbythesystemunlesstheuserchoosestheactivityagain.InthisscenariotheactivitylifecycleendswiththeonDestroymethod.

Thesecondreasonanactivitycancloseisinvoluntary.Whentheorientationofadevicechanges,theAndroidSDKwillforcefullyclosetheactivityandcalltheonDestroymethodfollowedbyre-creatingtheactivityandcallingtheonCreateagain.

Whenanactivityisinthebackgroundandifthesystemneedsmemory,AndroidmayshutdowntheprocessandmaynothaveanopportunitytocalltheonDestroymethod.Duetothisuncertainty,muchlikeonStop,don’tusethismethodtocontroltasksorservicesthatareoutsidetheprocessinwhichtheactivityhadbeenrunning.However,iftheprocessisstillinmemorytheonDestroywillbecalledaspartofthelifecycleandyoucanplacecleanupcodeinonDestroyaslongasthatcodebelongstothisprocess.

GeneralNotesonActivityCallbacks

Page 80: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UseFigure2-3toguideyoutoseetheorderofthesecallbacksandhowbesttousethem.Ifyouweretooverrideacallbackyouneedtocallbacktheparentmethod.TheSDKdocumentationexplicitlyindicateswhichderivedmethodsarerequiredtocallbacktheirparentequivalents.AlsorefertotheSDKdocumentationtolearnduringwhichcallbacksthesystemwillnotkilltheprocessduetolow-memoryconditions.Alsonoticethatonlyahandfulofcallbackscarryinstancestatebundle.

MoreonResourcesWewanttotellyoulittlemoreabouthowresourcesareusedinAndroidapplications.Inthecalculatorlayoutfile,youhaveseensomeoftheresourcesusedlikestrings,images,IDs,etc.

Otherresourcesthatarenotsoobviousincludedimensions,drawables,stringarrays,languagetermsforplurals,xmlfiles,andalltypesofinputfiles.InAndroid,somethingistreatedasaresourcea)ifitisaninputtoyourprogramandispartoftheapkfileandb)ifthevalueorcontentoftheinputcanhavedifferentvaluesbasedonlanguage,locale,ororientationofthedevice,generallycalledaconfigurationchange.

DirectoryStructureofResourcesAllresourcesinAndroidareplacedunderthe/ressubdirectoryoftherootofyourapplicationpackage.Listing2-10showsanexampleofwhata/resmaylooklike:

Listing2-10.AndroidResourceandAssetsDirectoryStructure

/res/values/strings.xml/colors.xml/dimens.xml/attrs.xml/styles.xml/drawable/*.png/*.jpg/*.gif/*.9.png/*.xml/anim/*.xml`/layout/*.xml/raw/*.*/xml/*.xml/assets/*.*/*.*

Wewillcoverattrs.xmlandstyles.xmlinChapter7.Thexmlfilesintheanimsubdirectorydefineanimationsthatcanbeappliedtovariousviews.Wewillcovertheseanimation-relatedresourcesintheanimationschapter(Chapter18).ThexmlfilesinthexmlsubdirectorygetcompiledawaytobinaryandtheirresourceIDscanbeusedtoread

Page 81: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

them.Wewillshowanexampleofthisshortly.The/rawsubdirectoryholdsfilesthatgetplaced,astheyare,withoutgettingconvertedtoanybinaryformat.

The/assetsdirectory,whichisasiblingof/res,isnotpartoftheresourcehierarchy.Thismeansthatthefilesinthissubdirectorydonotchangebasedonlanguageoralocale.AndroiddoesnotgenerateanyIDsforthesefiles.Thisdirectoryismorelikeastaticlocalstorageforanyfilesthatareusedasinputs,suchasconfigurationfilesforyourapplication.

Exceptfortheassetsdirectory,everyotherartifactinthe/ressubdirectorywillendupgeneratinganIDinR.*namespace,asyouhaveseenbefore.EachdistinctresourcetypewillhaveitsownnamespaceunderR.*,asinR.id,R.string,orR.drawable,etc.

ReadingResourcesfromJavaCodeInlayoutfiles,asyouhaveseentheincalculatorlayout,oneresourcecanrefertootherresources.Forexample,thecalculatorlayoutresourcefilereferencedthestringandcolorreferences.Thisapproachiscommon.Alternatively,youcanalsouseJavaAPItoretrievetheresourcevaluesusingthemethodActivity.getResources().ThismethodreturnsareferencetotheAndroidSDKjavaclassresources.YoucanusemethodsonthisclasstogettothevaluesofeachresourceidentifiedinyourlocalR.*namespace.Listing2-11showsanillustrationofthisapproach:

Listing2-11.ReadingResourceValuesinJavaCode

Resourcesres=activity.getResources();//Retrievingacolorresourceintsomecolor=res.getColor(R.color.main_back_ground_color);//UsingadrawableresourceColorDrawableredDrawable=(ColorDrawable)res.getDrawable(R.drawable.red_rectangle);

RuntimeBehaviorofDrawableResourcesThedrawabledirectoryisaninterestingcaseworthcoveringtodemonstratethefluencyofAndroid’sarchitecture.Asshownearlier,thisdirectorycancontainimagesthatcanbesetasbackgrounds.ThisdirectoryalsoallowsXMLfilesthatknowhowtogetconvertedtodrawablejavaobjectswhichcanthenbeusedasbackgroundsthatarerenderedatruntime.Listing2-12showsanexampleofthis:

Listing2-12.ExampleofaShapeDrawableXMLResourceFile

<?xmlversion="1.0"encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">

Page 82: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<solidandroid:color="#f0600000"/><strokeandroid:width="3dp"android:color="#ffff8080"/><cornersandroid:radius="13dp"/><paddingandroid:left="10dp"android:top="10dp"android:right="10dp"android:bottom="10dp"/></shape>

Ifyouplaceafilelikethisinthedrawablesubdirectoryandcallitbackground1.xml,itwillresultinanIDcalledR.drawable.background1.YoucanthenusethatIDasifitwereabackgroundimageforanyviewthatisdrawnwitharectangularborder.Otherpossibleshapesareovals,lines,andrings.

Similartotheshapexmlfile,eachallowedXMLfileinthedrawabledirectorydefinesadrawablethatdefinesaparticularwaytodraw.Examplesofthesedrawablesincludebitmapsthatcanbedecoratedwithcertainbehavior,orimagesthatcantransitionfromoneimagetoanother,layereddrawablesthatarecollectionsofotherdrawables,drawablesthatcanbeselectedbasedoninputparameters,drawablesthatcanrespondtoprogressbyshowingmultipleimages,drawablesthatcanclipotherdrawables,etc…SeethefollowingURLforanumberofsophisticatedthingsyoucandousingtheseruntimedrawableobjects:

http://androidbook.com/item/4236

UsingArbitraryXMLFilesasResourcesAndroidalsoallowsarbitraryXMLfilestobeusedasresourceswhichcanthenbelocalizedortunedforeachdevice.Listing2-13isanexampleofreadingandprocessinganXML-basedresourcefilefromthe/res/xmlsubdirectory.

Listing2-13.ReadinganXMLResourceFile

privateStringreadAnXMLFile(Activityactivity)throwsXmlPullParserException,IOException{StringBuffersb=newStringBuffer();Resourcesres=activity.getResources();XmlResourceParserxpp=res.getXml(R.xml.test);

xpp.next();inteventType=xpp.getEventType();while(eventType!=XmlPullParser.END_DOCUMENT){if(eventType==XmlPullParser.START_DOCUMENT){sb.append("******Startdocument");}elseif(eventType==XmlPullParser.START_TAG){sb.append("\nStarttag"+xpp.getName());}elseif(eventType==XmlPullParser.END_TAG){sb.append("\nEndtag"+xpp.getName());

Page 83: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}elseif(eventType==XmlPullParser.TEXT){sb.append("\nText"+xpp.getText());}eventType=xpp.next();}//eof-whilesb.append("\n******Enddocument");returnsb.toString();}//eof-function

WorkingwithRawResourceFilesAndroidalsoallowsanytypeofnon-compiledfilesasresources.Listing2-14isanexampleofreadingafilethatisplacedinthe/res/rawsubdirectory.Beingaresourceeventherawfilesthatareinthisdirectorycanbecustomizedforlanguageoradeviceconfiguration.AndroidgeneratesIDsautomaticallyforthesefilesaswell,astheyareresourceslikeanyotherresource.

Listing2-14.ReadingaRawResourceFile

StringgetStringFromRawFile(Activityactivity)throwsIOException{Resourcesr=activity.getResources();InputStreamis=r.openRawResource(R.raw.test);//assumingyouhaveafunctiontoconvertastreamtoastringStringmyText=convertStreamToString(is);is.close();//takecareofexceptionsetc.returnmyText;}

ReadingFilesfromtheAssetsDirectoryAlthoughusuallyclubbedwithresources,the/assetsdirectoryisabitdifferent.Thisdirectorydoesnotsitunderthe/respath,sothefilesinthisdirectorydonotbehavelikeresourcefiles.AndroiddoesnotgenerateresourceIDsforthesefilesintheR.*namespace.Thesefilesarenotcustomizablebasedonlocaleordeviceconfiguration.Listing2-15showsanexampleofreadingafilethatisplacedinthe/assetssubdirectory.

Listing2-15.ReadingaFilefromAssetsDirectory

StringgetStringFromAssetFile(Activityactivity){AssetManageram=activity.getAssets();InputStreamis=am.open("test.txt");Strings=convertStreamToString(is);is.close();

Page 84: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returns;}

Thusfar,wehaveusedanactivityreferencetogetholdoftheresourcesoranAssetManagerobjectasinListing2-15.Inreality,allweneedisthebaseclassoftheactivity,thecontextobject.

ReadingResourcesandAssetsWithoutanActivityReferenceSometimesyoumayneedtoreadanXMLresourcefileoranassetfilefromthebowelsofsourcecode,whereitisintrusivetopasstheactivityreference.Forthesecases,youcanusethefollowingapproachtoobtaintheapplicationcontextandthenusethatreferenceinsteadtogettotheassetsandresources.

WhenAndroidloadsyourapplication(inordertoinvokeanyofitscomponents),itinstantiatesandcallsanapplicationobjecttoinformthattheapplicationcouldinitializeitself.ThisapplicationclassnameisspecifiedintheAndroidmanifestfile.IfMyApplication.javaisyourapplicationjavaclass,thenitcanbespecifiedintheAndroidmanifestfileasshowninListing2-16.

Listing2-16.SpecifyinganApplicationClassintheManifestFile

<applicationandroid:name=".MyApplication"android:icon="@drawable/icon".../>

Listing2-17showshowwecancodetheMyApplicationandalsoshowshowwecancapturetheapplicationcontextinaglobalvariable.

Listing2-17.SampleCodeforanApplicationthatCapturesApplicationContext

publicclassMyApplicationextendsApplication{//MakesuretocheckfornullforthisvariablepublicstaticvolatileContexts_appContext=null;

@OverridepublicvoidonConfigurationChanged(ConfigurationnewConfig){super.onConfigurationChanged(newConfig);}@OverridepublicvoidonCreate(){super.onCreate();MyApplication.s_appContext=this.getApplicationContext();}@OverridepublicvoidonLowMemory(){

Page 85: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

super.onLowMemory();}@OverridepublicvoidonTerminate(){super.onTerminate();}}

Withtheapplicationcontextcapturedinaglobalvariable,wenowcangettotheassetmanagertoreadourassetsasinListing2-18.

Listing2-18.UsingApplicationObjecttoGettoApplicationAssetFiles

AssetManageram=MyApplication.s_appContext.getAssets();InputStreamis=am.open(filename);

UnderstandingResourceDirectories,Language,andLocaleLet’swrapuptheideaofAndroidresourcesbypointingouthowresourcedirectoriesareusedtoloadresourcesbasedonlanguage,locale,oraconfigurationchangeofthedevicelikesayorientation.SeehowinListing2-19alayoutfilewiththesamenameislocatedinmultiplelayoutdirectoriesstartingwithsameprefixoflayoutbutwithdifferentqualifierssuchas“port”forportraitand“land”forlandscape.TherearealargenumberofthesequalifiersavailableintheSDKdocumentation.WealsocoversomeoftheseaspectsinChapter9(ConfigurationChanges).Listing2-19showsanexampleofhowlayoutfilesarearrangedbyportraitorlandscapeconfiguration:

Listing2-19.DemonstratingResourceQualifiers

\res\layout\main_layout.xml\res\layout-port\main_layout.xml\res\layout-land\main_layout.xml

MoreonIntentsWehavetalkedabouthowintentsareusedtoinvokeactivities.Wewantcoverfewmoreessentialaspectsofintentsnow.Listing2-20showshowintentsareusedtoinvokeanumberofprebuiltGoogleapplications.

Listing2-20.SampleCodeUsingIntents

publicclassIntentsUtils{publicstaticvoidinvokeWebBrowser(Activityactivity){Intentintent=newIntent(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.google.com"));

Page 86: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

activity.startActivity(intent);}publicstaticvoidinvokeWebSearch(Activityactivity){Intentintent=newIntent(Intent.ACTION_WEB_SEARCH);intent.setData(Uri.parse("http://www.google.com"));activity.startActivity(intent);}publicstaticvoiddial(Activityactivity){Intentintent=newIntent(Intent.ACTION_DIAL);activity.startActivity(intent);}publicstaticvoidcall(Activityactivity){Intentintent=newIntent(Intent.ACTION_CALL);intent.setData(Uri.parse("tel:555–555–5555"));activity.startActivity(intent);}publicstaticvoidshowMapAtLatLong(Activityactivity){Intentintent=newIntent(Intent.ACTION_VIEW);//geo:lat,long?z=zoomlevel&q=question-stringintent.setData(Uri.parse("geo:0,0?z=4&q=business+near+city"));activity.startActivity(intent);}}

Noticehowtheseintentsdonotinvokeaspecificactivitybyitsclassnamebutratherusethetargetqualitiesofsuitableactivities.Forexampletoinvokeabrowsertoviewawebpage,theintentsimplysaystheactionisACTION_VIEWandthedataportionoftheintentissettothewebaddress.Androidthenlooksaroundtoseealltheactivitiesthatknowhowtoshowthetypeofdatarequestedinthedataattribute.ItwillthengivetheuseranoptionwhichoftheactivitiesthattheuserwantstochoosetoopentheURL.Thesetypesofintentsthatdon’tspecifytheclassnameofthecomponenttoinvokearecalledimplicitintents.Wewillcoverthisinalittlebitmoredetailshortly.

StartingActivitiesforResultsListing2-21showsanexampleofanactivitywhereoneofitsmethodsisinvokingatargetactivityinordertoobtainaresultwhenthattargetactivityiscompleted.ThisisdonethroughthemethodinvokePick()inasshowninListing2-21.

Listing2-21.UsingIntentstoGetResultsfromActivities

publicclassSomeActivityextendsActivity{.....//Callthismethodtostartatargetactivitythatknowshow

Page 87: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

topickanote//UseadataURIthattellsthetargetactivitywhichlistofnotestoshowpublicstaticvoidinvokePick(Activityactivity){

IntentpickIntent=newIntent(Intent.ACTION_PICK);intrequestCode=1;pickIntent.setData(Uri.parse("content://com.google.provider.NotePad/notes"));activity.startActivityForResult(pickIntent,requestCode);}

//thefollowingmethodwillbecalledwhenthetargetactivityfinishes//NoticetheoutputIntentobjectthatispassedbackwhichcould//containadditionalinformation

@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,IntentoutputIntent){

super.onActivityResult(requestCode,resultCode,outputIntent);parseResult(this,requestCode,resultCode,outputIntent);}publicstaticvoidparseResult(Activityactivity

,intrequestCode,intresultCode,IntentoutputIntent){if(requestCode!=1){Log.d("Test","Someoneelsecalledthis.notus");return;}if(resultCode!=Activity.RESULT_OK){Log.d("Test","Resultcodeisnotok:"+resultCode);return;}Log.d("Test","Resultcodeisok:"+resultCode);UriselectedUri=outputIntent.getData();Log.d("Test","Theoutputuri:"+selectedUri.toString());

//ProceedtodisplaythenoteoutputIntent.setAction(Intent.ACTION_VIEW);startActivity(outputIntent);}

TheconstantsRESULT_OK,RESULT_CANCELED,andRESULT_FIRST_USERarealldefinedintheactivityclass.TheconstantRESULT_FIRST_USERisusedasa

Page 88: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

startingnumberforuser-definedactivityresults.ThenumericalvaluesoftheseconstantsareshowninListing2-22:

Listing2-22.ResultValuesfromReturnedActivities

RESULT_OK=-1;RESULT_CANCELED=0;RESULT_FIRST_USER=1;

TomakethePICKfunctionalitywork,theimplementingorthetargetactivitythatisrespondingshouldhavecodethatexplicitlyaddressestheneedsofanACTION_PICK.Let’slookatanexampleofhowthisisdoneintheGooglesampleNotePadapplication.(Seethereferencessection,whereyoucanfindthisapplication.)Whentheitemisselectedinthelistofitems,theintentthatinvokedthetargetactivityischeckedtoseewhetherit’sanACTION_PICKintent.Ifitis,thedataURIoftheselectednoteitemissetinanewintentandreturnedthroughsetResult()asshowninListing2-23.Thecallingactivitythencaninvestigatethereturnedintenttoseewhatdataithasinit.SeethemethodparseResult()inListing2-21.

Listing2-23.TargetActivityReturningaResultthroughaDataURI

@OverrideprotectedvoidonListItemClick(ListViewl,Viewv,intposition,longid){Uriuri=ContentUris.withAppendedId(getIntent().getData(),id);

Stringaction=getIntent().getAction();if(Intent.ACTION_PICK.equals(action)||Intent.ACTION_GET_CONTENT.equals(action)){//Thecalleriswaitingforustoreturnanoteselectedby//theuser.Theyhaveclickedonone,soreturnitnow.setResult(RESULT_OK,newIntent().setData(uri));finish();}...otherwaysofhowthisactivitymayhavebeeninvoked}

ExercisingtheGET_CONTENTActionACTION_GET_CONTENTissimilartoACTION_PICK.InthecaseofACTION_PICK,youarespecifyingadataURIthatpointstoacollectionofitems,likealistofnotesfromaNotePad-likeapplication.Youwillexpecttheintentactiontopickoneofthenotesandreturnittothecaller.InthecaseofACTION_GET_CONTENT,youindicatetoAndroidthatyouneedanitemofaparticularMIMEtype.Androidsearchesforactivitiesthatcaneithercreateoneofthoseitemsorchoosefromanexistingsetofitemsthatsatisfythat

Page 89: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MIMEtype.

UsingACTION_GET_CONTENT,youcanpickanotefromacollectionofnotessupportedbytheNotePadapplicationusingthecodeshowninListing2-24:

Listing2-24.InvokingActivitiesforCreatingContent

publicstaticvoidinvokeGetContent(Activityactivity){IntentpickIntent=newIntent(Intent.ACTION_GET_CONTENT);intrequestCode=2;pickIntent.setType("vnd.android.cursor.item/vnd.google.note");activity.startActivityForResult(pickIntent,requestCode);}

NoticehowtheintenttypeissettotheMIMEtypeofasinglenote.ContrastthiswiththeACTION_PICKcode,whereitexplicitlyindicatedaURLthatpointstoacollectionofnotes(likeawebURLthatcanretrieveapageworthofdata).

ForanactivitytorespondtoACTION_GET_CONTENT,theactivityhastoregisteranintentfilterindicatingthattheactivitycanprovideanitemofthatMIMEtype.Listing2-25showshowtheSDK’sNotePadapplicationaccomplishesthis:

Listing2-25.ActivityFilterforGetContent

<activityandroid:name="NotesList"android:label="@string/title_notes_list">......<intent-filter><actionandroid:name="android.intent.action.GET_CONTENT"/><categoryandroid:name="android.intent.category.DEFAULT"/><dataandroid:mimeType="vnd.android.cursor.item/vnd.google.note"/></intent-filter>......</activity>

TherestofthecodeforrespondingtoonActivityResult()isidenticaltothepreviousACTION_PICKexample.IftherearemultipleactivitiesthatcanreturnthesameMIMEtype,Androidwillshowyouthechooserdialogtoletyoupickanactivity.

RelatingIntentsandActivitiesAnintentisusedtostartnotonlyactivitiesbutalsoothercomponentslikeaserviceorabroadcastreceiver.Thesecomponentsarecoveredinlaterchapters.Youcanseethese

Page 90: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

componentsashavingcertainattributes.Oneattributeofacomponentmaybethecategorytowhichthiscomponentbelongs.Anotherattributemaybewhattypeofdatathiscomponentcanview,edit,update,ordelete.Anotherattributemaybewhattypeofactionsacomponentcanrespondto.Ifyouweretolookuponthesecomponentsasentitiesinadatabase,theirattributescanbeseenascolumns.Thenanintentcanbeseenasawhereclausethatspecifiesallorsomeofthosecharacteristicstochooseacomponentlikeanactivitytostart.Listing2-26isanexampleofdemonstratinghowtoqueryforallactivitiesthatarecategorizedasCATEGORY_LAUNCHER.

Listing2-26.QueryingActivitiesthatMatchanIntent

IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);PackageManagerpm=getPackageManager();List<ResolveInfo>list=pm.queryIntentActivities(mainIntent,0);

PackageManagerisakeyclassthatallowsyoutodiscoveractivitiesthatmatchcertainintentswithoutinvokingthem.Youcancyclethroughthereceivedactivitiesandinvokethemasyouseefit,basedontheResolveInfoAPI.Listing2-27isanextensiontotheprecedingcodethatwalksthroughthelistofactivitiesandinvokesoneoftheactivitiesifitmatchesaname.Inthecode,wehaveusedanarbitrarynametotestit:

Listing2-27.WalkingThroughaMatchedActivityListforanIntent

for(ResolveInfori:list){//ri.activityInfo.Log.d("test",ri.toString());Stringpackagename=ri.activityInfo.packageName;Stringclassname=ri.activityInfo.name;Log.d("test",packagename+":"+classname);if(classname.equals("com.ai.androidbook.resources.TestActivity")){Intentni=newIntent();ni.setClassName(packagename,classname);activity.startActivity(ni);}}

UnderstandingExplicitandImplicitIntentsWhenyouspecifyanexplicitactivityname(oracomponentnamelikeaserviceorabroadcastreceiver)inanintent,suchanintentiscalledanexplicitintent.Whenthisintentisusedtostartanactivity,thatactivityisinvokedirrespectiveofwhatelseisthereinthatintentsuchasitscategoryordata.

Asyouhaveseen,anintentdoesnothavetohaveanactivityspecifiedexplicitlytoinvoke

Page 91: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

it.Anintentcanrelyonanactivity’sactionattribute,categoryattribute,ordataattribute.Theseintentsthatomittheexplicitactivityorcomponentclassarecalledimplicitintents.WhenyouuseanimplicitintenttoinvokeanactivityitisparamountthattheactivitymusthaveasoneofitscategoriesCATEGORY_DEFAULT.Ifyouexpectyouractivitytobeexplicitlystartedbyanintent,thenyoudon’tneedtospecifyanycategoryatalltothatactivity.Listing2-28showsanexampleofminimallyregisteringanactivityinanAndroidmanifestfilesothatitcanbeinvokedbyanexplicitintent.

Listing2-28.MinimalActivityDefinition

<activityandroid:name="com.androidbook.asynctask.TestProgressBarDriverActivity"android:label="TestProgressbars"/>

Ifyouwanttoinvokethisactivitythroughanimplicitintentwithoutspecifyingitsclassname,likethroughanactionsay,thenyouneedtoaddthefollowingintentfilters,onefortheactionandonefortheneededmandatorycategoryofdefault,asshowninListing2-29.

Listing2-29.AnActivityDefinitionwithFilters

<activityandroid:name="com.androidbook.asynctask.TestProgressBarDriverActivity"android:label="TestProgressbars"><intent-filter><actionandroid:name="com.androidbook.intent.action.ME"/><categoryandroid:name="android.intent.category.DEFAULT"/></intent-filter></activity>

SavingStateinAndroidAsyoureviewedthecalculatorapp,yournextlikelyneedishowtostorethedataofanAndroidapp.Let’sbrieflycovertheavailableoptions.TherearefivewaystostoredatainAndroid:1)sharedpreferences,2)internalfiles,3)externalfiles,4)SQLlite,and5)networkstorageinthecloud.

SharedpreferencesAPIisasophisticatedAPIintheAndroidSDKtosave,display,andmanipulatepreferencesforyourapplications.Althoughthisfeatureisintendedandtailoredforpreferencesitcanbeusedforsavingarbitrarystateofyourapplication.Sharedpreferencesareinternaltotheapplicationanddevice.Androiddoesnotmakethisdataavailabletootherapplications.AuserisnotexpectedtodirectlymanipulatethisdatabymountingontoaUSBport.Thisdataisremovedautomaticallywhentheapplicationisremoved.ThesesharedpreferencesarecoveredindetailinChapter11.

Whilesharedpreferencesdataisstructuredkey/valuepairdataandfollowsafewothersemanticsimposed,internalfilesarestand-alonefilesthatyoucanwritetowithouta

Page 92: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

predefinedstructure.Wehaven’tfoundacompellingadvantageofusinginternalfilesoversharedpreferences,ortheotherway,especiallyforsmall-tomedium-sizedstate.Soformostappsyoucanchooseoneortheother.

Unlikeinternalfiles,whicharestoredontheinternalstorageofthedevice,externalfilesarestoredontheSDcard.Thesebecomepublicfilesthatotherappsincludingtheusercouldseeoutsidethecontextofyourapplication.Theexternalfilescanbeusedtostoredatathatmakessenseevenoutsideofyourappsuchasimagefilesorvideofiles.Forstrictlytheinternalstateoftheapp,internalfilesareabetteroption.

Theexternalfilesmayalsobeanoptionifthestateisverylargerunningintotensofmegabytes.Usuallywhenthathappensyoudon’twanttosavethestateasamonolithicfileanywayandoptformoregranularstorageasarelationaldatabaseliketheSQLlite.

WewillgiveaquickoverviewandbriefcodesamplesinChapter25onhowtousepreferences,internalfiles,andexternalfilestostoreyourappstate.OneofthetricksistopersistjavaobjecttreedirectlyusingJSONandGSOnwhilegivingconsiderationtoseeifthislevelofgranularityisappropriate.IfyouarenotfamiliarwithJSON,itisanobjecttransportandstorageformatforJavaScript-basedobjects.Itisalsogenerallyapplicableanyobjectstructureaswellincludingjavaobjectsandoftenusedthatwaylately.TheGSONisaGooglelibrarythatconvertsJavaobjectstoandfromJSONstrings.

SQLliteisareallygoodoptionthatisrecommendedtostorethestateofanapp.Theshortdrawbackisyourlogictosaveandreaddatabecomeverboseandcumbersome.YoucanprobablyuseO/Rmappinglibrariestoovercomethismismatchbetweenjavaobjectsanditsrelationalrepresentation.SQLliteisalsooftenusedtostoredatathatneedstobesharedbymultipleapplicationsthroughaconceptcalledcontentproviders.ThisisthecentraltopicofChapter25.

Finally,cloud-basednetworkstorageiscomingintoitsown.ForexampleanumberofMBAAS(MobileBackendasaService)platformssuchasparse.comsupportstoringthemobiledatadirectlyinthecloudforbothonlineandofflineusage.Thismodelisgoingtobeincreasinglyrelevantasyoustartmakingyourappavailableonmultipledevicesforthesameuserorbeingabletocollaboratewithotherusers.ThistopiciscoveredingreatdetailinourcompanionbookExpertAndroidfromApress.

ManytimeforyourappstheGSONoptiontostoreappstateinaninternalfileisreallythequickestandmostpracticalwaytogo.Ofcourseyoudowanttoanalyzethegranularityofthesolutionandseeifthissimplerapproachwon’tbecomeaburdenoncomputingpowerorbatterylife.IfyourappgainslotofpopularityyoumaywanttouseasecondreleasewithSQLlitebyoptimizingstoragespeedorusecloudstorageifthatismoreappropriateforthatrelease.

RoadmapforLearningAndroidandtheRestoftheBookLet’squicklyreviewwhatwehavecoveredsofar.Intheone-pagerapplicationyouhaveseenhowtheUIisputtogether,howthebusinesslogiciscodedinJava,andthenhowthe

Page 93: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

applicationisdefinedtotheAndroidsdkusingtheAndroidmanifestfile.Weexplainedwhatresourcesare,howtheyreferenceeachother,howtheyarereferencedinlayoutfiles,andevenhowtoreadyourinputfilesasresources.Wehaveshownyouwhatintentsare,theirintricacies,andhowtousethemtoinvokeordiscoveractivities.Wehavecoveredtheactivity’slifecycle,whichisreallyimportanttounderstandAndroidarchitecture.Wehavealsogivenaquickrundownofhowyoucansavethestateofyourapplication.Thisisaprettygoodfoundationtoplanandwritesimpleapplications.

Wenowwanttofollowupthisbird’seyeviewofAndroidapplicationswitharoadmapofbecominganexpertappdeveloperontheAndroidplatform.Thisroadmapdividesthechaptersofthisbookintothefollowingsixkeylearningtracks:

Track1:UIessentialsforyourAndroidapplications

Track2:Savingstate

Track3:Preparing/takingyourapplicationtoGooglePlay

Track4:Makingyourapplicationrobust

Track5:Bringingfinessetoyourapps

Track6:Integratingwithotherdevicesandthecloud

Amongthesesixtracks,thefirstthreearethebasictracksthatyoumustknowwelltowriteAndroidappsthatareusefultoyouandthelargercommunity.Tracks4,5,and6aretheretomakeyourappsbetterandfeaturerichinsubsequentreleases.Wewilltalkaboutwhatchaptersmakeupeachtrackandwhatyouareexpectedtogainfromthattrack.

Track1:UIEssentialsforYourAndroidApplicationsAndroidhasanumberofUIcontrolsandlayoutsoutoftheboxtowriteveryfeaturerich-applications.Someexamplesarebuttons,variousTextViews,EditTextcontrols,checkboxes,RadioButtons,dateandtimecontrols,listcontrols,controlstoshowanaloganddigitalclocks,controlstoshowimagesandvideos,controlstopicknumbers,etc.WewillcoveranumberoftheseinChapter3.Inthatchapter,wewillalsocovertheessentiallayoutsthatareneededtocomposetheUIfromthosecontrols.

OnceyouareabletousethebasiccontrolstoconstructyourUI,theonecontrolthatyouabsolutelyneedinyourappsisthelistcontrol.Wedidnotcoverlistcontrolasabasiccontrolbecauseitisabitinvolved.AlsoAndroidhasanumberoffeaturesandapproachestodolist-basedapplications.Sowehavededicatedaseparatechapterforlistcontrolsandthedataadaptersthatarenecessarytopopulatethoselistcontrols.TheseaspectsarecoveredinChapter4.

Onceyoumasterthebasiccontrols,basiclayouts,andlistcontrols,youwillstartlookingaroundformoresophisticatedlayoutslikethegridandtablelayouts.ThesearecoveredinChapter5under“UsingAdvancedLayouts.”

MenusarecoveredinChapter6.Android’smenuinfrastructureincludescontextmenus,

Page 94: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

pop-upmenus,optioniconsinanactionbar,etc.

Yourmobileappisnotreallycompletewithoutrefiningitthroughstyling,muchlikeCSS.Chapter7covershowstylesandthemesworkinAndroid.

DialogsareessentialinanyUI.DialogsareabitinvolvedinAndroid.TounderstanddialogsinAndroidyouhavetofirstunderstandtheconceptoffragments.Architectureofdialogsisonlyoneaspectoffragments.FragmentsarenowcoretotheAndroidUI.Chapter8explainswhatfragmentsareandinChapter10wecoverdialogs,buildinguponChapter8.

Inmobileapps,youcannotwriteanappwithoutunderstandingwhathappenstoyourapplicationwhenthedeviceorientationchanges.ProgrammingcorrectlyfororientationchangeisnottrivialinAndroid.HowtoprogramfororientationandotherdeviceconfigurationchangesiscoveredinChapter9.

ForanyreasonablyusefulapplicationyouwilllikelyneedtoknowalltheseUIessentials.SoTrack1isanessentialtrack.

Track2:SavingStateOnceyouknowhowtoconstructtheUIofyourapplication,thenextneedyouwillrunintoistosavethestateofyourapplication.Refertotheearliersectiononsavingstatetoseewhatoptionsareavailableandinwhichchaptersthoseoptionsarecovered.Track2isalsoanessentialtrackasyoushouldknowhowtosavestate.

Track3:Preparing/TakingYourApplicationtotheMarketBycompletingTracks1and2youcanbuildaprettyreasonableapplicationthatyoucandeploytothemarketplace.Chapter30showsyouhowyoucantakeyourapptotheGooglePlaystore.

Track4:MakingYourApplicationRobustTrack4isanadvancedtrackgettingintotheinternalsofAndroid.YouwillneedtogothroughthechaptersinthistracktosolidifyyourunderstandingofhowAndroidworks.WestartthistrackwithChapter12oncompatibilitylibrary.Thischapterteacheshowtomakeyourapprunwellonolderreleaseswhileusingfeaturesthatareavailableonlyonthenewerplatforms.

Androidallowsyoutoruncodeinyourapplicationeventhoughyouarenotactivelyusingtheapplicationintheforeground.Itcouldbethemusicyouareplayinginthebackground,oritcouldbebackingupyourimagestoacloud,etc.ThistypeofcodeiscalledaServiceinAndroid.WorkingwithservicesiscoveredinChapter13.Theseservicescanbetriggeredbyadirectuseractionorthroughalarmsorbroadcastevents.AlarmmanageriscoveredinChapter17.

Page 95: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Whenyouuseintentstoinvokecomponentssuchasactivitiesorservicesyouaretargetingasinglecomponent.Androidalsosupportsapublish-and-subscribeprotocolwhereanintentcanbeusedtoinvokemultiplecomponentsthatregisterforitatthesametime.Thesecomponentsarecalledreceiversorbroadcastreceivers.Abroadcastreceiverisapieceofcodeinyourapplicationthatisexecutedinresponsetoabroadcastedeventevenifyourapplicationhadnotbeenstartedorwasjustdormantatthetimeoftheevent.HowtoworkwithbroadcastreceiversiscoveredinChapter16.

AsyoustartusingmoreandmorefeaturesofAndroidsuchasservices,broadcastreceivers,andcontentprovidersyouwillneedtounderstandhowAndroidusesasinglemainthreadtorunthecodeinthesecomponents.ThisthreadingmodeliscoveredindetailinChapter14.Knowingthiswillhelpyouwritecodethatisrobust.Inthistrack,youwillalsolearnabouttheveryusefulAsyncTask,whichisusedtosimplifyoffloadingworkfromthemainthread.ThisAPIisoftenusedfromUItoreadmessagesfromtheweborcheckfore-mails,etc.AsyncTaskiscoveredinChapter15.

Track5:BringingFinessetoYourAppsTomakeyourappslookappealing,oneofthefirstthingsyoucandoistoaddalittleoralotofanimation.ThisiscoveredinChapter18.Touch-basedinterfacesarenowthenorm.Manipulatingyourenvironmentwithdraganddropismorenatural.Youwanttoemploysensorstowriteappsthatintegratewiththeexternalworldbetter.Thesetouchscreens,draganddrop,andsensorsarerespectivelycoveredinChapters22,23,and24.

Homescreenwidgetsareawonderfulwaytoextractpiecesofyourappandmakeitavailableonanyhomescreenofyourchoosing.Thispersonalizationfeature,whenusedinnovativelywithvalueinmind,makestheinteractionwiththedevicesimpleandjoyful.WidgetsarecoveredinChapter21.

Map-andlocation-basedappsaremadeformobiledevices.ThistopiciscoveredinChapter19.

YoucanveryeasilyintegrateaudioandvideointoyourappsonAndroid.ThisAPIiscoveredinChapter20.

Track6:IntegratingwithOtherDevicesandtheCloudYoucanuseGooglecloudmessagingtoreachouttotheusersofyourmobileapplications.GooglecloudmessagingiscoveredinChapter29.WithNFCandBluetoothcapabilitiesinAndroidyoucanstartinteractingwithyourphysicalenvironmentinyourapps.Wehopetopostsomematerialonthesetopicstotheonlinecompanionforthebook.

FinalTrack:GettingaHelpingHandfromExpertAndroid

Page 96: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Now,wearegoingtotalkaboutafewtopicsthatarenotcoveredinthisbook.Youmaywanttoconsiderthesetopics,shouldyoufindthemrelevanttoyourneeds.MostofthesearebasedonourresearchfortheExpertAndroidbookthatwepublishedinearly2014throughApress.

AndroidhasapublicAPItowritecustomcomponentsthatcanworkandbehavedifferentlythanwhatcomeoutofthebox.Youcanwritecustomviewswhereyoucancontrolwhattodrawandhowtodraw,whichcanthencoexistwithothercontrolsthatareoutoftheboxlikeabuttonoratextcontrol.Youcanalsocombinemultipleexistingcontrolsintoacompoundcontrolthatcanthenbehavelikeanindependentcontrol.Youcanalsodesignnewlayoutsthatsuityourdisplayneeds.Therearealotoftrickythingstocreatethesecustomcomponentswell.YouhavetounderstandthecoreAndroidviewarchitecture.Thismaterialiscoveredoverthreechaptersand100pagesintheExpertAndroidbookfromApress.

Ifyourappsareformbased,youwillneedtowritealotofcodetovalidatetheforminput.Youreallyneedaframeworktohandlethis.ExpertAndroidhasachapteroncreatingasmallformprocessingframeworkthatisreallyusefulandwillreduceerrorsandtheamountofcodeyouneedtowrite.

MBAAS,MobileBackendasaService,isaneededtechnologyformobileappsandisnowprettywidelyavailable.ThefacilitiesanMBAASoffersareuserlogins,sociallogins,usermanagement,savinddataonbehalfofusersinthecloud,communicationwiththeusers,collaborationbetweentheusersthemselves,etc.InExpertAndroidwehavemultiplechaptersdedicatedtoanMBAASplatformcalledParse.

OpenGLhascomealongwayonAndroidwithnow-substantialsupportforthenewgenerationofprogrammableGPUs.AndroidhasbeensupportingES2.0forsometimenow.InExpertAndroidwehaveover100pagesofcoverageonOpenGL.Westartatthebeginningandexplainalltheconceptswithoutneedingtorefertoexternalbooks,althoughwedogiveanextensivebibliographyonOpenGL.WecoverES2.0reallywellandprovideguidancetocombineOpenGLandregularviewstopavethewayfor3Dcomponents.

FederatedsearchprotocolofAndroidispowerfulasyoucanuseitinquiteafewimaginativeways.ExpertAndroidfullyexploresitsfundamentalsandalsosomealternatewaysofusingitoptimally.

Androidprovidesanincreasinglylargesetoffeaturesfordebugging.ThesetopicsarecoveredinExpertAndroid.Acellphoneisultimatelyatalkingdevice,althoughitisusedlessandlessoftenforthat.WehaveachapteronutilizingthetelephonyAPIinExpertAndroidaswell.

AsWeLeaveYouNowwiththeRestoftheBookFinally,youmaybewonderingwhyyoushouldevenbecomeamobiledeveloper.Wecancitetwostrongarguments,oneofwhichneverexistedbefore.Thefamiliaroneistobe

Page 97: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

partofanITorganizationfortheirmobileprogrammingefforts.TheITopportunitiesareontherisebutnotfullyrealizedyetunlikewhathappenedwiththeWebprogrammingparadigmwhenitcameintobeing.Weexpectthisneed,however,tobeagraduallyincreasingdemand.

Ontheotherhand,theimmediateandexcitingopportunityisforyoutobecomeanindependentapppublisher.Theavailabilityofasaleschannelfortheappsthatyouwriteisauniqueoneinthesoftwareindustry.NoteveryoneofusisgoingtobearisingstarinanITorganization.Theindependentdeveloperpathgivesanavenueforyoutogrowatyourownpaceandinadirectionthatsatisfiesyou.Luckandpatiencemightevenmakeyourich.Atleastyoucanaddvaluetothesocietywhilemeetingyourneeds.

ShouldyoudecidetoventureintotheAndroidmobileprogrammingspace,youwanttobepreparedwiththerighthardwarethatmakesthisexperiencebearable.IfyouarebuyingaWindowslaptopseeifyoucangetonewithatleast8Gofmemory,solid-stateharddrive,andareasonablyfastprocessor.Expecttospendabout$1,000to$1,500.IfyouarebuyingaMaclaptop,asimilarconfigurationmaycostyouabout$2,500.AgoodfastconfigurationisimportantforAndroiddevelopment.IfyouareaseasonedJavaprogrammer,giventhisinvestment,andthisbookinhand,ifyoufollowthetrackslaidouthereyoucanbecomeacompetentmobileAndroidappdeveloperinaboutsixmonths.

ReferencesHereareadditionalresourcesforthetopicsdiscussedinthischapter.

http://androidbook.com/free-android-chapters:YoucanusethisURLtodownloaddetailedchaptersonresourcesandintents(madeavailablefreefrompreviouseditionsduetospacelimitations).

http://androidbook.com/working-with-avds:YouwillfindatthisURLnotesoninstallingAndroid,workingwithAVDs,signingAPKfiles,andmoretogetyoustartedwithAndroid.

http://androidbook.com/item/3574:ThisURLshowshowtorunanAndroidapplicationonadevicefromtheeclipseADT.ThislinkalsoshowsyouhowtohookupyourdevicethroughaUSBporttoyourdevelopmentcomputer.

http://androidbook.com/item/4629:ThisURLtalksaboutkeycallbackfunctionsonanactivity.Monitoringtheactivitycallbacksisagoodwaytogetahandleontheactivitylifecycle.Youcancopythecodefromheretocreateabaseactivitythatcanmonitorandlogthesecallbacksforyou.

http://androidbook.com/item/4440:ThisURLtalksabouthowyoucanuseGSONandJSONforpersistenceneedsofyourapplication.Thisarticlesuggestsaneasywaytopersistdataon

Page 98: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thedeviceforyourapps.

ExpertAndroidfromApresstalksaboutpassingobjectsthroughAndroidbundlesasparcelablesindepth.

http://developer.android.com/guide/topics/resources/index.htmlAndroidSDKroadmaptothedocumentationonresources.

http://developer.android.com/guide/topics/resources/available-resources.html:Androiddocumentationofvarioustypesofresourcesavailable.

http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources:AlistofvariousconfigurationqualifiersprovidedbythelatestAndroidSDK.

http://developer.android.com/guide/practices/screens_support.htmlGuidelinesonhowtodesignAndroidapplicationsformultiplescreensizes.

http://developer.android.com/reference/android/content/res/Resources.htmlVariousJavamethodsavailabletoreadresources.

http://developer.android.com/reference/android/R.htmlResourcesasdefinedtothecoreAndroidplatform.

http://androidbook.com/item/3542:Ourresearchonplurals,stringarrays,resourcequalifiers,andalternateresources,aswellaslinkstootherreferences.

http://androidbook.com/item/4236:Usingdrawableresourcestocontrolbackgrounds.

http://developer.android.com/training/notepad/index.htmlAbeginner’sguide,yetacomprehensiveintroductiontoAndroidapplicationsthroughaNotePadexample.

http://developer.android.com/reference/android/content/Intent.htmlOverviewofintents,includingwell-knownactions,extras,andsoon.

http://developer.android.com/guide/appendix/g-app-intents.html:ListstheintentsforasetofGoogleapplications.Here,youwillseeherehowtoinvokeBrowser,Map,Dialer,andGoogleStreetView.

http://developer.android.com/reference/android/content/IntentFilter.htmlTalksaboutintentfiltersandisusefulwhenyouareregisteringintentfiltersforactivitiesandothercomponentsinthemanifestfile.

http://developer.android.com/guide/topics/intents/intents-filters.html:Goesintotheresolutionrulesofintentfilters.

http://developer.android.com/training/notepad/index.html

Page 99: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

URLwhereyoucandownloadthesamplecodeforaNotePadapplication.ThisisagoodsampleapplicationthatfeaturesanumberofAndroidAPIs.Agoodplacetogoafterthecalculatorapplication.

http://developer.android.com/samples/index.html:ThisistheprimarylinktobrowsethroughthevarioussamplespresentedfortheAndroidSDKbyGoogle.

http://developer.android.com/training/index.html:ThisistheprimarylearningsitefromGooglethatpresentsaseriesoflessonstolearnAndroid.

https://code.google.com/p/openintents/:AwebefforttomakevariousAndroidapplicationsworktogether.

http://androidbook.com/item/4623:AroadmapforlearningAndroid.Althoughsomeofthesepointsarecoveredhere,seethisURLforthelatestguidanceonlearningandmaximizingAndroid.

http://androidbook.com/item/4764:ThisisaknowledgefoldercontainingaseriesofarticlesandtidbitsonprogrammingwithAndroidbasicUI.

http://www.androidbook.com/proandroid5/projects.Lookhereforalistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch02_Calculator.zip.

SummaryThischapterlaidouteverythingyouneedtounderstandtocreatemobileapplicationswiththeAndroidSDK.YouhaveseenhowUIisconstructed.Youknowwhatactivitiesare.Youknowtheintricaciesoftheactivitylifecycle.Youunderstoodresourcesandintents.Youknowhowtosavestate.Finally,yougottoseethebreadthoftheAndroidSDKbyreadingthelearningtracksthatsummarizedtherestofthebook.WehopethesefirsttwochaptersgaveyouaheadstartforyourdevelopmenteffortswiththeAndroidSDK.

Page 100: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter3

BuildingBasicUserInterfacesandUsingControlsThepreviouschaptergaveyouacrashcourseinsomeoftheUIelementsavailableinAndroid,andhowtoputthemtogetherquicklytocreatethecalculatorapplication.Whilethatwasfun,wehopeyoustartedthinkingaboutwhatotherUIwidgetsareavailableinAndroid,overandabovetheTextView,EditText,andButtoncontrolsintroducedinChapter2.

Inthischapter,wearegoingtodiscussuserinterfacesandcontrolsindetail.WewillbeginbydiscussingthegeneralphilosophyofUIdevelopmentinAndroid,andthenwe’lldescribemanyoftheUIcontrolsthatshipwiththeAndroidSDK.Thesearethebuildingblocksoftheinterfacesyou’llcreate.Inthesubsequentchapters,wewillalsodiscussviewadaptersandlayoutmanagers,andyou’llseehowtheybuildonthebasiccontrolsweintroduceinthischapter.

Bytheendofthischapter,you’llhaveasolidunderstandingofthemanyUIcontrolsavailableinthestockAndroidtoolset,andhowtolayoutUIcontrolsintoscreensandpopulatethemwithdata.

UIDevelopmentinAndroidUIdevelopmentinAndroidisfun.It’sfunbecauseit’srelativelyeasy.WithAndroid,wehaveasimple-to-understandframeworkwithalimitedsetofout-of-the-boxcontrols.Theavailablescreenareaisgenerallylimited—onphonesifnotontablets—andthisguidestheunderlyingphilosophyof“simplepower”forAndroidcontrols.AndroidalsotakescareofalotoftheheavyliftingnormallyassociatedtodesigningandbuildingqualityUIs.This,combinedwiththefactthattheuserusuallywantstodoonespecificaction,allowsustoeasilybuildagoodUItodeliveragooduserexperience.

TheAndroidSDKshipswithahostofcontrolsthatyoucanusetobuildUIsforyourapplication.SimilartootherSDKs,theAndroidSDKprovidestextfields,buttons,lists,grids,andsoon.Inaddition,Androidprovidesacollectionofcontrolsthatareappropriateformobiledevices.

Attheheartofthecommoncontrolsaretwoclasses:android.view.Viewandandroid.view.ViewGroup.Asthenameofthefirstclasssuggests,theViewclassrepresentsageneral-purposeViewobject.ThecommoncontrolsinAndroidultimatelyextendtheViewclass.ViewGroupisalsoaview,butitcontainsotherviewstoo.ViewGroupisthebaseclassforalistoflayoutclasses.Android,likeSwing,usestheconceptoflayoutstomanagehowcontrolsarelaidoutwithinacontainerview.Usinglayouts,aswe’llsee,makesiteasyforustocontrolthepositionandorientationofthe

Page 101: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

controlsinourUIs.

YoucanchoosefromseveralapproachestobuildUIsinAndroid.YoucanconstructUIsentirelyincode.YoucanalsodefineUIsinXML.Youcanevencombinethetwo—definetheUIinXMLandthenrefertoit,andmodifyit,incode.Todemonstratethis,inthischapterwearegoingtobuildasimpleUIusingeachofthesethreeapproaches.

Beforewegetstarted,let’sdefinesomenomenclature.InthisbookandotherAndroidliterature,youwillfindthetermsview,control,widget,container,andlayoutindiscussionsregardingUIdevelopment.IfyouarenewtoAndroidprogrammingorUIdevelopmentingeneral,youmightnotbefamiliarwiththeseterms.We’llbrieflydescribethembeforewegetstarted(seeTable3-1).

Table3-1.UINomenclature

Term Description

View,widget,control

EachoftheserepresentsaUIelement.Examplesincludeabutton,agrid,alist,awindow,adialogbox,andsoon.Thetermsview,widget,andcontrolareusedinterchangeablyinthischapter.

Container Thisisaviewusedtocontainotherviews.Forexample,agridcanbeconsideredacontainerbecauseitcontainscells,eachofwhichisaview.

Layout Thisisavisualarrangementofcontainersandviewsandcanincludeotherlayouts.WewillworkwithlayoutsinthischapterandreturnforafullexplorationofAndroid’sLayoutfeaturesinChapter5.

Figure3-1showsascreenshotoftheapplicationthatwearegoingtobuild.Nexttothescreenshotisthelayouthierarchyofthecontrolsandcontainersintheapplication.

Figure3-1.TheUIandlayoutofanactivity

Wewillrefertothislayouthierarchyaswediscussthesampleprograms.Fornow,knowthattheapplicationhasoneactivity.TheUIfortheactivityiscomposedofthreecontainers:acontainerthatcontainsaperson’sname,acontainerthatcontainstheaddress,andanouterparentcontainerforthechildcontainers.

BuildingaUICompletelyinCodeThefirstexample,Listing3-1,demonstrateshowtobuildtheUIentirelyincode.Totrythis,createanewAndroidApplicationprojectusingaprojectnameofcontrols,apackagenameofcom.androidbook.controls,andwithanactivitynamed

Page 102: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MainActivityandthencopythecodefromListing3-1intoyourMainActivityclass.

NoteWewillgiveyouaURLattheendofthechapterthatyoucanusetodownloadprojectsfromthischapter.ThiswillallowyoutoimporttheseprojectsintoEclipsedirectlyinsteadofcopyingandpastingcode.

Listing3-1.CreatingaSimpleUserInterfaceEntirelyinCode

packagecom.androidbook.controls;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.ViewGroup.LayoutParams;importandroid.widget.LinearLayout;importandroid.widget.TextView;publicclassMainActivityextendsActivity{privateLinearLayoutnameContainer;

privateLinearLayoutaddressContainer;

privateLinearLayoutparentContainer;

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

createNameContainer();

createAddressContainer();

createParentContainer();

setContentView(parentContainer);}

privatevoidcreateNameContainer(){nameContainer=newLinearLayout(this);

nameContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));nameContainer.setOrientation(LinearLayout.HORIZONTAL);

TextViewnameLbl=newTextView(this);

Page 103: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

nameLbl.setText("Name:");

TextViewnameValue=newTextView(this);nameValue.setText("JohnDoe");

nameContainer.addView(nameLbl);nameContainer.addView(nameValue);}

privatevoidcreateAddressContainer(){addressContainer=newLinearLayout(this);

addressContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));addressContainer.setOrientation(LinearLayout.VERTICAL);

TextViewaddrLbl=newTextView(this);addrLbl.setText("Address:");

TextViewaddrValue=newTextView(this);addrValue.setText("911HollywoodBlvd");

addressContainer.addView(addrLbl);addressContainer.addView(addrValue);}

privatevoidcreateParentContainer(){parentContainer=newLinearLayout(this);

parentContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));parentContainer.setOrientation(LinearLayout.VERTICAL);

parentContainer.addView(nameContainer);parentContainer.addView(addressContainer);}}

AsshowninListing3-1,theactivitycontainsthreeLinearLayoutobjects.WewillbediscussinglayoutsinmuchmoredepthinChapter5,butthere’salittlechicken-and-eggissueofneedingtoknowjustalittleaboutlayoutssoonecanlearnaboutthemanybasiccontrols.Fornow,it’senoughtoknowthatlayoutobjectscontainlogictopositionobjectswithinaportionofthescreen.ALinearLayout,forexample,knowshowtolayoutcontrolseitherverticallyorhorizontally.Layoutobjectscancontainanytypeofview—

Page 104: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

evenotherlayouts.

ThenameContainerobjectcontainstwoTextViewcontrols:oneforthelabelName:andtheothertoholdtheactualtextforthename(suchasJohnDoe).TheaddressContaineralsocontainstwoTextViewcontrols.ThedifferencebetweenthetwocontainersisthatthenameContainerislaidouthorizontallyandtheaddressContainerislaidoutvertically.BothofthesecontainerslivewithintheparentContainer,whichistherootviewoftheactivity.Afterthecontainershavebeenbuilt,theactivitysetsthecontentoftheviewtotherootviewbycallingsetContentView(parentContainer).WhenitcomestimetorendertheUIoftheactivity,therootviewiscalledtorenderitself.Therootviewthencallsitschildrentorenderthemselves,andthechildcontrolscalltheirchildren,andsoon,untiltheentireUIisrendered.

AsshowninListing3-1,wehaveseveralLinearLayoutcontrols.Twoofthemarelaidoutvertically,andoneislaidouthorizontally.ThenameContainerislaidouthorizontally.ThismeansthetwoTextViewcontrolsappearsidebysidehorizontally.TheaddressContainerislaidoutvertically,whichmeansthetwoTextViewcontrolsarestackedoneontopoftheother.TheparentContainerisalsolaidoutvertically,whichiswhythenameContainerappearsabovetheaddressContainer.Noteasubtledifferencebetweenthetwoverticallylaid-outcontainers,addressContainerandparentContainer.parentContainerissettotakeuptheentirewidthandheightofthescreen:

parentContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));

andaddressContainerwrapsitscontentvertically:

addressContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));

Saidanotherway,WRAP_CONTENTmeanstheviewshouldtakejustthespaceitneedsinthatdimensionandnomore,uptowhatthecontainingviewwillallow.FortheaddressContainer,thismeansthecontainerwilltaketwolinesvertically,becausethat’sallitneedsforthedummyaddresswehaveprovided.

BuildingaUICompletelyinXMLNowlet’sbuildthesameUIinXML(seeListing3-2).XMLlayoutfilesarestoredundertheresources(/res/)directoryinafoldercalledlayout.Totrythisexample,createanewAndroidprojectinEclipse.Bydefault,youwillgetanXMLlayoutfilenamedactivity_main.xml,locatedundertheres/layoutfolder.Double-clickactivity_main.xmltoseethecontents.Eclipsewilldisplayavisualeditorforyour

Page 105: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

layoutfile.Youprobablyhaveastringatthetopoftheviewthatsays“HelloWorld,MainActivity!”orsomethinglikethat.Clicktheactivity_main.xmltabatthebottomoftheviewtoseetheXMLoftheactivity_main.xmlfile.ThisrevealsaLinearLayoutandaTextViewcontrol.UsingeithertheLayoutoractivity_main.xmltab,orboth,re-createListing3-2intheactivity_main.xmlfile.Saveit.

Listing3-2.CreatingaUserInterfaceEntirelyinXML

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><!--NAMECONTAINER--><LinearLayoutandroid:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content">

<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Name:"/>

<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="JohnDoe"/>

</LinearLayout>

<!--ADDRESSCONTAINER--><LinearLayoutandroid:orientation="vertical"android:layout_width="fill_parent"android:layout_height="wrap_content">

<TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Address:"/>

<TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="911HollywoodBlvd"/></LinearLayout>

</LinearLayout>

Underyournewproject’ssrcdirectory,thereisa.javafilecontaininganActivityclassdefinition.Double-clickthatfiletoseeitscontents.Noticethestatement

Page 106: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

setContentView(R.layout.activity_main).TheXMLsnippetshowninListing3-2,combinedwithacalltosetContentView(R.layout.activity_main),willrenderthesameUIasbeforewhenwegenerateditcompletelyincode.TheXMLfileisself-explanatory,butnotethatwehavethreecontainerviewsdefined.ThefirstLinearLayoutistheequivalentofourparentcontainer.Thiscontainersetsitsorientationtoverticalbysettingthecorrespondingpropertylikethis:android:orientation=“vertical”.TheparentcontainercontainstwoLinearLayoutcontainers,whichrepresentnameContainerandaddressContainer.

RunningthisapplicationwillproducethesameUIasourpreviousexampleapplication.ThelabelsandvalueswillbedisplayedasshowninFigure3-1.

BuildingaUIinXMLwithCodeListing3-2isacontrivedexample.Itdoesn’tmakeanysensetohard-codethevaluesoftheTextViewcontrolsintheXMLlayout.Ideally,weshoulddesignourUIsinXMLandthenreferencethecontrolsfromcode.Thisapproachenablesustobinddynamicdatatothecontrolsdefinedatdesigntime.Infact,thisistherecommendedapproach.ItisfairlyeasytobuildlayoutsinXMLandthenusecodetopopulatethedynamicdata.

Listing3-3showsthesameUIwithslightlydifferentXML.ThisXMLassignsIDstotheTextViewcontrolssothatwecanrefertothemincode.

Listing3-3.CreatingaUserInterfaceinXMLwithIDs

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><!--NAMECONTAINER--><LinearLayoutandroid:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content">

<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/name_text"/>

<TextViewandroid:id="@+id/nameValue"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

</LinearLayout>

<!--ADDRESSCONTAINER-->

Page 107: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="wrap_content">

<TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/addr_text"/>

<TextViewandroid:id="@+id/addrValue"android:layout_width="fill_parent"android:layout_height="wrap_content"/></LinearLayout>

</LinearLayout>

InadditiontoaddingtheIDstotheTextViewcontrolsthatwewanttopopulatefromcode,wealsohavelabelTextViewcontrolsthatwe’repopulatingwithtextfromourstringsresourcefile.ThesearetheTextViewswithoutIDsthathaveanandroid:textattribute.TheactualstringsfortheseTextViewswillcomefromourstrings.xmlfileinthe/res/valuesfolder.Listing3-4showswhatourstrings.xmlfilemightlooklike.

Listing3-4.strings.xmlFileforListing3-3

<?xmlversion="1.0"encoding="utf-8"?><resources><stringname="app_name">CommonControls</string><stringname="name_text">Name:</string><stringname="addr_text">Address:</string></resources>

ThecodeinListing3-5demonstrateshowyoucanobtainreferencestothecontrolsdefinedintheXMLtosettheirproperties.YoumightputthisintoyouronCreate()methodforyouractivity.

Listing3-5.ReferringtoControlsinResourcesatRuntime

setContentView(R.layout.activity_main);TextViewnameValue=(TextView)findViewById(R.id.nameValue);nameValue.setText("JohnDoe");TextViewaddrValue=(TextView)findViewById(R.id.addrValue);addrValue.setText("911HollywoodBlvd.");

ThecodeinListing3-5isstraightforward,butnotethatweloadtheresourcebycallingsetContentView(R.layout.activity_main)beforecallingfindViewById()—wecannotgetreferencestoviewsiftheyhavenotbeenloadedyet.

Page 108: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThedevelopersofAndroidhavedoneanicejobofmakingjustabouteveryaspectofacontrolsettableviaXMLorcode.It’susuallyagoodideatosetthecontrol’sattributesintheXMLlayoutfileratherthanusingcode.However,therewillbeavarietyoftimeswhenyouneedtousecode,suchassettingavaluetobedisplayedtotheuser.

FILL_PARENTvs.MATCH_PARENTTheconstantFILL_PARENTwasdeprecatedinAndroid2.2andreplacedwithMATCH_PARENT.Thiswasstrictlyanamechange,though.Thevalueofthisconstantisstill–1.Similarly,forXMLlayouts,fill_parentwasreplacedwithmatch_parent.Sowhatvaluedoyouuse?InsteadofFILL_PARENTorMATCH_PARENT,youcouldsimplyusethevalue–1,andyou’dbefine.However,thisisn’tveryeasytoread,andyoudon’thaveanequivalentunnamedvaluetousewithyourXMLlayouts.There’sabetterway.

DependingonwhichAndroidAPIsyouneedtouseinyourapplication,youcaneitherbuildyourapplicationagainstaversionofAndroidbefore2.2andrelyonforwardcompatibilityorbuildyourapplicationagainstversion2.2orlaterofAndroidandsetminSdkVersiontothelowestversionofAndroidyourapplicationwillrunon.Forexample,ifyouonlyneedAPIsthatexistedinAndroid1.6,buildagainstAndroid1.6anduseFILL_PARENTandfill_parent.YourapplicationshouldrunwithnoproblemsinalllaterversionsofAndroidincluding2.2andbeyond.IfyouneedAPIsfromAndroid2.2orlater,goaheadandbuildagainstthatversionofAndroid,useMATCH_PARENTandmatch_parent,andsetminSdkVersiontosomethingolder:forexample,4(forAndroid1.6).YoucanstilldeployanAndroidapplicationbuiltinAndroid2.2toanolderversionofAndroid,butyou’llhavetobecarefulabouttheclassesand/ormethodsthataren’tintheearlierreleasesoftheAndroidSDK.Therearewaysaroundthis,suchasusingreflectionorcreatingwrapperclassestohandledifferencesinAndroidversions.Wewillcoverthoseadvancedtopicsinlaterchapters.

UnderstandingAndroid’sCommonControlsWewillnowstartourdiscussionofthecommoncontrolsintheAndroidSDK.We’llstartwithtextcontrolsandthencoverbuttons,checkboxes,radiobuttons,lists,grids,dateandtimecontrols,andamap-viewcontrol.Thesewillgohandinhandwiththelayoutcontrolswe’llintroduceinChapter4.

TextControlsTextcontrolsarelikelytobethefirsttypeofcontrolthatyou’llworkwithinAndroid.Androidhasacompletebutnotoverwhelmingsetoftextcontrols.Inthissection,wearegoingtodiscusstheTextView,EditText,AutoCompleteTextView,andMultiAutoCompleteTextViewcontrols.Figure3-2showsthecontrolsinaction.

Page 109: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure3-2.TextcontrolsinAndroid

TextViewYou’vealreadyseenasimpleXMLspecificationforaTextViewcontrol,inListing3-3,andhowtohandleTextViewsincodeinListing3-4.NoticehowwespecifiedtheID,width,height,andvalueofthetextinXMLandhowwesetthevalueusingthesetText()method.TheTextViewcontrolknowshowtodisplaytextbutdoesnotallowediting.Thismightleadyoutoconcludethatthecontrolisessentiallyadummylabel.Nottrue.TheTextViewcontrolhasafewinterestingpropertiesthatmakeitveryhandy.IfyouknowthatthecontentoftheTextViewisgoingtocontainawebURLorane-mailaddress,forexample,youcansettheautoLinkpropertytoemail|web,andthecontrolwillfindandhighlightanye-mailaddressesandURLs.Moreover,whentheuserclicksoneofthesehighlighteditems,thesystemwilltakecareoflaunchingthee-mailapplicationwiththee-mailaddressorabrowserwiththeURL.InXML,thisattributewouldbeinsidetheTextViewtagandwouldlooksomethinglikethis:

<TextView...android:autoLink="email|web".../>

Youspecifyapipe-delimitedsetofvaluesincludingweb,email,phone,ormap,oruse

Page 110: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

none(thedefault)orall.IfyouwanttosetautoLinkbehaviorincodeinsteadofusingXML,thecorrespondingmethodcallissetAutoLinkMask().Youwouldpassitanintrepresentingthecombinationofvaluessortoflikebefore,suchasLinkify.EMAIL_ADDRESSES|Linkify.WEB_URLS.Toachievethisfunctionality,TextViewisutilizingtheandroid.text.util.Linkifyclass.Listing3-6showsanexampleofauto-linkingwithcode.

Listing3-6.UsingLinkifyonTextinaTextView

TextViewtv=(TextView)this.findViewById(R.id.tv);tv.setAutoLinkMask(Linkify.ALL);tv.setText("Pleasevisitmywebsite,http://[email protected].");

Noticethatwesettheauto-linkoptionsonourTextViewbeforewesetthetext.Thisisimportantbecausesettingtheauto-linkoptionsaftersettingthetextwon’taffecttheexistingtext.Becausewe’reusingcodetoaddhyperlinkstoourtext,ourXMLfortheTextViewinListing3-6doesnotrequireanyspecialattributesandcanlookassimpleasthis:

<TextViewandroid:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

Ifyouwantto,youcaninvokethestaticaddLinks()methodoftheLinkifyclasstofindandaddlinkstothecontentofanyTextVieworanySpannableondemand.InsteadofusingsetAutoLinkMask(),wecouldhavedonethefollowingaftersettingthetext:

Linkify.addLinks(tv,Linkify.ALL);

Clickingalinkwillcausethedefaultintenttobecalledforthataction.Forexample,clickingawebURLwilllaunchthebrowserwiththeURL.Clickingaphonenumberwilllaunchthephonedialer,andsoon.TheLinkifyclasscanperformthisworkrightoutofthebox.

Linkifycanalsodetectcustompatternsyouwanttolookfor,decidewhethertheyareamatchforsomethingyoudecideneedstobeclickable,andsetuphowtofireanintenttomakeaclickturnintosomesortofaction.Wewon’tgointothosedetailshere,butknowthatthesethingscanbedone.

TherearemanymorefeaturesofTextViewtoexplore,fromfontattributestominLinesandmaxLinesandmanymore.Thesearefairlyself-explanatory,andyouareencouragedtoexperimenttoseehowyoumightbeabletousethem.AlthoughyoushouldkeepinmindthatsomefunctionalityintheTextViewclassisnotapplicabletoaread-onlyfield,thefunctionalityisthereforthesubclassesofTextView,oneofwhichwewillcovernext.

Page 111: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

EditTextTheEditTextcontrolisasubclassofTextView.Assuggestedbythename,theEditTextcontrolallowsfortextediting.EditTextisnotaspowerfulasthetext-editingcontrolsthatyoufindontheInternet,butusersofAndroid-baseddevicesprobablywon’ttypedocumentsdirectlyintoanEditTextcontrol—they’lltypeacoupleofparagraphsatmostoruseamorefullyfunctionalHTML-basedpageinstead.Therefore,theclasshaslimitedbutappropriatefunctionalityandmayevensurpriseyou.Forexample,oneofthemostsignificantpropertiesofanEditTextistheinputType.YoucansettheinputTypepropertytotextAutoCorrecttohavethecontrolcorrectcommonmisspellings.YoucansetittotextCapWordstohavethecontrolcapitalizewords.Otheroptionsexpectonlyphonenumbersorpasswords.

Thereareolder,nowdeprecated,waysofspecifyingcapitalization,multilinetext,andotherfeatures.IfthesearespecifiedwithoutaninputTypeproperty,theycanberead;butifinputTypeisspecified,theseolderpropertiesareignored.

TheolddefaultbehavioroftheEditTextcontrolistodisplaytextononelineandexpandasneeded.Inotherwords,iftheusertypespastthefirstline,anotherlinewillappear,andsoon.Youcould,however,forcetheusertoasinglelinebysettingthesingleLinepropertytotrue.Inthiscase,theuserwillhavetocontinuetypingonthesameline.WithinputType,ifyoudon’tspecifytextMultiLine,theEditTextwilldefaulttosingle-lineonly.Soifyouwanttheolddefaultbehaviorofmultilinetyping,youneedtospecifyinputTypewithtextMultiLine.

OneofthenicefeaturesofEditTextisthatyoucanspecifyhinttext.Thistextwillbedisplayedslightlyfadedanddisappearsassoonastheuserstartstotypetext.Thepurposeofthehintistolettheuserknowwhatisexpectedinthisfield,withouttheuserhavingtoselectanderasedefaulttext.InXML,thisattributeisandroid:hint=“yourhinttexthere”orandroid:hint=”@string/your_hint_name”,whereyour_hint_nameisaresourcenameofastringtobefoundin/res/values/strings.xml.Incode,youwouldcallthesetHint()methodwitheitheraCharSequenceoraresourceID.

AutoCompleteTextViewTheAutoCompleteTextViewcontrolisaTextViewwithauto-completefunctionality.Inotherwords,astheusertypesintheTextView,thecontrolcandisplaysuggestionsforselection.Listing3-7demonstratestheAutoCompleteTextViewcontrolwithXMLandwiththecorrespondingcode.

Listing3-7.UsinganAutoCompleteTextViewControl

<AutoCompleteTextViewandroid:id="@+id/actv"android:layout_width="fill_parent"android:layout_height="wrap_content"/>AutoCompleteTextViewactv=(AutoCompleteTextView)

Page 112: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

this.findViewById(R.id.actv);

ArrayAdapter<String>aa=newArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,newString[]{"English","Hebrew","Hindi","Spanish","German","Greek"});

actv.setAdapter(aa);

TheAutoCompleteTextViewcontrolshowninListing3-7suggestsalanguagetotheuser.Forexample,iftheusertypesen,thecontrolsuggestsEnglish.Iftheusertypesgr,thecontrolrecommendsGreek,andsoon.

Ifyouhaveusedasuggestioncontrolorasimilarauto-completecontrol,youknowthatcontrolslikethishavetwoparts:atext-viewcontrolandacontrolthatdisplaysthesuggestion(s).That’sthegeneralconcept.Touseacontrollikethis,youhavetocreatethecontrol,createthelistofsuggestions,tellthecontrolthelistofsuggestions,andpossiblytellthecontrolhowtodisplaythesuggestions.Alternatively,youcouldcreateasecondcontrolforthesuggestionsandthenassociatethetwocontrols.

Androidhasmadethissimple,asisevidentfromListing3-7.TouseanAutoCompleteTextView,youcandefinethecontrolinyourlayoutfileandreferenceitinyouractivity.YouthencreateanadapterclassthatholdsthesuggestionsanddefinetheIDofthecontrolthatwillshowthesuggestion(inthiscase,asimplelistitem).InListing3-7,thesecondparametertotheArrayAdaptertellstheadaptertouseasimplelistitemtoshowthesuggestion.ThefinalstepistoassociatetheadapterwiththeAutoCompleteTextView,whichyoudousingthesetAdapter()method.Don’tworryabouttheadapterforthemoment;we’llcoverthoselaterinthischapter.

MultiAutoCompleteTextViewIfyouhaveplayedwiththeAutoCompleteTextViewcontrol,youknowthatthecontrolofferssuggestionsonlyfortheentiretextinthetextview.Inotherwords,ifyoutypeasentence,youdon’tgetsuggestionsforeachword.That’swhereMultiAutoCompleteTextViewcomesin.YoucanusetheMultiAutoCompleteTextViewtoprovidesuggestionsastheusertypes.Forexample,Figure3-2showsthattheusertypedthewordEnglishfollowedbyacomma,andthenGe,atwhichpointthecontrolsuggestedGerman.Iftheuserweretocontinue,thecontrolwouldofferadditionalsuggestions.

UsingtheMultiAutoCompleteTextViewislikeusingtheAutoCompleteTextView.Thedifferenceisthatyouhavetotellthecontrolwheretostartsuggestingagain.Forexample,inFigure3-2,youcanseethatthecontrolcanoffersuggestionsatthebeginningofthesentenceandafteritseesacomma.TheMultiAutoCompleteTextViewcontrolrequiresthatyougiveitatokenizerthatcanparsethesentenceandtellitwhethertostartsuggestingagain.Listing3-8demonstratesusingtheMultiAutoCompleteTextViewcontrolwiththeXMLandthentheJava

Page 113: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

code.

Listing3-8.UsingtheMultiAutoCompleteTextViewControl

<MultiAutoCompleteTextViewandroid:id="@+id/mactv"android:layout_width="fill_parent"android:layout_height="wrap_content"/>

MultiAutoCompleteTextViewmactv=(MultiAutoCompleteTextView)this.findViewById(R.id.mactv);ArrayAdapter<String>aa2=newArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,newString[]{"English","Hebrew","Hindi","Spanish","German","Greek"});

mactv.setAdapter(aa2);

mactv.setTokenizer(newMultiAutoCompleteTextView.CommaTokenizer());

TheonlysignificantdifferencesbetweenListings3-7and3-8aretheuseofMultiAutoCompleteTextViewandthecalltothesetTokenizer()method.BecauseoftheCommaTokenizerinthiscase,afteracommaistypedintotheEditTextfield,thefieldwillagainmakesuggestionsusingthearrayofstrings.Anyothercharacterstypedinwillnottriggerthefieldtomakesuggestions.SoevenifyouweretotypeFrenchSpani,thepartialwordSpaniwouldnottriggerthesuggestionbecauseitdidnotfollowacomma.Androidprovidesanothertokenizerfore-mailaddressescalledRfc822Tokenizer.Youcanalwayscreateyourowntokenizerifyouwantto.

ButtonControlsButtonsarecommoninanywidgettoolkit,andAndroidisnoexception.Androidoffersthetypicalsetofbuttonsaswellasafewextras.Inthissection,wewilldiscussthreetypesofbuttoncontrols:thebasicbutton,theimagebutton,andthetogglebutton.Figure3-3showsaUIwiththesecontrols.Thebuttonatthetopisthebasicbutton,themiddlebuttonisanimagebutton,andthelastoneisatogglebutton.

Page 114: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure3-3.Androidbuttoncontrols

Let’sgetstartedwiththebasicbutton.

TheButtonControlThebasicbuttonclassinAndroidisandroid.widget.Button.There’snotmuchtothistypeofbutton,beyondhowyouuseittohandleclickevents.Listing3-9showsafragmentofanXMLlayoutfortheButtoncontrol,plussomeJavathatwemightsetupintheonCreate()methodofouractivity.OurbasicbuttonwouldlooklikethetopbuttoninFigure3-3.

Listing3-9.HandlingClickEventsonaButton

<Buttonandroid:id="@+id/button1"android:text="@string/basicBtnLabel"android:layout_width="fill_parent"android:layout_height="wrap_content"/>

Buttonbutton1=(Button)this.findViewById(R.id.button1);button1.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){Intentintent=newIntent(Intent.ACTION_VIEW,Uri.parse("http://www.androidbook.comstartActivity(intent);}});

Listing3-9showshowtoregisterforabutton-clickevent.Youregisterfortheon-clickeventbycallingthesetOnClickListener()methodwithanOnClickListener.InListing3-9,ananonymouslisteneriscreatedontheflytohandleclickeventsfor

Page 115: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

button1.Whenthebuttonisclicked,theonClick()methodofthelisteneriscalledand,inthiscase,launchesthebrowsertoourwebsite.

SinceAndroidSDK1.6,thereisaneasierwaytosetupaclickhandlerforyourbuttonorbuttons.Listing3-10showstheXMLforaButtonwhereyouspecifyanattributeforthehandler,plustheJavacodethatistheclickhandler.

Listing3-10.SettingUpaClickHandlerforaButton

<Button...android:onClick="myClickHandler".../>publicvoidmyClickHandler(Viewtarget){switch(target.getId()){caseR.id.button1:...

ThehandlermethodwillbecalledwithtargetsettotheViewobjectrepresentingthebuttonthatwasclicked.NoticehowtheswitchstatementintheclickhandlermethodusestheresourceIDsofthebuttonstoselectthelogictorun.Usingthismethodmeansyouwon’thavetoexplicitlycreateeachButtonobjectinyourcode,andyoucanreusethesamemethodacrossmultiplebuttons.Thismakesthingseasiertounderstandandmaintain.Thisworkswiththeotherbuttontypesaswell.

TheImageButtonControlAndroidprovidesanimagebuttonviaandroid.widget.ImageButton.Usinganimagebuttonissimilartousingthebasicbutton(seeListing3-11).OurimagebuttonwouldlooklikethemiddlebuttoninFigure3-3.

Listing3-11.UsinganImageButton

<ImageButtonandroid:id="@+id/imageButton2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="myClickHandler"android:src="@drawable/icon"/>

ImageButtonimageButton2=(ImageButton)this.findViewById(R.id.imageButton2);imageButton2.setImageResource(R.drawable.icon);

Herewe’vecreatedtheimagebuttoninXMLandsetthebutton’simagefromadrawableresource.Theimagefileforthebuttonmustexistunder/res/drawable.Inourcase,we’resimplyreusingtheAndroidiconforthebutton.WealsoshowinListing3-11howyoucansetthebutton’simagedynamicallybycallingsetImageResource()methodonthebuttonandpassingitaresourceID.Notethatyouonlyneedtodooneortheother.Youdon’tneedtospecifythebuttonimagebothintheXMLfileandincode.

Oneofthenicefeaturesofanimagebuttonisthatyoucanspecifyatransparentbackgroundforthebutton.Theresultwillbeaclickableimagethatactslikeabuttonbut

Page 116: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

canlooklikewhateveryouwantittolooklike.Justsetandroid:background=”@null”fortheimagebutton.

Becauseyourimagemaybesomethingverydifferentthanastandardbutton,youcancustomizehowthebuttonlooksinthetwootherstatesitcanbeinwhenusedinyourUI.Besidesappearingasnormal,buttonscanhavefocus,andtheycanbepressed.Havingfocussimplymeansthebuttoniscurrentlywhereeventswillgo.YoucandirectfocustoabuttonusingthearrowkeysonthekeypadorD-pad,forexample.Pressedmeansthatthebutton’sappearancechangeswhenithasbeenpressedbutbeforetheuserhasletgo.TotellAndroidwhatthethreeimagesareforourbutton,andwhichoneiswhich,wesetupaselector.ThisisasimpleXMLfile,imagebuttonselector,thatresidesinthe/res/drawablefolderofourproject.Thisissomewhatcounterintuitive,becausethisisanXMLfileandnotanimagefile,yetthatiswheretheselectorfilemustgo.ThecontentofaselectorfilewilllooklikeListing3-12.

Listing3-12.UsingaSelectorwithanImageButton

<?xmlversion="1.0"encoding="utf-8"?><selectorxmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:state_pressed="true"android:drawable="@drawable/button_pressed"/><!--pressed--><itemandroid:state_focused="true"android:drawable="@drawable/button_focused"/><!--focused--><itemandroid:drawable="@drawable/icon"/><!--default--></selector>

Thereareseveralthingstonoteabouttheselectorfile.First,youdonotspecifya<resources>tagasinvaluesXMLfiles.Second,theorderofthebuttonimagesisimportant.Androidwilltesteachitemintheselector,inorder,toseeifitmatches.Therefore,youwantthenormalimagetobelastsoitisusedonlyifthebuttonisnotpressedandifthebuttondoesnothavefocus.Ifthenormalimagewaslistedfirst,itwouldalwaysmatchandbeselectedevenifthebuttonispressedorhasfocus.Ofcourse,thedrawablesyourefertomustexistinthe/res/drawablesfolder.InthedefinitionofyourbuttoninthelayoutXMLfile,youwanttosettheandroid:srcpropertytotheselectorXMLfileasifitwerearegulardrawable,likeso:

<Button...android:src="@drawable/imagebuttonselector".../>

TheToggleButtonControlTheToggleButtoncontrol,likeacheckboxoraradiobutton,isatwo-statebutton.ThisbuttoncanbeineithertheOnorOffstate.AsshowninFigure3-3,the

Page 117: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ToggleButton’sdefaultbehavioristoshowacoloredbarwhenintheOnstateandagrayed-outbarwhenintheOffstate.Moreover,thedefaultbehavioralsosetsthebutton’stexttoOnwhenit’sintheOnstateandOffwhenit’sintheOffstate.YoucanmodifythetextfortheToggleButtonifOn/Offisnotappropriateforyourapplication.Forexample,ifyouhaveabackgroundprocessthatyouwanttostartandstopviaaToggleButton,youcouldsetthebutton’stexttoStopandRunbyusingandroid:textOnandandroid:textOffproperties.

Listing3-13showsanexample.OurtogglebuttonisthebottombuttoninFigure3-3,anditisintheOnposition,sothelabelonthebuttonsaysStop.

Listing3-13.TheAndroidToggleButton

<ToggleButtonandroid:id="@+id/cctglBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="ToggleButton"android:textOn="Stop"android:textOff="Run"/>

BecauseToggleButtonshaveonandofftextasseparateattributes,theandroid:textattributeofaToggleButtonisnotreallyused.It’savailablebecauseithasbeeninherited(fromTextView),butinthiscase,youdon’tneedtouseit.

TheCheckBoxControlTheCheckBoxcontrolisanothertwo-statebuttonthatallowstheusertotoggleitsstate.Thedifferenceisthat,formanysituations,theusersdon’tviewitasabuttonthatinvokesimmediateaction.FromAndroid’spointofview,however,itisabutton,andyoucandoanythingwithacheckboxthatyoucandowithabutton.

InAndroid,youcancreateacheckboxbycreatinganinstanceofandroid.widget.CheckBox.SeeListing3-14andFigure3-4.

Listing3-14.CreatingCheckBoxes

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<CheckBoxandroid:id="@+id/chickenCB"android:text="Chicken"android:checked="true"android:layout_width=""wrap_content"android:layout_height="wrap_content"/>

<CheckBoxandroid:id="@+id/fishCB"

Page 118: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:text="Fish"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<CheckBoxandroid:id="@+id/steakCB"android:text="Steak"android:checked="true"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

</LinearLayout>

Figure3-4.UsingtheCheckBoxcontrol

YoumanagethestateofacheckboxbycallingsetChecked()ortoggle().YoucanobtainthestatebycallingisChecked().

Ifyouneedtoimplementspecificlogicwhenacheckboxischeckedorunchecked,youcanregisterfortheon-checkedeventbycallingsetOnCheckedChangeListener()withanimplementationoftheCompoundButton.OnCheckedChangeListenerinterface.You’llthenhavetoimplementtheonCheckedChanged()method,whichwillbecalledwhenthecheckboxischeckedorunchecked.Listing3-15showsomecodethatdealswithaCheckBox.

Listing3-15.UsingCheckBoxesinCode

publicclassCheckBoxActivityextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.checkbox);

CheckBoxfishCB=(CheckBox)findViewById(R.id.fishCB);

if(fishCB.isChecked())

Page 119: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

fishCB.toggle();//flipsthecheckboxtouncheckedifitwaschecked

fishCB.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){

@OverridepublicvoidonCheckedChanged(CompoundButtonarg0,booleanisChecked){Log.v("CheckBoxActivity","Thefishcheckboxisnow"+(isChecked?"checked":"notchecked"));}});}}

ThenicepartofsettinguptheOnCheckedChangeListeneristhatyouarepassedthenewstateoftheCheckBoxbutton.YoucouldinsteadusetheOnClickListenertechniqueasweusedwithbasicbuttons.WhentheonClick()methodiscalled,youwouldneedtodeterminethenewstateofthebuttonbycastingitappropriatelyandthencallingisChecked()onit.Listing3-16showswhatthiscodemightlooklikeifweaddedandroid:onClick=“myClickHandler”totheXMLdefinitionofourCheckBoxbuttons.

Listing3-16.UsingCheckBoxesinCodewithandroid:onClick

publicvoidmyClickHandler(Viewview){switch(view.getId()){caseR.id.steakCB:Log.v("CheckBoxActivity","Thesteakcheckboxisnow"+(((CheckBox)view).isChecked()?"checked":"notchecked"));}}

TheSwitchControlTheSwitchwidgetwasintroducedinAndroid4.0andprovidesverysimilarbehaviortotheCheckBox.Infact,thetwowidgetsaresosimilar,you’llalmostcertainlygetasenseofdejavuwhenreviewingthecodeforaSwitchobject.Manypeople(includingsomeofthisbook’sauthors)believethattheSwitchwasintroducedforaestheticreasonsmorethananything.ThetrendinUIdesigninthelastfewyearshasbeentowardtheskewmorphicidealofwidgetslookinglikereal-worldthings,andaSwitchisaconcreteselectorintherealworld—notmanykitchenapplianceshaveaCheckBoxafterall.

Page 120: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheSwitchsimilaritiestotheCheckBoxcontrolextendtocommonmethodsforexaminingandchangingstate.ThismimickingofmethodsincludessetChecked()toturntheSwitchon,isChecked()totestcurrentstate,andsoon.OneaestheticdifferenceofferedbytheSwitchwidgetistheabilitytochangetheassociatedtextbetweenstates.Additionalmethodsareavailabletocontrolthistext:

getTextOn():returnsthetextdisplayediftheSwitchison.

getTextOff():returnsthetextdisplayediftheSwitchisoff.

setTextOn():setsthetexttobedisplayediftheSwitchison.Whilegooddesignwouldusuallymeanonewouldn’tchangethetext,thereareafewcaseswherealiveupdateofsomemetricintheswitchtextcanbehelpful.

setTextOff():setsthetexttobedisplayediftheSwitchisoff.

AnexamplelayoutincludingaSwitchisshowninListing3-17.

Listing3-17.CreatingaLayoutUsingaSwitch

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<Switchandroid:id="@+id/switchdemo"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Thisswitchis:off"/>

</LinearLayout>

CautionRememberthat“switch”isareservedwordinJava.SoweuseanIDthatdoesn’tclash.

ThecodeforourexampleSwitchinListing3-18shouldprovokethosefeelingsofdejavuwementionedwithrespecttotheCheckBoxcontrol.

Listing3-18.ControllingSwitchBehaviorinCode

publicclassSwitchDemoextendsActivityimplementsCompoundButton.OnCheckedChangeListener{Switchsw;

@OverridepublicvoidonCreate(Bundleicicle){

Page 121: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

super.onCreate(icicle);setContentView(R.layout.main);

sw=(Switch)findViewById(R.id.switchdemo);sw.setOnCheckedChangeListener(this);}

publicvoidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked){if(isChecked){sw.setTextOn("Thisswitchis:on");}else{sw.setTextOff("Thisswitchis:off");}}}

TheresultsofourSwitchworkareshowinginFigure3-5.

Figure3-5.UsingtheSwitchcontrol

TheRadioButtonControlRadioButtoncontrolsareanintegralpartofanyUItoolkit.Aradiobuttongivestheusersseveralchoicesandforcesthemtoselectasingleitem.Toenforcethissingle-selectionmodel,radiobuttonsgenerallybelongtoagroup,andeachgroupisforcedtohaveonlyoneitemselectedatatime.

TocreateagroupofradiobuttonsinAndroid,firstcreateaRadioGroup,andthenpopulatethegroupwithradiobuttons.Listing3-19andFigure3-6showanexample.

Listing3-19.UsingAndroidRadioButtonWidgets

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

Page 122: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<RadioGroupandroid:id="@+id/rBtnGrp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical">

<RadioButtonandroid:id="@+id/chRBtn"android:text="Chicken"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<RadioButtonandroid:id="@+id/fishRBtn"android:text="Fish"android:checked="true"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<RadioButtonandroid:id="@+id/stkRBtn"android:text="Steak"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

</RadioGroup>

</LinearLayout>

Figure3-6.Usingradiobuttons

InAndroid,youimplementaradiogroupusingandroid.widget.RadioGroupand

Page 123: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

aradiobuttonusingandroid.widget.RadioButton.

Notethattheradiobuttonswithintheradiogroupare,bydefault,uncheckedtobeginwith,althoughyoucansetonetocheckedintheXMLdefinition,aswedidwithFishinListing3-19.Tosetoneoftheradiobuttonstothecheckedstateprogrammatically,youcanobtainareferencetotheradiobuttonandcallsetChecked():

RadioButtonsteakBtn=(RadioButton)this.findViewById(R.id.stkRBtn);steakBtn.setChecked(true);

Youcanalsousethetoggle()methodtotogglethestateoftheradiobutton.AswiththeCheckBoxcontrol,youwillbenotifiedofon-checkedoron-uncheckedeventsifyoucallthesetOnCheckedChangeListener()withanimplementationoftheOnCheckedChangeListenerinterface.Thereisaslightdifferencehere,though.Thisisadifferentclassthanbefore.Thistime,it’stechnicallytheRadioGroup.OnCheckedChangeListenerclassactingfortheRadioGroup,whereasbeforeitwastheCompoundButton.OnCheckedChangeListenerclass.

TheRadioGroupcanalsocontainviewsotherthantheradiobutton.Forexample,Listing3-20addsaTextViewafterthelastradiobutton.Alsonotethatthefirstradiobutton(anotherRadBtn)liesoutsidetheradiogroup.

Listing3-20.ARadioGroupwithMoreThanJustRadioButtons

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<RadioButtonandroid:id="@+id/anotherRadBtn"android:text="Outside"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<RadioGroupandroid:id="@+id/radGrp"android:layout_width="wrap_content"android:layout_height="wrap_content">

<RadioButtonandroid:id="@+id/chRBtn"android:text="Chicken"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<RadioButtonandroid:id="@+id/fishRBtn"android:text="Fish"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

Page 124: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<RadioButtonandroid:id="@+id/stkRBtn"android:text="Steak"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<TextViewandroid:text="MyFavorite"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

</RadioGroup></LinearLayout>

Listing3-20showsthatyoucanhavenon-RadioButtoncontrolsinsidearadiogroup.Youshouldalsoknowthattheradiogroupcanonlyenforcesingle-selectionontheradiobuttonsinitsowncontainer.Thatis,theradiobuttonwithIDanotherRadBtnwillnotbeaffectedbytheradiogroupshowninListing3-20becauseitisnotoneofthegroup’schildren.

YoucanmanipulatetheRadioGroupprogrammatically.Forexample,youcanobtainareferencetoaradiogroupandaddaradiobutton(orothertypeofcontrol).Listing3-21demonstratesthisconcept.

Listing3-21.AddingaRadioButtontoaRadioGroupinCode

RadioGroupradGrp=(RadioGroup)findViewById(R.id.radGrp);RadioButtonnewRadioBtn=newRadioButton(this);newRadioBtn.setText("Pork");radGrp.addView(newRadioBtn);

Onceauserhascheckedaradiobuttonwithinaradiogroup,theusercannotuncheckitbyclickingitagain.TheonlywaytoclearallradiobuttonsinaradiogroupistocalltheclearCheck()methodontheRadioGroupprogrammatically.

Ofcourse,youwanttodosomethinginterestingwiththeRadioGroup.Youprobablydon’twanttopolleachRadioButtontodeterminewhetherit’schecked.Fortunately,theRadioGrouphasseveralmethodstohelpyouout.WedemonstratethosewithListing3-22.TheXMLforthiscodeisinListing3-20.

Listing3-22.UsingaRadioGroupProgrammatically

publicclassRadioGroupActivityextendsActivity{protectedstaticfinalStringTAG="RadioGroupActivity";

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.radiogroup);

Page 125: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RadioGroupradGrp=(RadioGroup)findViewById(R.id.radGrp);

intcheckedRadioButtonId=radGrp.getCheckedRadioButtonId();

radGrp.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){@OverridepublicvoidonCheckedChanged(RadioGrouparg0,intid){switch(id){case-1:Log.v(TAG,"Choicescleared!");break;caseR.id.chRBtn:Log.v(TAG,"ChoseChicken");break;caseR.id.fishRBtn:Log.v(TAG,"ChoseFish");break;caseR.id.stkRBtn:Log.v(TAG,"ChoseSteak");break;default:Log.v(TAG,"Huh?");break;}}});}}

WecanalwaysgetthecurrentlycheckedRadioButtonusinggetCheckedRadioButtonId(),whichreturnstheresourceIDofthecheckeditemor–1ifnothingischecked(possibleifthere’snodefaultandtheuserhasn’tchosenanoptionyet).WeshowedthisinouronCreate()methodpreviously,butinreality,you’dwanttouseitattheappropriatetimetoreadtheuser’scurrentchoice.WecanalsosetupalistenertobenotifiedimmediatelywhentheuserchoosesoneoftheRadioButtons.NoticethattheonCheckedChanged()methodtakesaRadioGroupparameter,allowingyoutousethesameOnCheckedChangeListenerformultipleRadioGroups.Youmayhavenoticedtheswitchoptionof–1.ThiscanalsooccuriftheRadioGroupisclearedthroughcodeusingclearCheck().

TheImageViewControlOneofthebasiccontrolswehaven’tcoveredyetistheImageViewcontrol.Thisisused

Page 126: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

todisplayanimage,wheretheimagecancomefromafile,acontentprovider,oraresourcesuchasadrawable.Youcanevenspecifyjustacolor,andtheImageViewwilldisplaythatcolor.Listing3-23showssomeXMLexamplesofImageViews,followedbysomecodethatshowshowtocreateanImageView.

Listing3-23.ImageViewsinXMLandinCode

<ImageViewandroid:id="@+id/image1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/icon"/>

<ImageViewandroid:id="@+id/image2"android:layout_width="125dip"android:layout_height="25dip"android:src="#555555"/>

<ImageViewandroid:id="@+id/image3"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<ImageViewandroid:id="@+id/image4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/manatee02"android:scaleType="centerInside"android:maxWidth="35dip"android:maxHeight="50dip"/>

ImageViewimgView=(ImageView)findViewById(R.id.image3);

imgView.setImageResource(R.drawable.icon);

imgView.setImageBitmap(BitmapFactory.decodeResource(this.getResources(),R.drawable.manatee14));

imgView.setImageDrawable(Drawable.createFromPath("/mnt/sdcard/dave2.jpg"));

imgView.setImageURI(Uri.parse("file://mnt/sdcard/dave2.jpg"));

Inthisexample,wehavefourimagesdefinedinXML.Thefirstissimplytheiconforourapplication.Thesecondisagraybarthatiswiderthanitistall.ThethirddefinitiondoesnotspecifyanimagesourceintheXML,butweassociateanIDwiththisone(image3)thatwecanusefromourcodetosettheimage.Thefourthimageisanotherofourdrawableimagefileswherewenotonlyspecifythesourceoftheimagefilebutalsosetthemaximumdimensionsoftheimageonthescreenanddefinewhattodoiftheimageislargerthanourmaximumsize.Inthiscase,wetelltheImageViewtocenterandscaletheimagesoitfitsinsidethesizewespecified.

IntheJavacodeofListing3-23weshowseveralwaystosettheimageofimage3.We

Page 127: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

firstofcoursemustgetareferencetotheImageViewbyfindingitusingitsresourceID.Thefirstsettermethod,setImageResource(),simplyusestheimage’sresourceIDtolocatetheimagefiletosupplytheimageforourImageView.ThesecondsetterusestheBitmapFactorytoreadinanimageresourceintoaBitmapobjectandthensetstheImageViewtothatBitmap.NotethatwecouldhavedonesomemodificationstotheBitmapbeforeapplyingittoourImageView,butinourcase,weuseditasis.Inaddition,theBitmapFactoryhasseveralmethodsofcreatingaBitmap,includingfromabytearrayandanInputStream.YoucouldusetheInputStreammethodtoreadanimagefromawebserver,createtheBitmapimage,andthensettheImageViewfromthere.

ThethirdsettingusesaDrawableforourimagesource.Inthiscase,we’reshowingthesourceoftheimagecomingfromtheSDcard.You’llneedtoputsomesortofimagefileoutontheSDcardwiththepropernameforthistoworkforyou.SimilartoBitmapFactory,theDrawableclasshasafewdifferentwaystoconstructDrawables,includingfromanXMLstream.

ThefinalsettermethodtakestheURIofanimagefileandusesthatastheimagesource.Forthislastcall,don’tthinkthatyoucanuseanyimageURIasthesource.Thismethodisreallyonlyintendedtobeusedforlocalimagesonthedevice,notforimagesthatyoumightfindthroughHTTP.TouseInternet-basedimagesasthesourceforyourImageView,you’dmostlikelyuseBitmapFactoryandanInputStream.

DateandTimeControlsDateandtimecontrolsarecommoninmanywidgettoolkits.Androidoffersseveraldate-andtime-basedcontrols,someofwhichwe’lldiscussinthissection.Specifically,wearegoingtointroducetheDatePicker,TimePicker,DigitalClock,andAnalogClockcontrols.

TheDatePickerandTimePickerControlsAsthenamessuggest,youusetheDatePickercontroltoselectadateandtheTimePickercontroltopickatime.Listing3-24andFigure3-7showexamplesofthesecontrols.

Listing3-24.TheDatePickerandTimePickerControlsinXML

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<TextViewandroid:id="@+id/dateDefault"android:layout_width="fill_parent"android:layout_height="wrap_content"/>

Page 128: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<DatePickerandroid:id="@+id/datePicker"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<TextViewandroid:id="@+id/timeDefault"android:layout_width="fill_parent"android:layout_height="wrap_content"/>

<TimePickerandroid:id="@+id/timePicker"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

</LinearLayout>

Figure3-7.TheDatePickerandTimePickerUIs

IfyoulookattheXMLlayout,youcanseethatdefiningthesecontrolsiseasy.AswithanyothercontrolintheAndroidtoolkit,youcanaccessthecontrolsprogrammaticallytoinitializethemortoretrievedatafromthem.Forexample,youcaninitializethesecontrolsasshowninListing3-23.

Listing3-25.InitializingtheDatePickerandTimePickerwithDateandTime,

Page 129: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Respectively

publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.datetimepicker);

TextViewdateDefault=(TextView)findViewById(R.id.dateDefault);TextViewtimeDefault=(TextView)findViewById(R.id.timeDefault);

DatePickerdp=(DatePicker)this.findViewById(R.id.datePicker);//Themonth,andjustthemonth,iszero-based.Add1fordisplay.dateDefault.setText("Datedefaultedto"+(dp.getMonth()+1)+"/"+dp.getDayOfMonth()+"/"+dp.getYear());//Andhere,subtract1fromDecember(12)tosetittoDecemberdp.init(2008,11,10,null);

TimePickertp=(TimePicker)this.findViewById(R.id.timePicker);

java.util.FormattertimeF=newjava.util.Formatter();timeF.format("Timedefaultedto%d:%02d",tp.getCurrentHour(),tp.getCurrentMinute());timeDefault.setText(timeF.toString());

tp.setIs24HourView(true);tp.setCurrentHour(newInteger(10));tp.setCurrentMinute(newInteger(10));}

Listing3-25setsthedateontheDatePickertoDecember10,2008.Notethatforthemonth,theinternalvalueiszero-based,whichmeansthatJanuaryis0andDecemberis11.FortheTimePicker,thenumberofhoursandminutesissetto10.Notealsothatthiscontrolsupports24-hourview.Ifyoudonotsetvaluesforthesecontrols,thedefaultvalueswillbethecurrentdateandtimeasknowntothedevice.

Finally,notethatAndroidoffersversionsofthesecontrolsasmodalwindows,suchasDatePickerDialogandTimePickerDialog.Thesecontrolsareusefulifyouwanttodisplaythecontroltotheuserandforcetheusertomakeaselection.We’llcoverdialogsinmoredetailinChapter8.

TheTextClockandAnalogClockControls

Page 130: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AndroidalsooffersTextClockandAnalogClockcontrols(seeFigure3-8).

Figure3-8.UsingtheAnalogClockandDigitalClock

Asshown,thetextclocksupportssecondsinadditiontohoursandminutes.TheanalogclockinAndroidisatwo-handedclock,withonehandforthehourindicatorandtheotherhandfortheminuteindicator.Toaddthesetoyourlayout,usetheXMLasshowninListing3-26.

Listing3-26.AddingaDigitalClockoranAnalogClockinXML

<TextClockandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:format12Hour="hh:mm:ssaa"android:format24Hour="kk:mm:ss"/>

<AnalogClockandroid:layout_width="wrap_content"android:layout_height="wrap_content"/>

Thesetwocontrolsarereallyjustfordisplayingthecurrenttime,astheydon’tletyoumodifythedateortime.Inotherwords,theyarecontrolswhoseonlycapabilityistodisplaythecurrenttime.Thus,ifyouwanttochangethedateortime,you’llneedtosticktotheDatePicker/TimePickerorDatePickerDialog/TimePickerDialog.Thenicepartaboutthesetwoclocks,though,isthattheywillupdatethemselveswithoutyouhavingtodoanything.Thatis,thesecondstickawayintheTextClock,andthehandsmoveontheAnalogClockwithoutanythingextrafromus.

TheMapViewControlWiththeintroductionofGooglePlayServices,Android’sapproachtodisplayingmap-baseddataunderwentsomechanges.However,thevastmajorityofdevelopersstillfavor

Page 131: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theoriginalMapViewControlforarangeofreasons—backwardcompatibility,simplicity,andsoon.Asthenamesuggests,thecom.google.android.maps.MapViewcontrolcandisplayamap.YoucaninstantiatethiscontroleitherviaXMLlayoutorcode,buttheactivitythatusesitmustextendMapActivity.MapActivitytakescareofmultithreadingrequeststoloadamap,performcaching,andsoon.

NoteStrictly,theMapViewispartoftheGoogleAPI,notthestockAndroidAPI.Inordertotestcodeetc.forMapView,ensureyouremulatoriscreatedagainstaversionoftheSDKwiththeGoogleAPIsincluded.

Listing3-27showsanexampleinstantiationofaMapView.

Listing3-27.CreatingaMapViewControlviaXMLLayout

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<com.google.android.maps.MapViewandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:enabled="true"android:clickable="true"android:apiKey="myAPIKey"/>

</LinearLayout>

We’lldiscussthelocation-basedservicesindetailinChapter19.Thisisalsowhereyou’lllearnhowtoobtainyourownmappingAPIkey.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch03_Controls.zip.ThisZIPfilecontainsallprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoEclipsefromoneoftheseZIPfiles.

http://developer.android.com/resources/articles/index.htmlSeveral“LayoutTricks”–typetechnicalarticlesthatarewellworth

Page 132: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

reading.TheygetintoperformanceaspectsofdesigningandbuildingUIsinAndroid.LookforotherarticlesinthislistrelatedtobuildingUIs.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedaboutbuildinguserinterfaces:

HowXMLresourcesdefineUIappearances,andhowcodefillsinthedata

ThefullrangeofbasicUserInterfacecontrolsavailableinAndroid

Ahintofwhat’stocomewithListviewsinChapter4andLayoutsinChapter5.

Page 133: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter4

AdaptersandListControlsInChapter3,weintroducedarangeofbasicUserInterfacecontrolswithwhichyoucanconstructAndroidapplications.IfyourecalltheexamplesonTextView,oneofthetypesofcontrolsweexploredwastheAutoCompleteTextView,whichwhencoupledwithasourceofdata—anadapter—wasabletoprompttheuserwitharangeofpredeterminedvalues.Inthischapter,we’llexploreadaptersfurther,andthewidertopicoflistcontrolsthatenableconstructionofmoreelaborateandsophisticatedscreendesigns.

UnderstandingAdaptersBeforewegetintothedetailsoflistcontrolsofAndroid,weneedtotalkaboutadapters.Listcontrolsareusedtodisplaycollectionsofdata.Butinsteadofusingasingletypeofcontroltomanageboththedisplayandthedata,Androidseparatesthesetworesponsibilitiesintolistcontrolsandadapters.Listcontrolsareclassesthatextendandroid.widget.AdapterViewandincludeListView,GridView,Spinner,andGallery(seeFigure4-1).

Figure4-1.AdapterViewclasshierarchy

AdapterViewitselfextendsandroid.widget.ViewGroup,whichmeansthatListView,GridView,andsoonarecontainercontrols.Inotherwords,listcontrolscontaincollectionsofchildviews.ThepurposeofanadapteristomanagethedataforanAdapterViewandtoprovidethechildviewsforit.Let’sseehowthisworksbyexaminingtheSimpleCursorAdapter.

Page 134: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

GettingtoKnowSimpleCursorAdapterTheSimpleCursorAdapterisdepictedinFigure4-2.

Figure4-2.TheSimpleCursorAdapter

Thisisaveryimportantpicturetounderstand.OntheleftsideistheAdapterView;inthisexample,itisaListViewmadeupofTextViewchildren.Ontherightsideisthedata;inthisexample,it’srepresentedasaresultsetofdatarowsthatcamefromaqueryagainstacontentprovider.

TomapthedatarowstotheListView,theSimpleCursorAdapterneedstohaveachildlayoutresourceID.Thechildlayoutmustdescribethelayoutforeachofthedataelementsfromtherightsidethatshouldbedisplayedontheleftside.Alayoutinthiscaseisjustlikethelayoutswe’vebeenworkingwithforouractivities,butitonlyneedstospecifythelayoutofasinglerowofourListView.Forexample,ifyouhavearesultsetofinformationfromtheContactscontentprovider,andyouonlywanttodisplayeachcontactnameinyourListView,youwouldneedtoprovidealayouttodescribewhatthenamefieldshouldlooklike.IfyouwantedtodisplaythenameandanimagefromtheresultsetineachrowoftheListView,yourlayoutmustsayhowtodisplaythenameandtheimage.

Thisdoesnotmeanyoumustprovidealayoutspecificationforeveryfieldinyourresultset,nordoesitmeanyoumusthaveapieceofdatainyourresultsetforeverythingyouwanttoincludeineachrowoftheListView.Forexample,we’llshowyouinabithowyoucanhavecheckboxesinyourListViewforselectingrows,andthosecheckboxesdon’tneedtobesetfromdatainaresultset.We’llalsoshowyouhowtogettodataintheresultsetthatisnotpartoftheListView.Andalthoughwe’vejusttalkedaboutListViews,TextViews,cursors,andresultsets,pleasekeepinmindthattheadapterconceptismoregeneralthanthis.Theleftsidecanbeagallery,andtherightsidecanbeasimplearrayofimages.Butlet’skeepthingsfairlysimplefornowandlookatSimpleCursorAdapterinmoredetail.

Page 135: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThesimplestconstructorofSimpleCursorAdapterlookslikethis:

SimpleCursorAdapter(Contextcontext,intchildLayout,Cursorc,String[]from,int[]to)

Thisadapterconvertsarowfromthecursortoachildviewforthecontainercontrol.ThedefinitionofthechildviewisdefinedinanXMLresource(childLayoutparameter).Notethatbecausearowinthecursormighthavemanycolumns,youtelltheSimpleCursorAdapterwhichcolumnsyouwanttoselectfromtherowbyspecifyinganarrayofcolumnnames(usingthefromparameter).

Similarly,becauseeachcolumnyouselectmustbemappedtoaViewinthelayout,youmustspecifytheIDsinthetoparameter.There’saone-to-onemappingbetweenthecolumnyouselectandaViewthatdisplaysthedatainthecolumn,sothefromandtoparameterarraysmusthavethesamenumberofelements.Aswementionedbefore,thechildviewcouldcontainothertypesofviews;theydon’thavetobeTextViews.YoucoulduseanImageView,forexample.

ThereisacarefulcollaborationgoingonbetweentheListViewandouradapter.WhentheListViewwantstodisplayarowofdata,itcallsthegetView()methodoftheadapter,passinginthepositiontospecifytherowofdatatobedisplayed.Theadapterrespondsbybuildingtheappropriatechildviewusingthelayoutthatwassetintheadapter’sconstructorandbypullingthedatafromtheappropriaterecordintheresultset.TheListView,therefore,doesn’thavetodealwithhowthedataexistsontheadapterside;itonlyneedstocallforchildviewsasneeded.Thisisacriticalpoint,becauseitmeansourListViewdoesn’tnecessarilyneedtocreateeverychildviewforeverydatarow.Itreallyonlyneedstohaveasmanychildviewsasarenecessaryforwhat’svisibleinthedisplaywindow.Ifonlytenrowsarebeingdisplayed,technicallytheListViewneedstohaveonlytenchildlayoutsinstantiated,eveniftherearehundredsofrecordsinourresultset.Inreality,morethantenchildlayoutsgetinstantiated,becauseAndroidusuallykeepsextrasonhandtomakeitfastertobringanewrowtovisibility.TheconclusionyoushouldreachisthatthechildviewsmanagedbytheListViewcanberecycled.We’lltalkmoreaboutthatalittlelater.

Figure4-2revealssomeflexibilityinusingadapters.Becausethelistcontrolusesanadapter,youcansubstitutevarioustypesofadaptersbasedonyourdataandchildview.Forexample,ifyouarenotgoingtopopulateanAdapterViewfromacontentproviderordatabase,youdon’thavetousetheSimpleCursorAdapter.Youcanoptforaneven“simpler”adapter—theArrayAdapter.

GettingtoKnowArrayAdapterTheArrayAdapteristhesimplestoftheadaptersinAndroid.ItspecificallytargetslistcontrolsandassumesthatTextViewcontrolsrepresentthelistitems(thechildviews).CreatinganewArrayAdaptercanlookassimpleasthis:

ArrayAdapter<String>adapter=newArrayAdapter<String>

Page 136: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(this,android.R.layout.simple_list_item_1,newString[]{"Dave","Satya","Dylan"});

Westillpassthecontext(this)andachildLayoutresourceID.Butinsteadofpassingafromarrayofdatafieldspecifications,wepassinanarrayofstringsastheactualdata.Wedon’tpassacursororatoarrayofViewresourceIDs.TheassumptionhereisthatourchildlayoutconsistsofasingleTextView,andthat’swhattheArrayAdapterwilluseasthedestinationforthestringsthatareinourdataarray.

Nowwe’regoingtointroduceaniceshortcutforthechildLayoutresourceID.Insteadofcreatingourownlayoutfileforthelistitems,wecantakeadvantageofpredefinedlayoutsinAndroid.NoticethattheprefixontheresourceforthechildlayoutresourceIDisandroid.Insteadoflookinginourlocal/resdirectory,Androidlooksinitsown.YoucanbrowsetothisfolderbynavigatingtotheAndroidSDKfolderandlookingunderplatforms/<android-version>/data/res/layout.Thereyou’llfindsimple_list_item_1.xmlandcanseeinsidethatitdefinesasimpleTextView.ThatTextViewiswhatourArrayAdapterwillusetocreateaview(initsgetView()method)togivetotheListView.Feelfreetobrowsethroughthesefolderstofindpredefinedlayoutsforallsortsofuses.We’llbeusingmoreoftheselater.

ArrayAdapterhasotherconstructors.IfthechildLayoutisnotasimpleTextView,youcanpassintherowlayoutresourceIDplustheresourceIDoftheTextViewtoreceivethedata.Whenyoudon’thaveaready-madearrayofstringstopassin,youcanusethecreateFromResource()method.Listings4-1,4-2,and4-3showanexampleinwhichwecreateanArrayAdapterforaspinner.

Listing4-1.ManifestFragmentforCreatinganArrayAdapterfromaString-ResourceFile

<Spinnerandroid:id="@+id/spinner"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

Listing4-2.CodeFragmentforCreatinganArrayAdapterfromaString-ResourceFile

Spinnerspinner=(Spinner)findViewById(R.id.spinner);

ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource(this,R.array.planets,android.R.layout.simple_spinner_item);

adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

spinner.setAdapter(adapter);

Listing4-3.TheActualString-ResourceFile

Page 137: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/values/planets.xml--><resources><string-arrayname="planets"><item>Mercury</item><item>Venus</item><item>Earth</item><item>Mars</item><item>Jupiter</item><item>Saturn</item><item>Uranus</item><item>Neptune</item></string-array></resources>

ThefirstlistingistheXMLlayoutforaspinner.ThesecondJavalistinginshowshowyoucancreateanArrayAdapterwhosedatasourceisdefinedinastringresourcefile.UsingthismethodallowsyoutonotonlyexternalizethecontentsofthelisttoanXMLfilebutalsouselocalizedversions.We’lltalkaboutspinnersalittlelater,butfornow,knowthataspinnerhasaviewtoshowthecurrentlyselectedvalue,plusalistviewtoshowthevaluesthatcanbeselectedfrom.It’sbasicallyadrop-downmenu.Listing4-3istheXMLresourcefilecalled/res/values/planets.xml,whichisreadintoinitializetheArrayAdapter.

WorthmentioningisthattheArrayAdapterallowsfordynamicmodificationstotheunderlyingdata.Forexample,theadd()methodwillappendanewvalueontheendofthearray.Theinsert()methodwilladdanewvalueataspecifiedpositionwithinthearray.Andremove()takesanobjectoutofthearray.Youcanalsocallsort()toreorderthearray.Ofcourse,onceyou’vedonethis,thedataarrayisoutofsyncwiththeListView,sothat’swhenyoucallthenotifyDataSetChanged()methodoftheadapter.ThismethodwillresynctheListViewwiththeadapter.

ThefollowinglistsummarizestheadaptersthatAndroidprovides:

ArrayAdapter<T>:Thisisanadapterontopofagenericarrayofarbitraryobjects.It’smeanttobeusedwithaListView.

CursorAdapter:Thisadapter,alsomeanttobeusedinaListView,providesdatatothelistviaacursor.

SimpleAdapter:Asthenamesuggests,thisadapterisasimpleadapter.Itisgenerallyusedtopopulatealistwithstaticdata(possiblyfromresources).

ResourceCursorAdapter:ThisadapterextendsCursorAdapterandknowshowtocreateviewsfromresources.

SimpleCursorAdapter:Thisadapterextends

Page 138: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ResourceCursorAdapterandcreatesTextView/ImageViewviewsfromthecolumnsinthecursor.Theviewsaredefinedinresources.

We’vecoveredenoughofadapterstostartshowingyousomerealexamplesofworkingwithadaptersandlistcontrols(alsoknownasAdapterViews).Let’sgettoit.

UsingAdapterswithAdapterViewsNowthatyou’vebeenintroducedtoadapters,itistimetoputthemtoworkforus,providingdataforlistcontrols.Inthissection,we’regoingtofirstcoverthebasiclistcontrol,theListView.Then,we’lldescribehowtocreateyourowncustomadapter,andfinally,we’lldescribetheothertypesoflistcontrols:GridViews,spinners,andthegallery.

TheBasicListControl:ListViewTheListViewcontroldisplaysalistofitemsvertically.Thatis,ifwe’vegotalistofitemstoviewandthenumberofitemsextendsbeyondwhatwecancurrentlyseeinthedisplay,wecanscrolltoseetherestoftheitems.YougenerallyuseaListViewbywritinganewactivitythatextendsandroid.app.ListActivity.ListActivitycontainsaListView,andyousetthedatafortheListViewbycallingthesetListAdapter()method.

Aswedescribedpreviously,adapterslinklistcontrolstothedataandhelppreparethechildviewsforthelistcontrol.ItemsinaListViewcanbeclickedtotakeimmediateactionorselectedtoactonthesetofselecteditemslater.We’regoingtostartreallysimpleandthenaddfunctionalityaswego.

DisplayingValuesinaListViewFigure4-3showsaListViewcontrolinitssimplestform.

Page 139: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure4-3.UsingtheListViewcontrol

Forthisexercise,wewillplaceaListViewintoadefaultAndroidlayout,withnospecialtweaksorchanges,soyoucanseehowtheyfitwithinatypicalmainlayoutXMLfile.Listing4-4showstheJavacodeforouractivity.

Listing4-4.AddingItemstoaListView

publicclassMainActivityextendsActivity{privateListViewlistView1;privateArrayAdapter<String>listAdapter1;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

listView1=(ListView)findViewById(R.id.listView1);

String[]someColors=newString[]{"Red","Orange","Yellow","Green","Blue","Indigo","Violet","Black","White"};ArrayList<String>colorArrayList=newArrayList<String>();colorArrayList.addAll(Arrays.asList(someColors));

listAdapter1=newArrayAdapter<String>(this,android.R.id.text1,colorArrayList);

listView1.setAdapter(listAdapter1);

Page 140: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}...}

Listing4-2createsaListViewcontrolpopulatedwiththelistofcolorswespecifyinanarray,someColors.Inourexample,wetakethecontentsofthearrayandmaptheStringcolornamestoaTextViewcontrol(android.R.id.text1).Afterthat,wecreateanarrayadapterandsetthelist’sadapter.TheadapterclasshasthesmartstotaketherowsinwhateverdatasourceyouprovidetopopulatetheUI.

WecouldhavetakenadvantageoftheverybasicListActivitysupplyingthemainlayout,astherearenootherUIelementsorcomplexitytotakecareof.Howeverwe’vechosentodeploytheListViewwithinatypicalnewprojectandutilizethebasicactivity.We’realsousinganAndroid-providedlayoutforourchildview(resourceIDandroid.R.layout.simple_list_item_1),whichcontainsanAndroid-providedTextView(resourceIDandroid.R.id.text1).Allinall,prettysimpletosetup.

Wecanextendthisexample,andyourunderstanding,byshowinghowtoreplacetheAndroid-providedlayoutforthechildviewwithoneofourowndesign.Createanewemptyfileintheres/layoutfolderofyourprojectandnameitsimple_list_row.xml.Listing4-5showstheXMLforourownlayoutforasimpleTextViewtorepresenteachlinetoberenderedinourListView(oranyotherlayoutthatreferstothissimple_list_rowlayout).

Listing4-5.CreatingaCustomTextViewChildViewforListRendering

<TextViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rowTextView"android:layout_width="fill_parent"android:layout_height="wrap_content"android:padding="12dp"android:textSize="24sp"></TextView>

WeneedonlychangethereferencethatbindsthechosenlayoutforuseintheListViewinourcode,tousethenewsimple_list_rowlayout,likeso:

listAdapter1=newArrayAdapter<String>(this,R.layout.simple_list_row,colorArrayList);

Notethatwhenwerefertoourowncustomlayoutinthisway,wedroptheleading“android”reference.Wecannowrunthisexampletoseethecompleteeffect,asshowninFigure4-4.

Page 141: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure4-4.TheListViewexampleinaction

ClickableItemsinaListViewOfcourse,whenyourunthisexample,you’llseethatyou’reabletoscrollupanddownthelisttoseeallyourcolornames,butthat’saboutit.Whatifwewanttodosomethingalittlemoreinterestingwiththisexample,likehavetheapplicationrespondwhenauserclicksoneoftheitemsinourListView?Listing4-6showsamodificationtoourexampletoacceptuserinput.

Listing4-6.AcceptingUserInputonaListView

publicclassMainActivityextendsActivity{

privateListViewlistView1;privateArrayAdapter<String>listAdapter1;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

Page 142: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

listView1=(ListView)findViewById(R.id.listView1);

String[]someColors=newString[]{"Red","Orange","Yellow","Green","Blue","Indigo","Violet","Black","White"};ArrayList<String>colorArrayList=newArrayList<String>();colorArrayList.addAll(Arrays.asList(someColors));

listAdapter1=newArrayAdapter<String>(this,android.R.layout.simple_list_item_1,colorArrayList);

listView1.setAdapter(listAdapter1);

listView1.setOnItemClickListener(newOnItemClickListener(){

@OverridepublicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){StringitemValue=(String)listView1.getItemAtPosition(position);Toast.makeText(getApplicationContext(),itemValue,Toast.LENGTH_LONG).show();}});}...}

OuractivityisnowimplementingtheOnItemClickListenerinterface,whichmeanswe’llreceiveacallbackwhentheuserclickssomethinginourListView.AsyoucanseebyouronItemClick()method,wegetalotofinformationaboutwhatwasclicked,includingtheviewreceivingtheclick,thepositionoftheclickeditemintheListView,andtheIDoftheitemaccordingtoouradapter.WecastaccordinglybeforecallingthemakeText()methodtoworkwiththecolor’sname.ThepositionvaluerepresentswherethisitemisinrelationtotheoveralllistofitemsintheListView,andit’szero-based.Therefore,thefirstiteminthelistisatposition0.

TheIDvaluedependsentirelyontheadapterandthesourceofthedata.Inourexample,wehappentobequeryingstringswiththenamesofcolorsinanarray,sotheIDaccordingtothisadapteristhepositionoftheentryinthearrayfromthecontentprovider.Butyourdatasourceinothersituationsmaynotbeasstraightforwardasthis,soyoushouldnot

Page 143: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thinkthatyoucanalwaysknowthingslikeorderinginadvanceaswe’vedoneinthisexample.IfwewereusinganSimpleCursorAdapterthathadreaditsvaluesfromthesystem’sContactsdatabase,theIDgiventouswillbetheunderlying_IDoftherecord,andthatcouldbeanyvaluedependingontheageofthecontactinthesystem.

WhenwediscussedArrayAdaptersbefore,wementionedthenotifyDataSetChanged()methodtohavetheadapterupdatetheListViewifthedatahaschanged.Someadapters,suchastheSimpleCursorAdapter,areawareofupdatesthathappentounderlyingdatasourcessuchastheContactscontentproviderandwilldynamicallyupdateListViewcontentsforyoubasedonchanges.WithArrayAdapters,however,youwillneedtoinvokethenotifyDataSetChanged()methodyourself.

Thatwasprettyeasytodo.WegeneratedourownListViewofcolornames,andbyclickingacolorweshowedamessagetotheuser.Butwhatifwewanttoselectabunchofnamesfirstandthendosomethingwiththesubsetofpeople?Forthenextexampleapplication,we’regoingtomodifythelayoutofalistitemtoincludeacheckbox,andwe’regoingtoaddabuttontotheUItothenactonthesubsetofselecteditems.

AddingOtherControlswithaListViewIfyouwantadditionalcontrolsinyourmainlayout,youcanprovideyourownlayoutXMLfile,putinaListView,andaddotherdesiredcontrols.Forexample,youcouldaddabuttonbelowtheListViewintheUItosubmitanactionontheselecteditems,asshowninFigure4-5.

Page 144: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure4-5.Anadditionalbuttonthatletstheusersubmittheselecteditem(s)

ThemainlayoutforthisexampleisinListing4-7,anditcontainstheUIdefinitionoftheactivity—theListViewandtheButton.

Listing4-7.OverridingtheListViewReferencedbyOurActivity

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.artifexdigital.android.listviewdemo3.MainActivity">

<ListViewandroid:id="@+id/listView1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"/>

Page 145: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<Buttonandroid:id="@+id/button1"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="doClick"android:text="Submitselection"/>

</LinearLayout>

NoticethewaywehavetospecifytheheightandweightoftheListViewinLinearLayout.WewantourbuttontoappearonthescreenatalltimesnomatterhowmanyitemsareinourListView,andwedon’twanttobescrollingallthewaytothebottomofthepagejusttofindthebutton.Toaccomplishthis,wesetthelayout_heighttowrap_contentandthenuselayout_weighttosaythatthiscontrolshouldtakeupallavailableroomfromtheparentcontainer.ThistrickallowsroomforthebuttonandretainsourabilitytoscrolltheListView.We’lltalkmoreaboutlayoutsandweightslaterinthischapter.

TheactivityimplementationwouldthenlooklikeListing4-8.

Listing4-8.ReadingUserInputfromtheListActivity

publicclassMainActivityextendsActivity{

privateListViewlistView1;privateArrayAdapter<String>listAdapter1;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

listView1=(ListView)findViewById(R.id.listView1);

String[]someColors=newString[]{"Red","Orange","Yellow","Green","Blue","Indigo","Violet","Black","White"};ArrayList<String>colorArrayList=newArrayList<String>();colorArrayList.addAll(Arrays.asList(someColors));

listAdapter1=newArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,colorArrayList);

listView1.setAdapter(listAdapter1);

listView1.setChoiceMode(listView1.CHOICE_MODE_MULTIPLE);

Page 146: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

listView1.setOnItemClickListener(newOnItemClickListener(){

@OverridepublicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){StringitemValue=(String)listView1.getItemAtPosition(position);Toast.makeText(getApplicationContext(),itemValue,Toast.LENGTH_LONG).show();}});}

publicvoiddoClick(Viewview){intcount=listView1.getCount();SparseBooleanArrayviewItems=listView1.getCheckedItemPositions();for(inti=0;i<count;i++){if(viewItems.get(i)){StringselectedColor=(String)listView1.getItemAtPosition(i);Log.v("ListViewDemo",selectedColor+"ischeckedatposition"+i);}}}}

Withinthesetupoftheadapter,we’repassinganotheroftheAndroid-providedviewsforaListViewlineitem(android.R.layout.simple_list_item_checked),whichresultsineachrowhavingaTextViewandaCheckBox.Ifyoulookinsidethislayoutfile,youwillseeanothersubclassofTextView,thisonecalledCheckedTextView.ThisspecialtypeofTextViewisintendedforusewithListViews.See,wetoldyouthereweresomeinterestingthingsinthatAndroidlayoutfolder!YouwillseethattheIDoftheCheckedTextViewistext1,whichiswhatweneededtopassinourviewsarraytotheconstructoroftheSimpleCursorAdapter.

Becausewewanttheusertobeabletoselectourrows,wesetthechoicemodetoCHOICE_MODE_MULTIPLE.Bydefault,thechoicemodeisCHOICE_MODE_NONE.TheotherpossiblevalueisCHOICE_MODE_SINGLE.Ifyouwanttousethatchoicemodeforthisexample,youwouldwanttouseadifferentlayout,mostlikelyandroid.R.layout.simple_list_item_single_choice.

Inthisexample,we’veimplementedabasicbuttonthatcallsthedoClick()methodof

Page 147: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ouractivity.Tokeepthingssimple,wejustwanttowriteouttoLogCatthenamesoftheitemsthatwerecheckedbytheuser.Thegoodnewsisthatthesolutionisprettyeasy;thebadnewsisthatAndroidhasevolvedsothebestsolutiondependsonwhichversionofAndroidyou’retargeting.TheListViewsolutionwe’veshownherehasworkedsinceAndroid1(althoughwetooktheAndroid1.6shortcutonthebuttoncallback).Thatis,thegetCheckedItemPositions()methodisold,butitstillworks.Thereturnvalueisanarraythatcantellyouwhetheranitemhasbeenchecked.So,weiteratethroughthearray.viewItems.get(i)willreturntrueifthecorrespondingrowinourListViewhasbeenchecked.OurdataisaccessibledirectlyfromtheListView,usingthegetItemAtPosition()methodoftheListView.Inourcase,theobjectreturnedfromgetItemAtPosition()wouldturnouttobeaStringobject.Aswesaidbefore,inothersituations,wemightgetsomeothertypeofobject,suchasaCursorWrapper,whenworkingwithsomespecificcontentprovidersliketheContactsproviderdiscussedlaterinthisbook.Youhavetounderstandyourdatasourceandyouradaptertoknowwhattoexpect.

IfwegoaheadandhittheSubmitSelectionbuttonshowninFigure4-5,wecanwatchthelogcatwindowinEclipseorAndroidStudioasitemitsthedatafromourselectionasimplementedinthedoClick()method.ThisisshowninFigure4-6.

Figure4-6.UsinguserinputfromaListViewforfurtherprocessing

AnotherWaytoReadSelectionsfromaListViewAndroid1.6introducedanothermethodforretrievingalistofthecheckedrowsfromaListView:getCheckItemIds().Then,inAndroid2.2,thismethodwasdeprecatedandreplacedwithgetCheckedItemIds().Itwasasubtlenamechange,butthewayyouusethemethodisbasicallythesame.Listing4-9showstheJavacodechangeswe’dmaketoreflectthisevolutionofdealingwithcheckeditemsinalist.FortheXMLlayoutoflist.xml,wecancontinuetousethefileinListing4-7.

Listing4-9.AnotherWayofReadingUserInputfromtheListActivity

publicclassMainActivityextendsActivity{privateListViewlistView1;privateArrayAdapter<String>listAdapter1;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){

Page 148: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

listView1=(ListView)findViewById(R.id.listView1);

String[]someColors=newString[]{"Red","Orange","Yellow","Green","Blue","Indigo","Violet","Black","White"};ArrayList<String>colorArrayList=newArrayList<String>();colorArrayList.addAll(Arrays.asList(someColors));

listAdapter1=newArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,colorArrayList);

listView1.setAdapter(listAdapter1);

listView1.setChoiceMode(listView1.CHOICE_MODE_MULTIPLE);

listView1.setOnItemClickListener(newOnItemClickListener(){

@OverridepublicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){StringitemValue=(String)listView1.getItemAtPosition(position);Toast.makeText(getApplicationContext(),itemValue,Toast.LENGTH_LONG).show();}});}

...

publicvoiddoClick(Viewview){if(!listAdapter1.hasStableIds()){Log.v(TAG,"Dataisnotstable");return;}long[]viewItems=listView1.getCheckedItemIds();for(inti=0;i<viewItems.length;i++){StringselectedColor=(String)listView1.getItemAtPosition(i);Log.v("ListViewDemo",selectedColor+"ischecked

Page 149: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

atposition"+i);}}}}

Inthisexampleapplication,whenweclickthebutton,ourcallbackcallsthemethodgetCheckedItemIds().Whereasinourlastexample,wegotanarrayofpositionsofthecheckeditemsintheListView,thistimewegetanarrayofIDsoftherecordsfromtheadapterthathavebeencheckedintheListView.WecanbypasstheListViewandthecursornow,becausetheIDscanbeusedtodrivewhateveractionwedesire.

We’veshownyouhowtoworkwithListViewsfromavarietyofscenarios.We’veshownthatadaptersdoalotoftheworktosupportaListView.Next,we’llcovertheothertypesoflistcontrols,startingwiththeGridView.

TheGridViewControlMostwidgettoolkitsofferoneormoregrid-basedcontrols.AndroidhasaGridViewcontrolthatcandisplaydataintheformofagrid.Notethatalthoughweusethetermdatahere,thecontentsofthegridcanbetext,images,andsoon.

TheGridViewcontroldisplaysinformationinagrid.TheusagepatternfortheGridViewistodefinethegridintheXMLlayout(seeListings4-10and4-11)andthenbindthedatatothegridusinganandroid.widget.ListAdapter.

Listing4-10.DefinitionofaGridViewinanXMLLayout

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.artifexdigital.android.gridviewdemo.MainActivity">

<GridViewandroid:id="@+id/gridView1"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="10dp"android:verticalSpacing="10dp"android:horizontalSpacing="10dp"android:numColumns="auto_fit"android:columnWidth="100dp"android:stretchMode="columnWidth"android:gravity="center"/>

Page 150: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

</RelativeLayout>

Listing4-11.JavaImplementationfortheGridView

publicclassMainActivityextendsActivity{privateGridViewgridView1;privateArrayAdapter<String>listAdapter1;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

gridView1=(GridView)findViewById(R.id.gridView1);

String[]someColors=newString[]{"Red","Orange","Yellow","Green","Blue","Indigo","Violet","Black","White"};

ArrayList<String>colorArrayList=newArrayList<String>();colorArrayList.addAll(Arrays.asList(someColors));

listAdapter1=newArrayAdapter<String>(this,android.R.layout.simple_list_item_1,colorArrayList);

gridView1.setAdapter(listAdapter1);

}

}

Listing4-10definesasimpleGridViewinanXMLlayout.Thegridisthenloadedintotheactivity’scontentview.ThegeneratedUIisshowninFigure4-7.

Page 151: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure4-7.AGridViewpopulatedwithcolors

ThegridshowninFigure4-7displaysthenamesofthecolorsfromourarray.WehavedecidedtoshowaTextViewwiththecolornames,butyoucouldeasilygenerateagridfilledwithimagesorothercontrols.We’veagaintakenadvantageofpredefinedlayoutsinAndroid.Infact,thisexamplelooksverymuchlikeListing4-7exceptforafewimportantdifferences.WemustcallsetContentView()tosetthelayoutforourGridView;therearenodefaultviewstofallbackon.Andtosettheadapter,wecallsetAdapter()ontheGridViewobjectinsteadofcallingsetListAdapter()onActivity.

You’venodoubtnoticedthattheadapterusedbythegridisaListAdapter.Listsaregenerallyone-dimensional,whereasgridsaretwo-dimensional.Wecanconclude,then,thatthegridactuallydisplayslist-orienteddata.Anditturnsoutthatthelistisdisplayedbyrows.Thatis,thelistgoesacrossthefirstrow,thenacrossthesecondrow,andsoon.

Asbefore,wehavealistcontrolthatworkswithanadaptertohandlethedatamanagementandthegenerationofthechildviews.ThesametechniquesweusedbeforeshouldworkjustfinewithGridViews.Oneexceptionrelatestomakingselections:thereisnowaytospecifymultiplechoicesinaGridView,aswedidinListing4-7.

TheSpinnerControlTheSpinnercontrolislikeadrop-downmenu.Itistypicallyusedtoselectfromarelativelyshortlistofchoices.Ifthechoicelististoolongforthedisplay,ascrollbarisautomaticallyaddedforyou.YoucaninstantiateaSpinnerviaXMLlayoutassimplyasthis:

<Spinnerandroid:id="@+id/spinner"android:prompt="@string/spinnerprompt"android:layout_width="wrap_content"android:layout_height="wrap_content"

Page 152: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/>

Althoughaspinneristechnicallyalistcontrol,itwillappeartoyoumorelikeasimpleTextViewcontrol.Inotherwords,onlyonevaluewillbedisplayedwhenthespinnerisatrest.Thepurposeofthespinneristoallowtheusertochoosefromasetofpredeterminedvalues:whentheuserclicksthesmallarrow,alistisdisplayed,andtheuserisexpectedtopickanewvalue.Populatingthislistisdoneinthesamewayastheotherlistcontrols:withanadapter.

Becauseaspinnerisoftenusedlikeadrop-downmenu,itiscommontoseetheadaptergetthelistchoicesfromaresourcefile.AnexamplethatsetsupaspinnerusingaresourcefileisshowninListing4-12.Noticethenewattributecalledandroid:promptforsettingapromptatthetopofthelisttochoosefrom.Theactualtextforourspinnerpromptisinour/res/values/strings.xmlfile.Asyoushouldexpect,theSpinnerclasshasamethodforsettingthepromptincodeaswell.

Listing4-12.CodetoCreateaSpinnerfromaResourceFile

publicclassSpinnerActivityextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.spinner);

Spinnerspinner=(Spinner)findViewById(R.id.spinner);

ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource(this,R.array.planets,android.R.layout.simple_spinner_item);

adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

spinner.setAdapter(adapter);}}

Youmayrecallseeingtheplanets.xmlfileinListing4-1.WeshowinthisexamplehowaSpinnercontroliscreated;theadapterissetupandthenassociatedtothespinner.SeeFigure4-8forwhatthislookslikeinaction.

Page 153: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure4-8.Aspinnerforchoosingaplanet

Oneofthedifferencesfromourearlierlistcontrolsisthatwe’vegotanextralayouttocontendwithwhenworkingwithaspinner.TheleftsideofFigure4-8showsthenormalmodeofaspinner,wherethecurrentselectionisshown.Inthiscase,thecurrentselectionisSaturn.Nexttothewordisadownward-pointingarrowindicatingthatthiscontrolisaspinnerandcanbeusedtopopupalisttoselectadifferentvalue.Thefirstlayout,suppliedasaparametertotheArrayAdapter.createFromResource()method,defineshowthespinnerlooksinnormalmode.OntherightsideofFigure4-8,weshowthespinnerinthepop-uplistmode,waitingfortheusertochooseanewvalue.ThelayoutforthislistissetusingthesetDropDownViewResource()method.Againinthisexample,we’reusingAndroid-providedlayoutsforthesetwoneeds,soifyouwanttoinspectthedefinitionofeitheroftheselayouts,youcanvisittheAndroidres/layoutfolder.Andofcourse,youcanspecifyyourownlayoutdefinitionforeitherofthesetogettheeffectyouwant.

TheGalleryControlTheGallerycontrolisahorizontallyscrollablelistcontrolthatalwaysfocusesatthecenterofthelist.Thiscontrolgenerallyfunctionsasaphotogalleryintouchmode.YoucaninstantiateaGalleryviaeitherXMLlayoutorcode:

<Galleryandroid:id="@+id/gallery"

Page 154: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:layout_width="fill_parent"android:layout_height="wrap_content"/>

TheGallerycontrolistypicallyusedtodisplayimages,soyouradapterislikelygoingtobespecializedforimages.We’llshowyouacustomimageadapterinnextsectiononcustomadapters.Visually,agallerylookslikeFigure4-9.

Figure4-9.Agallerywithimagesofmanatees

SummaryInthischapter,we’veexpandedyourunderstandingandproficiencywithUIcomponentsinthefollowingways:

ThemainlistcontrolsavailableinAndroid

Howtouseadapterstopopulatethedatainalistcontrol

Page 155: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter5

BuildingMoreAdvancedUILayoutsInthepreviouschapterswereviewedmanyofthestandardlayoutsprovidedwithAndroid,whichcoverabroadarrayofpossibleUIapproaches.WhenthestocklayoutsofferedbyAndroiddon'tquitedowhatyouwant,wheredoyouturn?Inthischapter,wewillquicklyexplorehowAndroidprovidesyouwiththeabilitytobuildyourowncustomlayoutsandmanagetherelatedadaptersforpopulatingthemwithusefuldata.

CreatingCustomAdaptersStandardadaptersinAndroidareeasytouse,buttheyhavesomelimitations.Toaddressthis,AndroidprovidesanabstractclasscalledBaseAdapterthatyoucanextendifyouneedacustomadapter.Youwoulduseacustomadapterifyouhadspecialdata-managementneedsorifyouwantedmorecontroloverhowtodisplaychildviews.Youmightalsouseacustomadaptertoimproveperformancebyusingcachingtechniques.We’regoingtoshowyouhowtobuildacustomadapternext.

Listing5-1showswhattheXMLlayoutandtheJavacodecouldlooklikeforacustomadapter.Forthisnextexample,ouradapterisgoingtodealwithimagesofmanatees,sowe’llcallitManateeAdapter.We’regoingtocreateitinsideofanactivityaswell.

Listing5-1.OurCustomAdapter:ManateeAdapter

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisat/res/layout/gridviewcustom.xml--><GridViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/gridview"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="10dip"android:verticalSpacing="10dip"android:horizontalSpacing="10dip"android:numColumns="auto_fit"android:gravity="center"/>

JavaImplementation

publicclassGridViewCustomAdapterextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState)

Page 156: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

{super.onCreate(savedInstanceState);setContentView(R.layout.gridviewcustom);GridViewgv=(GridView)findViewById(R.id.gridview);ManateeAdapteradapter=newManateeAdapter(this);gv.setAdapter(adapter);}

publicstaticclassManateeAdapterextendsBaseAdapter{privatestaticfinalStringTAG="ManateeAdapter";privatestaticintconvertViewCounter=0;privateContextmContext;privateLayoutInflatermInflater;staticclassViewHolder{ImageViewimage;}

privateint[]manatees={R.drawable.manatee00,R.drawable.manatee01,R.drawable.manatee02,//...manymoremanateeshere-seethesamplecodefolderR.drawable.manatee32,R.drawable.manatee33};

privateBitmap[]manateeImages=newBitmap[manatees.length];privateBitmap[]manateeThumbs=newBitmap[manatees.length];

publicManateeAdapter(Contextcontext){Log.v(TAG,"ConstructingManateeAdapter");this.mContext=context;mInflater=LayoutInflater.from(context);

for(inti=0;i<manatees.length;i++){manateeImages[i]=BitmapFactory.decodeResource(context.getResources(),manatees[i]);manateeThumbs[i]=Bitmap.createScaledBitmap(manateeImages[i],100,100,false);}}

@OverridepublicintgetCount(){Log.v(TAG,"ingetCount()");returnmanatees.length;

Page 157: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

publicintgetViewTypeCount(){Log.v(TAG,"ingetViewTypeCount()");return1;}

publicintgetItemViewType(intposition){Log.v(TAG,"ingetItemViewType()forposition"+position);return0;}

@OverridepublicViewgetView(intposition,ViewconvertView,ViewGroupparent){ViewHolderholder;

Log.v(TAG,"ingetViewforposition"+position+",convertViewis"+((convertView==null)?"null":"beingrecycled"));

if(convertView==null){convertView=mInflater.inflate(R.layout.gridimage,null);convertViewCounter++;Log.v(TAG,convertViewCounter+"convertViewshavebeencreated");holder=newViewHolder();holder.image=(ImageView)convertView.findViewById(R.id.gridImageView);convertView.setTag(holder);}else{holder=(ViewHolder)convertView.getTag();}

holder.image.setImageBitmap(manateeThumbs[position]);

returnconvertView;}

@OverridepublicObjectgetItem(intposition){Log.v(TAG,"ingetItem()forposition"+position);

Page 158: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returnmanateeImages[position];}

@OverridepubliclonggetItemId(intposition){Log.v(TAG,"ingetItemId()forposition"+position);returnposition;}}}

Whenyourunthisapplication,youshouldseeadisplaythatlookslikeFigure5-1.

Figure5-1.AGridViewwithimagesofmanatees

Thereisalottoexplaininthisexample,eventhoughitlooksrelativelysimple.We’llstartwithourActivityclass,whichlooksalotliketheoneswe’vebeenworkingwiththroughoutthissectionofthechapter.There’samainlayoutfromgridviewcustom.xml,whichcontainsjustaGridViewdefinition.WeneedtogetareferencetotheGridViewfrominsidethelayout,sowedefineandsetgv.We

Page 159: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

instantiateourManateeAdapter,passingitourcontext,andwesettheadapteronourGridView.Thisisprettystandardstuffsofar,althoughyou’venodoubtnoticedthatourcustomadapterdoesn’tusenearlyasmanyparametersaspredefinedadapterswhenbeingcreated.Thisismainlybecausewe’reincompletecontroloverthisparticularadapter,andwe’reusingitwithonlythisapplication.Ifweweremakingthisadaptermoregeneral,wewouldmostlikelybesettingmoreparameters.Butlet’skeepgoing.OurjobinsideanadapteristomanagethepassingofdataintoAndroidViewobjects.TheViewobjectswillbeusedbythelistcontrol(aGridViewinthiscase).Thedatacomesfromsomedatasource.Intheearlierexamples,thedatacameviaacursorobjectthatwaspassedintotheadapter.Inourcustomcasehere,ouradapterknowsallaboutthedataandwhereitcomesfrom.ThelistcontrolwillaskforthingssoitknowshowtobuildtheUI.Itisalsokindenoughtopassinviewsforrecyclingwhenithasaviewitnolongerneeds.Itmayseemabitstrangetothinkthatouradaptermustknowhowtoconstructviews,butintheend,itallmakessense.

WhenweinstantiateourcustomadapterManateeAdapter,itiscustomarytopassinthecontextandfortheadaptertoholdontoit.Itisoftenveryusefultohaveitavailablewhenneeded.Thesecondthingwewanttodoinouradapteristohangontotheinflater.Thiswillhelpperformancewhenweneedtocreateanewviewtoreturntothelistcontrol.ThethirdthingthatistypicalinanadapteristocreateaViewHolderobject,tocontaintheViewobjectsforthedatawearemanaging.Takingthisapproachalsoactsasaperformanceoptimization,savingusfromrepeatedlylookinguptheViews.Forthisexample,wearesimplystoringanImageView,butifwehadadditionalfieldstodealwith,wewouldaddthemintothedefinitionofViewHolder.Forexample,ifwehadaListViewwhereeachrowcontainedanImageViewandtwoTextViews,ourViewHolderwouldhaveanImageViewandtwoTextViews.

Becausewe’redealingwithimagesofmanateesinthisadapter,wesetupanarrayoftheirresourceIDstobeusedduringconstructiontocreatebitmaps.Wealsodefineanarrayofbitmapstouseasourdatalist.

AsyoucanseefromourManateeAdapterconstructor,wesavethecontext,createandhangontoaninflater,andthenweiteratethroughtheimageresourceIDsandbuildanarrayofbitmaps.Thisbitmaparraywillbeourdata.

Asyoulearnedpreviously,settingtheadapterwillcauseourGridViewtocallmethodsontheadaptertosetitselfupwithdatatodisplay.Forexample,ourGridViewgvwillcalltheadapter’sgetCount()methodtodeterminehowmanyobjectstherearefordisplaying.ItwillalsocallthegetViewTypeCount()methodtodeterminehowmanydifferenttypesofviewscouldbedisplayedwithintheGridView.Forourpurposesinthisexample,wesetthisto1.However,ifwehadaListViewandwantedtoputseparatorsinbetweenregularrowsofdata,wewouldhavetwotypesofviewsandwouldneedtoreturn2fromgetViewTypeCount().Youcouldhaveasmanydifferentviewtypesasyoulike,aslongasyouappropriatelyreturnthecorrectcountfromthismethod.RelatedtothismethodisgetItemViewType().Wejustsaidthatwecouldhavemorethanonetypeofviewtoreturnfromtheadapter,buttokeepthingssimpler,

Page 160: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

getItemViewType()needstoreturnonlyanintegervaluetoindicatewhichofourviewtypesisataparticularpositioninthedata.Therefore,ifwehadtwotypesofviewstoreturn,getItemViewType()wouldneedtoreturneither0or1toindicatewhichtype.Ifwehavethreetypesofviews,thismethodneedstoreturn0,1,or2.

IfouradapterisdealingwithseparatorsinaListView,itmusttreattheseparatorsasdata.Thatmeansthereisapositioninthedatathatistakenupbyaseparator.WhengetView()iscalledbyalistcontroltoretrievetheappropriateviewforthatposition,getView()willneedtoreturnaseparatorasaviewinsteadofregulardataasaview.AndwhenaskedingetItemViewType()fortheviewtypeforthatposition,weneedtoreturntheappropriateintegervaluethatwe’vedecidedmatchesthatviewtype.TheotherthingyoushoulddoifusingseparatorsistoimplementtheisEnabled()method.Thisshouldreturntrueforlistitemsandfalseforseparatorsbecauseseparatorsshouldnotbeselectableorclickable.

ThemostinterestingmethodinManateeAdapteristhegetView()methodcall.OncetheGridViewhasdeterminedhowmanyitemsareavailable,itstartstoaskforthedata.Now,wecantalkaboutrecyclingviews.Alistcontrolcanonlyshowasmanychildviewsonthedisplayaswillfit.Thatmeansthere’snopointincallinggetView()foreverypieceofdataintheadapter;itonlymakessensetocallgetView()forasmanyitemsascanbedisplayed.Asgvgetschildviewsbackfromtheadapter,itisdetermininghowmanywillfitonthedisplay.Whenthedisplayisfullofchildviews,gvcanstopcallinggetView().

IfyoulookatLogCatafterstartingthisexampleapplication,youwillseethevariouscalls,butyouwillalsoseethatgetView()stopsbeingcalledbeforeallimageshavebeenrequested.IfyoustartscrollingupanddowntheGridView,youwillseemorecallstogetView()inLogCat,andyouwillnoticethat,oncewe’vecreatedacertainnumberofchildviews,getView()isbeingcalledwithconvertViewsettosomething,notnull.Thismeanswe’renowrecyclingchildviews—andthat’sverygoodforperformance.

IfwegetanonnullconvertViewvaluefromgvingetView(),itmeansgvisrecyclingthatview.Byreusingtheviewpassedin,weavoidhavingtoinflateanXMLlayout,andweavoidhavingtofindtheImageView.BylinkingaViewHolderobjecttotheViewthatwereturn,wecanbemuchfasteratrecyclingtheviewthenexttimeitcomesbacktous.AllwehavetodoingetView()isreacquiretheViewHolderandassigntherightdataintotheview.

Forthisexample,wewantedtoshowthatthedataplacedintotheviewisnotnecessarilyexactlywhatexistsinthedata.ThecreateScaledBitmap()methodiscreatingasmallerversionofthedatafordisplaypurposes.ThepointisthatourlistcontroldoesnotcallthegetItem()method.Thismethodwouldbecalledbyourothercodethatwantstodosomethingwiththedataiftheuseractsonthelistcontrol.Onceagain,foranyadapter,itisveryimportantthatyouunderstandwhatitisdoing.Youdon’tnecessarilywanttorelyondataintheviewfromthelistcontrol,ascreatedbygetView()intheadapter.Sometimes,youwillneedtocalltheadapter’sgetItem()methodtogettheactualdatatobeoperatedon.Andsometimes,aswedidintheearlierListView

Page 161: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

examples,you’llwanttogotoacursorforthedata.Italldependsontheadapterandwherethedataisultimatelycomingfrom.AlthoughweusedthecreateScaledBitmap()methodinourexample,Android2.2introducedanotherclassthatmighthavebeenhelpfulhere:ThumbnailUtils.Thisclasshassomestaticmethodsforgeneratingthumbnailimagesfrombitmapsandvideos.

ThelastthingtopointoutfromthisexampleisthegetItemId()methodcall.InourearlierexampleswithListViewsandcontacts,theitemIDwasthe_IDvaluefromthecontentprovider.Forthisexample,wedon’treallyneedtouseanythingotherthanpositionfortheitemID.ThepointofitemIDsistoprovideamechanismtorefertothedataseparatelyfromitsposition.Thisisespeciallytruewhenthedatahasalifeawayfromthisadapter,asisthecasewithourcontacts.Whenwehavethiskindofdirectcontroloverthedata,aswedowithourimagesofmanatees,andweunderstandhowtogettotheactualdatainourapplication,itisacommonshortcuttosimplyusepositionastheitemID.Thisisparticularlytrueinourcase,becausewedon’tevenallowaddingorremovalofdata.

OtherControlsinAndroidTherearemany,manycontrolsinAndroidthatyoucanuse.We’vecoveredquiteafewsofar,andmorewillbecoveredinlaterchapters(suchasMapViewinChapter19andVideoViewandMediaControllerinChapter20).Youwillfindthattheothercontrols,becausethey’realldescendedfromView,havealotincommonwhattheoneswe’vecoveredhere.Fornow,we’lljustmentionafewofthecontrolsyoumightwanttoexplorefurtheronyourown.

ScrollViewisacontrolforsettingupaViewcontainerwithaverticalscrollbar.Thisisusefulwhenyouhavetoomuchtofitontoasinglescreen.

TheProgressBarandRatingBarcontrolsarelikesliders.Thefirstshowstheprogressofsomeoperationvisually(perhapsafiledownloadormusicplaying),andthesecondshowsaratingscaleofstars.

TheChronometercontrolisatimerthatcountsup.There’saCountDownTimerclassifyouwantsomethingtohelpyoudisplayacountdowntimer,butit’snotaViewclass.

TheSwitchcontrol,whichfunctionslikeaToggleButtonbutvisuallyhasaside-to-sidepresentation,wasintroducedinAndroid4.0,alongwiththeSpaceview,alightweightviewthatcanbeusedinlayoutstomoreeasilycreatespacesbetweenotherviews.

WebViewisaveryspecialviewfordisplayingHTML.Itcandoalotmorethanthat,includinghandlingcookiesandJavaScriptandlinkingtoJavacodeinyourapplication.Butbeforeyougoimplementingawebbrowserinsideyourapplication,youshouldcarefullyconsiderinvokingtheon-devicewebbrowsertoletitdoallthatheavylifting.

Thatcompletesourintroductionofcontrolsinthischapter.We’llnowmoveontostylesandthemesformodifyingthelookandfeelofourcontrolsandthentolayoutsforarrangingourcontrolsonscreens.

Page 162: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

StylesandThemesAndroidprovidesseveralwaystoalterthestyleofviewsinyourapplication.We’llfirstcoverusingmarkuptagsinstringsandthenhowtouseSpannablestochangespecificvisualattributesoftext.Butwhatifyouwanttocontrolhowthingslookusingacommonspecificationforseveralviewsoracrossanentireactivityorapplication?We’lldiscussAndroidstylesandthemestoshowyouhow.

UsingStylesSometimes,youwanttohighlightorstyleaportionoftheView’scontent.Youcandothisstaticallyordynamically.Statically,youcanapplymarkupdirectlytothestringsinyourstringresources,asshownhere:

<stringname="styledText"><i>Static</i>styleina<b>TextView</b>.</string>

YoucanthenreferenceitinyourXMLorfromcode.NotethatyoucanusethefollowingHTMLtagswithstringresources:<i>,<b>,and<u>foritalics,bold,andunderlined,respectively,aswellas<sup>(superscript),<sub>(subscript),<strike>(strikethrough),<big>,<small>,and<monospace>.Youcanevennestthesetoget,forexample,smallsuperscripts.ThisworksnotjustinTextViewsbutalsoinotherviews,likebuttons.Figure5-2showswhatstyledandthemedtextlookslike,usingmanyoftheexamplesinthissection.

Page 163: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure5-2.Examplesofstylesandthemes

StylingaTextViewcontrol’scontentprogrammaticallyrequiresalittleadditionalworkbutallowsformuchmoreflexibility(seeListing5-2),becauseyoucanstyleitatruntime.ThisflexibilitycanonlybeappliedtoaSpannable,though,whichishowEditTextnormallymanagestheinternaltext,whereasTextViewdoesnotnormallyuseSpannable.SpannableisbasicallyaStringtowhichyoucanapplystyles.TogetaTextViewtostoretextasaSpannable,youcancallsetText()thisway:

tv.setText("ThistextisstoredinaSpannable",TextView.BufferType.SPANNABLE);

Then,whenyoucalltv.getText(),you’llgetaSpannable.

AsshowninListing5-2,youcangetthecontentoftheEditText(asaSpannableobject)andthensetstylesforportionsofthetext.Thecodeinthelistingsetsthetextstylingtoboldanditalicsandsetsthebackgroundtored.YoucanuseallthestylingoptionsaswehavewiththeHTMLtagsasdescribedpreviously,andthensome.

Listing5-2.ApplyingStylesDynamicallytotheContentofanEditText

Page 164: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

EditTextet=(EditText)this.findViewById(R.id.et);et.setText("StylingthecontentofanEditTextdynamically");Spannablespn=(Spannable)et.getText();spn.setSpan(newBackgroundColorSpan(Color.RED),0,7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);spn.setSpan(newStyleSpan(android.graphics.Typeface.BOLD_ITALIC),0,7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Thesetwotechniquesforstylingworkonlyontheoneviewthey’reappliedto.Androidprovidesastylemechanismtodefineacommonstyletobereusedacrossviews,aswellasathememechanism,whichbasicallyappliesastyletoanentireactivityortheentireapplication.Tobeginwith,weneedtotalkaboutstyles.

AstyleisacollectionofViewattributesthatisgivenanamesoyoucanrefertothatcollectionbyitsnameandassignthatstylebynametoviews.Forexample,Listing5-3showsaresourceXMLfile,savedin/res/values,thatwecoulduseforallerrormessages.

Listing5-3.DefiningaStyletoBeUsedAcrossManyViews

<?xmlversion="1.0"encoding="utf-8"?><resources><stylename="ErrorText"><itemname="android:layout_width">fill_parent</item><itemname="android:layout_height">wrap_content</item><itemname="android:textColor">#FF0000</item><itemname="android:typeface">monospace</item></style></resources>

Thesizeoftheviewisdefinedaswellasthefontcolor(red)andtypeface.NoticehowthenameattributeoftheitemtagistheXMLattributenameweusedinourlayoutXMLfiles,andthevalueoftheitemtagnolongerrequiresdoublequotes.WecannowusethisstyleforanerrorTextView,asshowninListing5-4.

Listing5-4.UsingaStyleinaView

<TextViewandroid:id="@+id/errorText"style="@style/ErrorText"android:text="Noerrorsatthistime"/>

ItisimportanttonotethattheattributenameforastyleinthisViewdefinitiondoesnotstartwithandroid:.Watchoutforthis,becauseeverythingseemstouseandroid:exceptthestyle.Whenyou’vegotmanyviewsinyourapplicationthatshareastyle,changingthatstyleinoneplaceismuchsimpler;youneedtomodifythestyle’sattributesonlyintheoneresourcefile.Youcan,ofcourse,createmanydifferentstylesforvarious

Page 165: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

controls.Buttonscouldshareacommonstyle,forexample,that’sdifferentfromthecommonstylefortextinmenus.

Onereallyniceaspectofstylesisthatyoucansetupahierarchyofthem.WecoulddefineanewstyleforreallybaderrormessagesandbaseitonthestyleofErrorText.Listing5-5showshowthismightlook.

Listing5-5.DefiningaStylefromaParentStyle

<?xmlversion="1.0"encoding="utf-8"?><resources><stylename="ErrorText.Danger"><itemname="android:textStyle">bold</item></style></resources>

Thisexampleshowsthatwecansimplynameourchildstyleusingtheparentstyleasaprefixtothenewstylename.Therefore,ErrorText.DangerisachildofErrorTextandinheritsthestyleattributesoftheparent.ItthenaddsanewattributefortextStyle.Thiscanberepeatedagainandagaintocreateawholetreeofstyles.

Aswasthecaseforadapterlayouts,Androidprovidesalargesetofstylesthatwecanuse.TospecifyanAndroid-providedstyle,usesyntaxlikethis:

style="@android:style/TextAppearance"

ThisstylesetsthedefaultstylefortextinAndroid.TolocatethemasterAndroidstyles.xmlfile,visittheAndroidSDK/platforms/<android-version>/data/res/values/folder.Insidethisfile,youwillfindquiteafewstylesthatareready-madeforyoutouseorextend.Here’sawordofcautionaboutextendingtheAndroid-providedstyles:thepreviousmethodofusingaprefixwon’tworkwithAndroid-providedstyles.Instead,youmustusetheparentattributeofthestyletag,likethis:

<stylename="CustomTextAppearance"parent="@android:style/TextAppearance"><item...yourextensionsgohere…/></style>

Youdon’talwayshavetopullinanentirestyleonyourview.Youcouldchoosetoborrowjustapartofthestyleinstead.Forexample,ifyouwanttosetthecolorofthetextinyourTextViewtoasystemstylecolor,youcoulddothefollowing:

<EditTextandroid:id="@+id/et2"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textColor="?android:textColorSecondary"android:text="@string/hello_world"/>

Noticethatinthisexample,thenameofthetextColorattributevaluestartswiththe?

Page 166: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

[email protected]?characterisusedsoAndroidknowstolookforastylevalueinthecurrenttheme.Becausewesee?android,welookintheAndroidsystemthemeforthisstylevalue.

UsingThemesOneproblemwithstylesisthatyouneedtoaddanattributespecificationofstyle=”@style/…”toeveryviewdefinitionthatyouwantittoapplyto.Ifyouhavesomestyleelementsyouwantappliedacrossanentireactivity,oracrossthewholeapplication,youshoulduseathemeinstead.Athemeisreallyjustastyleappliedbroadly;butintermsofdefiningatheme,it’sexactlylikeastyle.Infact,themesandstylesarefairlyinterchangeable:youcanextendathemeintoastyleorrefertoastyleasatheme.Typically,onlythenamesgiveahintastowhetherastyleisintendedtobeusedasastyleoratheme.

Tospecifyathemeforanactivityoranapplication,addanattributetothe<activity>or<application>tagintheAndroidManifest.xmlfileforyourproject.Thecodemightlooklikethis:

<activityandroid:theme="@style/MyActivityTheme"><applicationandroid:theme="@style/MyApplicationTheme"><applicationandroid:theme="@android:style/Theme.NoTitleBar">

YoucanfindtheAndroid-providedthemesinthesamefolderastheAndroid-providedstyles,withthethemesinafilecalledthemes.xml.Whenyoulookinsidethethemesfile,youwillseealargesetofstylesdefined,withnamesthatstartwithTheme.YouwillalsonoticethatwithintheAndroid-providedthemesandstyles,thereisalotofextendinggoingon,whichiswhyyouendupwithstylescalledTheme.Dialog.AppError,forexample.

ThisconcludesourdiscussionoftheAndroidcontrolset.Aswementionedinthebeginningofthechapter,buildingUIsinAndroidrequiresyoutomastertwothings:thecontrolsetandthelayoutmanagers.Inthenextsection,wearegoingtodiscusstheAndroidlayoutmanagers.

UnderstandingLayoutManagersAndroidoffersacollectionofviewclassesthatactascontainersforviews.Thesecontainerclassesarecalledlayouts(orlayoutmanagers),andeachimplementsaspecificstrategytomanagethesizeandpositionofitschildren.Forexample,theLinearLayoutclasslaysoutitschildreneitherhorizontallyorvertically,oneaftertheother.AlllayoutmanagersderivefromtheViewclass,thereforeyoucannestlayoutmanagersinsideofoneanother.

ThelayoutmanagersthatshipwiththeAndroidSDKincludethecommonlyusedonesdefinedinTable5-1.

Page 167: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Table5-1.AndroidLayoutManagers

LayoutManager Description

LinearLayout Organizesitschildreneitherhorizontallyorvertically

TableLayout Organizesitschildrenintabularform

RelativeLayout Organizesitschildrenrelativetooneanotherortotheparent

FrameLayout Allowsyoutodynamicallychangethecontrol(s)inthelayout

GridLayout Organizesitschildreninagridarrangement

Wewilldiscusstheselayoutmanagersinthesectionsthatfollow.ThelayoutmanagercalledAbsoluteLayouthasbeendeprecatedandwillnotbecoveredinthisbook.

TheLinearLayoutLayoutManagerTheLinearLayoutlayoutmanageristhemostbasic.Thislayoutmanagerorganizesitschildreneitherhorizontallyorverticallybasedonthevalueoftheorientationproperty.We’veusedLinearLayoutinseveralofourexamplessofar.Listing5-6showsLinearLayoutwithahorizontalconfiguration.

Listing5-6.LinearLayoutwithaHorizontalConfiguration

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content">

<!--addchildrenhere-->

</LinearLayout>

YoucancreateaverticallyorientedLinearLayoutbysettingthevalueoforientationtovertical.Becauselayoutmanagerscanbenested,youcould,forexample,constructaverticallayoutmanagerthatcontainedhorizontallayoutmanagerstocreateafill-inform,whereeachrowhadalabelnexttoanEditTextcontrol.Eachrowwouldbeitsownhorizontallayout,buttherowsasacollectionwouldbeorganizedvertically.

UnderstandingWeightandGravityTheorientationattributeisthefirstimportantattributerecognizedbytheLinearLayoutlayoutmanager.Otherimportantpropertiesthatcanaffectsizeandpositionofchildcontrolsareweightandgravity.

Page 168: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Youuseweighttoassignsizeimportancetoacontrolrelativetotheothercontrolsinthecontainer.Supposeacontainerhasthreecontrols:onehasaweightof1,whereastheothershaveaweightof0.Inthiscase,thecontrolwhoseweightequals1willconsumetheemptyspaceinthecontainer.Gravityisessentiallyalignment.Forexample,ifyouwanttoalignalabel’stexttotheright,youwouldsetitsgravitytoright.Therearequiteafewpossiblevaluesforgravity,includingleft,center,right,top,bottom,center_vertical,clip_horizontal,andothers.Seedeveloper.android.comfordetailsontheseandtheothervaluesofgravity.

NoteLayoutmanagersextendandroid.widget.ViewGroup,asdomanycontrol-basedcontainerclassessuchasListView.Althoughthelayoutmanagersandcontrol-basedcontainersextendthesameclass,thelayoutmanagerclasses,byconventionifnotstrictrequirement,dealwiththesizingandpositionofcontrolsandnotuserinteractionwithchildcontrols.

Nowlet’slookatanexampleinvolvingtheweightandgravityproperties(seeFigure5-3).

Figure5-3.UsingtheLinearLayoutlayoutmanager

Figure5-3showsthreeUIsthatutilizeLinearLayout,withdifferentweightandgravitysettings.TheUIontheleftusesthedefaultsettingsforweightandgravity.TheXMLlayoutforthisfirstUIisshowninListing5-7.

Listing5-7.ThreeTextFieldsArrangedVerticallyinaLinearLayout,UsingDefaultValuesforWeightandGravity

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<EditTextandroid:layout_width="fill_parent"

Page 169: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:layout_height="wrap_content"android:text="one"/><EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="two"/><EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="three"/></LinearLayout>

TheUIinthecenterofFigure5-3usesthedefaultvalueforweightbutsetsandroid:gravityforthecontrolsinthecontainertoleft,center,andright,respectively.Thelastexamplesetstheandroid:layout_weightattributeofthecentercomponentto1.0andleavestheotherstothedefaultvalueof0.0(seeListing5-8).Bysettingtheweightattributeto1.0forthemiddlecomponentandleavingtheweightattributesfortheothertwocomponentsat0.0,wearespecifyingthatthecentercomponentshouldtakeupalltheremainingwhitespaceinthecontainerandthattheothertwocomponentsshouldremainattheiridealsize.

Similarly,ifyouwanttwoofthethreecontrolsinthecontainertosharetheremainingwhitespaceamongthem,youwouldsettheweightto1.0forthosetwoandleavethethirdoneat0.0.Finally,ifyouwantthethreecomponentstosharethespaceequally,you’dsetalloftheirweightvaluesto1.0.Doingthiswouldexpandeachtextfieldequally.

Listing5-8.LinearLayoutwithWeightConfigurations

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<EditTextandroid:layout_width="fill_parent"android:layout_weight="0.0"android:layout_height="wrap_content"android:text="one"android:gravity="left"/>

<EditTextandroid:layout_width="fill_parent"android:layout_weight="1.0"android:layout_height="wrap_content"android:text="two"android:gravity="center"/>

<EditTextandroid:layout_width="fill_parent"android:layout_weight="0.0"android:layout_height="wrap_content"android:text="three"android:gravity="right"/></LinearLayout>

Page 170: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:gravityvs.android:layout_gravityNotethatAndroiddefinestwosimilargravityattributes:android:gravityandandroid:layout_gravity.Here’sthedifference:android:gravityisasettingusedbytheview,whereasandroid:layout_gravityisusedbythecontainer(android.view.ViewGroup).Forexample,youcansetandroid:gravitytocentertohavethetextintheEditTextcenteredwithinthecontrol.Similarly,youcanalignanEditTexttothefarrightofaLinearLayout(thecontainer)bysettingandroid:layout_gravity=“right”.SeeFigure5-4andListing5-9.

Figure5-4.Applyinggravitysettings

Listing5-9.UnderstandingtheDifferenceBetweenandroid:gravityandandroid:layout_gravity

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<EditTextandroid:layout_width="wrap_content"android:gravity="center"android:layout_height="wrap_content"android:text="one"android:layout_gravity="right"/></LinearLayout>

AsshowninFigure5-4,thetextiscenteredintheEditText,whichisalignedtotherightoftheLinearLayout.

TheTableLayoutLayoutManagerTheTableLayoutlayoutmanagerisanextensionofLinearLayout.Thislayoutmanagerstructuresitschildcontrolsintorowsandcolumns.Listing5-10showsanexample.

Listing5-10.ASimpleTableLayout

<?xmlversion="1.0"encoding="utf-8"?><TableLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent">

Page 171: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<TableRow><TextViewandroid:text="FirstName:"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<EditTextandroid:text="Edgar"android:layout_width="wrap_content"android:layout_height="wrap_content"/></TableRow>

<TableRow><TextViewandroid:text="LastName:"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<EditTextandroid:text="Poe"android:layout_width="wrap_content"android:layout_height="wrap_content"/></TableRow>

</TableLayout>

Tousethislayoutmanager,youcreateaninstanceofTableLayoutandplaceTableRowelementswithinit.TheseTableRowelementscontainthecontrolsofthetable.TheUIforListing5-10isshowninFigure5-5.

Figure5-5.TheTableLayoutlayoutmanager

ThereareanumberofmorecomplexlayoutspossiblewithTableLayout,includingnesting,asymmetricalrowsandcolumns,andmore.WehaveabonussectiononmoreoptionsforTableLayoutonthebookwebsite,www.androidbook.com.

TheRelativeLayoutLayoutManagerAnotherinterestinglayoutmanagerisRelativeLayout.Asthenamesuggests,thislayoutmanagerimplementsapolicywherethecontrolsinthecontainerarelaidoutrelativetoeitherthecontaineroranothercontrolinthecontainer.Listing5-11andFigure5-6showanexample.

Page 172: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing5-11.UsingaRelativeLayoutLayoutManager

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content">

<TextViewandroid:id="@+id/userNameLbl"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Username:"android:layout_alignParentTop="true"/>

<EditTextandroid:id="@+id/userNameText"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_toRightOf="@id/userNameLbl"/>

<TextViewandroid:id="@+id/pwdLbl"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/userNameText"android:text="Password:"/>

<EditTextandroid:id="@+id/pwdText"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_toRightOf="@id/pwdLbl"android:layout_below="@id/userNameText"/>

<TextViewandroid:id="@+id/pwdCriteria"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@id/pwdText"android:text="PasswordCriteria…"/>

<TextViewandroid:id="@+id/disclaimerLbl"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="Useatyourownrisk…"/>

</RelativeLayout>

Page 173: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure5-6.AUIlaidoutusingtheRelativeLayoutlayoutmanager

Asshown,theUIlookslikeasimpleloginform.Theusernamelabelispinnedtothetopofthecontainer,becausewesetandroid:layout_alignParentToptotrue.Similarly,theUsernameinputfieldispositionedbelowtheUsernamelabelbecausewesetandroid:layout_below.ThePasswordlabelappearsbelowtheUsernamelabel,andthePasswordinputfieldappearsbelowthePasswordlabel.Thedisclaimerlabelispinnedtothebottomofthecontainerbecausewesetandroid:layout_alignParentBottomtotrue.

Besidesthesethreelayoutattributes,youcanalsospecifylayout_above,layout_toRightOf,layout_toLeftOf,layout_centerInParent,andseveralmore.WorkingwithRelativeLayoutisfunduetoitssimplicity.Infact,onceyoustartusingit,it’llbecomeyourfavoritelayoutmanager—you’llfindyourselfgoingbacktoitoverandoveragain.

TheFrameLayoutLayoutManagerThelayoutmanagersthatwe’vediscussedsofarimplementvariouslayoutstrategies.Inotherwords,eachonehasaspecificwaythatitpositionsandorientsitschildrenonthescreen.Withtheselayoutmanagers,youcanhavemanycontrolsonthescreenatonetime,eachtakingupaportionofthescreen.Androidalsooffersalayoutmanagerthatismainlyusedtodisplayasingleitem:FrameLayout.Youmainlyusethisutilitylayoutclasstodynamicallydisplayasingleview,butyoucanpopulateitwithmanyitems,settingonetovisiblewhiletheothersareinvisible.Listing5-12demonstratesusingFrameLayout.

Listing5-12.PopulatingFrameLayout

<?xmlversion="1.0"encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/frmLayout"android:layout_width="fill_parent"android:layout_height="fill_parent">

<ImageView

Page 174: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:id="@+id/oneImgView"android:src="@drawable/one"android:scaleType="fitCenter"android:layout_width="fill_parent"android:layout_height="fill_parent"/><ImageViewandroid:id="@+id/twoImgView"android:src="@drawable/two"android:scaleType="fitCenter"android:layout_width="fill_parent"android:layout_height="fill_parent"android:visibility="gone"/>

</FrameLayout>

publicclassFrameLayoutActivityextendsActivity{privateImageViewone=null;privateImageViewtwo=null;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.listing6_48);

one=(ImageView)findViewById(R.id.oneImgView);two=(ImageView)findViewById(R.id.twoImgView);

one.setOnClickListener(newOnClickListener(){

publicvoidonClick(Viewview){two.setVisibility(View.VISIBLE);

view.setVisibility(View.GONE);}});

two.setOnClickListener(newOnClickListener(){

publicvoidonClick(Viewview){one.setVisibility(View.VISIBLE);

view.setVisibility(View.GONE);}});}}

Listing5-12showsthelayoutfileaswellastheonCreate()methodoftheactivity.TheideaofthedemonstrationistoloadtwoImageViewobjectsintheFrameLayout,withonlyoneoftheImageViewobjectsvisibleatatime.IntheUI,whentheuserclicksthevisibleimage,wehideoneimageandshowtheotherone.

LookatListing5-12morecloselynow,startingwiththelayout.Youcanseethatwe

Page 175: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

defineaFrameLayoutwithtwoImageViewobjects(anImageViewisacontrolthatknowshowtodisplayimages).NoticethatthesecondImageView’svisibilityissettogone,makingthecontrolinvisible.Now,lookattheonCreate()method.IntheonCreate()method,weregisterlistenerstoclickeventsontheImageViewobjects.Intheclickhandler,wehideoneImageViewandshowtheother.

Aswesaidearlier,yougenerallyuseFrameLayoutwhenyouneedtodynamicallysetthecontentofaviewtoasinglecontrol.Althoughthisisthegeneralpractice,thecontrolwillacceptmanychildren,aswedemonstrated.Listing5-12addstwocontrolstothelayoutbuthasoneofthecontrolsvisibleatatime.FrameLayout,however,doesnotforceyoutohaveonlyonecontrolvisibleatatime.Ifyouaddmanycontrolstothelayout,FrameLayoutwillsimplystackthecontrols,oneontopoftheother,withthelastoneontop.ThiscancreateaninterestingUI.Forexample,Figure5-7showsaFrameLayoutcontrolwithtwoImageViewobjectsthatarevisible.Youcanseethatthecontrolsarestacked,andthatthetoponeispartiallycoveringtheimagebehindit.

Figure5-7.FrameLayoutwithtwoImageViewobjects

AnotherinterestingaspectoftheFrameLayoutisthatifyouaddmorethanonecontroltothelayout,thesizeofthelayoutiscomputedasthesizeofthelargestiteminthecontainer.InFigure5-7,thetopimageisactuallymuchsmallerthantheimagebehindit,

Page 176: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

butbecausethesizeofthelayoutiscomputedbasedonthelargestcontrol,theimageontopisstretched.AlsonotethatifyouputmanycontrolsinsideaFrameLayoutwithoneormoreoftheminvisibletostart,youmightwanttoconsiderusingsetMeasureAllChildren(true)onyourFrameLayout.Becausethelargestchilddictatesthelayoutsize,you’llhaveaproblemifthelargestchildisinvisibletobeginwith:whenitbecomesvisible,itisonlypartiallyvisible.Toensurethatallitemsarerenderedproperly,callsetMeasureAllChildren()andpassitavalueoftrue.TheequivalentXMLattributeforFrameLayoutisandroid:measureAllChildren=“true”.

TheGridLayoutLayoutManagerAndroid4.0broughtwithitanewlayoutmanagercalledGridLayout.Asyoumightexpect,itlaysoutviewsinagridpatternofrowsandcolumns,somewhatlikeTableLayout.However,it’seasiertousethanTableLayout.WithaGridLayout,youcanspecifyarowandcolumnvalueforaview,andthat’swhereitgoesinthegrid.Thismeansyoudon’tneedtospecifyaviewforeverycell,justthosethatyouwanttoholdaview.Viewscanspanmultiplegridcells.Youcanevenputmorethanoneviewintothesamegridcell.

Whenlayingoutviews,youmustnotusetheweightattribute,becauseitdoesnotworkinchildviewsofaGridLayout.Youcanusethelayout_gravityattributeinstead.OtherinterestingattributesyoucanusewithGridLayoutchildviewsincludelayout_columnandlayout_columnSpantospecifytheleft-mostcolumnandthenumberofcolumnstheviewtakesup,respectively.Similarly,therearelayout_rowandlayout_rowSpanattributes.Interestingly,youdonotneedtospecifylayout_heightandlayout_widthforGridLayoutchildviews;theydefaulttoWRAP_CONTENT.

CustomizingtheLayoutforVariousDeviceConfigurationsBynow,youknowverywellthatAndroidoffersahostoflayoutmanagersthathelpyoubuildUIs.Ifyou’veplayedaroundwiththelayoutmanagerswe’vediscussed,youknowthatyoucancombinethelayoutmanagersinvariouswaystoobtainthelookandfeelyouwant.Butevenwithallthelayoutmanagers,buildingUIs—andgettingthemright—canbeachallenge.Thisisespeciallytrueformobiledevices.Usersandmanufacturersofmobiledevicesaregettingmoreandmoresophisticated,andthatmakesthedeveloper’sjobevenmorechallenging.

OneofthechallengesisbuildingaUIforanapplicationthatdisplaysinvariousscreenconfigurations.Forexample,whatwouldyourUIlooklikeifyourapplicationweredisplayedinportraitversuslandscapemode?Ifyouhaven’trunintothisyet,yourmindisprobablyracingrightnow,wonderinghowtodealwiththiscommonscenario.

Page 177: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Interestingly,andfortunately,Androidprovidessomesupportforthisusecase.

Here’showitworks:whenbuildingalayout,Androidwillfindandloadlayoutsfromspecificfoldersbasedontheconfigurationofthedevice.Adevicecanbeinoneofthreeconfigurations:portrait,landscape,orsquare(squareisrare).Toprovidedifferentlayoutsforthevariousconfigurations,youhavetocreatespecificfoldersforeachconfigurationfromwhichAndroidwillloadtheappropriatelayout.Asyouknow,thedefaultlayoutfolderislocatedatres/layout.Tosupportportraitdisplay,createafoldercalledres/layout-port.Forlandscape,createafoldercalledres/layout-land.Andforasquare,createonecalledres/layout-square.

Agoodquestionatthispointis,“Withthesethreefolders,doIneedthedefaultlayoutfolder(res/layout)?”Generally,yes.Android’sresource-resolutionlogiclooksintheconfiguration-specificdirectoryfirst.IfAndroiddoesn’tfindaresourcethere,itgoestothedefaultlayoutdirectory.Therefore,youshouldplacedefaultlayoutdefinitionsinres/layoutandthecustomizedversionsintheconfiguration-specificfolders.

Anothertrickistousethe<include/>taginalayoutfile.Thisallowsyoutocreatecommonchunksoflayoutcode(forexample,inthedefaultlayoutdirectory)andincludetheminlayoutsdefinedinlayout-portandlayout-land.Anincludetagmightlooklikethis:

<includelayout="@layout/common_chunk1"/>

Iftheconceptofincludeinterestsyou,youshouldalsocheckoutthe<merge/>tagandtheViewStubclassintheAndroidAPI.Thesegiveyouevenmoreflexibilitywhenorganizinglayouts,withoutduplicatingviews.

NotethattheAndroidSDKdoesnotofferanyAPIsforyoutoprogrammaticallyspecifywhichconfigurationtoload—thesystemsimplyselectsthefolderbasedontheconfigurationofthedevice.Youcan,however,settheorientationofthedeviceincode,forexample,usingthefollowing:

importandroid.content.pm.ActivityInfo;...setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Thisforcesyourapplicationtoappearonthedeviceinlandscapemode.Goaheadandtryitinoneofyourearlierprojects.AddthecodetoyouronCreate()methodofanactivity,runitintheemulator,andseeyourapplicationsideways.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedaboutbuildinguserinterfaces:

Themaintypesoflayoutsandwhentouseeach

ViewssupportedinAndroidandhowtodefinethembothinXML

Page 178: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

andviacode

Stylesandthemesyoucanusetomanagethelookandfeelofyourapplicationfromacommonsetofresources

Page 179: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter6

WorkingwithMenusandActionBarsAndroidSDKsupportsregularmenus,submenus,contextmenus,iconmenus,andsecondarymenus.Android3.0introducedtheactionbar,whichintegrateswellwithmenus.Wewillcoverbothmenusandactionbarsinthischapter.

Likemanyotherchaptersinthebook,wewillpresenttheessentialcodesnippetsthatyoucanusetoworkwithmenusandactionbars.Thecompletercodecontextforthesesnippetsisavailableinthedownloadableapplicationthatisspecificallydevelopedforthischapter.Thelinkforthesedownloadableprojectsisgiveninthe“Resources”sectionattheendofthischapter.

WorkingwithMenusThroughXMLFilesInAndroidtheeasiestwaytoworkwithmenusisthroughXMLmenuresourcefiles.ThisXMLapproachtomenucreationoffersseveraladvantages,suchastheabilitytonamemenus,orderthemautomatically,andallocateIDs.AsXMLmenusareresources,youalsogetthelocalizationsupportforthemenutextandicons.

CreatingXMLMenuResourceFilesAsamplemenuXMLfileisgivenListing6-1.YouseeinthislistingaseriesofmenuitemsgroupedtogetherunderagroupXMLnode.YoucanspecifyanIDforthegroupusingthe@+idresourcereferenceapproach.YoucanusethisIDinjavacodetogetaccesstothemenugroupandmanageitwhenneeded.GroupingisoptionalandyoucanomitthegroupXMLnode.

EachmenuXMLfilehasaseriesofmenuitemswiththeirmenuitemIDstiedtosymbolicnames.Thetitleindicatesthemenutitle,andtheorderInCategoryindicatestheorderinwhichthemenuitemappearsinthemenu.YoucanrefertotheAndroidSDKdocumentationforallthepossibleattributesfortheseXMLtags.ThereferenceURLisprovidedinthe“Resources”sectionofthischapter.

Listing6-1.MenuXMLResourceFilewithMenuDefinitions

<menuxmlns:android="http://schemas.android.com/apk/res/android"><groupandroid:id="@+id/menuGroup_Main">

<itemandroid:id="@+id/menu_item1"

android:orderInCategory="1"android:title="item1text"/><itemandroid:id="@+id/menu_item2"

android:orderInCategory="2"android:enabled="true"

Page 180: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:icon="@drawable/some-file"android:title="item2text"/><itemandroid:id="@+id/menu_item3"

android:orderInCategory="3"android:title="item3text"/></group></menu>

AllthechildmenuitemsinListing6-1areallocatedmenuitemIDsbasedontheirnames(example:menu_item1)inthisXMLfile.Let’sseenowhowwetakethismenuXMLfileandassociateitwithanactivity.

PopulatingActivityMenufromMenuXMLFilesAssumethatthenameofthemenuXMLfileismy_menu.xml.Youneedtoplacethisfileinthe/res/menusubdirectory.Placingthefilein/res/menuautomaticallygeneratesaresourceIDcalledR.menu.my_menu.

ThekeyclassinAndroidmenusupportisandroid.view.Menu.EveryactivityinAndroidisassociatedwithonemenuobjectofthistype.InthelifecycleofanactivityAndroidcallsamethodcalledonCreateOptionsMenu()topopulatethisMenuobject.InthismethodweloadtheXMLmenufileintotheMenuobject.ThisisshowninListing6-2.

Listing6-2.UsingMenuInflater

//Thiscallbackmethodisavailableoneveryactivityclass@OverridepublicbooleanonCreateOptionsMenu(Menumenu){super.onCreateOptionsMenu(menu);MenuInflaterinflater=getMenuInflater();//fromactivityinflater.inflate(R.menu.my_menu,menu);

//Itisimportanttoreturntruetoseethemenureturntrue;

}

Oncethemenuitemsarepopulated,thecodeshouldreturntruetomakethemenuvisible.Ifthismethodreturnsfalse,themenuisinvisible.

RespondingtoXML-BasedMenuItemsYourespondtomenuitemsintheonOptionsItemSelected()callbackmethod.AndroidnotonlygeneratesaresourceIDfortheXMLmenufile(asusedinListing6-2)butalsogeneratesthenecessarymenuitemIDstohelpyoudistinguishbetweenthemenuitems.ThecodeinListing6-3illustrateshowtorespondtomenuitems.

Page 181: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing6-3.RespondingtoMenuItemsfromanXMLMenuResourceFile

@OverridepublicvoidonOptionsItemSelected(MenuItemitem){if(item.getItemId()==R.id.menu_item1){

//dosomething//foritemshandledreturntrue;}elseif(item.getItemId()==R.id.menu_item2){

//dosomethingreturntrue;}//fortherest...returnsuper.onOptionsItemSelected(item);}

NoticehowthemenuitemnamesfromtheXMLmenuresourcefilehaveautomaticallygeneratedmenuitemIDsintheR.idspace.

StartinginSDK3.0,youcanalsousetheandroid:onClickattributeofamenuitemtodirectlyindicatethenameofamethodinanactivitythatisattachedtothismenu.Thisactivitymethodisthencalledwiththemenuitemobjectasthesoleinput.Thisfeatureisonlyavailablein3.0andabove.Listing6-4showsanexample.

Listing6-4.SpecifyingaMenuCallbackMethodinanXMLMenuResourceFile

<itemandroid:id="..."android:onClick="a-method-name-in-your-activity"...</item>

ItisthissimpletoworkwithmenuitemsinAndroid.Let’sexploretheJavaAPIforthemenusabitnow.

WorkingwithMenusinJavaCodeAsindicatedthekeyclassinAndroidmenusupportisandroid.view.Menu.EveryactivityinAndroidisassociatedwithonemenuobjectofthistype.Themenuobjectthencontainsanumberofmenuitemsandsubmenus.Menuitemsarerepresentedbyandroid.view.MenuItem.Submenusarerepresentedbyandroid.view.SubMenu.

PriortoSDK3.0,onCreateOptionsMenu()iscalledthefirsttimeanactivity’soptionsmenuisaccessed.Startingwith3.0,thismethodiscalledaspartofactivitycreation.Alsonotethatthismethodiscalledonlyonceforthelifecycleoftheactivity.IfyouwanttoaddmenusdynamicallyyouwillneedtousethemethodonPrepareOptionsMenu(),whichiscoveredalittlelater.ThecodeinListing6-5

Page 182: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

showshowtoaddthreemenuitemsusingasinglegroupIDalongwithincrementalmenuitemIDsandorderIDs.

Listing6-5.AddingMenuItems

@OverridepublicbooleanonCreateOptionsMenu(Menumenu){super.onCreateOptionsMenu(menu);menu.add(0//Group,1//itemid,0//order,"item1");//title

menu.add(0,2,1,"item2");menu.add(0,3,2,"item3");//Itisimportanttoreturntruetoseethemenureturntrue;}

Youshouldalsocallthebase-classimplementationofthismethodtogivethesystemanopportunitytopopulatethemenuwithsystemmenuitems(nosystemmenuitemsaredefinedsofar).

TheargumentstocreatethemenuitemareexplainedinListing6-5.Thelastargumentisthenameortitleofthemenuitem.Insteadoffreetext,youcanuseastringresourcethroughtheR.javaconstantsfile.Thegroup,menuitem,andorderIDsarealloptional;youcanuseMenu.NONEifyoudon’twanttospecifyanyofthem.IfMenu.NONEisspecifiedforagroup,thentheitemsareoutsideofanygroup.IfMenu.NONEisspecifiedforanitem,thenthismightbeasubmenuoraseparator.IfMenu.NONEisspecifiedfortheorder,Androidwillchoosesomemechanismtoorderthem.

WorkingwithMenuGroupsNow,let’slookathowtoworkwithmenugroups.Listing6-6showshowyouaddtwogroupsofmenus:Group1andGroup2.

Listing6-6.UsingGroupIDstoCreateMenuGroups

@OverridepublicbooleanonCreateOptionsMenu(Menumenu){//Group1intgroup1=1;menu.add(group1,1,1,"g1.item1");menu.add(group1,2,2,"g1.item2");

//Group2intgroup2=2;menu.add(group2,3,3,"g2.item1");menu.add(group2,4,4,"g2.item2");

Page 183: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returntrue;//itisimportanttoreturntrue}

Androidprovidesasetofmethodsontheandroid.view.MenuclassthatarebasedongroupIDs.Youcanmanipulateagroup’smenuitemsusingthemethodsshowninListing6-7:

Listing6-7.MenuGroup–RelatedMethods

removeGroup(id)setGroupCheckable(id,checkable,exclusive)setGroupEnabled(id,enabled)setGroupVisible(id,visible)

removeGroup()removesallmenuitemsfromthatgroup,giventhegroupID.YoucanenableordisablemenuitemsinagivengroupusingthesetGroupEnabledmethod().Similarly,youcancontrolthevisibilityofagroupofmenuitemsusingsetGroupVisible().

setGroupCheckable()isinteresting.Youcanusethismethodtoshowacheckmarkonamenuitemwhenthatmenuitemisselected.Whenappliedtoagroup,itenablesthisfunctionalityforallmenuitemswithinthatgroup.Ifthismethod’sexclusiveflagisset,onlyonemenuitemwithinthatgroupisallowedtogointoacheckedstate.Theothermenuitemsremainunchecked.

Younowknowhowtopopulateanactivity’smainmenuwithasetofmenuitemsandgroupthemaccordingtotheirnature.ThewayyourespondtothesemenuitemsisidenticaltohowyouwouldhaverespondedtofortheirXMLcounterpartsexceptthatthemenuitemsIDsareexplicitlycontrolledbytheprogrammer.

RespondingtoMenuItemsThroughListenersYouusuallyrespondtomenusbyoverridingonOptionsItemSelected();amenuitemalsoallowsyoutoregisteralistenerthatcouldbeusedasacallback.Thisapproachisatwo-stepprocess.Inthefirststep,youimplementtheMenuItem.OnMenuItemClickListenerinterface.Then,youtakeaninstanceofthisimplementationandpassittothemenuitem.Whenthemenuitemisclicked,themenuitemcallstheonMenuItemClick()methodoftheMenuItem.OnMenuItemClickListenerinterface(seeListing6-8).

Listing6-8.UsingaListenerasaCallbackforaMenuItemClick

//Step1publicclassMyResponseimplementsMenuItem.OnMenuItemClickListener{publicMyResponse(...someargs…){}//aconstructor@overridepublicbooleanOnMenuItemClick(MenuItemitem){

Page 184: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//doyourthingreturntrue;}}

//Step2MyResponsemyResponse=newMyResponse(..yourargs..);//supplyyourargsmenuItem.setOnMenuItemClickListener(myResponse);...

TheonMenuItemClick()methodiscalledwhenthemenuitemhasbeeninvoked.Thiscodeexecutesassoonasthemenuitemisclicked,evenbeforetheonOptionsItemSelected()methodiscalled.IfonMenuItemClick()returnstrue,noothercallbacksareexecuted—includingtheonOptionsItemSelected()callbackmethod.ThismeansthatthelistenercodetakesprecedenceovertheonOptionsItemSelected()method.

UsinganIntenttoRespondtoMenuItemsYoucanalsoassociateamenuitemwithanintentbyusingtheMenuItem’smethodsetIntent(intent).Whenanintentisassociatedwithamenuitem,andnothingelsehandlesthemenuitem,thenthedefaultbehavioristoinvoketheintentusingstartActivity(intent).Forthistowork,allthehandlers—especiallytheonOptionsItemSelected()method—shouldcalltheparentclass’sonOptionsItemSelected()methodforthosemenuitemsthatarenothandled.

UnderstandingExpandedMenusIfanapplicationhasmoremenuitemsthanitcandisplayonthemainscreen,AndroidshowsaMoremenuitemtoallowtheusertoseetherest.Thismenu,calledanexpandedmenu,appearsautomaticallywhentherearetoomanymenuitemstodisplayinthelimitedamountofspace.

WorkingwithIconMenusAndroidsupportsnotonlytextbutalsoimagesoriconsaspartofitsmenurepertoire.Creatinganiconmenuitemisstraightforward.Youcreatearegulartext-basedmenuitemasbefore,andthenyouusethesetIcon()methodontheMenuItemclasstosettheimage.Youneedtousetheimage’sresourceID,soyoumustgenerateitfirstbyplacingtheimageoriconinthe/res/drawabledirectory.Forexample,iftheicon’sfilenameisballoons,thentheresourceIDisR.drawable.balloons.Listing6-9demonstrateshowtoaddanicontoamenuitem.

Listing6-9.AttachinganIcontoaMenuItem

Page 185: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//addamenuitemandrememberitsothatyoucanuseit//subsequentlytosettheicononit.MenuItemitem=menu.add(...);//supplythemenuitemdetailsitem.setIcon(R.drawable.balloons);

Theiconshowsaslongasthemenuitemisdisplayedonthemainapplicationscreen.Ifit’sdisplayedaspartoftheexpandedmenu,theicondoesn’tshow,justthetext.ThereisanicontagavailableaswelltoindicatetheiconinanXMLmenuresourcefile.ThereareconditionsunderwhichAndroidmaychoosenottoshowtheiconsandrecommendsthattextisalwaysprovided.

WorkingwithSubmenusAMenuobjectcanhavemultipleSubMenuobjects.EachSubMenuobjectisaddedtotheMenuobjectthroughacalltotheMenu.addSubMenu()method(seeListing6-10).Youaddmenuitemstoasubmenuthesamewaythatyouaddmenuitemstoamenu.ThisisbecauseSubMenuisalsoderivedfromaMenuobject.However,youcannotaddadditionalsubmenustoasubmenu.

Listing6-10.AddingSubmenus

privatevoidaddSubMenu(Menumenu){//Secondaryitemsareshownjustlikeeverythingelseintbase=Menu.FIRST+100;SubMenusm=menu.addSubMenu(base,base+1,Menu.NONE,"submenu");sm.add(base,base+2,base+2,"subitem1");sm.add(base,base+3,base+3,"subitem2");sm.add(base,base+4,base+4,"subitem3");

//thefollowingisoksm.setIcon(R.drawable.icon48x48_1);

//Thiswillresultinruntimeexception//sm.addSubMenu("trythis");}

NoteSubMenu,asasubclassoftheMenuobject,continuestocarrytheaddSubMenu()method.Thecompilerwon’tcomplainifyouaddasubmenutoanothersubmenu,butyou’llgetaruntimeexceptionifyoutrytodoit.

TheAndroidSDKdocumentationalsosuggeststhatsubmenusdonotsupporticonmenuitems.Whenyouaddanicontoamenuitemandthenaddthatmenuitemtoasubmenu,themenuitemignoresthaticon,evenifyoudon’tseeacompile-timeorruntimeerror.However,thesubmenuitselfcanhaveanicon.

Page 186: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WorkingwithContextMenusAndroidsupportstheideaofcontextmenusthroughanactioncalledalongclick.AlongclickisalongpresshelddownslightlylongerthanusualonanyAndroidview.Anactivityownsaregularoptionsmenu,whereasaviewownsacontextmenu.Thisistobeexpected,becausethelongclicksthatactivatecontextmenusapplytotheviewbeingclicked.Soanactivitycanhaveonlyoneoptionsmenubutmanycontextmenus.

RegisteringaViewforaContextMenuThefirststepinimplementingacontextmenuistoregisteraviewforthecontextmenuinanactivity’sonCreate()method.YoucanregisteraTextViewforacontextmenubyusingthecodeinListing6-11.YoufirstfindtheTextViewandthencallregisterForContextMenu()ontheactivityusingtheTextViewasanargument.ThissetsuptheTextViewforcontextmenus.

Listing6-11.RegisteringaTextViewforaContextMenu

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

TextViewtv=(TextView)this.findViewById(R.id.textViewId);registerForContextMenu(tv);}

PopulatingaContextMenuOnceaviewliketheTextViewinthisexampleisregisteredforcontextmenus,AndroidcallstheonCreateContextMenu()methodwiththisviewastheargument.Thisiswhereyoucanpopulatethecontextmenuitemsforthatcontextmenu.TheonCreateContextMenu()callbackmethodprovidesthreeargumentstoworkwith.Listing6-12demonstratestheonCreateContextMenu()method.

Listing6-12.TheonCreateContextMenu()Method

@OverridepublicvoidonCreateContextMenu(ContextMenumenu,Viewv,ContextMenuInfomenuInfo){menu.setHeaderTitle("SampleContextMenu");menu.add(200,200,200,"item1");}

ThefirstargumentisapreconstructedContextMenuobject,thesecondistheview

Page 187: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(suchastheTextView)thatgeneratedthecallback,andthethirdistheContextMenuInfoclass.Foralotofsimplecases,youcanjustignoretheContextMenuInfoobject.However,someviewsmaypassextrainformationthroughthisobject.Inthosecases,youneedtocasttheContextMenuInfoclasstoasubclassandthenusetheadditionalmethodstoretrievetheadditionalinformation.

SomeexamplesofclassesderivedfromContextMenuInfoincludeAdapterContextMenuInfoandExpandableListContextMenuInfo.ViewsthatareAdapterViewssuchastheListViewinAndroidusetheAdapterContextMenuInfoclasstopasstherowIDwithinthatviewforwhichthecontextmenuisbeingdisplayed.Inasense,youcanusethisclasstofurtherclarifytheobjectunderneaththetouchortheclick,evenwithinagivencompositeview.

RespondingtoContextMenuItemsAndroidprovidesacallbackmethodsimilartoonOptionsItemSelected()calledonContextItemSelected().Listing6-13demonstratesonContextItemSelected().

Listing6-13.RespondingtoContextMenus

//Thismethodisavailableforallactivities@OverridepublicbooleanonContextItemSelected(MenuItemitem){if(item.getItemId()==some-menu-item-id){//handlethismenuitemreturntrue;}...otherexceptionprocessing}

IncorporatingDynamicMenusSofar,we’vetalkedaboutstaticmenus—yousetthemuponce,andtheydon’tchangedynamicallyaccordingtowhat’sonscreen.Ifyouwanttocreatedynamicmenus,usetheonPrepareOptionsMenu()methodthatAndroidprovidesonanactivityclass.ThismethodresemblesonCreateOptionsMenu()exceptthatitiscalledeverytimeamenuisdisplayedpriortodisplaying.YoushoulduseonPrepareOptionsMenu()alongwiththeonCreateOptionsMenu()toeffectivelymanageyourmenuifithasdynamicmenuoptions.onPrepareOptionMenu()iswhereyouwanttoenableordisablesomemenuitemsormenugroupsbasedonwhatyouaredisplaying.For3.0andabovewhenyouwanttochangeamenu,becauseamenu-relatedcomponentliketheactionbarisalwaysdisplayed,youhavetoexplicitlycallanewprovisionedmethodcalledActivity.invalidateOptionsMenu(),whichinturninvokestheonCreateOptionsMenu()andredrawsthemenuandtherebyalsoresultsincallingonPrepareOptionsMenu()priortothedisplay.Youcancallthismethodanytime

Page 188: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

somethingchangesinyourapplicationstatethatwouldrequireachangetothemenu.

WorkingwithPop-upMenusAndroid3.0introducedanothertypeofmenucalledapop-upmenu.SDK4.0enhancedthisslightlybyaddingacoupleofutilitymethods(forexample,PopupMenu.inflate)tothePopupMenuclass.(SeethePopupMenuAPIdocumentationtolearnaboutthesemethods.Listing6-14alsodrawsattentiontothisdifference.)

Apop-upmenucanbeinvokedagainstanyviewinresponsetoanyUIevent.AnexampleofaUIeventisabuttonclickoraclickonanimageview.Figure6-1showsapop-upmenuinvokedagainstaview.

Figure6-1.Pop-upmenuattachedtoatextview

Tocreateapop-upmenuliketheoneinFigure6-1,startwitharegularXMLmenufileandusetheJavacodeinListing6-14toloadthismenuXMLasapop-upmenu.Seethedownloadableprojectforthischapterifyouwanttoseethefullimplementation.

Listing6-14.WorkingwithaPop-upMenu

//Otheractivitycodegoeshere…//InvokethefollowingmethodtoshowapopupmenuprivatevoidshowPopupMenu(){//GetholdofaviewtoanchorthepopupTextViewtv=findViewById(R.id.SOME_TEXT_VIEW_ID);

Page 189: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//instantiateapopupmenu.var"this"standsforactivityPopupMenupopup=newPopupMenu(this,tv);

//thefollowingcodefor3.0sdk//popup.getMenuInflater().inflate(R.menu.popup_menu,popup.getMenu());//Orinsdk4.0andabovepopup.inflate(R.menu.popup_menu);popup.setOnMenuItemClickListener(newPopupMenu.OnMenuItemClickListener(){publicbooleanonMenuItemClick(MenuItemitem){//dosomethingherereturntrue;}});popup.show();}

Asyoucansee,apop-upmenubehavesmuchlikeanoptionsmenu.Thekeydifferencesareasfollows:

Apop-upmenuisusedondemand,whereasanoptionsmenuisalwaysavailable.

Apop-upmenuisanchoredtoaview,whereasanoptionsmenubelongstotheentireactivity.

Apop-upmenuusesitsownmenuitemcallback,whereastheoptionsmenuusestheonOptionsItemSelected()callbackontheactivity.

ExploringActionBarsIntroducedinAndroid3.0andexpandedinAndroid4.0,anActionBarextendsthereachofmenusintothetitlebarofanactivity.Thisallowsfrequentlyusedactionseasilyavailabletotheuserwithoutsearchingthroughoptionmenusorcontextmenus.Inadditiontoiconsandmenuitems,anactionbarcanaccommodateotherviewssuchastabs,oralist,orasearchboxtohelpwithnavigation.Figure6-2showsanactionbarintabbednavigationmode.

Figure6-2.Anactivitywithatabbedactionbar

Page 190: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Youcanseethevariouspartsofanactionbarhere.TheiconatupperleftontheactionbariscalledaHomeicon.ClickingthisHomeiconsendsacallbacktotheoptionmenuwithmenuIDandroid.R.id.home.Followedbythehomeiconisthetitleareaforthisactivity.Thenyouseeasetoftabs(oradrop-downlistifthisweretobealist-basedactionbar).Inthemiddle,youseesearchview.Towardstheend,youseeasetofactionicons.Thelastpartofthisactionbarisadottedverticallinerepresentingthemenuforthisactivity.Whenyouclickonthaticon,astandarddrop-downmenuwillappear(SeeFigure6-3).

TheactionbaryouseeinFigure6-1isatabbedactionbar.Thetwoothermodesofanactionbarareastandardandalist.Inalistactionbar,thetabsarereplacedbyadrop-downlist.Inastandardactionbar,thereisnoareasetasideforalistortabs.Now,let’sshowyouhowtoimplementasimplestandardactionbar.

ImplementingaStandardActionBarListing6-15presentssamplesourcecodeforimplementingastandardnavigationactionbarforanactivity.

Listing6-15.StandardNavigationActionBarActivity

publicclassStandardNavigationActionBarActivityextendsActivity{//.....othercode@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

ActionBarbar=this.getActionBar();bar.setTitle("Sometitleofyourchoosing");bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);}publicbooleanonCreateOptionsMenu(MenumainMenu){//loadthemenuxmlfileintothemainMenuobjectasusualherereturntrue;}}

AsyoucanseefromListing6-15,itiseasytoworkwithanactionbar.NoticeinthatlistinghowwehaveusedthegetActionBar()togetaccesstotheactionbarobjectandthensetitstitleandnavigationmode.AnymenuyousetintheonCreateOptionsMenu()canbeinvokeddirectlyfromtheactionbarasshowninFigure6-3.(However,whenamenuispresentedinthisfashionfromanactionbar,duetospacelimitations,thesystemmaynotshowtheiconsalongwithmenutext.)

Page 191: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure6-3.Anactivitywithanactionbarandexpandedmenu

Withtheintroductionofactionbar,themenuXMLfileisenhancedwithnewattributestoindicatesomemenuitemstobeshownintheactionbardirectlyasicons.(YoucanseetheseiconsinactionbarabovetheexpandedmenuinFigure6-3).TheXMLmenufileexampleinListing6-16demonstrateshowamenuitemcanbespecifiedtobecomeanicondirectlyontheactionbar.

Listing6-16.MenuXMLFileforThisProject

<!--/res/menu/menu.xml--><menuxmlns:android="http://schemas.android.com/apk/res/android"><!--Thisgroupusesthedefaultcategory.--><groupandroid:id="@+id/menuGroup_Main"><!--aregularmenuitem--><itemandroid:id="@+id/menu_da_clear"android:title="clear"/><!--itemtobeshowndirectlyontheactionbar--><itemandroid:id="@+id/menu_action_icon1"android:title="ActionIcon1"android:icon="@drawable/creep001"android:showAsAction="ifRoom"/>

<!--..othermenuitems--></group></menu>

ThemenuitemsthataretobeshownontheactionbarareindicatedwiththetagshowAsAction.Intheprecedingcode,thisattributeissetto“ifRoom“.TheotherpossiblevaluesforthisXMLtagareasfollows:always,never,withText,collapseActionView.YoucanalsoaccomplishthesameeffectwithaJavaAPIavailableontheMenuItemclass.Theoptionalwaysmeans“showthisitemasabuttonintheactionbar.”Theoptionnevermeans“nevershowthisitem.”TheoptionwithTextmeans“showthisitemwithitstextlabelandtheicon.”TheoptioncollapseActionViewmeans“collapsethespacetakenbytheactionviewofthisactionmenuitemwhennotselected.”Becausetheseactionsaremerelymenuitems,theybehaveassuchandcalltheonOptionsItemSelected()callbackmethodoftheactivityclass.

Page 192: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ImplementingaTabbedActionBarListing6-17showshowtosetupatabbedactionbar.

Listing6-17.Tab-Navigation–EnabledActionBarActivity

//ActivitySourcecodepublicclassTabNavigationActionBarActivityextendsActivity{@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);workwithTabbedActionBar();}publicvoidworkwithTabbedActionBar(){ActionBarbar=this.getActionBar();bar.setTitle(tag);bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);TestTabListenertl=newTestTabListener();Tabtab1=bar.newTab();tab1.setText("Tab1");tab1.setTabListener(tl);bar.addTab(tab1);Tabtab2=bar.newTab();tab2.setText("Tab2");tab2.setTabListener(tl);bar.addTab(tab2);}}//eof-class

Atabbedactionbar,asthenamesuggests,hasmultipletabs.InListing6-17youseethatthereareafewadditionalmethodsandclassesthatareusedtoworkwithtabbedactionbars.Unlikeastandardactionbar,atabbedactionbarrequiresatablistenerforeachtab.ThislistenerneedstoimplementtheTabListenerinterface.InListing6-18theclassTestTabListenerimplementstheTabListenerinterface.IfyouforgettocallthesetTabListener()methodonatabthatisaddedtotheactionbar,yougetaruntimeerrorindicatingthatalistenerisneeded.Listing6-18showsthecodefortheTestTabListenerclass.

Listing6-18.TabListenertoRespondtoTabActions

publicclassTestTabListenerimplementsActionBar.TabListener{//constructorcodepublicTestTabListener(){}//callbackspublicvoidonTabReselected(Tabtab,FragmentTransactionft){//applynecessarylogichere

Page 193: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}publicvoidonTabSelected(Tabtab,FragmentTransactionft){//applynecessarylogichere}publicvoidonTabUnselected(Tabtab,FragmentTransactionft){//applynecessarylogichere}}

Astabsareselectedandunselected,thecallbackmethodsinListing6-18willbecalled.Actionbarisapropertyoftheactivityanddoesnotcrossactivityboundaries.Inotherwords,onecannotuseanactionbartocontrolorinfluencemultipleactivities.Eachactivitymustprovisionitsownactionbars.Anycommonalityofactionsbetweenactionbarsislefttotheprogrammertoorchestrate.

InListing6-17,onceweobtainedtheactionbarforanactivity,wesetitsnavigationmodetoActionBar.NAVIGATION_MODE_TABS.TheothertwopossibleactionbarnavigationmodesareNAVIGATION_MODE_LISTandNAVIGATION_MODE_STANDARD.Let’sseenowhowtoimplementalist-basedactionbar.

ImplementingaList-BasedActionBarTobeabletoinitializeanactionbarwithlistnavigationmode,youneedthefollowingtwothings:

Aspinneradapterthatcanbeusedpopulatethedrop-downlistofnavigationchoices.

Alistnavigationlistenersothatwhenoneofthelistitemsispickedyoucangetacallback.

Listing6-19presentstheSimpleSpinnerArrayAdapterthatimplementstheSpinnerAdapterinterface.Asstatedearlier,thegoalofthisclassistogivealistofitemstoshow.

Listing6-19.CreatingaSpinnerAdapterforListNavigation

publicclassSimpleSpinnerArrayAdapterextendsArrayAdapter<String>implementsSpinnerAdapter{publicSimpleSpinnerArrayAdapter(Contextctx){super(ctx,android.R.layout.simple_spinner_item,newString[]{"one","two"});

Page 194: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

this.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);}publicViewgetDropDownView(intposition,ViewconvertView,ViewGroupparent){returnsuper.getDropDownView(position,convertView,parent);}}

ThereisnoSDKclassthatdirectlyimplementstheSpinnerAdapterinterfacerequiredbylistnavigation.So,youderivethisclassfromanArrayAdapterandprovideasimpleimplementationfortheSpinnerAdapter.AttheendofthechapterisareferenceURLonspinneradaptersforfurtherreading.Let’smoveonnowtothelistnavigationlistener.ThisisasimpleclassimplementingtheActionBar.OnNavigationListener.Listing6-20showsthecodeforthisclass.

Listing6-20.CreatingaListListenerforListNavigation

publicclassListListenerimplementsActionBar.OnNavigationListener{//simpleconstructor…publicListListener(){}//neededcallbacktorespondtoactionspublicbooleanonNavigationItemSelected(intitemPosition,longitemId){//respondandreturntruereturntrue;}}

Younowhavewhatyourequiretosetupalistnavigationactionbar.Thesourcecodenecessaryforworkingwithalist-basedactionbarisshowninListing6-21.

Listing6-21.ListNavigationActionBarActivity

//ActivitySourcecodepublicclassTabNavigationActionBarActivityextendsActivity{@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);workwithTabbedActionBar();}publicvoidworkwithListActionBar(){ActionBarbar=this.getActionBar();bar.setTitle("title");bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

Page 195: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

bar.setListNavigationCallbacks(newSimpleSpinnerArrayAdapter(this),newListListener());}}//eof-class

Figure6-4showshowalistbaractionbarlookswhenexpanded.

Figure6-4.Anactivitywithanopenednavigationlist

Thatconcludeshowwecanuseanactionbarforregularmenus,tabbednavigation,andlist-basednavigation.Let’sseenowhowwecanembedasearchviewliketheoneshowninFigure6-2.

ExploringActionBarandSearchViewThissectionshowshowtouseasearchwidgetintheactionbar.Youneedthefollowingtousesearchinyouractionbar:

1. DefineamenuiteminamenuXMLfilepointingtoasearchviewclassprovidedbytheSDK.Youalsoneedanactivityintowhichyoucanloadthismenu.Thisisoftencalledthesearchinvokeractivity.

2. Createanotheractivitythatcantakethequeryfromthesearchviewinstep1andprovideresults.Thisisoftencalledthesearchresultsactivity.

3. CreateanXMLfilethatallowsyoutocustomizethesearchviewintheactionbar.Thisfileisoftencalledsearchable.xmlandresidesintheres/xmlsubdirectory.

4. Declarethesearchresultsactivityinthemanifestfile.ThisdefinitionneedstopointtotheXMLfiledefinedinstep3.

5. Inyourmenusetupforthesearchinvokeractivity,indicatethatthesearchviewneedstotargetthesearchresultsactivityfromstep2.

Let’sstartwiththeSearchviewwidget.

DefiningaSearchViewWidgetasaMenuItemTodefineasearchviewtoappearintheactionbarofyouractivity,youneedtodefinea

Page 196: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

menuiteminoneofyourmenuXMLfiles,asshowninListing6-22.

Listing6-22.SearchViewMenuItemDefinition

<itemandroid:id="@+id/menu_search"android:title="Search"android:showAsAction="ifRoom"

android:actionViewClass="android.widget.SearchView"

/>

ThekeyelementinListing6-22istheactionViewClassattributepointingtoandroid.widget.SearchView.Yousawtheotherattributesearlierinthechapterwhenyoudeclaredyournormalmenuitemstoappearasactioniconsintheactionbar.

CreatingaSearchResultsActivityToenablesearchinyourapplication,youneedanactivitythatcanrespondtoasearchquery.Thiscanbelikeanyotheractivity.AnexampleisshowninListing6-23.

Listing6-23.SearchResultsActivity

publicclassSearchResultsActivityextendsActivity{publicstaticStringtag="SearchResultsActivity";@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);finalIntentqueryIntent=getIntent();doSearchQuery(queryIntent);}@OverridepublicvoidonNewIntent(finalIntentnewIntent){super.onNewIntent(newIntent);finalIntentqueryIntent=getIntent();doSearchQuery(queryIntent);}privatevoiddoSearchQuery(finalIntentqueryIntent){finalStringqueryAction=queryIntent.getAction();if(!(Intent.ACTION_SEARCH.equals(queryAction))){Log.d(tag,"intentNOTforsearch");return;}finalStringqueryString=queryIntent.getStringExtra(SearchManager.QUERY);Log.d(tag,queryString);}}//eof-class

InListing6-23,theactivitycheckstoseewhethertheactionthatinvokeditisinitiatedby

Page 197: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

search.Or,thisactivitycouldhavebeennewlycreatedorjustbroughttothetop,inwhichcaseitneedstodosomethingidenticaltotheonCreate()methodinitsonNewIntent()methodaswell.Ontheotherhand,ifthisactivityisinvokedbysearch,itretrievesthequerystringusinganextraparametercalledSearchManager.QUERY.Thentheactivitylogswhatthatstringis.Inarealscenario,youwouldusethatstringtopaintmatchingresults.

SpecifyingaSearchableXMLFileAsindicatedintheearliersteps,let’slookattheXMLfilethatisrequiredandcustomizesthesearchwidget;seeListing6-24.

Listing6-24.SearchableXMLFile

<!--/res/xml/searchable.xml--><searchablexmlns:android="http://schemas.android.com/apk/res/android"android:label="@string/search_label"android:hint="@string/search_hint"/>

Thehintattributewillappearonthesearchviewwidgetasahintthatdisappearswhenyoustarttyping.Thelabeldoesn’tplayasignificantroleintheactionbar.However,whenyouusethesamesearchresultsactivityinasearchdialog,thedialoghasthelabeldefinedhere.YoucanlearnmoreaboutsearchableXMLattributesatthefollowingURL:

http://developer.android.com/guide/topics/search/searchable-config.html

DefiningtheSearchResultsActivityintheManifestFileNowlet’sseehowtotiethisXMLfiletothesearchresultsactivity.Thisisdoneinthemanifestfileaspartofdefiningthesearchresultsactivity:seeListing6-25.NoticethemetadatadefinitionpointingtothesearchableXMLfileresource.

Listing6-25.TyinganActivitytoItsSearchable.xml

<activityandroid:name=".SearchResultsActivity"android:label="SearchResults"><intent-filter><actionandroid:name="android.intent.action.SEARCH"/></intent-filter><meta-dataandroid:name="android.app.searchable"android:resource="@xml/searchable"/></activity>

Page 198: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IdentifyingtheSearchTargetfortheSearchViewWidgetSofar,youhavethesearchviewinyouractionbar,andyouhavetheactivitythatcanrespondtosearch.YouneedtotietogetherthesetwopiecesusingJavacode.YoudothisintheonCreateOptions()callbackofthesearch-invokingactivityaspartofsettingupyourmenu.ThefunctioninListing6-26canbecalledfromonCreateOptions()tolinkthesearchviewwidgetandthesearchresultsactivity.

Listing6-26.TyingtheSearchViewWidgettotheSearchResultsActivity

privatevoidsetupSearchView(Menumenu){//Step1:LocatethesearchviewwidgetSearchViewsearchView=(SearchView)menu.findItem(R.id.menu_search).getActionView();//reporterrorandreturnifsearchViewisnull

//Step2:getSearchManagerandsearchableInfoSearchManagersearchManager=(SearchManager)getSystemService(Context.SEARCH_SERVICE);ComponentNamecn=newComponentName(this,SearchResultsActivity.class);SearchableInfoinfo=searchManager.getSearchableInfo(cn);//reporterrorandreturnifsearchableinfoisnull

//Step3:setsearchableInfoonthesearchviewwidgetsearchView.setSearchableInfo(info);//Donoticonifythewidget;expanditbydefaultsearchView.setIconifiedByDefault(false);}

Let’swalkthroughwhatishappeninginListing6-26.Thegoalofthiscodeistotellthesearchviewwhereitcanfindthesearchable.xmlthatdefinesthesearchbehavior.Todothis,thefirststepistogetareferencetotheSearchView.ThisisdonethroughtheMenuobject.Thesecondstepistoaskthesystem-widesearchmanagerwhatsearchableXMLfileistiedtotheactivitySearchResultsActivity.ThisisdonebycallingthemethodgetSearchableInfoontheSearchManagersystemservice.OncewehavetheSearchableInfoobjectrepresentingtheXMLfile,wepassthatinformationtotheSearchViewobject.Withallthisinplace,nowifyoutypesomethinginthesearchbox,thatinformationwillbepassedtothesearchresultsactivity,whichwillshowtheresults.

AndroidSearchAPIisalargeAPIwithalotofnuancesthat,duetospace,wehavenotincludedinthisbook.Therearethreesuggestions.WehaveprovidedaURLinthe“Resources”sectionthatpointstoaseriesofarticlesandnotesontheGooglesearchAPI.

Page 199: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WealsohavealargechapteronSearchfromthepreviouseditionmadeavailableonline.Thelinktothisisalsointhe“Resources”section.WehavealsoupdatedthatSearchmaterialfromthepreviouseditionandaddedthatcontenttotheExpertAndroideditionfromApress.

ResourcesAsyoulearnaboutandworkwithAndroidmenusandactionbars,youmaywanttokeepthefollowingURLshandy:

http://developer.android.com/guide/topics/ui/menus.htmlPrimarydocumentfromGoogledescribinghowtoworkwithmenus.

http://developer.android.com/guide/topics/resources/menu-resource.html:InformationaboutvariousXMLtagsyoucanuseinamenuresource.

http://developer.android.com/reference/android/app/ActionBar.htmlAPIURLfortheActionBarclass.

http://www.androidbook.com/item/3624:Ourresearchonactionbar,includingalistoffurtherreferences,samplecode,linkstoexamples,andUIfiguresrepresentingvariousactionbarmodes.

http://www.androidbook.com/item/3627:Tosetuplistnavigationmode,youneedtounderstandhowdrop-downlistsandspinnerswork.ThisbriefarticleshowsafewsamplesandreferencelinksonhowtousespinnersinAndroid.

http://www.androidbook.com/item/3885:Explainshowsearchworks,tohelpyouutilizetheactionbartoitsfullextent.

http://www.androidicons.com:Websitefromwhichacoupleoftheiconsusedinthischapterareborrowed.TheseiconsareunderCreativeCommonsLicense3.0.

http://www.androidbook.com/item/3302:“PleasingAndroidLayouts.”Afewnotesandsamplecodeforsimplelayouts.

http://www.androidbook.com/item/4060:YouwillfindhereafreecopyoftheSearchchapterfromthepreviousedition.ThisprovidesextensivecoverageonAndroidsearch.

http://androidbook.com/proandroid5/projects:ProjectdownloadURLforthisbook.ThedownloadableprojectZIPfilesforthischapterareProAndroid5_ch06_TestMenus.zipandProAndroid5_ch06_TestActionBar.zip.

Page 200: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SummaryMenusandactionbarsareanintegralpartofwritingmobileapps.Thischaptercoversregularmenus,contextmenus,pop-upmenus,standardactionbars,tabbedactionbars,andlist-basedactionbars.Thischapteralsocoversthebasicsofhowtoembedasearchviewwidgetinanactionbar.

Page 201: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter7

StylesandThemesThusfar,wehavecoveredsomefundamentalsoftheAndroiduserinterface(UI).Inthischapter,wearegoingtodiscussstylesandthemes,whichhelptoencapsulatecontrol-appearanceattributesforeasiersetupandmaintenance.Androidprovidesseveralwaystoalterthestyleofviewsinyourapplication,inXMLandincode.We’llfirstcoverusingmarkuptagsinstringsandthenhowtousespannablestochangespecificvisualattributesoftext.Butwhatifyouwanttocontrolhowthingslookusingacommonspecificationforseveralviewsoracrossanentireactivityorapplication?We’lldiscussAndroidstylesandthemestoshowyouhow.

UsingStylesSometimes,youwanttohighlightorstyleaportionoftheView’scontent.Youcandothisstaticallyordynamically.Statically,youcanapplymarkupdirectlytothestringsinyourstringresources,asshownhere:

<stringname="styledText"><i>Static</i>styleina<b>TextView</b>.</string>

YoucanthenreferenceitinyourXMLorfromcode.NotethatyoucanusethefollowingHTMLtagswithstringresources:<i>,<b>,and<u>,foritalics,bold,andunderlined,respectively,aswellas<sup>(superscript),<sub>(subscript),<strike>(strikethrough),<big>,<small>,and<monospace>.Youcanevennestthesetoget,forexample,smallsuperscripts.ThisworksnotjustinTextViewsbutalsoinotherviews,likebuttons.Figure7-1showswhatstyledandthemedtextlookslike,usingmanyoftheexamplesinthissection.

Page 202: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure7-1.Examplesofstylesandthemes

StylingaTextViewcontrol’scontentprogrammaticallyrequiresalittleadditionalworkbutallowsformuchmoreflexibility(seeListing7-1),becauseyoucanstyleitatruntime.Thisflexibilitycanonlybeappliedtoaspannable,though,whichishowEditTextnormallymanagestheinternaltext,whereasTextViewdoesnotnormallyuseSpannable.SpannableisbasicallyaStringthatyoucanapplystylesto.TogetaTextViewtostoretextasaspannable,youcancallsetTextthisway:

tv.setText("ThistextisstoredinaSpannable",TextView.BufferType.SPANNABLE);

Then,whenyoucalltv.getText,you’llgetaspannable.

AsshowninListing7-1,youcangetthecontentoftheEditText(asaSpannableobject)andthensetstylesforportionsofthetext.Thecodeinthelistingsetsthetextstylingtoboldanditalicsandsetsthebackgroundtored.YoucanuseallthestylingoptionsaswehavewiththeHTMLtagsasdescribedpreviously,andthensome.

Listing7-1.ApplyingStylesDynamicallytotheContentofanEditText

EditTextet=(EditText)this.findViewById(R.id.et);

Page 203: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

et.setText("StylingthecontentofanEditTextdynamically");Spannablespn=(Spannable)et.getText();spn.setSpan(newBackgroundColorSpan(Color.RED),0,7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);spn.setSpan(newStyleSpan(android.graphics.Typeface.BOLD_ITALIC),0,7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Thesetwotechniquesforstylingonlyworkontheoneviewthey’reappliedto.Androidprovidesastylemechanismtodefineacommonstyletobereusedacrossviews,aswellasathememechanism,whichbasicallyappliesastyletoanentireactivityortheentireapplication.Tobeginwith,weneedtotalkaboutstyles.

AstyleisacollectionofViewattributesthatisgivenanamesoyoucanrefertothatcollectionbyitsnameandassignthatstylebynametoviews.Forexample,Listing7-2showsaresourceXMLfile,savedin/res/values,thatwecoulduseforallerrormessages.

Listing7-2.DefiningaStyletoBeUsedAcrossManyViews

<?xmlversion="1.0"encoding="utf-8"?><resources><stylename="ErrorText"><itemname="android:layout_width">fill_parent</item><itemname="android:layout_height">wrap_content</item><itemname="android:textColor">#FF0000</item><itemname="android:typeface">monospace</item></style></resources>

Thesizeoftheviewisdefinedaswellasthefontcolor(red)andtypeface.Noticehowthenameattributeoftheitemtag(e.g.,android:layout_width)istheXMLattributenameweusedinourlayoutXMLfilesinearlierchapters,andthevalueoftheitemtagnolongerrequiresdoublequotes.WecannowusethisstyleforanerrorTextView,asshowninListing7-3.

Listing7-3.UsingaStyleinaView

<TextViewandroid:id="@+id/errorText"style="@style/ErrorText"android:text="Noerrorsatthistime"/>

ItisimportanttonotethattheattributenameforastyleinthisViewdefinitiondoesnotstartwithandroid:.Watchoutforthis,becauseeverythingseemstouseandroid:exceptthestyle.Whenyou’vegotmanyviewsinyourapplicationthatshareastyle,changingthatstyleinoneplaceismuchsimpler;youonlyneedtomodifythestyle’sattributesintheoneresourcefile.

Page 204: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Youcan,ofcourse,createmanydifferentstylesforvariouscontrols.Forexample,buttonscouldshareacommonstylethatisdifferentfromthecommonstylefortextinmenus.Itiscommontoseetextattributesmanagedwithstyles,includingandroid:textColor,android:textStyle,andandroid:textSize.Othercommonattributesusedwithstylesincludethepaddingvalues,android:background,andcolors.

Onereallyniceaspectofstylesisthatyoucansetupahierarchyofthem.WecoulddefineanewstyleforreallybaderrormessagesandbaseitonthestyleofErrorText.Listing7-4showshowthismightlook.

Listing7-4.DefiningaStylefromaParentStyle

<?xmlversion="1.0"encoding="utf-8"?><resources><stylename="ErrorText.Danger"><itemname="android:textStyle">bold</item></style></resources>

Thisexampleshowsthatwecansimplynameourchildstyleusingtheparentstyleasaprefixtothenewstylename.Therefore,ErrorText.DangerisachildofErrorTextandinheritsthestyleattributesoftheparent.ItthenaddsanewattributefortextStyle.Thiscanberepeatedagainandagaintocreateawholetreeofstyles.

Aswasthecaseforadapterlayouts,Androidprovidesalargesetofstylesthatwecanuse.TospecifyanAndroid-providedstyle,usesyntaxlikethis:

style="@android:style/TextAppearance"

ThisstylesetsthedefaultstylefortextinAndroid.TolocatethemasterAndroidstyles.xmlfile,visittheAndroidSDK/platforms/<android-version>/data/res/values/folder,whereyouinstalledtheAndroidSDK;<android-version>istheparticularversionofAndroidyouwanttoseestylesfor.Insidethisfile,youwillfindquiteafewstylesthatareready-madeforyoutouseorextend.Aquicknoteabout@android:style/TextAppearance:thisstyledoesnotsetandroid:layout_heightorandroid:layout_width,soaViewspecificationwouldneedmorethanthisstyletocompileproperly.

Here’sawordofcautionaboutextendingtheAndroid-providedstyles:thepreviousmethodofusingaprefixwon’tworkwithAndroid-providedstyles.Instead,youmustusetheparentattributeofthestyletag,likethis:

<stylename="CustomTextAppearance"parent="@android:style/TextAppearance"><item...yourextensionsgohere…/></style>

Youdon’talwayshavetopullinanentirestyleonyourview.Youcouldchoosetoborrowjustapartofthestyleinstead.Forexample,ifyouwanttosetthecolorofthetextinyour

Page 205: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TextViewtoasystemstylecolor,youcoulddothefollowing:

<TextViewandroid:id="@+id/tv2"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textColor="?android:textColorSecondary"android:text="@string/hello_world"/>

Noticethatinthisexample,thenameofthetextColorattributevaluestartswiththe?characterinsteadofthe@character.The?characterisusedsoAndroidknowstolookforastylevalueinthecurrenttheme.Becausewesee?android,welookintheAndroidsystemthemeforthisstylevalue.

UsingThemesOneproblemwithstylesisthatyouneedtoaddanattributespecificationofstyle=”@style/…”toeveryviewdefinitionthatyouwantittoapplyto.Ifyouhavesomestyleelementsyouwantappliedacrossanentireactivity,oracrossthewholeapplication,youshoulduseathemeinstead.Athemeisreallyjustastyleappliedbroadly;butintermsofdefiningatheme,it’sexactlylikeastyle.Infact,themesandstylesarefairlyinterchangeable:youcanextendathemeintoastyleorrefertoastyleasatheme.Typically,onlythenamesgiveahintastowhetherastyleisintendedtobeusedasastyleoratheme.

Tospecifyathemeforanactivityoranapplication,youwouldaddanattributetothe<activity>or<application>tagintheAndroidManifest.xmlfileforyourproject.Thecodemightlooklikeoneofthese:

<activityandroid:theme="@style/MyActivityTheme"><applicationandroid:theme="@style/MyApplicationTheme"><applicationandroid:theme="@android:style/Theme.NoTitleBar">

YoucanfindtheAndroid-providedthemesinthesamefolderastheAndroid-providedstyles,withthethemesinafilecalledthemes.xml.Whenyoulookinsidethethemesfile,youwillseealargesetofstylesdefined,withnamesthatstartwithTheme.Itmightbegoodtoreadthatlastlineafewtimes.Putanotherway,allstylesandthemesareoftypestyle,evenifthestylenamehas“Theme”init.YouwillalsonoticethatwithintheAndroid-providedthemesandstyles,thereisalotofextendinggoingon,whichiswhyyouendupwithstylescalledTheme.Dialog.AppError,forexample.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistof

Page 206: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

downloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch07_Styles.zip.ThisZIPfilecontainsallprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoyourIDEfromoneoftheseZIPfiles.

http://developer.android.com/guide/topics/ui/themes.htmlTheAndroidguidetostylesandthemes.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedaboutstylesandthemes:

Stylesarejustcollectionsofviewattributesforeasyreuseacrossviews,activities,andapplications.

Youcanmakeyourownstyles,useapredefinedstyle,orextendanexistingstyle.

Themesarewhatyoucallastylewhenitisappliedtoanactivityorapplication.

Page 207: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter8

FragmentsSofar,we’veexploredseveralbitsandpiecesofanAndroidapplication,andyou’verunsomesimpleapplicationstailoredtoasmartphone-sizedscreen.AllyouhadtothinkaboutwashowtolayouttheUIcontrolsonthescreenforanactivity,andhowoneactivityflowedtothenext,andsoon.ForthefirsttwomajorreleasesofAndroid,smallscreenswereit.ThencametheAndroidtablets:deviceswithscreensizesof10”.Andthatcomplicatedthings.Why?Becausenowtherewassomuchscreenrealestatethatasimpleactivityhadahardtimefillingascreenwhileatthesametimekeepingtoasinglefunction.Itnolongermadesensetohaveane-mailapplicationthatshowedonlyheadersinoneactivity(fillingalargescreen),andaseparateactivitytoshowanindividuale-mail(alsofillingalargescreen).Withthatmuchroomtoworkwith,anapplicationcouldshowalistofe-mailheadersdowntheleftsideofthescreenandtheselectede-mailcontentsontherightsideofthescreen.Coulditbedoneinasingleactivitywithasinglelayout?Well,yes,butyoucouldn’treusethatactivityorlayoutforanyofthesmaller-screendevices.

OneofthecoreclassesintroducedinAndroid3.0wastheFragmentclass,especiallydesignedtohelpdevelopersmanageapplicationfunctionalitysoitwouldprovidegreatusabilityaswellaslotsofreuse.Thischapterwillintroduceyoutothefragment,whatitis,howitfitsintoanapplication’sarchitecture,andhowtouseit.Fragmentsmakealotofinterestingthingspossiblethatweredifficultbefore.Ataboutthesametime,GooglereleasedafragmentSDKthatworksonoldAndroids.Soevenifyouweren’tinterestedinwritingapplicationsfortablets,youmayhavefoundthatfragmentsmadeyourlifeeasieronnon-tabletdevices.Nowit’seasierthanevertowritegreatapplicationsforsmartphonesandtabletsandevenTVsandotherdevices.

Let’sgetstartedwithAndroidfragments.

WhatIsaFragment?Thisfirstsectionwillexplainwhatafragmentisandwhatitdoes.Butfirst,let’ssetthestagetoseewhyweneedfragments.Asyoulearnedearlier,anAndroidapplicationonsmall-screendevicesusesactivitiestoshowdataandfunctionalitytoauser,andeachactivityhasafairlysimple,well-definedpurpose.Forexample,anactivitymightshowtheuseralistofcontactsfromtheiraddressbook.Anotheractivitymightallowtheusertotypeane-mail.TheAndroidapplicationistheseriesoftheseactivitiesgroupedtogethertoachievealargerpurpose,suchasmanagingane-mailaccountviathereadingandsendingofmessages.Thisisfineforasmall-screendevice,butwhentheuser’sscreenisverylarge(10”orlarger),there’sroomonthescreentodomorethanjustonesimplething.Anapplicationmightwanttolettheuserviewthelistofe-mailsintheirinboxandatthesametimeshowthecurrentlyselectede-mailtextnexttothelist.Oranapplicationmightwanttoshowalistofcontactsandatthesametimeshowthecurrentlyselectedcontactin

Page 208: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

adetailview.

AsanAndroiddeveloper,youknowthatthisfunctionalitycouldbeaccomplishedbydefiningyetanotherlayoutforthexlargescreenwithListViewsandlayoutsandallsortsofotherviews.Andby“yetanotherlayout”wemeanlayoutsinadditiontothoseyou’veprobablyalreadydefinedforthesmallerscreens.Ofcourse,you’llwanttohaveseparatelayoutsfortheportraitcaseaswellasthelandscapecase.Andwiththesizeofanxlargescreen,thiscouldmeanquiteafewviewsforallthelabelsandfieldsandimagesandsoonthatyou’llneedtolayoutandthenprovidecodefor.Ifonlytherewereawaytogrouptheseviewobjectstogetherandconsolidatethelogicforthem,sothatchunksofanapplicationcouldbereusedacrossscreensizesanddevices,minimizinghowmuchworkadeveloperhastodotomaintaintheirapplication.Andthatiswhywehavefragments.

Onewaytothinkofafragmentisasasub-activity.Andinfact,thesemanticsofafragmentarealotlikeanactivity.Afragmentcanhaveaviewhierarchyassociatedwithit,andithasalifecyclemuchlikeanactivity’slifecycle.FragmentscanevenrespondtotheBackbuttonlikeactivitiesdo.Ifyouwerethinking,“IfonlyIcouldputmultipleactivitiestogetheronatablet’sscreenatthesametime,”thenyou’reontherighttrack.Butbecauseitwouldbetoomessytohavemorethanoneactivityofanapplicationactiveatthesametimeonatabletscreen,fragmentswerecreatedtoimplementbasicallythatthought.Thismeansfragmentsarecontainedwithinanactivity.Fragmentscanonlyexistwithinthecontextofanactivity;youcan’tuseafragmentwithoutanactivity.Fragmentscancoexistwithotherelementsofanactivity,whichmeansyoudonotneedtoconverttheentireuserinterfaceofyouractivitytousefragments.Youcancreateanactivity’slayoutasbeforeandonlyuseafragmentforonepieceoftheuserinterface.

Fragmentsarenotlikeactivities,however,whenitcomestosavingstateandrestoringitlater.Thefragmentsframeworkprovidesseveralfeaturestomakesavingandrestoringfragmentsmuchsimplerthantheworkyouneedtodoonactivities.

Howyoudecidewhentouseafragmentdependsonafewconsiderations,whicharediscussednext.

WhentoUseFragmentsOneoftheprimaryreasonstouseafragmentissoyoucanreuseachunkofuserinterfaceandfunctionalityacrossdevicesandscreensizes.Thisisespeciallytruewithtablets.Thinkofhowmuchcanhappenwhenthescreenisaslargeasatablet’s.It’smorelikeadesktopthanaphone,andmanyofyourdesktopapplicationshaveamultipaneuserinterface.Asdescribedearlier,youcanhavealistandadetailviewoftheselecteditemonscreenatthesametime.Thisiseasytopictureinalandscapeorientationwiththelistontheleftandthedetailsontheright.Butwhatiftheuserrotatesthedevicetoportraitmodesothatnowthescreenistallerthanitiswide?Perhapsyounowwantthelisttobeinthetopportionofthescreenandthedetailsinthebottomportion.Butwhatifthisapplicationisrunningonasmallscreenandthere’sjustnoroomforthetwoportionstobeonthescreenatthesametime?Wouldn’tyouwanttheseparateactivitiesforthelistandforthedetailstobeabletosharethelogicyou’vebuiltintotheseportionsforalargescreen?Wehopeyouansweredyes.Fragmentscanhelpwiththat.Figure8-1makesthisalittle

Page 209: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

clearer.

Figure8-1.FragmentsusedforatabletUIandforasmartphoneUI

Inlandscapemode,twofragmentsmaysitnicelysidebyside.Inportraitmode,wemightbeabletoputonefragmentabovetheother.Butifwe’retryingtorunthesameapplicationonadevicewithasmallerscreen,wemightneedtoshoweitherfragment1orfragment2butnotbothatthesametime.Ifwetriedtomanageallthesescenarioswithlayouts,we’dbecreatingquiteafew,whichmeansdifficultytryingtokeepeverythingcorrectacrossmanyseparatelayouts.Whenusingfragments,ourlayoutsstaysimple;eachactivitylayoutdealswiththefragmentsascontainers,andtheactivitylayoutsdon’tneedtospecifytheinternalstructureofeachfragment.Eachfragmentwillhaveitsownlayoutforitsinternalstructureandcanbereusedacrossmanyconfigurations.

Let’sgobacktotherotatingorientationexample.Ifyou’vehadtocodefororientationchangesofanactivity,youknowthatitcanbearealpaintosavethecurrentstateoftheactivityandtorestorethestateoncetheactivityhasbeenre-created.Wouldn’titbeniceifyouractivityhadchunksthatcouldbeeasilyretainedacrossorientationchanges,soyoucouldavoidallthetearingdownandre-creatingeverytimetheorientationchanged?Ofcourseitwould.Fragmentscanhelpwiththat.

Nowimaginethatauserisinyouractivity,andthey’vebeendoingsomework.Andimaginethattheuserinterfacehaschangedwithinthesameactivity,andtheuserwantstogobackastep,ortwo,orthree.Inanold-styleactivity,pressingtheBackbuttonwilltaketheuseroutoftheactivityentirely.Withfragments,theBackbuttoncanstepbackwardthroughastackoffragmentswhilestayinginsidethecurrentactivity.

Next,thinkaboutanactivity’suserinterfacewhenabigchunkofcontentchanges;you’dliketomakethetransitionlooksmooth,likeapolishedapplication.Fragmentscandothat,too.

Nowthatyouhavesomeideaofwhatafragmentisandwhyyou’dwanttouseone,let’sdigalittledeeperintothestructureofafragment.

TheStructureofaFragmentAsmentioned,afragmentislikeasub-activity:ithasafairlyspecificpurposeandalmost

Page 210: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

alwaysdisplaysauserinterface.ButwhereanactivityissubclassedfromContext,afragmentisextendedfromObjectinpackageandroid.app.AfragmentisnotanextensionofActivity.Likeactivities,however,youwillalwaysextendFragment(oroneofitssubclasses)soyoucanoverrideitsbehavior.

Afragmentcanhaveaviewhierarchytoengagewithauser.Thisviewhierarchyislikeanyotherviewhierarchyinthatitcanbecreated(inflated)fromanXMLlayoutspecificationorcreatedincode.Theviewhierarchyneedstobeattachedtotheviewhierarchyofthesurroundingactivityifitistobeseenbytheuser,whichyou’llgettoshortly.Theviewobjectsthatmakeupafragment’sviewhierarchyarethesamesortsofviewsthatareusedelsewhereinAndroid.Soeverythingyouknowaboutviewsappliestofragmentsaswell.

Besidestheviewhierarchy,afragmenthasabundlethatservesasitsinitializationarguments.Similartoanactivity,afragmentcanbesavedandlaterrestoredautomaticallybythesystem.Whenthesystemrestoresafragment,itcallsthedefaultconstructor(withnoarguments)andthenrestoresthisbundleofargumentstothenewlycreatedfragment.Subsequentcallbacksonthefragmenthaveaccesstotheseargumentsandcanusethemtogetthefragmentbacktoitspreviousstate.Forthisreason,itisimperativethatyou

Ensurethatthere’sadefaultconstructorforyourfragmentclass.

Addabundleofargumentsassoonasyoucreateanewfragmentsothesesubsequentmethodscanproperlysetupyourfragment,andsothesystemcanrestoreyourfragmentproperlywhennecessary.

Anactivitycanhavemultiplefragmentsinplayatonetime;andifafragmenthasbeenswitchedoutwithanotherfragment,thefragment-switchingtransactioncanbesavedonabackstack.Thebackstackismanagedbythefragmentmanagertiedtotheactivity.ThebackstackishowtheBackbuttonbehaviorismanaged.Thefragmentmanagerisdiscussedlaterinthischapter.Whatyouneedtoknowhereisthatafragmentknowswhichactivityitistiedto,andfromthereitcangettoitsfragmentmanager.Afragmentcanalsogettotheactivity’sresourcesthroughitsactivity.

Alsosimilartoanactivity,afragmentcansavestateintoabundleobjectwhenthefragmentisbeingre-created,andthisbundleobjectgetsgivenbacktothefragment’sonCreate()callback.ThissavedbundleisalsopassedtoonInflate(),onCreateView(),andonActivityCreated().Notethatthisisnotthesamebundleastheoneattachedasinitializationarguments.Thisbundleisoneinwhichyouarelikelytostorethecurrentstateofthefragment,notthevaluesthatshouldbeusedtoinitializeit.

AFragment’sLifeCycleBeforeyoustartusingfragmentsinsampleapplications,youneedunderstandthelifecycleofafragment.Why?Afragment’slifecycleismorecomplicatedthananactivity’slifecycle,andit’sveryimportanttounderstandwhenyoucandothingswithfragments.Figure8-2showsthelifecycleofafragment.

Page 211: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure8-2.Lifecycleofafragment

IfyoucomparethistoFigure2-3(thelifecycleforanactivity),you’llnoticeseveraldifferences,duemostlytotheinteractionrequiredbetweenanactivityandafragment.Afragmentisverydependentontheactivityinwhichitlivesandcangothroughmultiplestepswhileitsactivitygoesthroughone.

Attheverybeginning,afragmentisinstantiated.Itnowexistsasanobjectinmemory.Thefirstthingthatislikelytohappenisthatinitializationargumentswillbeaddedtoyourfragmentobject.Thisisdefinitelytrueinthesituationwherethesystemisre-creatingyourfragmentfromasavedstate.Whenthesystemisrestoringafragmentfromasavedstate,thedefaultconstructorisinvoked,followedbytheattachmentoftheinitializationargumentsbundle.Ifyouaredoingthecreationofthefragmentincode,anicepatterntouseisthatinListing8-1,whichshowsafactorytypeofinstantiatorwithintheMyFragmentclassdefinition.

Listing8-1.InstantiatingaFragmentUsingaStaticFactoryMethod

publicstaticMyFragmentnewInstance(intindex){MyFragmentf=newMyFragment();Bundleargs=newBundle();args.putInt("index",index);f.setArguments(args);

Page 212: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returnf;}

Fromtheclient’spointofview,theygetanewinstancebycallingthestaticnewInstance()methodwithasingleargument.Theygettheinstantiatedobjectback,andtheinitializationargumenthasbeensetonthisfragmentintheargumentsbundle.Ifthisfragmentissavedandreconstructedlater,thesystemwillgothroughaverysimilarprocessofcallingthedefaultconstructorandthenreattachingtheinitializationarguments.Foryourparticularcase,youwoulddefinethesignatureofyournewInstance()method(ormethods)totaketheappropriatenumberandtypeofarguments,andthenbuildtheargumentsbundleappropriately.ThisisallyouwantyournewInstance()methodtodo.Thecallbacksthatfollowwilltakecareoftherestofthesetupofyourfragment.

TheonInflate()CallbackThenextthingthathappensislayoutviewinflation.Ifyourfragmentisdefinedbya<fragment>taginalayout,yourfragment’sonInflate()callbackwillbecalled.Thispassesinareferencetothesurroundingactivity,anAttributeSetwiththeattributesfromthe<fragment>tag,andasavedbundle.Thesavedbundleistheonewiththesavedstatevaluesinit,puttherebyonSaveInstanceState()ifthisfragmentexistedbeforeandisbeingre-created.TheexpectationofonInflate()isthatyou’llreadattributevaluesandsavethemforlateruse.Atthisstageinthefragment’slife,it’stooearlytoactuallydoanythingwiththeuserinterface.Thefragmentisnotevenassociatedtoitsactivityyet.Butthat’sthenexteventtooccurtoyourfragment.

TheonAttach()CallbackTheonAttach()callbackisinvokedafteryourfragmentisassociatedwithitsactivity.Theactivityreferenceispassedtoyouifyouwanttouseit.Youcanatleastusetheactivitytodetermineinformationaboutyourenclosingactivity.Youcanalsousetheactivityasacontexttodootheroperations.OnethingtonoteisthattheFragmentclasshasagetActivity()methodthatwillalwaysreturntheattachedactivityforyourfragmentshouldyouneedit.Keepinmindthatallduringthislifecycle,theinitializationargumentsbundleisavailabletoyoufromthefragment’sgetArguments()method.However,oncethefragmentisattachedtoitsactivity,youcan’tcallsetArguments()again.Therefore,youcan’taddtotheinitializationargumentsexceptintheverybeginning.

TheonCreate()CallbackNextupistheonCreate()callback.Althoughthisissimilartotheactivity’sonCreate(),thedifferenceisthatyoushouldnotputcodeinherethatreliesontheexistenceoftheactivity’sviewhierarchy.Yourfragmentmaybeassociatedtoitsactivitybynow,butyouhaven’tyetbeennotifiedthattheactivity’sonCreate()hasfinished.That’scomingup.Thiscallbackgetsthesavedstatebundlepassedin,ifthereisone.Thiscallbackisaboutasearlyaspossibletocreateabackgroundthreadtogetdatathatthis

Page 213: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

fragmentwillneed.YourfragmentcodeisrunningontheUIthread,andyoudon’twanttododiskinput/output(I/O)ornetworkaccessesontheUIthread.Infact,itmakesalotofsensetofireoffabackgroundthreadtogetthingsready.Yourbackgroundthreadiswhereblockingcallsshouldbe.You’llneedtohookupwiththedatalater,perhapsusingahandlerorsomeothertechnique.

NoteOneofthewaystoloaddatainabackgroundthreadistousetheLoaderclass.ThiswillbecoveredinChapter28.

TheonCreateView()CallbackThenextcallbackisonCreateView().Theexpectationhereisthatyouwillreturnaviewhierarchyforthisfragment.TheargumentspassedintothiscallbackincludeaLayoutInflater(whichyoucanusetoinflatealayoutforthisfragment),aViewGroupparent(calledcontainerinListing8-2),andthesavedbundleifoneexists.ItisveryimportanttonotethatyoushouldnotattachtheviewhierarchytotheViewGroupparentpassedin.Thatassociationwillhappenautomaticallylater.Youwillverylikelygetexceptionsifyouattachthefragment’sviewhierarchytotheparentinthiscallback—oratleastoddandunexpectedapplicationbehavior.

Listing8-2.CreatingaFragmentViewHierarchyinonCreateView()

@OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){if(container==null)returnnull;

Viewv=inflater.inflate(R.layout.details,container,false);TextViewtext1=(TextView)v.findViewById(R.id.text1);text1.setText(myDataSet[getPosition()]);returnv;}

Theparentisprovidedsoyoucanuseitwiththeinflate()methodoftheLayoutInflater.Iftheparentcontainervalueisnull,thatmeansthisparticularfragmentwon’tbeviewedbecausethere’snoviewhierarchyforittoattachto.Inthiscase,youcansimplyreturnnullfromhere.Rememberthattheremaybefragmentsfloatingaroundinyourapplicationthataren’tbeingdisplayed.Listing8-2showsasampleofwhatyoumightwanttodointhismethod.

HereyouseehowyoucanaccessalayoutXMLfilethatisjustforthisfragmentandinflateittoaviewthatyoureturntothecaller.Thereareseveraladvantagestothisapproach.Youcouldalwaysconstructtheviewhierarchyincode,butbyinflatingalayout

Page 214: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

XMLfile,you’retakingadvantageofthesystem’sresource-findinglogic.Dependingonwhichconfigurationthedeviceisin,orforthatmatterwhichdeviceyou’reon,theappropriatelayoutXMLfilewillbechosen.Youcanthenaccessaparticularviewwithinthelayout—inthiscase,thetext1TextViewfield—todowhatyouwantwith.Torepeataveryimportantpoint:donotattachthefragment’sviewtothecontainerparentinthiscallback.YoucanseeinListing8-2thatyouuseacontainerinthecalltoinflate(),butyoualsopassfalsefortheattachToRootparameter.

TheonViewCreated()CallbackThisoneiscalledrightafteronCreateView()butbeforeanysavedstatehasbeenputintotheUI.TheviewobjectpassedinisthesameviewobjectthatgotreturnedfromonCreateView().

TheonActivityCreated()CallbackYou’renowgettingclosetothepointwheretheusercaninteractwithyourfragment.ThenextcallbackisonActivityCreated().ThisiscalledaftertheactivityhascompleteditsonCreate()callback.Youcannowtrustthattheactivity’sviewhierarchy,includingyourownviewhierarchyifyoureturnedoneearlier,isreadyandavailable.Thisiswhereyoucandofinaltweakstotheuserinterfacebeforetheuserseesit.It’salsowhereyoucanbesurethatanyotherfragmentforthisactivityhasbeenattachedtoyouractivity.

TheonViewStateRestored()CallbackThisoneisrelativelynew,introducedwithJellyBean4.2.Yourfragmentwillhavethiscallbackcalledwhentheviewhierarchyofthisfragmenthasallstaterestored(ifapplicable).PreviouslyyouhadtomakedecisionsinonActivityCreated()abouttweakingtheUIforarestoredfragment.Nowyoucanputthatlogicinthiscallbackknowingdefinitelythatthisfragmentisbeingrestoredfromasavedstate.

TheonStart()CallbackThenextcallbackinyourfragmentlifecycleisonStart().Nowyourfragmentisvisibletotheuser.Butyouhaven’tstartedinteractingwiththeuserjustyet.Thiscallbackistiedtotheactivity’sonStart().Assuch,whereaspreviouslyyoumayhaveputyourlogicintotheactivity’sonStart(),nowyou’remorelikelytoputyourlogicintothefragment’sonStart(),becausethatisalsowheretheuserinterfacecomponentsare.

TheonResume()CallbackThelastcallbackbeforetheusercaninteractwithyourfragmentisonResume().Thiscallbackistiedtotheactivity’sonResume().Whenthiscallbackreturns,theuserisfreetointeractwiththisfragment.Forexample,ifyouhaveacamerapreviewinyourfragment,youwouldprobablyenableitinthefragment’sonResume().

Page 215: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Sonowyou’vereachedthepointwheretheappisbusilymakingtheuserhappy.Andthentheuserdecidestogetoutofyourapp,eitherbyBack’ingout,orbypressingtheHomebutton,orbylaunchingsomeotherapplication.Thenextsequence,similartowhathappenswithanactivity,goesintheoppositedirectionofsettingupthefragmentforinteraction.

TheonPause()CallbackThefirstundocallbackonafragmentisonPause().Thiscallbackistiedtotheactivity’sonPause();justaswithanactivity,ifyouhaveamediaplayerinyourfragmentorsomeothersharedobject,youcouldpauseit,stopit,orgiveitbackviayouronPause()method.Thesamegood-citizenrulesapplyhere:youdon’twanttobeplayingaudioiftheuseristakingaphonecall.

TheonSaveInstanceState()CallbackSimilartoactivities,fragmentshaveanopportunitytosavestateforlaterreconstruction.ThiscallbackpassesinaBundleobjectforthisfragmenttobeusedasthecontainerforwhateverstateinformationyouwanttohangonto.Thisisthesaved-statebundlepassedtothecallbackscoveredearlier.Topreventmemoryproblems,becarefulaboutwhatyousaveintothisbundle.Onlysavewhatyouneed.Ifyouneedtokeepareferencetoanotherfragment,don’ttrytosaveorputtheotherfragment,ratherjustsavetheidentifierfortheotherfragmentsuchasitstagorID.WhenthisfragmentrunsonViewStateRestored(),thenyoucouldre-establishconnectionstotheotherfragmentsthatthisfragmentdependson.

AlthoughyoumayseethismethodusuallycalledrightafteronPause(),theactivitytowhichthisfragmentbelongscallsitwhenitfeelsthatthefragment’sstateshouldbesaved.ThiscanoccuranytimebeforeonDestroy().

TheonStop()CallbackThenextundocallbackisonStop().Thisoneistiedtotheactivity’sonStop()andservesapurposesimilartoanactivity’sonStop().AfragmentthathasbeenstoppedcouldgostraightbacktotheonStart()callback,whichthenleadstoonResume().

TheonDestroyView()CallbackIfyourfragmentisonitswaytobeingkilledofforsaved,thenextcallbackintheundodirectionisonDestroyView().ThiswillbecalledaftertheviewhierarchyyoucreatedonyouronCreateView()callbackearlierhasbeendetachedfromyourfragment.

TheonDestroy()CallbackNextupisonDestroy().Thisiscalledwhenthefragmentisnolongerinuse.Notethatitisstillattachedtotheactivityandisstillfindable,butitcan’tdomuch.

Page 216: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheonDetach()CallbackThefinalcallbackinafragment’slifecycleisonDetach().Oncethisisinvoked,thefragmentisnottiedtoitsactivity,itdoesnothaveaviewhierarchyanymore,andallitsresourcesshouldhavebeenreleased.

UsingsetRetainInstance()YoumayhavenoticedthedottedlinesinthediagraminFigure8-2.Oneofthecoolfeaturesofafragmentisthatyoucanspecifythatyoudon’twantthefragmentcompletelydestroyediftheactivityisbeingre-createdandthereforeyourfragmentswillbecomingbackalso.Therefore,FragmentcomeswithamethodcalledsetRetainInstance(),whichtakesabooleanparametertotellit“Yes;Iwantyoutohangaroundwhenmyactivityrestarts”or“No;goaway,andI’llcreateanewfragmentfromscratch.”AgoodplacetocallsetRetainInstance()isintheonCreate()callbackofafragment,butinonCreateView()works,asdoesonActivityCreated().

Iftheparameteristrue,thatmeansyouwanttokeepyourfragmentobjectinmemoryandnotstartoverfromscratch.However,ifyouractivityisgoingawayandbeingre-created,you’llhavetodetachyourfragmentfromthisactivityandattachittothenewone.Thebottomlineisthatiftheretaininstancevalueistrue,youwon’tactuallydestroyyourfragmentinstance,andthereforeyouwon’tneedtocreateanewoneontheotherside.ThedottedlinesonthediagrammeanyouwouldskiptheonDestroy()callbackonthewayout,you’dskiptheonCreate()callbackwhenyourfragmentisbeingre-attachedtoyournewactivity,andallothercallbackswouldfire.Becauseanactivityisre-createdmostlikelyforconfigurationchanges,yourfragmentcallbacksshouldprobablyassumethattheconfigurationhaschanged,andthereforeshouldtakeappropriateaction.ThiswouldincludeinflatingthelayouttocreateanewviewhierarchyinonCreateView(),forexample.ThecodeprovidedinListing8-2wouldtakecareofthatasitiswritten.Ifyouchoosetousetheretain-instancefeature,youmaydecidenottoputsomeofyourinitializationlogicinonCreate()becauseitwon’talwaysgetcalledthewaytheothercallbackswill.

SampleFragmentAppShowingtheLifeCycleThere’snothinglikeseeingarealexampletogetanappreciationforaconcept.You’lluseasampleapplicationthathasbeeninstrumentedsoyoucanseeallthesecallbacksinaction.You’regoingtoworkwithasampleapplicationthatusesalistofShakespeareantitlesinonefragment;whentheuserclicksoneofthetitles,sometextfromthatplaywillappearinaseparatefragment.Thissampleapplicationwillworkinbothlandscapeandportraitmodesonatablet.Thenyou’llconfigureittorunasifonasmallerscreensoyoucanseehowtoseparatethetextfragmentintoanactivity.You’llstartwiththeXMLlayoutofyouractivityinlandscapemodeinListing8-3,whichwilllooklikeFigure8-3whenitruns.

Page 217: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing8-3.YourActivity’sLayoutXMLforLandscapeMode

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout-land/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent">

<fragmentclass="com.androidbook.fragments.bard.TitlesFragment"android:id="@+id/titles"android:layout_weight="1"android:layout_width="0px"android:layout_height="match_parent"/><FrameLayoutandroid:id="@+id/details"android:layout_weight="2"android:layout_width="0px"android:layout_height="match_parent"/>

</LinearLayout>

Figure8-3.Theuserinterfaceofyoursamplefragmentapplication

NoteAttheendofthechapteristheURLyoucanusetodownloadtheprojects

Page 218: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

inthischapter.ThiswillallowyoutoimporttheseprojectsintoyourIDE(suchasEclipseorAndroidStudio)directly.

Thislayoutlookslikealotofotherlayoutsyou’veseenthroughoutthebook,horizontallylefttorightwithtwomainobjects.There’saspecialnewtag,though,called<fragment>,andthistaghasanewattributecalledclass.Keepinmindthatafragmentisnotaview,sothelayoutXMLisalittledifferentforafragmentthanitisforeverythingelse.Theotherthingtokeepinmindisthatthe<fragment>tagisjustaplaceholderinthislayout.Youshouldnotputchildtagsunder<fragment>inalayoutXMLfile.

Theotherattributesforafragmentlookfamiliarandserveapurposesimilartothatforaview.Thefragmenttag’sclassattributespecifiesyourextendedclassforthetitlesofyourapplication.Thatis,youmustextendoneoftheAndroidFragmentclassestoimplementyourlogic,andthe<fragment>tagmustknowthenameofyourextendedclass.Afragmenthasitsownviewhierarchythatwillbecreatedlaterbythefragmentitself.ThenexttagisaFrameLayout—notanother<fragment>tag.Whyisthat?We’llexplaininmoredetaillater,butfornow,youshouldbeawarethatyou’regoingtobedoingsometransitionsonthetext,swappingoutonefragmentwithanother.YouusetheFrameLayoutastheviewcontainertoholdthecurrenttextfragment.Withyourtitlesfragment,youhaveone—andonlyone—fragmenttoworryabout:noswappingandnotransitions.FortheareathatdisplaystheShakespeareantext,you’llhaveseveralfragments.

TheMainActivityJavacodeisinListing8-4.Actually,thelistingonlyshowstheinterestingcode.Thecodeisinstrumentedwithloggingmessagessoyoucanseewhat’sgoingonthroughLogCat.PleasereviewthesourcecodefilesforShakespeareInstrumentedfromthewebsitetoseeallofit.

Listing8-4.InterestingSourceCodefromMainActivity

publicbooleanisMultiPane(){returngetResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE;}

/***Helperfunctiontoshowthedetailsofaselecteditem,eitherby*displayingafragmentin-placeinthecurrentUI,orstartinga*wholenewactivityinwhichitisdisplayed.*/publicvoidshowDetails(intindex){Log.v(TAG,"inMainActivityshowDetails("+index+")");

if(isMultiPane()){//Checkwhatfragmentisshown,replaceifneeded.

Page 219: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

DetailsFragmentdetails=(DetailsFragment)getFragmentManager().findFragmentById(R.id.details);if((details==null)||(details.getShownIndex()!=index)){//Makenewfragmenttoshowthisselection.details=DetailsFragment.newInstance(index);

//Executeatransaction,replacinganyexisting//fragmentwiththisoneinsidetheframe.Log.v(TAG,"abouttorunFragmentTransaction…");FragmentTransactionft=getFragmentManager().beginTransaction();ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);//ft.addToBackStack("details");ft.replace(R.id.details,details);ft.commit();}

}else{//Otherwiseyouneedtolaunchanewactivitytodisplay//thedialogfragmentwithselectedtext.Intentintent=newIntent();intent.setClass(this,DetailsActivity.class);intent.putExtra("index",index);startActivity(intent);}}

Thisisaverysimpleactivitytowrite.Todeterminemultipanemode(thatis,whetheryouneedtousefragmentssidebyside),youjustusetheorientationofthedevice.Ifyou’reinlandscapemode,you’remultipane;ifyou’reinportraitmode,you’renot.ThehelpermethodshowDetails()istheretofigureouthowtoshowthetextwhenatitleisselected.Theindexisthepositionofthetitleinthetitlelist.Ifyou’reinmultipanemode,you’regoingtouseafragmenttoshowthetext.You’recallingthisfragmentaDetailsFragment,andyouuseafactory-typemethodtocreateonewiththeindex.TheinterestingcodefortheDetailsFragmentclassisshowninListing8-5(minusalloftheloggingcode).AswedidbeforeinTitlesFragment,thevariouscallbacksofDetailsFragmenthaveloggingaddedsowecanwatchwhathappensviaLogCat.You’llcomebacktoyourshowDetails()methodlater.

Listing8-5.SourceCodeforDetailsFragment

publicclassDetailsFragmentextendsFragment{

privateintmIndex=0;

Page 220: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicstaticDetailsFragmentnewInstance(intindex){Log.v(MainActivity.TAG,"inDetailsFragmentnewInstance("+index+")");

DetailsFragmentdf=newDetailsFragment();

//Supplyindexinputasanargument.Bundleargs=newBundle();args.putInt("index",index);df.setArguments(args);returndf;}

publicstaticDetailsFragmentnewInstance(Bundlebundle){intindex=bundle.getInt("index",0);returnnewInstance(index);}

@OverridepublicvoidonCreate(BundlemyBundle){Log.v(MainActivity.TAG,"inDetailsFragmentonCreate.Bundlecontains:");if(myBundle!=null){for(Stringkey:myBundle.keySet()){Log.v(MainActivity.TAG,""+key);}}else{Log.v(MainActivity.TAG,"myBundleisnull");}super.onCreate(myBundle);

mIndex=getArguments().getInt("index",0);}

publicintgetShownIndex(){returnmIndex;}

@OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){Log.v(MainActivity.TAG,

Page 221: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

"inDetailsFragmentonCreateView.container="+container);

//Don'ttiethisfragmenttoanythingthroughtheinflater.//Androidtakescareofattachingfragmentsforus.The//containerisonlypassedinsoyoucanknowaboutthe//containerwherethisViewhierarchyisgoingtogo.Viewv=inflater.inflate(R.layout.details,container,false);TextViewtext1=(TextView)v.findViewById(R.id.text1);text1.setText(Shakespeare.DIALOGUE[mIndex]);returnv;}}

TheDetailsFragmentclassisactuallyfairlysimpleaswell.Nowyoucanseehowtoinstantiatethisfragment.It’simportanttopointoutthatyou’reinstantiatingthisfragmentincodebecauseyourlayoutdefinestheViewGroupcontainer(aFrameLayout)thatyourdetailsfragmentisgoingtogointo.BecausethefragmentisnotitselfdefinedinthelayoutXMLfortheactivity,asyourtitlesfragmentwas,youneedtoinstantiateyourdetailsfragmentsincode.

Tocreateanewdetailsfragment,youuseyournewInstance()method.Asdiscussedearlier,thisfactorymethodinvokesthedefaultconstructorandthensetstheargumentsbundlewiththevalueofindex.OncenewInstance()hasrun,yourdetailsfragmentcanretrievethevalueofindexinanyofitscallbacksbyreferringtotheargumentsbundleviagetArguments().Foryourconvenience,inonCreate()youcansavetheindexvaluefromtheargumentsbundletoamemberfieldinyourDetailsFragmentclass.

Youmightwonderwhyyoudidn’tsimplysetthemIndexvalueinnewInstance().ThereasonisthatAndroidwill,behindthescenes,re-createyourfragmentusingthedefaultconstructor.Thenitsetstheargumentsbundletowhatitwasbefore.Androidwon’tuseyournewInstance()method,sotheonlyreliablewaytoensurethatmIndexissetistoreadthevaluefromtheargumentsbundleandsetitinonCreate().TheconveniencemethodgetShownIndex()retrievesthevalueofthatindex.NowtheonlymethodlefttodescribeinthedetailsfragmentisonCreateView().Andthisisverysimple,too.

ThepurposeofonCreateView()istoreturntheviewhierarchyforyourfragment.Rememberthatbasedonyourconfiguration,youcouldwantallkindsofdifferentlayoutsforthisfragment.Therefore,themostcommonthingtodoisutilizealayoutXMLfilefor

Page 222: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

yourfragment.Inyoursampleapplication,youspecifythelayoutforthefragmenttobedetails.xmlusingtheresourceR.layout.details.TheXMLfordetails.xmlisinListing8-6.

Listing8-6.Thedetails.xmlLayoutFilefortheDetailsFragment

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/details.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ScrollViewandroid:id="@+id/scroller"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/text1"android:layout_width="match_parent"android:layout_height="match_parent"/></ScrollView></LinearLayout>

Foryoursampleapplication,youcanusetheexactsamelayoutfilefordetailswhetheryou’reinlandscapemodeorinportraitmode.Thislayoutisnotfortheactivity,it’sjustforyourfragmenttodisplaythetext.Becauseitcouldbeconsideredthedefaultlayout,youcanstoreitinthe/res/layoutdirectoryanditwillbefoundandusedevenifyou’reinlandscapemode.WhenAndroidgoeslookingforthedetailsXMLfile,ittriesthespecificdirectoriesthatcloselymatchthedevice’sconfiguration,butitwillendupinthe/res/layoutdirectoryifitcan’tfindthedetails.xmlfileinanyoftheotherplaces.Ofcourse,ifyouwanttohaveadifferentlayoutforyourfragmentinlandscapemode,youcoulddefineaseparatedetails.xmllayoutfileandstoreitunder/res/layout-land.Feelfreetoexperimentwithdifferentdetails.xmlfiles.

Whenyourdetailsfragment’sonCreateView()iscalled,youwillsimplygrabtheappropriatedetails.xmllayoutfile,inflateit,andsetthetexttothetextfromtheShakespeareclass.TheentireJavacodeforShakespeareisnotshownhere,butaportionisinListing8-7soyouunderstandhowitwasdone.Forthecompletesource,accesstheprojectdownloadfiles,asdescribedinthe“References”sectionattheendofthischapter.

Listing8-7.SourceCodeforShakespeare.java

publicclassShakespeare{publicstaticStringTITLES[]={"HenryIV(1)","HenryV","HenryVIII","RomeoandJuliet","Hamlet",

Page 223: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

"TheMerchantofVenice","Othello"};publicstaticStringDIALOGUE[]={"Soshakenasweare,sowanwithcare,\n…...andsoon…

Nowyourdetailsfragmentviewhierarchycontainsthetextfromtheselectedtitle.Yourdetailsfragmentisreadytogo.AndyoucanreturntoMainActivity’sshowDetails()methodtotalkaboutFragmentTransactions.

FragmentTransactionsandtheFragmentBackStackThecodeinshowDetails()thatpullsinyournewdetailsfragment(partiallyshownagaininListing8-8)looksrathersimple,butthere’salotgoingonhere.It’sworthspendingsometimetoexplainwhatishappeningandwhy.Ifyouractivityisinmultipanemode,youwanttoshowthedetailsinafragmentnexttothetitlelist.Youmayalreadybeshowingdetails,whichmeansyoumayhaveadetailsfragmentvisibletotheuser.Eitherway,theresourceIDR.id.detailsisfortheFrameLayoutforyouractivity,asshowninListing8-3.Ifyouhaveadetailsfragmentsittinginthelayoutbecauseyoudidn’tassignanyotherIDtoit,itwillhavethisID.Therefore,tofindoutifthere’sadetailsfragmentinthelayout,youcanaskthefragmentmanagerusingfindFragmentById().Thiswillreturnnulliftheframelayoutisemptyorwillgiveyouthecurrentdetailsfragment.Youcanthendecideifyouneedtoplaceanewdetailsfragmentinthelayout,eitherbecausethelayoutisemptyorbecausethere’sadetailsfragmentforsomeothertitle.Onceyoumakethedeterminationtocreateanduseanewdetailsfragment,youinvokethefactorymethodtocreateanewinstanceofadetailsfragment.Nowyoucanputthisnewfragmentintoplacefortheusertosee.

Listing8-8.FragmentTransactionExample

publicvoidshowDetails(intindex){Log.v(TAG,"inMainActivityshowDetails("+index+")");

if(isMultiPane()){//Checkwhatfragmentisshown,replaceifneeded.DetailsFragmentdetails=(DetailsFragment)getFragmentManager().findFragmentById(R.id.details);if(details==null||details.getShownIndex()!=index){//Makenewfragmenttoshowthisselection.details=DetailsFragment.newInstance(index);

//Executeatransaction,replacinganyexisting

Page 224: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//fragmentwiththisoneinsidetheframe.Log.v(TAG,"abouttorunFragmentTransaction…");FragmentTransactionft=getFragmentManager().beginTransaction();ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);//ft.addToBackStack("details");ft.replace(R.id.details,details);ft.commit();}//Therestwasleftouttosavespace.}

Akeyconcepttounderstandisthatafragmentmustliveinsideaviewcontainer,alsoknownasaviewgroup.TheViewGroupclassincludessuchthingsaslayoutsandtheirderivedclasses.FrameLayoutisagoodchoiceasthecontainerforthedetailsfragmentinthemain.xmllayoutfileofyouractivity.AFrameLayoutissimple,andallyouneedisasimplecontainerforyourfragment,withouttheextrabaggagethatcomeswithothertypesoflayouts.TheFrameLayoutiswhereyourdetailsfragmentisgoingtogo.Ifyouhadinsteadspecifiedanother<fragment>tagintheactivity’slayoutfileinsteadofaFrameLayout,youwouldnotbeabletoreplacethecurrentfragmentwithanewfragment(i.e.,swapfragments).

TheFragmentTransactioniswhatyouusetodoyourswapping.Youtellthefragmenttransactionthatyouwanttoreplacewhateverisinyourframelayoutwithyournewdetailsfragment.YoucouldhaveavoidedallthisbylocatingtheresourceIDofthedetailsTextViewandjustsettingthetextofittothenewtextforthenewShakespearetitle.Butthere’sanothersidetofragmentsthatexplainswhyyouuseFragmentTransactions.

Asyouknow,activitiesarearrangedinastack,andasyougetdeeperanddeeperintoanapplication,it’snotuncommontohaveastackofseveralactivitiesgoingatonce.WhenyoupresstheBackbutton,thetopmostactivitygoesaway,andyouarereturnedtotheactivitybelow,whichresumesforyou.Thiscancontinueuntilyou’reatthehomescreenagain.

Thiswasfinewhenanactivitywasjustsingle-purpose,butnowthatanactivitycanhaveseveralfragmentsgoingatonce,andbecauseyoucangodeeperintoyourapplicationwithoutleavingthetopmostactivity,AndroidreallyneededtoextendtheBackbuttonstackconcepttoincludefragmentsaswell.Infact,fragmentsdemandthisevenmore.Whenthereareseveralfragmentsinteractingwitheachotheratthesametimeinanactivity,andthere’satransitiontonewcontentacrossseveralfragmentsatonce,pressingtheBackbuttonshouldcauseeachofthefragmentstorollbackonesteptogether.Toensurethateachfragmentproperlyparticipatesintherollback,aFragmentTransactioniscreatedandmanagedtoperformthatcoordination.

Beawarethatabackstackforfragmentsisnotrequiredwithinanactivity.YoucancodeyourapplicationtolettheBackbuttonworkattheactivitylevelandnotatthefragment

Page 225: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

levelatall.Ifthere’snobackstackforyourfragments,pressingtheBackbuttonwillpopthecurrentactivityoffthestackandreturntheusertowhateverwasunderneath.Ifyouchoosetotakeadvantageofthebackstackforfragments,youwillwanttouncommentinListing8-8thelinethatsaysft.addToBackStack(“details”).Forthisparticularcase,you’vehardcodedthetagparametertobethestring“details”.Thistagshouldbeanappropriatestringnamethatrepresentsthestateofthefragmentsatthetimeofthetransaction.Thetagisnotnecessarilyanameforaspecificfragmentbutratherforthefragmenttransactionandallthefragmentsinthetransaction.Youwillbeabletointerrogatethebackstackincodeusingthetagvaluetodeleteentries,aswellaspopentriesoff.Youwillwantmeaningfultagsonthesetransactionstobeabletofindtheappropriateoneslater.

FragmentTransactionTransitionsandAnimationsOneoftheverynicethingsaboutfragmenttransactionsisthatyoucanperformtransitionsfromanoldfragmenttoanewfragmentusingtransitionsandanimations.Thesearenotliketheanimationscominglater,inChapter18.Thesearemuchsimpleranddonotrequirein-depthgraphicsknowledge.Let’suseafragmenttransactiontransitiontoaddspecialeffectswhenyouswapouttheolddetailsfragmentwithanewdetailsfragment.Thiscanaddpolishtoyourapplication,makingtheswitchfromtheoldtothenewfragmentlooksmooth.

OnemethodtoaccomplishthisissetTransition(),asshowninListing8-8.However,thereareafewdifferenttransitionsavailable.Youusedafadeinyourexample,butyoucanalsousethesetCustomAnimations()methodtodescribeotherspecialeffects,suchasslidingonefragmentouttotherightasanotherslidesinfromtheleft.Thecustomanimationsusethenewobjectanimationdefinitions,nottheoldones.TheoldanimXMLfilesusetagssuchas<translate>,whereasthenewXMLfilesuse<objectAnimator>.TheoldstandardXMLfilesarelocatedinthe/data/res/animdirectoryundertheappropriateAndroidSDKplatformsdirectory(suchasplatforms/android-11forHoneycomb).TherearesomenewXMLfileslocatedinthe/data/res/animatordirectoryhere,too.Yourcodecouldbesomethinglike

ft.setCustomAnimations(android.R.animator.fade_in,android.R.animator.fade_out);

whichwillcausethenewfragmenttofadeinastheoldfragmentfadesout.Thefirstparameterappliestothefragmententering,andthesecondparameterappliestothefragmentexiting.FeelfreetoexploretheAndroidanimatordirectoryformorestockanimations.Ifyou’dliketocreateyourown,there’ssectionontheobjectanimatorinChapter18tohelpyou.Theotherveryimportantbitofknowledgeyouneedisthatthetransitioncallsneedtocomebeforethereplace()call;otherwise,theywillhavenoeffect.

Usingtheobjectanimatorforspecialeffectsonfragmentscanbeafunwaytodotransitions.TherearetwoothermethodsonFragmentTransactionyoushouldknow

Page 226: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

about:hide()andshow().Bothofthesemethodstakeafragmentasaparameter,andtheydoexactlywhatyou’dexpect.Forafragmentinthefragmentmanagerassociatedtoaviewcontainer,themethodssimplyhideorshowthefragmentintheuserinterface.Thefragmentdoesnotgetremovedfromthefragmentmanagerintheprocess,butitcertainlymustbetiedintoaviewcontainerinordertoaffectitsvisibility.Ifafragmentdoesnothaveaviewhierarchy,orifitsviewhierarchyisnottiedintothedisplayedviewhierarchy,thenthesemethodswon’tdoanything.

Onceyou’vespecifiedthespecialeffectsforyourfragmenttransaction,youhavetotellitthemainworkthatyouwantdone.Inyourcase,you’rereplacingwhateverisintheframelayoutwithyournewdetailsfragment.That’swherethereplace()methodcomesin.Thisisequivalenttocallingremove()foranyfragmentsthatarealreadyintheframelayoutandthenadd()foryournewdetailsfragment,whichmeansyoucouldjustcallremove()oradd()asneededinstead.

Thefinalactionyoumusttakewhenworkingwithafragmenttransactionistocommitit.Thecommit()methoddoesnotcausethingstohappenimmediatelybutratherschedulestheworkforwhentheUIthreadisreadytodoit.

Nowyoushouldunderstandwhyyouneedtogotosomuchtroubletochangethecontentinasimplefragment.It’snotjustthatyouwanttochangethetext;youmightwantaspecialgraphicseffectduringthetransition.Youmayalsowanttosavethetransitiondetailsinafragmenttransactionthatyoucanreverselater.Thatlastpointmaybeconfusing,sowe’llclarify.

Thisisnotatransactioninthetruestsenseoftheword.Whenyoupopfragmenttransactionsoffthebackstack,youarenotundoingallthedatachangesthatmayhavetakenplace.Ifdatachangedwithinyouractivity,forexample,asyoucreatedfragmenttransactionsonthebackstack,pressingtheBackbuttondoesnotcausetheactivitydatachangestorevertbacktotheirpreviousvalues.Youaremerelysteppingbackthroughtheuserinterfaceviewsthewayyoucamein,justasyoudowithactivities,butinthiscaseit’sforfragments.Becauseofthewayfragmentsaresavedandrestored,theinnerstateofafragmentthathasbeenrestoredfromasavedstatewilldependonwhatvaluesyousavedwiththefragmentandhowyoumanagetorestorethem.Soyourfragmentsmaylookthesameastheydidpreviouslybutyouractivitywillnot,unlessyoutakestepstorestoreactivitystatewhenyourestorefragments.

Inyourexample,you’reonlyworkingwithoneviewcontainerandbringinginonedetailsfragment.Ifyouruserinterfaceweremorecomplicated,youcouldmanipulateotherfragmentswithinthefragmenttransaction.Whatyouareactuallydoingisbeginningthetransaction,replacinganyexistingfragmentinyourdetailsframelayoutwithyournewdetailsfragment,specifyingafade-inanimation,andcommittingthetransaction.Youcommentedoutthepartwherethistransactionisaddedtothebackstack,butyoucouldcertainlyuncommentittotakepartinthebackstack.

TheFragmentManager

Page 227: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheFragmentManagerisacomponentthattakescareofthefragmentsbelongingtoanactivity.Thisincludesfragmentsonthebackstackandfragmentsthatmayjustbehangingaround.We’llexplain.

Fragmentsshouldonlybecreatedwithinthecontextofanactivity.Thisoccurseitherthroughtheinflationofanactivity’slayoutXMLorthroughdirectinstantiationusingcodelikethatinListing8-1.Wheninstantiatedthroughcode,afragmentusuallygetsattachedtotheactivityusingafragmenttransaction.Ineithercase,theFragmentManagerclassisusedtoaccessandmanagethesefragmentsforanactivity.

YouusethegetFragmentManager()methodoneitheranactivityoranattachedfragmenttoretrieveafragmentmanager.YousawinListing8-8thatafragmentmanageriswhereyougetafragmenttransaction.Besidesgettingafragmenttransaction,youcanalsogetafragmentusingthefragment’sID,itstag,oracombinationofbundleandkey.Thefragment’sIDwilleitherbethefragment’sresourceIDifthefragmentwasinflatedfromXML,oritwillbethecontainer’sresourceIDifthefragmentwasplacedintoaviewusingafragmenttransaction.Afragment’stagisaStringthatyoucanassigninthefragment’sXMLdefinition,orwhenthefragmentisplacedinaviewviaafragmenttransaction.ThebundleandkeymethodofretrievingafragmentonlyworksforfragmentsthatwerepersistedusingtheputFragment()method.

Forgettingafragment,thegettermethodsincludefindFragmentById(),findFragmentByTag(),andgetFragment().ThegetFragment()methodwouldbeusedinconjunctionwithputFragment(),whichalsotakesabundle,akey,andthefragmenttobeput.ThebundleismostlikelygoingtobethesavedStatebundle,andputFragment()willbeusedintheonSaveInstanceState()callbacktosavethestateofthecurrentactivity(oranotherfragment).ThegetFragment()methodwouldprobablybecalledinonCreate()tocorrespondtoputFragment(),althoughforafragment,thebundleisavailabletotheothercallbackmethods,asdescribedearlier.

Obviously,youcan’tusethegetFragmentManager()methodonafragmentthathasnotbeenattachedtoanactivityyet.Butit’salsotruethatyoucanattachafragmenttoanactivitywithoutmakingitvisibletotheuseryet.Ifyoudothis,youshouldassociateaStringtagtothefragmentsoyoucangettoitinthefuture.You’dmostlikelyusethismethodofFragmentTransactiontodothis:

publicFragmentTransactionadd(Fragmentfragment,Stringtag)

Infact,youcanhaveafragmentthatdoesnotexhibitaviewhierarchy.Thismightbedonetoencapsulatecertainlogictogethersuchthatitcouldbeattachedtoanactivity,yetstillretainsomeautonomyfromtheactivity’slifecycleandfromotherfragments.Whenanactivitygoesthroughare-createcycleduetoadevice-configurationchange,thisnon-UIfragmentcouldremainlargelyintactwhiletheactivitygoesawayandcomesbackagain.ThiswouldbeagoodcandidateforthesetRetainInstance()option.

Thefragmentbackstackisalsothedomainofthefragmentmanager.Whereasafragment

Page 228: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

transactionisusedtoputfragmentsontothebackstack,thefragmentmanagercantakefragmentsoffthebackstack.Thisisusuallydoneusingthefragment’sIDortag,butitcanbedonebasedonpositioninthebackstackorjusttopopthetopmostfragment.

Finally,thefragmentmanagerhasmethodsforsomedebuggingfeatures,suchasturningondebuggingmessagestoLogCatusingenableDebugLogging()ordumpingthecurrentstateofthefragmentmanagertoastreamusingdump().NotethatyouturnedonfragmentmanagerdebuggingintheonCreate()methodofyouractivityinListing8-4.

CautionWhenReferencingFragmentsIt’stimetorevisittheearlierdiscussionofthefragment’slifecycleandtheargumentsandsaved-statebundles.Androidcouldsaveoneofyourfragmentsatmanydifferenttimes.Thismeansthatatthemomentyourapplicationwantstoretrievethatfragment,it’spossiblethatitisnotinmemory.Forthisreason,wecautionyounottothinkthatavariablereferencetoafragmentisgoingtoremainvalidforalongtime.Iffragmentsarebeingreplacedinacontainerviewusingfragmenttransactions,anyreferencetotheoldfragmentisnowpointingtoafragmentthatispossiblyonthebackstack.Orafragmentmaygetdetachedfromtheactivity’sviewhierarchyduringanapplicationconfigurationchangesuchasascreenrotation.Becareful.

Ifyou’regoingtoholdontoareferencetoafragment,beawareofwhenitcouldgetsavedaway;whenyouneedtofinditagain,useoneofthegettermethodsofthefragmentmanager.Ifyouwanttohangontoafragmentreference,suchaswhenanactivityisgoingthroughaconfigurationchange,youcanusetheputFragment()methodwiththeappropriatebundle.Inthecaseofbothactivitiesandfragments,theappropriatebundleisthesavedStatebundlethatisusedinonSaveInstanceState()andthatreappearsinonCreate()(or,inthecaseoffragments,theotherearlycallbacksofthefragment’slifecycle).Youwillprobablyneverstoreadirectfragmentreferenceintotheargumentsbundleofafragment;ifyou’retemptedtodoso,pleasethinkverycarefullyaboutitfirst.

TheotherwayyoucangettoaspecificfragmentisbyqueryingforitusingaknowntagorknownID.Thegettermethodsdescribedpreviouslywillallowretrievaloffragmentsfromthefragmentmanagerthisway,whichmeansyouhavetheoptionofjustrememberingthetagorIDofafragmentsothatyoucanretrieveitfromthefragmentmanagerusingoneofthosevalues,asopposedtousingputFragment()andgetFragment().

SavingFragmentStateAnotherinterestingclasswasintroducedinAndroid3.2:Fragment.SavedState.UsingthesaveFragmentInstanceState()methodofFragmentManager,youcanpassthismethodafragment,anditreturnsanobjectrepresentingthestateofthatfragment.Youcanthenusethatobjectwheninitializingafragment,usingFragment’ssetInitialSavedState()method.Chapter9discussesthisinmoredetail.

Page 229: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ListFragmentsand<fragment>Therearestillafewmorethingstocovertomakeyoursampleapplicationcomplete.ThefirstistheTitlesFragmentclass.Thisistheonethatiscreatedviathemain.xmlfileofyourmainactivity.The<fragment>tagservesasyourplaceholderforwherethisfragmentwillgoanddoesnotdefinewhattheviewhierarchywilllooklikeforthisfragment.TheinterestingcodeforyourTitlesFragmentisinListing8-9.Forallofthecodepleaserefertothesourcecodefiles.TitlesFragmentdisplaysthelistoftitlesforyourapplication.

Listing8-9.TitlesFragmentJavaCode

publicclassTitlesFragmentextendsListFragment{privateMainActivitymyActivity=null;intmCurCheckPosition=0;

@OverridepublicvoidonAttach(ActivitymyActivity){Log.v(MainActivity.TAG,"inTitlesFragmentonAttach;activityis:"+myActivity);super.onAttach(myActivity);this.myActivity=(MainActivity)myActivity;}

@OverridepublicvoidonActivityCreated(BundlesavedState){Log.v(MainActivity.TAG,"inTitlesFragmentonActivityCreated.savedStatecontains:");if(savedState!=null){for(Stringkey:savedState.keySet()){Log.v(MainActivity.TAG,""+key);}}else{Log.v(MainActivity.TAG,"savedStateisnull");}super.onActivityCreated(savedState);

//Populatelistwithyourstaticarrayoftitles.setListAdapter(newArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,Shakespeare.TITLES));

if(savedState!=null){//Restorelaststateforcheckedposition.

Page 230: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

mCurCheckPosition=savedState.getInt("curChoice",0);}

//GetyourListFragment'sListViewandupdateitListViewlv=getListView();lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);lv.setSelection(mCurCheckPosition);

//Activityiscreated,fragmentsareavailable//GoaheadandpopulatethedetailsfragmentmyActivity.showDetails(mCurCheckPosition);}@OverridepublicvoidonSaveInstanceState(BundleoutState){Log.v(MainActivity.TAG,"inTitlesFragmentonSaveInstanceState");super.onSaveInstanceState(outState);outState.putInt("curChoice",mCurCheckPosition);}

@OverridepublicvoidonListItemClick(ListViewl,Viewv,intpos,longid){Log.v(MainActivity.TAG,"inTitlesFragmentonListItemClick.pos="+pos);myActivity.showDetails(pos);mCurCheckPosition=pos;}

@OverridepublicvoidonDetach(){Log.v(MainActivity.TAG,"inTitlesFragmentonDetach");super.onDetach();myActivity=null;}}

UnlikeDetailsFragment,forthisfragmentyoudon’tdoanythingintheonCreateView()callback.Thisisbecauseyou’reextendingtheListFragmentclass,whichcontainsaListViewalready.ThedefaultonCreateView()foraListFragmentcreatesthisListViewforyouandreturnsit.It’snotuntilonActivityCreated()thatyoudoanyrealapplicationlogic.Bythistimeinyourapplication,youcanbesurethattheactivity’sviewhierarchy,plusthisfragment’s,hasbeencreated.TheresourceIDforthatListViewisandroid.R.id.list1,butyou

Page 231: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

canalwayscallgetListView()ifyouneedtogetareferencetoit,whichyoudoinonActivityCreated().BecauseListFragmentmanagestheListView,donotattachtheadaptertotheListViewdirectly.YoumustusetheListFragment’ssetListAdapter()methodinstead.Theactivity’sviewhierarchyisnowsetup,soyou’resafegoingbackintotheactivitytodotheshowDetails()call.

Atthispointinyoursampleactivity’slife,you’veaddedalistadaptertoyourlistview,you’verestoredthecurrentposition(ifyoucamebackfromarestore,dueperhapstoaconfigurationchange),andyou’veaskedtheactivity(inshowDetails())tosetthetexttocorrespondtotheselectedShakespeareantitle.

YourTitlesFragmentclassalsohasalisteneronthelistsowhentheuserclicksanothertitle,theonListItemClick()callbackiscalled,andyouswitchthetexttocorrespondtothattitle,againusingtheshowDetails()method.

Anotherdifferencebetweenthisfragmentandtheearlierdetailsfragmentisthatwhenthisfragmentisbeingdestroyedandre-created,yousavestateinabundle(thevalueofthecurrentpositioninthelist),andyoureaditbackinonCreate().UnlikethedetailsfragmentsthatgetswappedinandoutoftheFrameLayoutonyouractivity’slayout,thereisjustonetitlesfragmenttothinkabout.Sowhenthereisaconfigurationchangeandyourtitlesfragmentisgoingthroughasave-and-restoreoperation,youwanttorememberwhereyouwere.Withthedetailsfragments,youcanre-createthemwithouthavingtorememberthepreviousstate.

InvokingaSeparateActivityWhenNeededThere’sapieceofcodewehaven’ttalkedaboutyet,andthatisinshowDetails()whenyou’reinportraitmodeandthedetailsfragmentwon’tfitproperlyonthesamepageasthetitlesfragment.Ifthescreenrealestatewon’tpermitfeasibleviewingofafragmentthatwouldotherwisebeshownalongsidetheotherfragments,youwillneedtolaunchaseparateactivitytoshowtheuserinterfaceofthatfragment.Foryoursampleapplication,youimplementadetailsactivity;thecodeisinListing8-10.

Listing8-10.ShowingaNewActivityWhenaFragmentDoesn’tFit

publicclassDetailsActivityextendsActivity{

@OverridepublicvoidonCreate(BundlesavedInstanceState){Log.v(MainActivity.TAG,"inDetailsActivityonCreate");super.onCreate(savedInstanceState);

if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){//Ifthescreenisnowinlandscapemode,itmeans//thatyourMainActivityisbeingshownwithboth

Page 232: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//thetitlesandthetext,sothisactivityis//nolongerneeded.BailoutandlettheMainActivity//doallthework.finish();return;}

if(getIntent()!=null){//Thisisanotherwaytoinstantiateadetails//fragment.DetailsFragmentdetails=DetailsFragment.newInstance(getIntent().getExtras());

getFragmentManager().beginTransaction().add(android.R.id.content,details).commit();}}}

Thereareseveralinterestingaspectstothiscode.Foronething,itisreallyeasytoimplement.Youmakeasimpledeterminationofthedevice’sorientation,andaslongasyou’reinportraitmode,yousetupanewdetailsfragmentwithinthisdetailsactivity.Ifyou’reinlandscapemode,yourMainActivityisabletodisplayboththetitlesfragmentandthedetailsfragment,sothereisnoreasontobedisplayingthisactivityatall.Youmaywonderwhyyouwouldeverlaunchthisactivityifyou’reinlandscapemode,andtheansweris,youwouldn’t.However,oncethisactivityhasbeenstartedinportraitmode,iftheuserrotatesthedevicetolandscapemode,thisdetailsactivitywillgetrestartedduetotheconfigurationchange.Sonowtheactivityisstartingup,andit’sinlandscapemode.Atthatmoment,itmakessensetofinishthisactivityandlettheMainActivitytakeoveranddoallthework.

AnotherinterestingaspectaboutthisdetailsactivityisthatyouneversettherootcontentviewusingsetContentView().Sohowdoestheuserinterfacegetcreated?Ifyoulookcarefullyattheadd()methodcallonthefragmenttransaction,youwillseethattheviewcontainertowhichyouaddthefragmentisspecifiedastheresourceandroid.R.id.content.Thisisthetop-levelviewcontainerforanactivity,andthereforewhenyouattachyourfragmentviewhierarchytothiscontainer,yourfragmentviewhierarchybecomestheonlyviewhierarchyfortheactivity.YouusedtheverysameDetailsFragmentclassasbeforewiththeothernewInstance()methodtocreatethefragment(theonethattakesabundleasaparameter),thenyousimplyattachedittothetopoftheactivity’sviewhierarchy.Thiscausesthefragmenttobedisplayedwithinthisnewactivity.

Fromtheuser’spointofview,theyarenowlookingatjustthedetailsfragmentview,whichisthetextfromtheShakespeareanplay.Iftheuserwantstoselectadifferenttitle,

Page 233: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theypresstheBackbutton,whichpopsthisactivitytorevealyourmainactivity(withthetitlesfragmentonly).Theotherchoicefortheuseristorotatethedevicetogetbacktolandscapemode.Thenyourdetailsactivitywillcallfinish()andgoaway,revealingthealso-rotatedmainactivityunderneath.

Whenthedeviceisinportraitmode,ifyou’renotshowingthedetailsfragmentinyourmainactivity,youshouldhaveaseparatemain.xmllayoutfileforportraitmodeliketheoneinListing8-11.

Listing8-11.TheLayoutforaPortraitMainActivity

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent">

<fragmentclass="com.androidbook.fragments.bard.TitlesFragment"android:id="@+id/titles"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>

Ofcourse,youcouldmakethislayoutwhateveryouwantittobe.Foryourpurposeshere,yousimplymakeitshowthetitlesfragmentbyitself.It’sverynicethatyourtitlesfragmentclassdoesn’tneedtoincludemuchcodetodealwiththedevicereconfiguration.

Takeamomenttoviewthisapplication’smanifestfile.InityoufindthemainactivitywithacategoryofLAUNCHERsothatitwillappearinthedevice’slistofapps.ThenyouhavetheseparateDetailsActivitywithacategoryofDEFAULT.ThisallowsyoutostartthedetailsactivityfromcodebutwillnotshowthedetailsactivityasanappintheApplist.

PersistenceofFragmentsWhenyouplaywiththissampleapplication,makesureyourotatethedevice(pressingCtrl+F11rotatesthedeviceintheemulator).Youwillseethatthedevicerotates,andthefragmentsrotaterightalongwithit.IfyouwatchtheLogCatmessages,youwillseealotofthemforthisapplication.Inparticular,duringadevicerotation,paycarefulattentiontothemessagesaboutfragments;notonlydoestheactivitygetdestroyedandre-created,butthefragmentsdoalso.

Sofar,youonlywroteatinybitofcodeonthetitlesfragmenttorememberthecurrentpositioninthetitleslistacrossrestarts.Youdidn’tdoanythinginthedetailsfragmentcodetohandlereconfigurations,andthat’sbecauseyoudidn’tneedto.Androidwilltakecareofhangingontothefragmentsthatareinthefragmentmanager,savingthemaway,

Page 234: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thenrestoringthemwhentheactivityisbeingre-created.Youshouldrealizethatthefragmentsyougetbackafterthereconfigurationiscompleteareverylikelynotthesamefragmentsinmemorythatyouhadbefore.Thesefragmentshavebeenreconstructedforyou.Androidsavedtheargumentsbundleandtheknowledgeofwhichtypeoffragmentitwas,anditstoredthesaved-statebundlesforeachfragmentthatcontainsaved-stateinformationaboutthefragmenttousetorestoreitontheotherside.

TheLogCatmessagesshowyouthefragmentsgoingthroughtheirlifecyclesinsyncwiththeactivity.Youwillseethatyourdetailsfragmentgetsre-created,butyournewInstance()methoddoesnotgetcalledagain.Instead,Androidusesthedefaultconstructor,attachestheargumentsbundletoit,andthenstartscallingthecallbacksonthefragment.ThisiswhyitissoimportantnottodoanythingfancyinthenewInstance()method:whenthefragmentgetsre-created,itwon’tdoitthroughnewInstance().

Youshouldalsoappreciatebynowthatyou’vebeenabletoreuseyourfragmentsinafewdifferentplaces.Thetitlesfragmentwasusedintwodifferentlayouts,butifyoulookatthetitlesfragmentcode,itdoesn’tworryabouttheattributesofeachlayout.Youcouldmakethelayoutsratherdifferentfromeachother,andthetitlesfragmentcodewouldlookthesame.Thesamecanbesaidofthedetailsfragment.Itwasusedinyourmainlandscapelayoutandwithinthedetailsactivityallbyitself.Again,thelayoutforthedetailsfragmentcouldhavebeenverydifferentbetweenthetwo,andthecodeofthedetailsfragmentwouldbethesame.Thecodeofthedetailsactivitywasverysimple,also.

Sofar,you’veexploredtwoofthefragmenttypes:thebaseFragmentclassandtheListFragmentsubclass.Fragmenthasothersubclasses:theDialogFragment,PreferenceFragment,andWebViewFragment.We’llcoverDialogFragmentandPreferenceFragmentinChapters10and11,respectively.

CommunicationswithFragmentsBecausethefragmentmanagerknowsaboutallfragmentsattachedtothecurrentactivity,theactivityoranyfragmentinthatactivitycanaskforanyotherfragmentusingthegettermethodsdescribedearlier.Oncethefragmentreferencehasbeenobtained,theactivityorfragmentcouldcastthereferenceappropriatelyandthencallmethodsdirectlyonthatactivityorfragment.Thiswouldcauseyourfragmentstohavemoreknowledgeabouttheotherfragmentsthanmightnormallybedesired,butdon’tforgetthatyou’rerunningthisapplicationonamobiledevice,socuttingcornerscansometimesbejustified.AcodesnippetisprovidedinListing8-12toshowhowonefragmentmightcommunicatedirectlywithanotherfragment.ThesnippetwouldbepartofoneofyourextendedFragmentclasses,andFragmentOtherisadifferentextendedFragmentclass.

Listing8-12.DirectFragment-to-FragmentCommunication

FragmentOtherfragOther=(FragmentOther)getFragmentManager().findFragmentByTag("other");fragOther.callCustomMethod(arg1,arg2);

Page 235: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

InListing8-12,thecurrentfragmenthasdirectknowledgeoftheclassoftheotherfragmentandalsowhichmethodsexistonthatclass.Thismaybeokaybecausethesefragmentsarepartofoneapplication,anditcanbeeasiertosimplyacceptthefactthatsomefragmentswillknowaboutotherfragments.We’llshowyouacleanerwaytocommunicatebetweenfragmentsintheDialogFragmentsampleapplicationinChapter10.

UsingstartActivity()andsetTargetFragment()Afeatureoffragmentsthatisverymuchlikeactivitiesistheabilityofafragmenttostartanactivity.FragmenthasastartActivity()methodandstartActivityForResult()method.Theseworkjustliketheonesforactivities;whenaresultispassedback,itwillcausetheonActivityResult()callbacktofireonthefragmentthatstartedtheactivity.

There’sanothercommunicationmechanismyoushouldknowabout.Whenonefragmentwantstostartanotherfragment,thereisafeaturethatletsthecallingfragmentsetitsidentitywiththecalledfragment.Listing8-13showsanexampleofwhatitmightlooklike.

Listing8-13.Fragment-to-Target-FragmentSetup

mCalledFragment=newCalledFragment();mCalledFragment.setTargetFragment(this,0);fm.beginTransaction().add(mCalledFragment,"work").commit();

Withthesefewlines,you’vecreatedanewCalledFragmentobject,setthetargetfragmentonthecalledfragmenttothecurrentfragment,andaddedthecalledfragmenttothefragmentmanagerandactivityusingafragmenttransaction.Whenthecalledfragmentstartstorun,itwillbeabletocallgetTargetFragment(),whichwillreturnareferencetothecallingfragment.Withthisreference,thecalledfragmentcouldinvokemethodsonthecallingfragmentorevenaccessviewcomponentsdirectly.Forexample,inListing8-14,thecalledfragmentcouldsettextintheUIofthecallingfragmentdirectly.

Listing8-14.TargetFragment-to-FragmentCommunication

TextViewtv=(TextView)getTargetFragment().getView().findViewById(R.id.text1);tv.setText("Setfromthecalledfragment");

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.ThefilecalledProAndroid5_Ch08_Fragments.zipcontainsallprojects

Page 236: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

fromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoanIDEfromoneofthesezipfiles.ItincludessomeprojectsthatusetheFragmentCompatibilitySDKforolderAndroidsaswell.

http://developer.android.com/guide/components/fragments.htmlTheAndroidDeveloper’sGuidepagetofragments.

http://developer.android.com/design/patterns/multi-pane-layouts.html:Androiddesignguidelinesformultipanelayouts.

http://developer.android.com/training/basics/fragments/index.htmlAndroidtrainingpageforfragments.

SummaryThischapterintroducedtheFragmentclassanditsrelatedclassesforthemanager,transactions,andsubclasses.Thisisasummaryofwhat’sbeencoveredinthischapter:

TheFragmentclass,whatitdoes,andhowtouseit.

Whyfragmentscannotbeusedwithoutbeingattachedtooneandonlyoneactivity.

ThatalthoughfragmentscanbeinstantiatedwithastaticfactorymethodsuchasnewInstance(),youmustalwayshaveadefaultconstructorandawaytosaveinitializationvaluesintoaninitializationargumentsbundle.

Thelifecycleofafragmentandhowitisintertwinedwiththelifecycleoftheactivitythatownsthefragment.

FragmentManageranditsfeatures.

Managingdeviceconfigurationsusingfragments.

Combiningfragmentsintoasingleactivity,orsplittingthembetweenmultipleactivities.

Usingfragmenttransactionstochangewhat’sdisplayedtoauser,andanimatingthosetransitionsusingcooleffects.

NewbehaviorsthatarepossiblewiththeBackbuttonwhenusingfragments.

Usingthe<fragment>taginalayout.

UsingaFrameLayoutasaplaceholderforafragmentwhenyouwanttousetransitions.

ListFragmentandhowtouseanadaptertopopulatethedata

Page 237: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(verymuchlikeaListView).

Launchinganewactivitywhenafragmentcan’tfitontothecurrentscreen,andhowtoadjustwhenaconfigurationchangemakesitpossibletoseemultiplefragmentsagain.

Communicatingbetweenfragments,andbetweenafragmentanditsactivity.

Page 238: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter9

RespondingtoConfigurationChangesWe’vecoveredafairbitofmaterialsofar,andnowseemslikeagoodtimetocoverconfigurationchanges.Whenanapplicationisrunningonadevice,andthedevice’sconfigurationchanges(forexample,isrotated90degrees),yourapplicationneedstorespondaccordingly.Thenewconfigurationwillmostlikelylookdifferentfromthepreviousconfiguration.Forexample,switchingfromportraittolandscapemodemeansthescreenwentfrombeingtallandnarrowtobeingshortandwide.TheUIelements(buttons,text,lists,andsoon)willneedtoberearranged,resized,orevenremovedtoaccommodatethenewconfiguration.

InAndroid,aconfigurationchangebydefaultcausesthecurrentactivitytogoawayandbere-created.Theapplicationitselfkeepsonrunning,butithastheopportunitytochangehowtheactivityisdisplayedinresponsetotheconfigurationchange.Intherarecasethatyouneedtohandleaconfigurationchangewithoutdestroyingandre-creatingyouractivity,Androidprovidesawaytohandlethataswell.

Beawarethatconfigurationchangescantakeonmanyforms,notjustdevicerotation.Ifadevicegetsconnectedtoadock,that’salsoaconfigurationchange.Soischangingthelanguageofthedevice.Whateverthenewconfigurationis,aslongasyou’vedesignedyouractivityforthatconfiguration,Androidtakescareofmosteverythingtotransitiontoit,givingtheuseraseamlessexperience.

Thischapterwilltakeyouthroughtheprocessofaconfigurationchange,fromtheperspectivesofbothactivitiesandfragments.We’llshowyouhowtodesignyourapplicationforthosetransitionsandhowtoavoidtrapsthatcouldcauseyourapplicationtocrashormisbehave.

TheDefaultConfigurationChangeProcessTheAndroidoperatingsystemkeepstrackofthecurrentconfigurationofthedeviceit’srunningon.Configurationincludeslotsoffactors,andnewonesgetaddedallthetime.Forexample,ifadeviceispluggedintoadockingstation,thatrepresentsachangeinthedeviceconfiguration.WhenaconfigurationchangeisdetectedbyAndroid,callbacksareinvokedinrunningapplicationstotellthemachangeisoccurring,soanapplicationcanproperlyrespondtothechange.We’lldiscussthosecallbacksalittlelater,butfornowlet’srefreshyourmemorywithregardtoresources.

OneofthegreatfeaturesofAndroidisthatresourcesgetselectedforyouractivitybasedonthecurrentconfigurationofthedevice.Youdon’tneedtowritecodetofigureoutwhichconfigurationisactive;youjustaccessresourcesbyname,andAndroidgetstheappropriateresourcesforyou.Ifthedeviceisinportraitmodeandyourapplication

Page 239: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

requestsalayout,yougettheportraitlayout.Ifthedeviceisinlandscapemode,yougetthelandscapelayout.Thecodejustrequestsalayoutwithoutspecifyingwhichoneitshouldget.Thisispowerfulbecauseasnewconfigurationfactorsgetintroduced,ornewvaluesforconfigurationfactors,thecodestaysthesame.Alladeveloperneedstodoisdecideifnewresourcesneedtobecreated,andcreatethemasnecessaryforthenewconfiguration.Then,whentheapplicationgoesthroughaconfigurationchange,Androidprovidesthenewresourcestotheapplication,andeverythingcontinuestofunctionasdesired.

Becauseofagreatdesiretokeepthingssimple,Androiddestroysthecurrentactivitywhentheconfigurationchangesandcreatesanewoneinitsplace.Thismightseemratherharsh,butit’snot.Itisabiggerchallengetotakearunningactivityandfigureoutwhichpartswouldstaythesameandwhichwouldnot,andthenonlyworkwiththepiecesthatneedtochange.

Anactivitythat’sabouttobedestroyedisproperlynotifiedfirst,givingyouachancetosaveanythingthatneedstobesaved.Whenthenewactivitygetscreated,ithastheopportunitytorestorestateusingdatafromthepreviousactivity.Foragooduserexperience,obviouslyyoudonotwantthissaveandrestoretotakeverylong.

It’sfairlyeasytosaveanydatathatyouneedsavedandthenletAndroidthrowawaytherestandstartover,aslongasthedesignoftheapplicationanditsactivitiesissuchthatactivitiesdon’tcontainalotofnon-UIstuffthatwouldtakealongtimetore-create.Thereinliesthesecrettosuccessfulconfigurationchangedesign:donotput“stuff”insideanactivitythatcannotbeeasilyre-createdduringaconfigurationchange.

Keepinmindthatourapplicationisnotbeingdestroyed,soanythingthatisintheapplicationcontext,andnotapartofourcurrentactivity,willstillbethereforthenewactivity.Singletonswillstillbeavailable,aswellasanybackgroundthreadswemighthavespunofftodoworkforourapplication.Anydatabasesorcontentprovidersthatwewereworkingwithwillalsostillbearound.Takingadvantageofthesemakesconfigurationchangesquickandpainless.Keepdataandbusinesslogicoutsideofactivitiesifyoucan.

Theconfigurationchangeprocessissomewhatsimilarbetweenactivitiesandfragments.Whenanactivityisbeingdestroyedandre-created,thefragmentswithinthatactivitygetdestroyedandre-created.Whatweneedtoworryaboutthenisstateinformationaboutourfragmentsandactivity,suchasdatacurrentlybeingdisplayedtotheuser,orinternalvaluesthatwewanttopreserve.Wewillsavewhatwewanttokeep,andpickitupagainontheothersidewhenthefragmentsandactivitiesarebeingre-created.You’llwanttoprotectdatathatcan’teasilybere-createdbynotlettingitgetdestroyedinthedefaultconfigurationchangeprocess.

TheDestroy/CreateCycleofActivitiesTherearethreecallbackstobeawareofwhendealingwithdefaultconfigurationchangesinactivities:

onSaveInstanceState()

Page 240: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

onCreate()

onRestoreInstanceState()

ThefirstisthecallbackthatAndroidwillinvokewhenitdetectsthataconfigurationchangeishappening.Theactivityhasachancetosavestatethatitwantstorestorewhenthenewactivitygetscreatedattheendoftheconfigurationchange.TheonSaveInstanceState()callbackwillbecalledpriortothecalltoonStop().WhateverstateexistscanbeaccessedandsavedintoaBundleobject.Thisobjectwillgetpassedintobothoftheothercallbacks(onCreate()andonRestoreInstanceState())whentheactivityisre-created.Youonlyneedtoputlogicinoneortheothertorestoreyouractivity’sstate.

ThedefaultonSaveInstanceState()callbackdoessomenicethingsforyou.Forexample,itgoesthroughthecurrentlyactiveviewhierarchyandsavesthevaluesforeachviewthathasanandroid:id.ThismeansifyouhaveanEditTextviewthathasreceivedsomeuserinput,thatinputwillbeavailableontheothersideoftheactivitydestroy/createcycletopopulatetheEditTextbeforetheusergetscontrolback.Youdonotneedtogothroughandsavethisstateyourself.IfyoudooverrideonSaveInstanceState(),besuretocallsuper.onSaveInstanceState()withthebundleobjectsoitcantakecareofthisforyou.It’snottheviewsthataresaved,onlytheattributesoftheirstatethatshouldpersistacrossthedestroy/createboundary.

Tosavedatainthebundleobject,usemethodssuchasputInt()forintegersandputString()forstrings.Therearequiteafewmethodsintheandroid.os.Bundleclass;youarenotlimitedtointegersandstrings.Forexample,putParcelable()canbeusedtosavecomplexobjects.Eachputisusedwithastringkey,andyouwillretrievethevaluelaterusingthesamekeyusedtoputthevaluein.AsampleonSaveInstanceState()mightlooklikeListing9-1.

Listing9-1.SampleonSaveInstanceState()

@OverridepublicvoidonSaveInstanceState(Bundleicicle){super.onSaveInstanceState(icicle);icicle.putInt("counter",1);}

Sometimesthebundleiscallediciclebecauseitrepresentsasmallfrozenpieceofanactivity.Inthissample,youonlysaveonevalue,andithasakeyofcounter.Youcouldsavemorevaluesbysimplyaddingmoreputstatementstothiscallback.Thecountervalueinthisexampleissomewhattemporarybecauseiftheapplicationiscompletelydestroyed,thecurrentvaluewillbelost.Thiscouldhappeniftheuserturnedofftheirdevice,forexample.InChapter11,you’lllearnaboutwaystosavevaluesmorepermanently.Thisinstancestateisonlymeanttohangontovalueswhiletheapplicationisrunningthistime.Donotusethismechanismforstatethatisimportanttokeepforalongerterm.

Page 241: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Torestoreactivitystate,youaccessthebundleobjecttoretrievevaluesthatyoubelievearethere.Again,youusemethodsoftheBundleclasssuchasgetInt()andgetString()withtheappropriatekeypassedtotellwhichvalueyouwantback.IfthekeydoesnotexistintheBundle,avalueof0ornullispassedback(dependingonthetypeoftheobjectbeingrequested).Oryoucanprovideadefaultvalueintheappropriategettermethod.Listing9-2showsasampleonRestoreInstanceState()callback.

Listing9-2.SampleonRestoreInstanceState()

@OverridepublicvoidonRestoreInstanceState(Bundleicicle){super.onRestoreInstanceState(icicle);intsomeInt=icicle.getInt("counter",-1);//NowgodosomethingwithsomeInttorestorethe//stateoftheactivity.-1isthedefaultifno//valuewasfound.}

It’suptoyouwhetheryourestorestateinonCreate()orinonRestoreInstanceState().ManyapplicationswillrestorestateinonCreate()becausethatiswherealotofinitializationisdone.Onereasontoseparatethetwowouldbeifyou’recreatinganactivityclassthatcouldbeextended.ThedevelopersdoingtheextendingmightfinditeasiertojustoverrideonRestoreInstanceState()withthecodetorestorestate,ascomparedtohavingtooverrideallofonCreate().

What’sveryimportanttonotehereisthatyouneedtobeveryconcernedwithreferencestoactivitiesandviewsandotherobjectsthatneedtobegarbage-collectedwhenthecurrentactivityisfullydestroyed.Ifyouputsomethingintothesavedbundlethatrefersbacktotheactivitybeingdestroyed,thatactivitycan’tbegarbagecollected.Thisisverylikelyamemoryleakthatcouldgrowandgrowuntilyourapplicationcrashes.ObjectstoavoidinbundlesincludeDrawables,Adapters,Views,andanythingelsethatistiedtotheactivitycontext.InsteadofputtingaDrawableintothebundle,serializethebitmapandsavethat.Orbetteryet,managethebitmapsoutsideoftheactivityandfragmentinsteadofinside.Addsomesortofreferencetothebitmaptothebundle.Whenitcomestimetore-createanyDrawablesforthenewfragment,usethereferencetoaccesstheoutsidebitmapstoregenerateyourDrawables.

TheDestroy/CreateCycleofFragmentsThedestroy/createcycleforfragmentsisverysimilartothatofactivities.Afragmentintheprocessofbeingdestroyedandre-createdwillhaveitsonSaveInstanceState()callbackcalled,allowingthefragmenttosavevaluesinaBundleobjectforlater.OnedifferenceisthatsixfragmentcallbacksreceivethisBundleobjectwhenafragmentisbeingre-created:onInflate(),onCreate(),onCreateView(),onActivityCreated(),onViewCreated(),andonViewStateRestored().

Page 242: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thelasttwocallbacksaremorerecent,fromHoneycomb3.2andJellyBean4.2respectively.Thisgivesuslotsofopportunitiestorebuildtheinternalstateofourreconstructedfragmentfromitspreviousstate.

AndroidguaranteesonlythatonSaveInstanceState()willbecalledforafragmentsometimebeforeonDestroy().ThatmeanstheviewhierarchymayormaynotbeattachedwhenonSaveInstanceState()iscalled.Therefore,don’tcountontraversingtheviewhierarchyinsideofonSaveInstanceState().Forexample,ifthefragmentisonthefragmentbackstack,noUIwillbeshowing,sonoviewhierarchywillexist.ThisisOKofcoursebecauseifnoUIisshowing,thereisnoneedtoattempttocapturethecurrentvaluesofviewstosavethem.Youneedtocheckifaviewexistsbeforetryingtosaveitscurrentvalue,andnotconsideritanerroriftheviewdoesnotexist.

Justlikewithactivities,becarefulnottoincludeitemsinthebundleobjectthatrefertoanactivityortoafragmentthatmightnotexistlaterwhenthisfragmentisbeingre-created.Keepthesizeofthebundleassmallaspossible,andasmuchaspossiblestorelong-lastingdataoutsideofactivitiesandfragmentsandsimplyrefertoitfromyouractivitiesandfragments.Thenyourdestroy/createcycleswillgothatmuchfaster,you’llbemuchlesslikelytocreateamemoryleak,andyouractivityandfragmentcodeshouldbeeasiertomaintain.

UsingFragmentManagertoSaveFragmentStateFragmentshaveanotherwaytosavestate,inadditionto,orinsteadof,Androidnotifyingthefragmentsthattheirstateshouldbesaved.WithHoneycomb3.2,theFragmentManagerclassgotasaveFragmentInstanceState()methodthatcanbecalledtogenerateanobjectoftheclassFragment.SavedState.ThemethodsmentionedintheprevioussectionsforsavingstatedosowithintheinternalsofAndroid.Whileweknowthatthestateisbeingsaved,wedonothaveanydirectaccesstoit.Thismethodofsavingstategivesyouanobjectthatrepresentsthesavedstateofafragmentandallowsyoutocontrolifandwhenafragmentiscreatedfromthatstate.

ThewaytouseaFragment.SavedStateobjecttorestoreafragmentisthroughthesetInitialSavedState()methodoftheFragmentclass.InChapter8,youlearnedthatitisbesttocreatenewfragmentsusingastaticfactorymethod(forexample,newInstance()).Withinthismethod,yousawhowadefaultconstructoriscalledandthenanargumentsbundleisattached.YoucouldinsteadcallthesetInitialSavedState()methodtosetitupforrestorationtoapreviousstate.

Thereareafewcaveatsyoushouldknowaboutthismethodofsavingfragmentstate:

Thefragmenttobesavedmustcurrentlybeattachedtothefragmentmanager.

Anewfragmentcreatedusingthissavedstatemustbethesameclasstypeasthefragmentitwascreatedfrom.

Thesavedstatecannotcontaindependenciesonotherfragments.Otherfragmentsmaynotexistwhenthesavedfragmentisre-created.

Page 243: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UsingsetRetainInstanceonaFragmentAfragmentcanavoidbeingdestroyedandre-createdonaconfigurationchange.IfthesetRetainInstance()methodiscalledwithanargumentoftrue,thefragmentwillberetainedintheapplicationwhenitsactivityisbeingdestroyedandre-created.Thefragment’sonDestroy()callbackwillnotbecalled,norwillonCreate().TheonDetach()callbackwillbecalledbecausethefragmentmustbedetachedfromtheactivitythat’sgoingaway,andonAttach()andonActivityCreated()willbecalledbecausethefragmentisattachedtoanewactivity.Thisonlyworksforfragmentsthatarenotonthebackstack.ItisespeciallyusefulforfragmentsthatdonothaveaUI.

Thisfeatureisverypowerfulinthatyoucanuseanon-UIfragmenttohandlereferencestoyourdataobjectsandbackgroundthreads,andcallsetRetainInstance(true)onthisfragmentsoitwon’tgetdestroyedandre-createdonaconfigurationchange.Theaddedbonusisthatduringthenormalconfigurationchangeprocess,thenon-UIfragmentcallbacksonDetach()andonAttach()willswitchtheactivityreferencefromtheoldtothenew.

DeprecatedConfigurationChangeMethodsAcoupleofmethodsonActivityhavebeendeprecated,soyoushouldnolongerusethem:

getLastNonConfigurationInstance()

onRetainNonConfigurationInstance()

Thesemethodspreviouslyallowedyoutosaveanarbitraryobjectfromanactivitythatwasbeingdestroyed,tobepassedtothenextinstanceoftheactivitythatwasbeingcreated.Althoughtheywereuseful,youshouldnowusethemethodsdescribedearlierinsteadtomanagedatabetweeninstancesofactivitiesinthedestroy/createcycle.

HandlingConfigurationChangesYourselfSofar,you’veseenhowAndroidhandlesconfigurationchangesforyou.Ittakescareofdestroyingandre-creatingactivitiesandfragments,pullinginthebestresourcesforthenewconfiguration,retaininganyuser-entereddata,andgivingyoutheopportunitytoexecutesomeextralogicinsomecallbacks.Thisisusuallygoingtobeyourbestoption.Butwhenitisn’t,whenyouhavetohandleaconfigurationchangeyourself,Androidprovidesawayout.Thisisn’trecommendedbecauseitisthencompletelyuptoyoutodeterminewhatneedstochangeduetothechange,andthenforyoutotakecareofmakingallthechanges.Asmentionedbefore,therearemanyconfigurationchangesbesidesjustanorientationchange.Luckily,youdon’tnecessarilyhavetohandleall

Page 244: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

configurationchangesyourself.

Thefirststeptohandlingconfigurationchangesyourselfistodeclareinthe<activity>taginAndroidManifest.xmlfilewhichchangesyou’regoingtohandleusingtheandroid:configChangesattribute.Androidwillhandletheotherconfigurationchangesusingthepreviouslydescribedmethods.Youcanspecifyasmanyconfigurationchangetypesasneededbyor’ingthemtogetherwiththe‘|’symbol,likethis:

<activity...android:configChanges="orientation|keyboardHidden"...>

ThecompletelistofconfigurationchangetypescanbefoundonthereferencepageforR.attr.BeawarethatifyoutargetAPI13orhigherandyouneedtohandleorientation,youalsoneedtohandlescreenSize.

Thedefaultprocessforaconfigurationchangeistheinvokingofcallbackstodestroyandre-createtheactivityorfragment.Whenyou’vedeclaredthatyouwillhandlethespecificconfigurationchange,theprocesschangessoonlytheonConfigurationChanged()callbackisinvokedinstead,ontheactivityanditsfragments.AndroidpassesinaConfigurationobjectsothecallbackknowswhatthenewconfigurationis.Itisuptothecallbacktodeterminewhatmighthavechanged;however,sinceyoulikelyhandleonlyasmallnumberofconfigurationchangesyourself,itshouldn’tbetoohardtofigurethisout.

You’dreallyonlywanttohandleaconfigurationchangeyourselfwhenthereisverylittletobedone,whenyoucouldskipdestroyingandre-creating.Forexample,iftheactivitylayoutforportraitandlandscapeisthesamelayoutandallimageresourcesarethesame,destroyingandre-creatingtheactivitydoesn’treallyaccomplishanything.Inthiscaseitwouldbefairlysafetodeclarethatyouwillhandletheorientationconfigurationchange.Duringanorientationchangeofyouractivity,theactivitywouldremainintactandsimplyre-renderitselfintheneworientationusingtheexistingresourcessuchasthelayout,images,strings,etc.Butit’sreallynotthatbigadealtojustletAndroidtakecareofthingsifyoucan.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch09_ConfigChanges.zip.ThisZIPfilecontainsalltheprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoyourIDEfromoneoftheseZIPfiles.

http://developer.android.com/guide/topics/fundamentals/activities.html#SavingActivityStateTheAndroidDeveloper’sGuide,whichdiscussessavingand

Page 245: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

restoringstate.

http://developer.android.com/guide/topics/resources/runtime-changes.html:TheAndroidAPIGuideforHandlingRuntimeChanges.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedabouthandlingconfigurationchanges:

Activitiesbydefaultgetdestroyedandre-createdduringconfigurationchanges.Sodofragments.

Avoidputtinglotsofdataandlogicintoactivitiessoconfigurationchangesoccurquickly.

LetAndroidprovidetheappropriateresources.

Usesingletonstoholddataoutsideofactivitiestomakeiteasiertodestroyandre-createactivitiesduringconfigurationchanges.

TakeadvantageofthedefaultonSaveInstanceState()callbacktosaveUIstateonviewswithandroid:ids.

Ifafragmentcansurvivewithnoissuesacrossanactivitydestroy-and-createcycle,usesetRetainInstance()totellAndroiditdoesn’tneedtodestroyandcreatethefragment.

Page 246: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter10

WorkingwithDialogsTheAndroidSDKoffersextensivesupportfordialogs.Adialogisasmallerwindowthatpopsupinfrontofthecurrentwindowtoshowanurgentmessage,toprompttheuserforapieceofinput,ortoshowsomesortofstatusliketheprogressofadownload.Theuserisgenerallyexpectedtointeractwiththedialogandthenreturntothewindowunderneathtocontinuewiththeapplication.Technically,Androidallowsadialogfragmenttoalsobeembeddedwithinanactivity’slayout,andwe’llcoverthataswell.

DialogsthatareexplicitlysupportedinAndroidincludethealert,prompt,pick-list,single-choice,multiple-choice,progress,time-picker,anddate-pickerdialogs.(ThislistcouldvarydependingontheAndroidrelease.)Androidalsosupportscustomdialogsforotherneeds.TheprimarypurposeofthischapterisnottocovereverysingleoneofthesedialogsbuttocovertheunderlyingarchitectureofAndroiddialogswithasampleapplication.FromthereyoushouldbeabletouseanyoftheAndroiddialogs.

It’simportanttonotethatAndroid3.0addeddialogsbasedonfragments.TheexpectationfromGoogleisthatdeveloperswillonlyusefragmentdialogs,evenintheversionsofAndroidbefore3.0.Thiscanbedonewiththefragment-compatibilitylibrary.Forthisreason,thischapterfocusesonDialogFragment.

UsingDialogsinAndroidDialogsinAndroidareasynchronous,whichprovidesflexibility.However,ifyouareaccustomedtoaprogrammingframeworkwheredialogsareprimarilysynchronous(suchasMicrosoftWindows,orJavaScriptdialogsinwebpages),youmightfindasynchronousdialogsabitunintuitive.Withasynchronousdialog,thelineofcodeafterthedialogisshowndoesnotrununtilthedialoghasbeendismissed.Thismeansthenextlineofcodecouldinterrogatewhichbuttonwaspressed,orwhattextwastypedintothedialog.InAndroidhowever,dialogsareasynchronous.Assoonasthedialoghasbeenshown,thenextlineofcoderuns,eventhoughtheuserhasn’ttouchedthedialogyet.Yourapplicationhastodealwiththisfactbyimplementingcallbacksfromthedialog,toallowtheapplicationtobenotifiedofuserinteractionwiththedialog.

Thisalsomeansyourapplicationhastheabilitytodismissthedialogfromcode,whichispowerful.Ifthedialogisdisplayingabusymessagebecauseyourapplicationisdoingsomething,assoonasyourapplicationhascompletedthattask,itcandismissthedialogfromcode.

UnderstandingDialogFragmentsInthissection,youlearnhowtousedialogfragmentstopresentasimplealertdialogand

Page 247: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

acustomdialogthatisusedtocollectprompttext.

DialogFragmentBasicsBeforeweshowyouworkingexamplesofapromptdialogandanalertdialog,wewouldliketocoverthehigh-levelideaofdialogfragments.Dialog-relatedfunctionalityusesaclasscalledDialogFragment.ADialogFragmentisderivedfromtheclassFragmentandbehavesmuchlikeafragment.YouwillthenusetheDialogFragmentasthebaseclassforyourdialogs.Onceyouhaveaderiveddialogfromthisclasssuchas

publicclassMyDialogFragmentextendsDialogFragment{...}

youcanthenshowthisdialogfragmentMyDialogFragmentasadialogusingafragmenttransaction.Listing10-1showsacodesnippettodothis.

Listing10-1.ShowingaDialogFragment

publicclassSomeActivityextendsActivity{//....otheractivityfunctionspublicvoidshowDialog(){//constructMyDialogFragmentMyDialogFragmentmdf=MyDialogFragment.newInstance(arg1,arg2);FragmentManagerfm=getFragmentManager();FragmentTransactionft=fm.beginTransaction();mdf.show(ft,"my-dialog-tag");}//....otheractivityfunctions}

NoteWeprovidealinktoadownloadableprojectattheendofthischapterinthe“References”section.Youcanusethisdownloadtoexperimentwiththecodeandtheconceptspresentedinthischapter.

FromListing10-1,thestepstoshowadialogfragmentareasfollows:

1. Createadialogfragment.

2. Getafragmenttransaction.

3. Showthedialogusingthefragmenttransactionfromstep2.

Let’stalkabouteachofthesesteps.

ConstructingaDialogFragmentWhenconstructingadialogfragment,therulesarethesameaswhenbuildinganyother

Page 248: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

kindoffragment.TherecommendedpatternistouseafactorymethodsuchasnewInstance()asyoudidbefore.InsidethatnewInstance()method,youusethedefaultconstructorforyourdialogfragment,andthenyouaddanargumentsbundlethatcontainsyourpassed-inparameters.Youdon’twanttodootherworkinsidethismethodbecauseyoumustmakesurethatwhatyoudohereisthesameaswhatAndroiddoeswhenitrestoresyourdialogfragmentfromasavedstate.AndallthatAndroiddoesistocallthedefaultconstructorandre-createtheargumentsbundleonit.

OverridingonCreateViewWhenyouinheritfromadialogfragment,youneedtooverrideoneoftwomethodstoprovidetheviewhierarchyforyourdialog.ThefirstoptionistooverrideonCreateView()andreturnaview.ThesecondoptionistooverrideonCreateDialog()andreturnadialog(liketheoneconstructedbyanAlertDialog.Builder,whichwe’llgettoshortly).

Listing10-2showsanexampleofoverridingtheonCreateView().

Listing10-2.OverridingonCreateView()ofaDialogFragment

publicclassMyDialogFragmentextendsDialogFragmentimplementsView.OnClickListener{.....otherfunctionspublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){//CreateaviewbyinflatingdesiredlayoutViewv=inflater.inflate(R.layout.prompt_dialog,container,false);

//youcanlocateaviewandsetvaluesTextViewtv=(TextView)v.findViewById(R.id.promptmessage);tv.setText(this.getPrompt());

//YoucansetcallbacksonbuttonsButtondismissBtn=(Button)v.findViewById(R.id.btn_dismiss);dismissBtn.setOnClickListener(this);

ButtonsaveBtn=(Button)v.findViewById(R.id.btn_save);saveBtn.setOnClickListener(this);returnv;}.....otherfunctions}

Page 249: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

InListing10-2,youareloadingaviewidentifiedbyalayout.Thenyoulookfortwobuttonsandsetupcallbacksonthem.ThisisverysimilartohowyoucreatedthedetailsfragmentinChapter8.However,unliketheearlierfragments,adialogfragmenthasanotherwaytocreatetheviewhierarchy.

OverridingonCreateDialogAsanalternatetosupplyingaviewinonCreateView(),youcanoverrideonCreateDialog()andsupplyadialoginstance.Listing10-3suppliessamplecodeforthisapproach.

Listing10-3.OverridingonCreateDialog()ofaDialogFragment

publicclassMyDialogFragmentextendsDialogFragmentimplementsDialogInterface.OnClickListener{.....otherfunctions@OverridepublicDialogonCreateDialog(Bundleicicle){AlertDialog.Builderb=newAlertDialog.Builder(getActivity()).setTitle("MyDialogTitle").setPositiveButton("Ok",this).setNegativeButton("Cancel",this).setMessage(this.getMessage());returnb.create();}.....otherfunctions}

Inthisexample,youusethealertdialogbuildertocreateadialogobjecttoreturn.Thisworkswellforsimpledialogs.ThefirstoptionofoverridingonCreateView()isequallyeasyandprovidesmuchmoreflexibility.

AlertDialog.Builderisactuallyacarryoverfrompre-3.0Android.Thisisoneoftheoldwaystocreateadialog,andit’sstillavailabletoyoutocreatedialogswithinDialogFragments.Asyoucansee,it’sfairlyeasytobuildadialogbycallingthevariousmethodsavailable,aswe’vedonehere.

DisplayingaDialogFragmentOnceyouhaveadialogfragmentconstructed,youneedafragmenttransactiontoshowit.Likeallotherfragments,operationsondialogfragmentsareconductedthroughfragmenttransactions.

Theshow()methodonadialogfragmenttakesafragmenttransactionasaninput.YoucanseethisinListing10-1.Theshow()methodusesthefragmenttransactiontoaddthisdialogtotheactivityandthencommitsthefragmenttransaction.However,theshow()

Page 250: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

methoddoesnotaddthetransactiontothebackstack.Ifyouwanttodothis,youneedtoaddthistransactiontothebackstackfirstandthenpassittotheshow()method.Theshow()methodofadialogfragmenthasthefollowingsignatures:

publicintshow(FragmentTransactiontransaction,Stringtag)publicintshow(FragmentManagermanager,Stringtag)

Thefirstshow()methoddisplaysthedialogbyaddingthisfragmenttothepassed-intransactionwiththespecifiedtag.Thismethodthenreturnstheidentifierofthecommittedtransaction.

Thesecondshow()methodautomatesgettingatransactionfromthetransactionmanager.Thisisashortcutmethod.However,whenyouusethissecondmethod,youdon’thaveanoptiontoaddthetransactiontothebackstack.Ifyouwantthatcontrol,youneedtousethefirstmethod.Thesecondmethodcouldbeusedifyouwantedtosimplydisplaythedialog,andyouhadnootherreasontoworkwithafragmenttransactionatthattime.

Anicethingaboutadialogbeingafragmentisthattheunderlyingfragmentmanagerdoesthebasicstatemanagement.Forexample,evenifthedevicerotateswhenadialogisbeingdisplayed,thedialogisreproducedwithoutyouperforminganystatemanagement.

Thedialogfragmentalsooffersmethodstocontroltheframeinwhichthedialog’sviewisdisplayed,suchasthetitleandtheappearanceoftheframe.RefertotheDialogFragmentclassdocumentationtoseemoreoftheseoptions;thisURLisprovidedattheendofthischapter.

DismissingaDialogFragmentTherearetwowaysyoucandismissadialogfragment.Thefirstistoexplicitlycallthedismiss()methodonthedialogfragmentinresponsetoabuttonorsomeactiononthedialogview,asshowninListing10-4.

Listing10-4.Callingdismiss()

if(someview.getId()==R.id.btn_dismiss){//usesomecallbackstoadviseclients//ofthisdialogthatitisbeingdismissed//andcalldismissdismiss();return;}

Thedialogfragment’sdismiss()methodremovesthefragmentfromthefragmentmanagerandthencommitsthattransaction.Ifthereisabackstackforthisdialogfragment,thenthedismiss()popsthecurrentdialogoutofthetransactionstackandpresentsthepreviousfragmenttransactionstate.Whetherthereisabackstackornot,callingdismiss()resultsincallingthestandarddialogfragmentdestroycallbacks,

Page 251: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

includingonDismiss().

Onethingtonoteisthatyoucan’trelyononDismiss()toconcludethatadismiss()hasbeencalledbyyourcode.ThisisbecauseonDismiss()isalsocalledwhenadeviceconfigurationchangesandhenceisnotagoodindicatorofwhattheuserdidtothedialogitself.Ifthedialogisbeingdisplayedwhentheuserrotatesthedevice,thedialogfragmentseesonDismiss()calledeventhoughtheuserdidnotpressabuttoninthedialog.Instead,youshouldalwaysrelyonexplicitbuttonclicksonthedialogview.

IftheuserpressestheBackbuttonwhilethedialogfragmentisdisplayed,thiscausestheonCancel()callbacktofireonthedialogfragment.Bydefault,Androidmakesthedialogfragmentgoaway,soyoudon’tneedtocalldismiss()onthefragmentyourself.Butifyouwantthecallingactivitytobenotifiedthatthedialoghasbeencancelled,youneedtoinvokelogicfromwithinonCancel()tomakethathappen.ThisisadifferencebetweenonCancel()andonDismiss()withdialogfragments.WithonDismiss(),youcan’tbesureexactlywhathappenedthatcausedtheonDismiss()callbacktofire.Youmightalsohavenoticedthatadialogfragmentdoesnothaveacancel()method,justdismiss();butaswesaid,whenadialogfragmentisbeingcancelledbypressingtheBackbutton,Androidtakescareofcancelling/dismissingitforyou.

Theotherwaytodismissadialogfragmentistopresentanotherdialogfragment.Thewayyoudismissthecurrentdialogandpresentthenewoneisslightlydifferentthanjustdismissingthecurrentdialog.Listing10-5showsanexample.

Listing10-5.SettingUpaDialogforaBackStack

if(someview.getId()==R.id.btn_invoke_another_dialog){Activityact=getActivity();FragmentManagerfm=act.getFragmentManager();FragmentTransactionft=fm.beginTransaction();ft.remove(this);

ft.addToBackStack(null);//nullrepresentsnonameforthebackstacktransaction

HelpDialogFragmenthdf=HelpDialogFragment.newInstance(R.string.helptext);hdf.show(ft,"HELP");return;}

Withinasingletransaction,you’reremovingthecurrentdialogfragmentandaddingthenewdialogfragment.Thishastheeffectofmakingthecurrentdialogdisappearvisuallyandmakingthenewdialogappear.IftheuserpressestheBackbutton,becauseyou’vesavedthistransactiononthebackstack,thenewdialogisdismissedandtheprevious

Page 252: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

dialogisdisplayed.Thisisahandywayofdisplayingahelpdialog,forexample.

ImplicationsofaDialogDismissWhenyouaddanyfragmenttoafragmentmanager,thefragmentmanagerdoesthestatemanagementforthatfragment.Thismeanswhenadeviceconfigurationchanges(forexample,thedevicerotates),theactivityisrestartedandthefragmentsarealsorestarted.YousawthisearlierwhenyourotatedthedevicewhilerunningtheShakespearesampleapplicationinchapter8.

Adevice-configurationchangedoesn’taffectdialogsbecausetheyarealsomanagedbythefragmentmanager.Buttheimplicitbehaviorofshow()anddismiss()meansyoucaneasilylosetrackofadialogfragmentifyou’renotcareful.Theshow()methodautomaticallyaddsthefragmenttothefragmentmanager;thedismiss()methodautomaticallyremovesthefragmentfromthefragmentmanager.Youmayhaveadirectpointertoadialogfragmentbeforeyoustartshowingthefragment.Butyoucan’taddthisfragmenttothefragmentmanagerandlatercallshow(),becauseafragmentcanonlybeaddedoncetothefragmentmanager.Youmayplantoretrievethispointerthroughrestoreoftheactivity.However,ifyoushowanddismissthisdialog,thisfragmentisimplicitlyremovedfromthefragmentmanager,therebydenyingthatfragment’sabilitytoberestoredandrepointed(becausethefragmentmanagerdoesn’tknowthisfragmentexistsafteritisremoved).

Ifyouwanttokeepthestateofadialogafteritisdismissed,youneedtomaintainthestateoutsideofthedialogeitherintheparentactivityorinanon-dialogfragmentthathangsaroundforalongertime.

DialogFragmentSampleApplicationInthissection,youreviewasampleapplicationthatdemonstratestheseconceptsofadialogfragment.Youalsoexaminecommunicationbetweenafragmentandtheactivitythatcontainsit.Tomakeitallhappen,youneedfiveJavafiles:

MainActivity.java:Themainactivityofyourapplication.Itdisplaysasimpleviewwithhelptextinitandamenufromwhichdialogscanbestarted.

PromptDialogFragment.java:AnexampleofadialogfragmentthatdefinesitsownlayoutinXMLandallowsinputfromtheuser.Ithasthreebuttons:Save,Dismiss(cancel),andHelp.

AlertDialogFragment.java:AnexampleofadialogfragmentthatusestheAlertBuilderclasstocreateadialogwithinthisfragment.Thisistheold-schoolwayofcreatingadialog.

HelpDialogFragment.java:Averysimplefragmentthatdisplaysahelpmessagefromtheapplication’sresources.Thespecifichelpmessageisidentifiedwhenahelpdialogobjectis

Page 253: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

created.Thishelpfragmentcanbeshownfromboththemainactivityandthepromptdialogfragment.

OnDialogDoneListener.java:Aninterfacethatyourequireyouractivitytoimplementinordertogetmessagesbackfromthefragments.Usinganinterfacemeansyourfragmentsdon’tneedtoknowmuchaboutthecallingactivity,exceptthatitmusthaveimplementedthisinterface.Thishelpsencapsulatefunctionalitywhereitbelongs.Fromtheactivity’spointofview,ithasacommonwaytoreceiveinformationbackfromfragmentswithoutneedingtoknowtoomuchaboutthem.

Therearethreelayoutsforthisapplication:forthemainactivity,forthepromptdialogfragment,andforthehelpdialogfragment.Notethatyoudon’tneedalayoutforthealertdialogfragmentbecausetheAlertBuildertakescareofthatlayoutforyouinternally.Whenyou’redone,theapplicationlookslikeFigure10-1.

Figure10-1.Theuserinterfaceforthedialogfragmentsampleapplication

DialogSample:MainActivityLet’sgettothesourcecode,whichyoucandownloadfromthebook’swebsite(seethe“References”section).We’llusetheDialogFragmentDemoproject.OpenupthesourcecodeforMainActivity.javabeforewecontinue.

Thecodeforthemainactivityisverystraightforward.Youdisplayasimplepageoftextandsetupamenu.Eachmenuiteminvokesanactivitymethod,andeachmethoddoesbasicallythesamething:getsafragmenttransaction,createsanewfragment,andshows

Page 254: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thefragment.Notethateachfragmenthasauniquetagthat’susedwiththefragmenttransaction.Thistagbecomesassociatedwiththefragmentinthefragmentmanager,soyoucanlocatethesefragmentslaterbytagname.ThefragmentcanalsodetermineitsowntagvaluewiththegetTag()methodonFragment.

ThelastmethoddefinitioninthemainactivityisonDialogDone(),whichisacallbackthatispartoftheOnDialogDoneListenerinterfacethatyouractivityisimplementing.Asyoucansee,thecallbacksuppliesatagofthefragmentthatiscallingyou,abooleanvalueindicatingwhetherthedialogfragmentwascancelled,andamessage.Foryourpurposes,youmerelywanttologtheinformationtoLogCat;youalsoshowittotheuserusingToast.Toastwillbecoveredlaterinthischapter.

DialogSample:OnDialogDoneListenerSothatyoucanknowwhenadialoghasgoneaway,createalistenerinterfacethatyourdialogcallersimplement.ThecodeoftheinterfaceisinOnDialogDoneListener.java.

Thisisaverysimpleinterface,asyoucansee.Youchooseonlyonecallbackforthisinterface,whichtheactivitymustimplement.Yourfragmentsdon’tneedtoknowthespecificsofthecallingactivity,onlythatthecallingactivitymustimplementtheOnDialogDoneListenerinterface;thereforethefragmentscancallthiscallbacktocommunicatewiththecallingactivity.Dependingonwhatthefragmentisdoing,therecouldbemultiplecallbacksintheinterface.Forthissampleapplication,you’reshowingtheinterfaceseparatelyfromthefragmentclassdefinitions.Foreasiermanagementofcode,youcouldembedthefragmentlistenerinterfaceinsideofthefragmentclassdefinitionitself,thusmakingiteasiertokeepthelistenerandthefragmentinsyncwitheachother.

DialogSample:PromptDialogFragmentNowlet’slookatyourfirstfragment,PromptDialogFragment,whoselayoutisin/res/layout/prompt_dialog.xmlandJavacodeisunder/srcinPromptDialogFragment.java.

Thispromptdialoglayoutlookslikemanyyou’veseenpreviously.ThereisaTextViewtoserveastheprompt;anEditTexttotaketheuser’sinput;andthreebuttonsforsavingtheinput,dismissing(cancelling)thedialogfragment,andpoppingahelpdialog.

ThePromptDialogFragmentJavacodestartsoutlookingjustlikeyourearlierfragments.YouhaveanewInstance()staticmethodtocreatenewobjects,andwithinthismethodyoucallthedefaultconstructor,buildanargumentsbundle,andattachittoyournewobject.Next,youhavesomethingnewintheonAttach()callback.YouwanttomakesuretheactivityyoujustgotattachedtohasimplementedtheOnDialogDoneListenerinterface.Inordertotestthat,youcasttheactivitypassedintotheOnDialogDoneListenerinterface.Here’sthatcode:

try{OnDialogDoneListenertest=(OnDialogDoneListener)act;}

Page 255: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

catch(ClassCastExceptioncce){//Hereiswherewefailgracefully.Log.e(MainActivity.LOGTAG,"Activityisnotlistening");}

Iftheactivitydoesnotimplementthisinterface,aClassCastExceptionisthrown.Youcouldhandlethisexceptionanddealwithitmoregracefully,butthisexamplekeepsthecodeassimpleaspossible.

NextupistheonCreate()callback.Asiscommonwithfragments,youdon’tbuildyouruserinterfacehere,butyoucansetthedialogstyle.Thisisuniquetodialogfragments.Youcansetboththestyleandthethemeyourself,oryoucansetjuststyleanduseathemevalueofzero(0)toletthesystemchooseanappropriatethemeforyou.Here’sthatcode:

intstyle=DialogFragment.STYLE_NORMAL,theme=0;setStyle(style,theme);

InonCreateView()youcreatetheviewhierarchyforyourdialogfragment.Justlikeotherfragments,youdonotattachyourviewhierarchytotheviewcontainerpassedin(thatis,bysettingtheattachToRootparametertofalse).Youthenproceedtosetupthebuttoncallbacks,andyousetthedialogprompttexttothepromptthatwaspassedoriginallytonewInstance().

TheonCancel()andonDismiss()callbacksarenotshownbecausealltheydoislogging;you’llbeabletoseewhenthesecallbacksfireduringthefragment’slifecycle.

Thefinalcallbackinthepromptdialogfragmentisforthebuttons.Onceagain,yougrabareferencetoyourenclosingactivityandcastittotheinterfaceyouexpecttheactivitytohaveimplemented.IftheuserpressedtheSavebutton,yougrabthetextasenteredandcalltheinterface’scallbackonDialogDone().Thiscallbacktakesthetagnameofthisfragment,abooleanindicatingwhetherthisdialogfragmentwascancelled,andamessage,whichinthiscaseisthetexttypedbytheuser.HereitisfromtheMainActivity:

publicvoidonDialogDone(Stringtag,booleancancelled,CharSequencemessage){Strings=tag+"respondswith:"+message;if(cancelled)s=tag+"wascancelledbytheuser";Toast.makeText(this,s,Toast.LENGTH_LONG).show();Log.v(LOGTAG,s);}

TofinishhandlingaclickontheSavebutton,youthencalldismiss()togetridofthedialogfragment.Rememberthatdismiss()notonlymakesthefragmentgoawayvisually,butalsopopsthefragmentoutofthefragmentmanagersoitisnolongeravailabletoyou.

IfthebuttonpressedisDismiss,youagaincalltheinterfacecallback,thistimewithno

Page 256: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

message,andthenyoucalldismiss().Andfinally,iftheuserpressedtheHelpbutton,youdon’twanttolosethepromptdialogfragment,soyoudosomethingalittledifferent.Wedescribedthisearlier.Inordertorememberthepromptdialogfragmentsoyoucancomebacktoitlater,youneedtocreateafragmenttransactiontoremovethepromptdialogfragmentandaddthehelpdialogfragmentwiththeshow()method;thisneedstogoontothebackstack.Notice,too,howthehelpdialogfragmentiscreatedwithareferencetoaresourceID.Thismeansyourhelpdialogfragmentcanbeusedwithanyhelptextavailabletoyourapplication.

DialogSample:HelpDialogFragmentYoucreatedafragmenttransactiontogofromthepromptdialogfragmenttothehelpdialogfragment,andyouplacedthatfragmenttransactiononthebackstack.Thishastheeffectofmakingthepromptdialogfragmentdisappearfromview,butit’sstillaccessiblethroughthefragmentmanagerandthebackstack.Thenewhelpdialogfragmentappearsinitsplaceandallowstheusertoreadthehelptext.Whentheuserdismissesthehelpdialogfragment,thefragmentbackstackentryispopped,withtheeffectofthehelpdialogfragmentbeingdismissed(bothvisuallyandfromthefragmentmanager)andthepromptdialogfragmentrestoredtoview.Thisisaprettyeasywaytomakeallthishappen.Itisverysimpleyetverypowerful;itevenworksiftheuserrotatesthedevicewhilethesedialogsarebeingdisplayed.

LookatthesourcecodeoftheHelpDialogFragment.javafileanditslayout(help_dialog.xml).Thepointofthisdialogfragmentistodisplayhelptext.ThelayoutisaTextViewandaClosebutton.TheJavacodeshouldbestartingtolookfamiliartoyou.There’sanewInstance()methodtocreateanewhelpdialogfragment,anonCreate()methodtosetthestyleandtheme,andanonCreateView()methodtobuildtheviewhierarchy.Inthisparticularcase,youwanttolocateastringresourcetopopulatetheTextView,soyouaccesstheresourcesthroughtheactivityandchoosetheresourceIDthatwaspassedintonewInstance().Finally,onCreateView()setsupabutton-clickhandlertocapturetheclicksoftheClosebutton.Inthiscase,youdon’tneedtodoanythinginterestingatthetimeofdismissal.

Thisfragmentiscalledtwoways:fromtheactivityandfromthepromptdialogfragment.Whenthishelpdialogfragmentisshownfromthemainactivity,dismissingitsimplypopsthefragmentoffthetopandrevealsthemainactivityunderneath.Whenthishelpdialogfragmentisshownfromthepromptdialogfragment,becausethehelpdialogfragmentwaspartofafragmenttransactiononthebackstack,dismissingitcausesthefragmenttransactiontoberolledback,whichpopsthehelpdialogfragmentbutrestoresthepromptdialogfragment.Theuserseesthepromptdialogfragmentreappear.

DialogSample:AlertDialogFragmentWehaveonelastdialogfragmenttoshowyouinthissampleapplication:thealertdialogfragment.Althoughyoucouldcreateanalertdialogfragmentinawaysimilartothehelpdialogfragment,youcanalsocreateadialogfragmentusingtheoldAlertBuilderframeworkthathasworkedformanyreleasesofAndroid.Lookatthesourcecodein

Page 257: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AlertDialogFragment.java.

Youdon’tneedalayoutforthisonebecausetheAlertBuildertakescareofthatforyou.Notethatthisdialogfragmentstartsoutlikeanyother,butinsteadofanonCreateView()callback,youhaveaonCreateDialog()callback.YouimplementeitheronCreateView()oronCreateDialog()butnotboth.ThereturnfromonCreateDialog()isnotaview;it’sadialog.Ofinteresthereisthattogetparametersforthedialog,youshouldbeaccessingyourargumentsbundle.Inthisexampleapplication,youonlydothisforthealertmessage,butyoucouldaccessotherparametersthroughtheargumentsbundleaswell.

Noticealsothatwiththistypeofdialogfragment,youneedyourfragmentclasstoimplementtheDialogInterface.OnClickListener,whichmeansyourdialogfragmentmustimplementtheonClick()callback.Thiscallbackisfiredwhentheuseractsontheembeddeddialog.Onceagain,yougetareferencetothedialogthatfiredandanindicationofwhichbuttonwaspressed.Asbefore,youshouldbecarefulnottodependonanonDismiss()becausethiscouldfirewhenthereisadeviceconfigurationchange.

DialogSample:EmbeddedDialogsThere’sonemorefeatureofaDialogFragmentthatyoumayhavenoticed.Inthemainlayoutfortheapplication,underthetext,isaFrameLayoutthatcanbeusedtoholdadialog.Intheapplication’smenu,thelastitemcausesafragmenttransactiontoaddanewinstanceofaPromptDialogFragmenttothemainscreen.Withoutanymodifications,thedialogfragmentcanbedisplayedembeddedinthemainlayout,anditfunctionsasyouwouldexpect.

Onethingthatisdifferentaboutthistechniqueisthatthecodetoshowtheembeddeddialogisnotthesameasthecodetodoapop-updialog.Theembeddeddialogcodelookslikethis:

ft.add(R.id.embeddedDialog,pdf,EMBED_DIALOG_TAG);ft.commit();

ThislooksjustthesameasinChapter8,whenwedisplayedafragmentinaFrameLayout.Thistime,however,youmakesuretopassinatagname,whichisusedwhenthedialogfragmentnotifiesyouractivityoftheuser’sinput.

DialogSample:ObservationsWhenyourunthissampleapplication,makesureyoutryallthemenuoptionsindifferentorientationsofthedevice.Rotatethedevicewhilethedialogfragmentsaredisplayed.Youshouldbepleasedtoseethatthedialogsgowiththerotations;youdonotneedtoworryaboutalotofcodetomanagethesavingandrestoringoffragmentsduetoconfigurationchanges.

Theotherthingwehopeyouappreciateistheeasewithwhichyoucancommunicatebetweenthefragmentsandtheactivity.Ofcourse,theactivityhasreferences,orcanget

Page 258: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

references,toalltheavailablefragments,soitcanaccessmethodsexposedbythefragmentsthemselves.Thisisn’ttheonlywaytocommunicatebetweenfragmentsandtheactivity.Youcanalwaysusethegettermethodsonthefragmentmanagertoretrieveaninstanceofamanagedfragment,andthencastthatreferenceappropriatelyandcallamethodonthatfragmentdirectly.Youcanevendothisfromwithinanotherfragment.Thedegreetowhichyouisolateyourfragmentsfromeachotherwithinterfacesandthroughactivities,orbuildindependencieswithfragment-to-fragmentcommunication,isbasedonhowcomplexyourapplicationisandhowmuchreuseyouwanttoachieve.

WorkingwithToastAToastislikeaminialertdialogthathasamessageanddisplaysforacertainamountoftimeandthengoesawayautomatically.Itdoesnothaveanybuttons.Soitcanbesaidthatitisatransientalertmessage.It’scalledToastbecauseitpopsupliketoastoutofatoaster.

Listing10-10showsanexampleofhowyoucanshowamessageusingToast.

Listing10-10.UsingToastforDebugging

//Createafunctiontowrapamessageasatoast//showthetoastpublicvoidreportToast(Stringmessage){Strings=MainActivity.LOGTAG+":"+message;Toast.makeText(activity,s,Toast.LENGTH_SHORT).show();}

ThemakeText()methodinListing10-10cantakenotonlyanactivitybutanycontextobject,suchastheonepassedtoabroadcastreceiveroraservice,forexample.ThisextendstheuseofToastoutsideofactivities.

Referenceswww.androidbook.com/proandroid5/projects:Thischapter’stestproject.ThenameoftheZIPfileisProAndroid5_ch10_Dialogs.zip.Thedownloadincludesanexampleofthedate-andtime-pickerdialogsinPickerDialogFragmentDemo.

http://developer.android.com/guide/topics/ui/dialogs.htmlAndroidSDKdocumentthatprovidesanexcellentintroductiontoworkingwithAndroiddialogs.Youwillfindhereanexplanationofhowtousemanageddialogsandvariousexamplesofavailabledialogs.

Page 259: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

http://developer.android.com/reference/android/content/DialogInterface.htmlThemanyconstantsdefinedfordialogs.

http://developer.android.com/reference/android/app/AlertDialog.Builder.htmlAPIdocumentationfortheAlertDialogbuilderclass.

http://developer.android.com/reference/android/app/ProgressDialog.htmlAPIdocumentationforProgressDialog.

http://developer.android.com/guide/topics/ui/controls/pickers.htmlAnAndroidtutorialforusingthedate-pickerandtime-pickerdialogs.

SummaryThischapterdiscussedasynchronousdialogsandhowtousedialogfragments,includingthefollowingtopics:

Whatadialogisandwhyyouuseone

TheasynchronousnatureofadialoginAndroid

Thethreestepsofgettingadialogtodisplayonthescreen

Creatingafragment

Twomethodsforhowadialogfragmentcancreateaviewhierarchy

Howafragmenttransactionisinvolvedindisplayingadialogfragment,andhowtogetone

WhathappenswhentheuserpressestheBackbuttonwhileviewingadialogfragment

Thebackstack,andmanagingdialogfragments

Whathappenswhenabuttononadialogfragmentisclicked,andhowyoudealwithit

Acleanwaytocommunicatebacktothecallingactivityfromadialogfragment

Howonedialogfragmentcancallanotherdialogfragmentandstillgetbacktothepreviousdialogfragment

TheToastclassandhowitcanbeusedasasimplealertpop-up

Page 260: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter11

WorkingwithPreferencesandSavingStateAndroidoffersarobustandflexibleframeworkfordealingwithsettings,alsoknownaspreferences.Andbysettings,wemeanthosefeaturechoicesthatausermakesandsavestocustomizeanapplicationtotheirliking.(Inthischapter,thetermssettingsandpreferenceswillbeusedinterchangeably.)Forexample,iftheuserwantsanotificationviaaringtoneorvibrationornotatall,thatisapreferencetheusersaves;theapplicationremembersthechoiceuntiltheuserchangesit.AndroidprovidessimpleAPIsthathidethemanagementandpersistingofpreferences.Italsoprovidesprebuiltuserinterfacesthatyoucanusetolettheusermakepreferenceselections.BecauseofthepowerbuiltintotheAndroidpreferencesframework,wecanalsousepreferencesformoregeneral-purposestoringofapplicationstate,toallowourapplicationtopickupwhereitleftoff,shouldourapplicationgoawayandcomebacklater.Asanotherexample,agame’shighscorescouldbestoredaspreferences,althoughyou’llwanttouseyourownUItodisplaythem.

Thischaptercovershowtoimplementyourownsettingsscreensforyourapplication,howtointeractwithAndroidsystemsettings,andhowtousesettingstosecretlysaveapplicationstate,anditalsoprovidesbest-practiceguidance.You’lldiscoverhowtomakeyoursettingslookgoodonsmallscreensaswellaslargerscreenssuchasthosefoundontablets.

ExploringthePreferencesFrameworkAndroid’spreferencesframeworkbuildsfromtheindividualsettingschoices,toahierarchyofscreensthatcontainsettingschoices.Settingscouldbebinarysettingssuchason/off,ortextinput,oranumericvalue,orcouldbeaselectionfromalistofchoices.AndroidusesaPreferenceManagertoprovidesettingsvaluestoapplications.Theframeworktakescareofmakingandpersistingchanges,andnotifyingtheapplicationwhenasettingchangesorisabouttochange.Whilesettingsarepersistedinfiles,applicationsdon’tdealdirectlywiththefiles.Thefilesarehiddenaway,andyou’llseeshortlywheretheyare.

AswithviewscoveredinChapter3,preferencescanbespecifiedwithXML,orbywritingcode.Forthischapter,you’llworkwithasampleapplicationthatdemonstratesthedifferenttypesofchoices.XMListhepreferredwaytospecifyapreference,sothatishowtheapplicationwaswritten.XMLspecifiesthelowest-levelsettings,plushowtogroupsettingstogetherintocategoriesandscreens.Forreference,thesampleapplicationforthischapterpresentsthefollowingsettingsasshowninFigure11-1.

Page 261: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure11-1.ThemainsettingsfromthesampleapppreferenceUI.Duetothescreen’sheight,ithasbeenshownwiththetopontheleftandthebottomontheright.Noticetheoverlapbetweenthetwoimages

Androidprovidesanend-to-endpreferencesframework.Thismeanstheframeworkletsyoudefineyourpreferences,displaythesetting(s)totheuser,andpersisttheuser’sselectiontothedatastore.YoudefineyourpreferencesinXMLunder/res/xml/.Toshowpreferencestotheuser,youwriteanactivityclassthatextendsapredefinedAndroidclasscalledandroid.preference.PreferenceActivityandusefragmentstohandlethescreensofpreferences.Theframeworktakescareoftherest(displayingandpersisting).Withinyourapplication,yourcodewillgetreferencestospecificpreferences.Withapreferencereference,youcangetthecurrentvalueofthepreference.

Inorderforpreferencestobesavedacrossusersessions,thecurrentvaluesmustbesavedsomewhere.TheAndroidframeworktakescareofpersistingpreferencesinanXMLfilewithintheapplication’s/data/datadirectoryonthedevice(seeFigure11-2).

Page 262: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure11-2.Pathtoanapplication’ssavedpreferences

NoteYouwillbeabletoinspectsharedpreferencesfilesintheemulatoronly.Onarealdevice,thesharedpreferencesfilesarenotreadableduetoAndroidsecurity(unlessyouhaverootprivileges,ofcourse).

Thedefaultpreferencesfilepathforanapplicationis/data/data/[PACKAGE_NAME]/shared_prefs/[PACKAGE_NAME]_preferences.xml,where[PACKAGE_NAME]isthepackageoftheapplication.Listing11-1showsthecom.androidbook.preferences.main_preferences.xmldatafileforthisexample.

Listing11-1.SavedPreferencesforOurExample

<?xmlversion='1.0'encoding='utf-8'standalone='yes'?><map><booleanname="notification_switch"value="true"/><stringname="package_name_preference">com.androidbook.win</string><booleanname="potato_selection_pref"value="true"/><booleanname="show_airline_column_pref"value="true"/><stringname="flight_sort_option">2</string><booleanname="alert_email"value="false"/><setname="pizza_toppings"><string>pepperoni</string><string>cheese</string><string>olive</string></set><stringname="alert_email_address">[email protected]</string></map>

Asyoucansee,valuesarestoredinamap,withpreferencekeysasnamestothedatavalues.Someofthevalueslookcrypticanddonotmatchwhatisdisplayedtotheuser.Forexample,thevalueforflight_sort_optionis2.Androiddoesnotstorethedisplayedtextas

Page 263: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thevalueofthepreference;rather,itstoresavaluethattheuserwon’tsee,thatyoucanuseindependentlyofwhattheusersees.Youwantthefreedomtochangethedisplayedtextbasedontheuser’slanguage,andyoualsowanttheabilitytotweakthedisplayedtextwhilekeepingthesamestoredvalueinthepreferencesfile.Youmightevenbeabletodosimplerprocessingofthepreferenceifthevalueisanintegerinsteadofsomedisplaystring.Whatyoudon’thavetoworryaboutisparsingthisdatafile.TheAndroidpreferencesframeworkprovidesaniceAPIfordealingwithpreferences,whichwillbedescribedinmoredetaillaterinthischapter.IfyoucomparethepreferencesmapinListing11-1withthescreenshotsinFigure11-1,youwillnoticethatnotallpreferencesarelistedwithvaluesinthepreferencesXMLdatafile.Thisisbecausethepreferencedatafiledoesnotautomaticallystoreadefaultvalueforyou.You’llseeshortlyhowtodealwithdefaultvalues.

Nowthatyou’veseenwherethevaluesaresaved,youneedtoseehowtodefinethescreenstodisplaytotheusersotheycanmakeselections.Beforeyouseehowtocollectpreferencestogetherintoscreens,you’lllearnaboutthedifferenttypesofpreferencesyoucanuse,andthenyou’llseehowtoputthemtogetherintoscreens.Eachpersistedvalueinthe/data/dataXMLfileisfromaspecificpreference.Solet’sunderstandwhateachofthesemeans.

UnderstandingCheckBoxPreferenceandSwitchPreferenceThesimplestofthepreferencesaretheCheckBoxPreferenceandSwitchPreference.Theseshareacommonparentclass(TwoStatePreference)andareeitheron(valueistrue)oroff(valueisfalse).Forthesampleapplication,ascreenwascreatedwithfiveCheckBoxPreferences,asshowninFigure11-3.Listing11-2showswhattheXMLlookslikeforaCheckBoxPreference.

Page 264: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure11-3.Theuserinterfaceforthecheckboxpreference

Listing11-2.UsingCheckBoxPreference

<CheckBoxPreferenceandroid:key="show_airline_column_pref"android:title="Airline"android:summary="ShowAirlinecolumn"/>

NoteWewillgiveyouaURLattheendofthechapterthatyoucanusetodownloadprojectsfromthischapter.ThiswillallowyoutoimporttheseprojectsintoyourIDEdirectly.ThemainsampleapplicationiscalledPrefDemo.YoushouldrefertothatprojectuntilyoucometotheSavingStatesection.

Thisexampleshowstheminimumthat’srequiredtospecifyapreference.Thekeyisthereferenceto,ornameof,thepreference,thetitleisthetitledisplayedforthepreference,andsummaryisadescriptionofwhatthepreferenceisfororastatusofthecurrentsetting.LookingbackonthesavedvaluesinListing11-1,youwillseea<boolean>tagfor“show_airline_column_pref”(thekey),andithasanattributevalueoftrue,whichindicatesthatthepreferenceischeckedon.

WithCheckBoxPreference,thestateofthepreferenceissavedwhentheusersetsthestate.Inotherwords,whentheuserchecksorunchecksthepreferencecontrol,itsstateissavedimmediately.

TheSwitchPreferenceisverysimilarexceptthatthevisualdisplayisdifferent.Insteadofacheckboxintheuserinterface,theuserseesanon-offswitch,asshowninFigure11-1nextto“Notificationsare”.

OneotherusefulfeatureofCheckBoxPreferenceandSwitchPreferenceisthatyoucansetdifferentsummarytextdependingonwhetherit’schecked.TheXMLattributesaresummaryOnandsummaryOff.Ifyoulookinthemain.xmlfilefortheCheckBoxPreferencecalled“potato_selection_pref”youwillseeanexampleofthis.

Beforeyoulearntheotherpreferencetypes,nowwouldbeagoodtimetounderstandhowtoaccessthispreferencetoreaditsvalueandperformotheroperations.

AccessingaPreferenceValueinCodeNowthatyouhaveapreferencedefinedyouneedtoknowhowtoaccessthepreferenceincodesoyoucanreadthevalue.Listing11-3showscodetoaccesstheSharedPreferencesobjectinAndroidwherethepreferencesexist.ThiscodeisfromtheMainActivity.javafileinthesetOptionText()method.

Listing11-3.AccessingtheCheckBoxPreferenceSharedPreferencesprefs=

PreferenceManager.getDefaultSharedPreferences(this);

Page 265: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Thisistheotherwaytogettothesharedpreferences://SharedPreferencesprefs=getSharedPreferences(//“com.androidbook.preferences.main_preferences”,0);booleanshowAirline=prefs.getBoolean(“show_airline_column_pref”,false);

Usingthereferencetopreferences,itisstraightforwardtoreadthecurrentvalueoftheshow_airline_column_prefpreference.AsshowninListing11-3,therearetwowaystogettothepreferences.Thefirstwayshownistogetthedefaultpreferencesforthecurrentcontext.Inthiscase,thecontextisthatoftheMainActivityofourapplication.Thesecondcase,whichisshowncommentedout,retrievesthepreferencesusingapackagename.Youcouldusewhateverpackagenameyouwantincaseyouneedtostoredifferentsetsofpreferencesindifferentfiles.

Onceyouhaveareferencetothepreferences,youcalltheappropriategettermethodwiththekeyofthepreferenceandadefaultvalue.Sinceshow_airline_column_prefisaTwoStatePreference,thevaluereturnedisaboolean.Thedefaultvalueforshow_airline_column_prefishard-codedhereasfalse.Ifthispreferencehasnotyetbeensetatall,thehard-codedvalue(false)willbeassignedtoshowAirline.However,thatbyitselfdoesnotpersistthepreferencetofalseforfutureuse,nordoesithonoranydefaultvaluethatmighthavebeensetintheXMLspecificationforthispreference.IftheXMLspecificationusesaresourcevaluetospecifythedefaultvalue,thenthesameresourcecouldbereferredtoincodetosetthedefaultvalue,asshowninthefollowingforadifferentpreference:

Stringflight_option=prefs.getString(resources.getString(R.string.flight_sort_option),resources.getString(R.string.flight_sort_option_default_value));

Noticeherethatthekeyforthepreferenceisalsousingastringresourcevalue(R.string.flight_sort_option).Thiscanbeawisechoicesinceitmakestyposlesslikely.Iftheresourcenameistypedwrongyou’llverylikelygetabuilderror.Ifyouusejustsimplestrings,itispossibleforatypotogounnoticed,exceptthatyourpreferenceswon’twork.

Weshowedonewaytoreadadefaultvalueforapreferenceincode.Androidprovidesanotherwaythatisabitmoreelegant.InonCreate(),youcandothefollowinginstead:

PreferenceManager.setDefaultValues(this,R.xml.main,false);

Then,insetOptionText(),youwouldhavedonethistoreadtheoptionvalue:

Stringoption=prefs.getString(resources.getString(R.string.flight_sort_option),null);

Thefirstcallwillusemain.xmltofindthedefaultvaluesandgeneratethepreferencesXMLdatafileforususingthedefaultvalues.Ifwealreadyhaveaninstanceofthe

Page 266: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SharedPreferencesobjectinmemory,itwillupdatethattoo.Thesecondcallwillthenfindavalueforflight_sort_option,becausewetookcareofloadingdefaultsfirst.

Afterrunningthiscodethefirsttime,ifyoulookintheshared_prefsfolder,youwillseethepreferencesXMLfileevenifthepreferencesscreenhasnotyetbeeninvoked.Youwillalsoseeanotherfilecalled_has_set_default_values.xml.ThisfiletellsyourapplicationthatthepreferencesXMLfilehasalreadybeencreatedwiththedefaultvalues.ThethirdargumenttosetDefaultValues()—thatis,false—indicatesthatyouwantthedefaultssetinthepreferencesXMLfileonlyifithasn’tbeendonebefore.AndroidremembersthisinformationthroughtheexistenceofthisnewXMLfile.However,Androidremembersevenifyouupgradeyourapplicationandaddnewsettingswithnewdefaultvalues,whichmeansthistrickwon’tsetthosenewdefaults.Yourbestoptionistoalwaysusearesourceforthedefaultvalue,andalwaysprovidethatresourceasthedefaultvaluewhengettingthecurrentvalueofapreference.

UnderstandingListPreferenceAlistpreferencecontainsradiobuttonsforeachoption,andthedefault(orcurrent)selectionispreselected.Theuserisexpectedtoselectoneandonlyoneofthechoices.Whentheuserchoosesanoption,thedialogisimmediatelydismissedandthechoiceissavedinthepreferencesXMLfile.Figure11-4showswhatthislookslike.

Figure11-4.TheuserinterfacefortheListPreference

Listing11-4containsanXMLfragmentthatrepresentstheflight-optionpreferencesetting.Thistimethefilecontainsreferencestostringsandtoarrays,whichwouldbethe

Page 267: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

morecommonwaytospecifytheseratherthanhard-codingthestrings.Asmentionedbefore,thevalueofalistpreferenceasstoredintheXMLdatafileunderthe/data/data/{package}directoryisnotthesameaswhattheuserseesintheuserinterface.Thenameofthekeyisstoredinthedatafile,alongwithahiddenvaluethattheuserdoesnotsee.Therefore,togetaListPreferencetowork,thereneedstobetwoarrays:thevaluesdisplayedtotheuserandthestringsusedaskeyvalues.Thisiswhereyoucaneasilygettrippedup.Theentriesarrayholdsthestringsdisplayedtotheuser,andtheentryValuesarrayholdsthestringsthatwillbestoredinthepreferencesdataXMLfile.

Listing11-4.SpecifyingaListPreferenceinXML

<ListPreferenceandroid:key="@string/flight_sort_option"android:title="@string/listTitle"android:summary="@string/listSummary"android:entries="@array/flight_sort_options"android:entryValues="@array/flight_sort_options_values"android:dialogTitle="@string/dialogTitle"android:defaultValue="@string/flight_sort_option_default_value"/>

Theelementsbetweenthetwoarrayscorrespondtoeachotherpositionally.Thatis,thethirdelementintheentryValuesarraycorrespondstothethirdelementintheentriesarray.Itistemptingtouse0,1,2,etc.,asentryValuesbutitisnotrequired,anditcouldcauseproblemslaterwhenthearraysmustbemodified.Ifouroptionwerenumericinnature(forexample,acountdowntimerstartingvalue),thenwecouldhaveusedvaluessuchas60,120,300,andsoon.Thevaluesdon’tneedtobenumericatallaslongastheymakesensetothedeveloper;theuserdoesn’tseethesevaluesunlessyouchoosetoexposethem.Theuseronlyseesthetextfromthefirststringarrayflight_sort_options.Theexampleapplicationforthischaptershowsitbothways.

Awordofcautionhere:becausethepreferencesXMLdatafileisstoringonlythevalueandnotthetext,shouldyoueverupgradeyourapplicationandchangethetextoftheoptionsoradditemstothestringarrays,anyvaluestoredinthepreferencesXMLdatafileshouldstilllineupwiththeappropriatetextaftertheupgrade.ThepreferencesXMLdatafileiskeptduringtheapplicationupgrade.IfthepreferencesXMLdatafilehada“1”init,andthatmeant“#ofStops”beforetheupgrade,itshouldstillmean“#ofStops”aftertheupgrade.

SincetheentryValuesarrayisnotseenbytheenduser,itisbestpracticetostoreitonceandonlyoncewithinyourapplication.Therefore,makeoneandonlyone/res/values/prefvaluearrays.xmlfiletocontainthesearrays.Theentriesarrayisverylikelytobecreatedmultipletimesperapplication,fordifferentlanguagesorperhapsdifferentdeviceconfigurations.Therefore,makeseparateprefdisplayarrays.xmlfilesforeachvariationthatyouneed.Forexample,ifyourapplicationwillbeusedinEnglishandinFrench,therewillbeseparate

Page 268: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

prefdisplayarrays.xmlfilesforEnglishandFrench.YoudonotwanttoincludetheentryValuesarrayineachoftheseotherfiles.ItisimperativethoughthattherearethesamenumbersofarrayelementsbetweenentryValuesandentriesarrays.Theelementsmustlineup.Whenyoumakechanges,becarefultokeepeverythinginalignment.Listing11-5containsthesourceofListPreferencefilesfortheexample.

Listing11-5.OtherListPreferenceFilesfromOurExample

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/values/prefvaluearrays.xml--><resources><string-arrayname="flight_sort_options_values"><item>0</item><item>1</item><item>2</item></string-array><string-arrayname="pizza_toppings_values"><item>cheese</item><item>pepperoni</item><item>onion</item><item>mushroom</item><item>olive</item><item>ham</item><item>pineapple</item></string-array><string-arrayname="default_pizza_toppings"><item>cheese</item><item>pepperoni</item></string-array></resources>

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/values/prefdisplayarrays.xml--><resources><string-arrayname="flight_sort_options"><item>TotalCost</item><item>#ofStops</item><item>Airline</item></string-array><string-arrayname="pizza_toppings"><item>Cheese</item><item>Pepperoni</item><item>Onions</item><item>PortobelloMushrooms</item><item>BlackOlives</item><item>SmokedHam</item><item>Pineapple</item>

Page 269: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

</string-array></resources>

Also,don’tforgetthatyourdefaultvalueasspecifiedintheXMLsourcefilemustmatchanentryValueinthearrayfromprefvaluearrays.xml.

ForaListPreference,thevalueofthepreferenceisaString.Ifyouareusingnumberstrings(e.g.,0,1,1138)asentryValues,youcouldconvertthosetointegersorwhateveryouneedinyourcode,asisusedintheflight_sort_options_valuesarray.

Yourcodeislikelygoingtowanttodisplaytheuser-friendlytextfromthepreference’sentriesarray.Thisexampletookashortcut,becausearrayindiceswereusedfortheelementsinflight_sort_options_values.Bysimplyconvertingthevaluetoanint,youknowwhichstringtoreadfromflight_sort_options.Hadyouusedsomeothersetofvaluesforflight_sort_options_values,youwouldneedtodeterminetheindexoftheelementthatisyourpreferenceandthenturnaroundandusethatindextograbthetextofyourpreferencefromflight_sort_options.ListPreference’shelpermethodfindIndexOfValue()canhelpwiththis,byprovidingtheindexintothevaluesarraysoyoucantheneasilygetthecorrespondingdisplaytextfromtheentriesarray.

ReturningnowtoListing11-4,thereareseveralstringsfortitles,summaries,andmore.Thestringcalledflight_sort_option_default_valuesetsthedefaultvalueto1torepresent“#ofStops”intheexample.Itisusuallyagoodideatochooseadefaultvalueforeachoption.Ifyoudon’tchooseadefaultvalueandnovaluehasyetbeenchosen,themethodsthatreturnthevalueoftheoptionwillreturnnull.Yourcodewouldhavetodealwithnullvaluesinthiscase.

UnderstandingEditTextPreferenceThepreferencesframeworkalsoprovidesafree-formtextpreferencecalledEditTextPreference.Thispreferenceallowsyoutocapturerawtextratherthanasktheusertomakeaselection.Todemonstratethis,let’sassumeyouhaveanapplicationthatgeneratesJavacodefortheuser.Oneofthepreferencesettingsofthisapplicationmightbethedefaultpackagenametouseforthegeneratedclasses.Here,youwanttodisplayatextfieldtotheuserforsettingthepackagenameforthegeneratedclasses.Figure11-5showstheUI,andListing11-6showstheXML.

Page 270: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure11-5.UsingtheEditTextPreference

Listing11-6.AnExampleofanEditTextPreference

<EditTextPreferenceandroid:key="package_name_preference"android:title="SetPackageName"android:summary="Setthepackagenameforgeneratedcode"android:dialogTitle="PackageName"/>

WhenSetPackageNameisselected,theuserispresentedwithadialogtoinputthepackagename.WhentheOKbuttonisclicked,thepreferenceissavedtothepreferencestore.

Aswiththeotherpreferences,youcanobtainthevalueofthepreferencebycallingtheappropriategettermethod,inthiscasegetString().

UnderstandingMultiSelectListPreferenceAndfinally,apreferencecalledMultiSelectListPreferencewasintroducedinAndroid3.0.TheconceptissomewhatsimilartoaListPreference,butinsteadofonlybeingabletoselectoneiteminthelist,theusercanselectseveralornone.InListing11-1,theMultiSelectListPreferencestoresa<setname=“pizza_toppings”>taginthepreferencesXMLdatafile,insteadofasinglevalue.TheothersignificantdifferencewithaMultiSelectListPreferenceisthatthedefaultvalueisanarrayjustliketheentryValuesarray.Thatis,thearrayforthedefaultvaluesmustcontainzeroormoreoftheelementsfromtheentryValuesarrayforthispreference.Thiscanalsobeseeninthesampleapplicationforthischapter;justviewtheendofthemain.xmlfileinthe/res/xmldirectory.

TogetthecurrentvalueofaMultiSelectListPreference,usethegetStringSet()methodofSharedPreferences.Toretrievethedisplaystringsfromtheentriesarray,youwouldneedtoiteratethroughthesetofstringsthatisthevalue

Page 271: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ofthispreference,determinetheindexofthestring,andusetheindextoaccesstheproperdisplaystringfromtheentriesarray.

UpdatingAndroidManifest.xmlBecausetherearetwoactivitiesinthesampleapplication,weneedtwoactivitytagsinAndroidManifest.xml.ThefirstoneisastandardactivityofcategoryLAUNCHER.ThesecondoneisforaPreferenceActivity,sosettheactionnameaccordingtoconventionforintents,andsetthecategorytoPREFERENCEasshowninListing11-7.Youprobablydon’twantthePreferenceActivityshowingupontheAndroidpagewithallourotherapplications,whichiswhyyoudon’tuseLAUNCHERforit.YouwouldneedtomakesimilarchangestoAndroidManifest.xmlifyouweretoaddotherpreferenceactivities.

Listing11-7.PreferenceActivityEntryinAndroidManifest.xml<activityandroid:name=”.MainPreferenceActivity”

android:label=”@string/prefTitle”><intent-filter><actionandroid:name=“com.androidbook.preferences.main.intent.action.MainPreferences”/><categoryandroid:name=“android.intent.category.PREFERENCE”/></intent-filter></activity>

UsingPreferenceCategoryThepreferencesframeworkprovidessupportforyoutoorganizeyourpreferencesintocategories.Ifyouhavealotofpreferences,forexample,youcanusePreferenceCategory,whichgroupspreferencesunderaseparatorlabel.Figure11-6showswhatthiscouldlooklike.Noticetheseparatorscalled“MEATS”and“VEGETABLES.”Youcanfindthespecificationsforthesein/res/xml/main.xml.

Page 272: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure11-6.UsingPreferenceCategorytoorganizepreferences

CreatingChildPreferenceswithDependencyAnotherwaytoorganizepreferencesistouseapreferencedependency.Thiscreatesaparent-childrelationshipbetweenpreferences.Forexample,youmighthaveapreferencethatturnsonalerts;andifalertsareon,theremightbeseveralotheralert-relatedpreferencestochoosefrom.Ifthemainalertspreferenceisoff,theotherpreferencesarenotrelevantandshouldbedisabled.Listing11-8showstheXML,andFigure11-7showswhatitlookslike.

Listing11-8.PreferenceDependencyinXML

<PreferenceScreen><PreferenceCategoryandroid:title="Alerts">

<CheckBoxPreferenceandroid:key="alert_email"android:title="Sendemail?"/>

Page 273: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<EditTextPreferenceandroid:key="alert_email_address"android:layout="?android:attr/preferenceLayoutChild"android:title="EmailAddress"android:dependency="alert_email"/>

</PreferenceCategory></PreferenceScreen>

Figure11-7.Preferencedependency

PreferenceswithHeadersAndroid3.0introducedanewwaytoorganizepreferences.YouseethisontabletsunderthemainSettingsapp.Becausetabletscreenrealestateoffersmuchmoreroomthanasmartphonedoes,itmakessensetodisplaymorepreferenceinformationatthesametime.Toaccomplishthis,youusepreferenceheaders.TakealookatFigure11-8.

Figure11-8.MainSettingspagewithpreferenceheaders

Page 274: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Noticethatheadersappeardowntheleftside,likeaverticaltabbar.Asyouclickeachitemontheleft,thescreentotherightdisplaysthepreferencesforthatitem.InFigure11-8,Soundischosen,andthesoundpreferencesaredisplayedatright.TherightsideisaPreferenceScreenobject,andthissetupusesfragments.Obviously,weneedtodosomethingdifferentthanwhathasbeendiscussedsofarinthischapter.

ThebigchangefromAndroid3.0wastheadditionofheaderstoPreferenceActivity.ThisalsomeansusinganewcallbackwithinPreferenceActivitytodotheheaderssetup.Now,whenyouextendPreferenceActivity,you’llwanttoimplementthismethod:

publicvoidonBuildHeaders(List<Header>target){loadHeadersFromResource(R.xml.preferences,target);}

PleaserefertothePrefDemosampleapplicationforthecompletesourcecode.Thepreferences.xmlfilecontainssomenewtagsthatlooklikethis:

<preference-headersxmlns:android="http://schemas.android.com/apk/res/android<headerandroid:fragment="com.example.PrefActivity$Prefs1Fragment"android:icon="@drawable/ic_settings_sound"android:title="Sound"android:summary="Yoursoundpreferences"/>...

EachheadertagpointstoaclassthatextendsPreferenceFragment.Intheexamplejustgiven,theXMLspecifiesanicon,thetitle,andsummarytext(whichactslikeasubtitle).Prefs1FragmentisaninnerclassofPreferenceActivitythatcouldlooksomethinglikethis:

publicstaticclassPrefs1FragmentextendsPreferenceFragment{@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);addPreferencesFromResource(R.xml.sound_preferences);}}

AllthisinnerclassneedstodoispullintheappropriatepreferencesXMLfile,asshown.ThatpreferencesXMLfilecontainsthetypesofpreferencespecificationswecoveredearlier,suchasListPreference,CheckBoxPreference,PreferenceCategory,andsoon.What’sveryniceisthatAndroidtakescareofdoingtherightthingwhenthescreenconfigurationchangesandwhenthepreferencesaredisplayedonasmallscreen.Headersbehavelikeoldpreferenceswhenthescreenistoosmalltodisplaybothheadersandthepreferencescreentotheright.Thatis,youonlysee

Page 275: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theheaders;andwhenyouclickaheader,youthenseeonlytheappropriatepreferencescreen.

PreferenceScreensThetop-levelcontainerforpreferencesisaPreferenceScreen.BeforetabletsandPreferenceFragments,youcouldnestPreferenceScreens,andwhentheuserclickedonanestedPreferenceScreenitem,thenewPreferenceScreenwouldreplacethecurrentlydisplayedPreferenceScreen.Thisworkedfineonasmallscreen,butdoesn’tlookasgoodonatablet,especiallyifyoustartedwithheadersandfragments.WhatyouprobablywantisforthenewPreferenceScreentoappearwherethecurrentfragmentis.

TomakeaPreferenceScreenworkinsideofafragment,allyouneedtodoisspecifyafragmentclassnameforthatPreferenceScreen.Listing11-9showstheXMLfromthesampleapplication.

Listing11-9.PreferenceScreeninvokedviaaPreferenceFragment

<PreferenceScreenandroid:title="Launchanewscreenintoafragment"android:fragment="com.androidbook.preferences.main.BasicFrag"/>

Whentheuserclicksonthisitem,thecurrentfragmentisreplacedwithBasicFrag,whichthenloadsanewXMLlayoutforaPreferenceScreenasspecifiedinnested_screen_basicfrag.xml.Inthiscase,wechosenottomaketheBasicFragclassaninnerclassoftheMainPreferenceActivityclass,mainlybecausethereisnosharingneededfromtheouterclass,andtoshowyouthatyoucandoitthiswayifyouprefer.

DynamicPreferenceSummaryTextYou’veprobablyseenpreferenceswherethepreferencesummarycontainsthecurrentvalue.Thisisactuallyalittlehardertoimplementthanyoumightthink.Toaccomplishthisfeat,youcreatealistenercallbackthatdetectswhenapreferencevalueisabouttochange,andyouthenupdatethepreferencesummaryaccordingly.ThefirststepisforyourPreferenceFragmenttoimplementtheOnPreferenceChangeListenerinterface.YouthenneedtoimplementtheonPreferenceChange()callback.Listing11-10showsanexample.ThepkgPrefobjectinthecallbackwassetearliertothepreferenceintheonCreate()method.

Listing11-10.SettingUpaPreferenceListener

publicbooleanonPreferenceChange(Preferencepreference,ObjectnewValue){

Page 276: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

finalStringkey=preference.getKey();if("package_name_preference".equals(key)){pkgPref.setSummary(newValue.toString());}...returntrue;}

YouhavetoregisterthefragmentasalistenerinonResume()usingsetOnPreferenceChangeListener(this)oneachpreferenceyouwanttolistenon,andunregisterinonPause()bycallingitagainwithnull.Noweverytimethereisapendingchangetoapreferenceyou’veregisteredfor,thiscallbackwillbeinvokedpassinginthepreferenceandthepotentialnewvalue.Thecallbackreturnsabooleanindicatingwhethertoproceedwithsettingthepreferencetothenewvalue(true)ornot(false).Assumingyouwouldreturntruetoallowthenewsetting,thisiswhereyoucanupdatethesummaryvalueaswell.Youcouldalsovalidatethenewvalueandrejectthechange.PerhapsyouwantaMultiSelectListPreferencetohaveamaximumnumberofcheckeditems.Youcouldcounttheselecteditemsinthecallbackandrejectthechangeiftherearetoomany.

SavingStatewithPreferencesPreferencesaregreatforallowinguserstocustomizeapplicationstotheirliking,butwecanusetheAndroidpreferenceframeworkformorethanthat.Whenyourapplicationneedstokeeptrackofsomedatabetweeninvocationsoftheapplication,preferencesareonewaytoaccomplishthetaskeveniftheusercan’tseethedatainpreferencescreens.PleasefindthesampleapplicationcalledSavingStateDemotofollowalongwiththecompletesourcecode.

TheActivityclasshasagetPreferences(intmode)method.This,inreality,simplycallsgetSharedPreferences()withtheclassnameoftheactivityasthetagplusthemodeaspassedin.Theresultisanactivity-specificsharedpreferencesfilethatyoucanusetostoredataaboutthisactivityacrossinvocations.AsimpleexampleofhowyoucouldusethisisshowninListing11-11.

Listing11-11.UsingPreferencestoSaveStateforanActivityfinalStringINITIALIZED=“initialized”;

privateStringsomeString;

[…]

SharedPreferencesmyPrefs=getPreferences(MODE_PRIVATE);

booleanhasPreferences=myPrefs.getBoolean(INITIALIZED,false);if(hasPreferences){

Page 277: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.v(“Preferences”,“We'vebeencalledbefore”);//Readothervaluesasdesiredfrompreferencesfile…someString=myPrefs.getString(“someString”,””);}else{Log.v(“Preferences”,“Firsttimeeverbeingcalled”);//Setupinitialvaluesforwhatwillendup//inthepreferencesfilesomeString=“somedefaultvalue”;}

[…]

//LaterwhenreadytowriteoutvaluesEditoreditor=myPrefs.edit();editor.putBoolean(INITIALIZED,true);editor.putString(“someString”,someString);//Writeothervaluesasdesirededitor.commit();

Whatthiscodedoesisacquireareferencetopreferencesforouractivityclassandcheckfortheexistenceofaboolean“preference”calledinitialized.Wewrite“preference”indoublequotationmarksbecausethisvalueisnotsomethingtheuserisgoingtoseeorset;it’smerelyavaluethatwewanttostoreinasharedpreferencesfileforusenexttime.Ifwegetavalue,thesharedpreferencesfileexists,sotheapplicationmusthavebeencalledbefore.Youcouldthenreadothervaluesoutofthesharedpreferencesfile.Forexample,someStringcouldbeanactivityvariablethatshouldbesetfromthelasttimethisactivityranorsettothedefaultvalueifthisisthefirsttime.

Towritevaluestothesharedpreferencesfile,youmustfirstgetapreferencesEditor.Youcanthenputvaluesintopreferencesandcommitthosechangeswhenyou’refinished.Notethat,behindthescenes,AndroidismanagingaSharedPreferencesobjectthatistrulyshared.Ideally,thereisnevermorethanoneEditoractiveatatime.Butitisveryimportanttocallthecommit()methodsothattheSharedPreferencesobjectandthesharedpreferencesXMLfilegetupdated.Intheexample,thevalueofsomeStringiswrittenouttobeusedthenexttimethisactivityruns.

Youcanaccess,write,andcommitvaluesanytimetoyourpreferencesfile.Possibleusesforthisincludewritingouthighscoresforagameorrecordingwhentheapplicationwaslastrun.YoucanalsousethegetSharedPreferences()callwithdifferentnamestomanageseparatesetsofpreferences,allwithinthesameapplicationoreventhesameactivity.

MODE_PRIVATEwasusedformodeinourexamplesthusfar.Becausethesharedpreferencesfilesarealwaysstoredwithinyourapplication’s/data/data/{package}directoryandthereforearenotaccessibletootherapplications,youonlyneedtouse

Page 278: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MODE_PRIVATE.

UsingDialogPreferenceSofar,you’veseenhowtousetheout-of-the-boxcapabilitiesofthepreferencesframework,butwhatifyouwanttocreateacustompreference?WhatifyouwantsomethingliketheslideroftheBrightnesspreferenceunderScreenSettings?ThisiswhereDialogPreferencecomesin.DialogPreferenceistheparentclassofEditTextPreferenceandListPreference.Thebehaviorisadialogthatpopsup,displayschoicestotheuser,andisclosedwithabuttonorviatheBackbutton.ButyoucanextendDialogPreferencetosetupyourowncustompreference.Withinyourextendedclass,youprovideyourownlayout,yourownclickhandlers,andcustomcodeinonDialogClosed()towritethedataforyourpreferencetothesharedpreferencesfile.

ReferenceHerearehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://developer.android.com/design/patterns/settings.htmlAndroid’sDesignGuidetoSettings.SomegoodadviceaboutlayingoutSettingsscreensandoptions.

http://developer.android.com/guide/topics/ui/settings.htmlAndroid’sAPIGuidetoSettings.ThispagedescribestheSettingsframework.

http://developer.android.com/reference/android/provider/Settings.htmlReferencepagethatliststhesettingsconstantsforcallingasystemsettingsactivity.

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforthefileProAndroid5_Ch11_Preferences.zip.ThisZIPfilecontainsalltheprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribeshowtoimportprojectsintoyourIDEfromoneoftheseZIPfiles.

SummaryThischaptertalkedaboutmanagingpreferencesinAndroid:

Typesofpreferencesavailable

Readingthecurrentvaluesofpreferencesintoyourapplication

Page 279: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SettingdefaultvaluesfromembeddedcodeandbywritingthedefaultvaluesfromtheXMLfiletothesavedpreferencesfile

Organizingpreferencesintogroups,anddefiningdependenciesbetweenpreferences

Callbacksonpreferencestovalidatechangesandtosetdynamicsummarytext

Usingthepreferencesframeworktosaveandrestoreinformationfromanactivityacrossinvocations

Creatingacustompreference

Page 280: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter12

UsingtheCompatibilityLibraryforOlderDevicesTheAndroidplatformhasgonethroughanimpressiveevolutionsinceitwasfirstintroducedseveralyearsago.WhiletheintentionhasalwaysbeenforAndroidtopowerlotsofdifferenttypesofdevices,itwasn’tarchitectedfromthebeginningtomeetthatgoal.Instead,theGoogleengineershaveadded,removed,andchangedAPIsinordertoprovidenewfeatures.OneofthebiggestchangeswasthecreationoffragmentsinordertohandlelargerscreensizessuchasontabletsandTVs.ButtherehavebeenotherchangessuchaswithActionBarandMenus.

ThenewAPIscreatedadifficultproblemfordeveloperswhowantedtheirapplicationstorunonthenewdeviceswiththenewAPIs,aswellasolderdevicesthatdidnothavethoseAPIs.ManyolderdevicesdonotgetAndroidupgrades.EvenifGoogleaddedthenewAPIstoarevisionoftheoldAndroidOS,theolddevicesaren’tgoingtogetthatnewrevision,becauseofthetestingandsupportrequiredfromboththedevicemanufacturerandthecellularcarrier.ThesolutionthatGooglecameupwithwastocreatecompatibilitylibrariesthatcouldbelinkedintoanapplicationsoitcouldtakeadvantageofthenewAPIfunctionalityyetstillrunonanolderversionofAndroid.ThelibraryfiguresouthowtousetheolderAPIstoimplementthenewfeatures.IfthesameapplicationrunsonanewerversionofAndroidthatalreadyhasthosenewfeatures,thecompatibilitylibrarycallsthroughtotheunderlyingAPIspresentinthatnewerversionofAndroid.

Thischapterwilldiveintothecompatibilitylibrariesandexplainhowtousethemandwhattowatchoutfor.Ifyouaren’tdevelopingapplicationsforolderversionsofAndroid,youcouldsafelyskipthischapterasyouwon’tneedthelibraries.ThelibrariesareonlyusefulifyouwanttoincludethefunctionalityofanewAPIinanapplicationthatwillrunonanoldversionofAndroidthatdoesn’thavethatnewAPI.

ItAllStartedwithTabletsTheAndroidoperatingsystemwasdoingfineuntilitcametimetosupporttablets.Thebasicbuildingblockofanapplicationwastheactivity,meanttoperformasingletaskfortheuserandtofillthescreenofthedevice.Buttabletsofferedmorerealestatesotheusercouldseeanddoafewthingsatatimeononescreen.SowithHoneycomb(Android3.0),Googleintroducedfragments.Thiswasawholenewconcept,whichchangedhowdeveloperscreatedUIsandthelogicthatranbehindthem.Andthiswouldhavebeenfine,exceptthattherewerestillplentyofAndroiddevices(e.g.,smartphones)inthewildwhichdidnotsupportfragments.WhatGooglefiguredoutisthatacompatibilitylibrarycouldbewrittentoprovidecomparableimplementationsofFragment,etc.,thatusedtheexistingAPIsintheolderversionsofAndroid.Ifanapplicationlinkedinthecompatibilitylibrary,

Page 281: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

itcouldworkwithfragmentseventhoughtheolderversionofAndroiddidn’tsupportfragmentsintheOS.

TheGoogleengineersthenlookedatotherfeaturesandAPIsinnewAndroidandprovidedcompatibilitylibraryfeaturesandAPIstomatch,sothatthesefeaturescouldalsobeusedinolderversionsofAndroidwithouthavingtoreleaseupdatestothoseolderversionsofAndroid.InadditiontosupportforFragments,compatibilitylibrariesprovidesupportforLoaders,RenderScript,ActionBar,andothers.

Thecompatibilitylibrarydoesn’talwaysmakethingsperfectlythesamebetweenoldandnew.Forexample,thenewActivityclassisawareoffragments.Tousethecompatibilitylibrary,youmustextendtheFragmentActivityclassinsteadofActivity;itistheFragmentActivityclassthatworkswithfragmentsinoldAndroidversions.

Whenyouusethecompatibilitylibrary,youwillusethoseclassesforyourapplicationregardlessofwhichversionofAndroiditwillrunon.Inotherwords,youwouldonlyuseFragmentActivityinyourapplicationanditwilldotherightthinginallversionsofAndroid,includingAndroid3.0andlater.YouwouldnottrytoincludeinthesameapplicationbothActivityforAndroid3.0+andFragmentActivityforAndroidbelow3.0.WhenFragmentActivityisexecutingonAndroid3.0andabove,itcanprettymuchcallstraightthroughtotheunderlyingActivityclass.ThereisnorealpenaltytousingacompatibilitylibraryonarecentAndroidversion.

AddingtheLibrarytoYourProjectAsofthiswriting,therearefourcompatibilitylibraries;togetherthecollectioniscalledtheAndroidSupportLibrary,revision22.1.1:

v4—containsFragmentActivity,Fragment,Loader,andquiteafewotherclassesintroducedafterAndroid3.0.Thenumber4representsAndroidAPIversion4(i.e.,Donut1.6).ItmeansthislibrarycanbeusedforapplicationsthatrunonAndroidAPIversion4andabove.

v7—makesavailabletheActionBar,CardView,GridLayout,MediaRouter,PaletteandRecyclerViewclasses.ThislibrarycanbeusedwithAndroidAPIversion7(i.e.,Eclair2.1)andabove.Thereareactuallysixlibrarieshere:appcompat,cardview,gridlayout,mediarouter,paletteandrecyclerview

v8—addsRenderSciptcapabilitytoAndroidAPIversion8(i.e.,Froyo2.2)andabove.RenderScriptallowsforparallelizationofworkacrossdeviceprocessors(CPUcores,GPUs,DSPs)andwasintroducedinAndroidAPIversion11(i.e.,Honeycomb3.0).

v13—addssomespecialFragmentfunctionalityforthingsliketabbedandpagerinterfaces.Thislibraryalsocontainsmanyofthe

Page 282: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

classesfromv4soitcanbeincludedinyourapplicationwithoutrequiringotherlibraries.

v17—addsLeanbackfeaturesrelatedtoAndroidTVapplications

Foracompletelistofallcompatibilityfunctionalitybyversionnumber,pleaseseethereferencesattheendofthischapter.

TodownloadtheAndroidSupportLibrarytoyourcomputer,usetheAndroidSDKManagerandlookforitatthebottomofthelistunderExtras.Ifyou’reusingAndroidStudio,downloadtheAndroidSupportRepository.Otherwise,downloadAndroidSupportLibraryinstead.ThefileswillbeplacedunderyourAndroidSDKdirectory.TheAndroidSupportLibrarycanbefoundinextras/android/support/,andtheAndroidSupportRepositorycanbefoundinextras/android/m2repository.

Asyoucanseefromtheprecedingbulletlist,notallfeaturesoftheAndroidSupportLibraryareavailableonallolderversionsofAndroid.Thereforeyoumustproperlysetandroid:minSdkVersioninyourAndroidManifest.xmlfile.Ifyouareusingacompatibilitylibraryfeaturefromv7,android:minSdkVersionshouldnotbelowerthan7.

Includingthev7SupportLibraryThere’sverylittlechancethatyou’deverwanttoincludethev4libraryandnotthev7library.Sincethev7libraryrequiresthatthev4libraryalsobeincludedtoprovidethenecessaryclassesforv7tofunctionproperly,you’llwanttoincludeboth.IfyouareusingEclipse,theADTplug-inmakesallofthisprettyeasy.WhenyoucreateanewAndroidprojectinEclipse,youspecifytheminimumversionofAndroidthatitwillrunon.IfADTthinksthatyoumightwantthecompatibilitylibraryincluded,itwillautomaticallyincludeit.

Forexample,ifyouspecifyatargetSDKof16(JellyBean4.1)butaminimumSDKof8(Froyo2.2),ADTwillautomaticallysetupanappcompatv7libraryproject,includethatlibraryprojectinyournewapplication,andalsoincludethev4libraryaswellinyourapplication.Theresourcesfromthev7libraryarethereforeavailabletoyourapplicationwithoutyouhavingtodoextrawork.However,ifyouwanttouseeitheroftheothertwov7libraries(gridlayoutand/ormediarouter),thosewillrequirealittleextrawork,aswillnowbeexplained.Bycreatingalibraryprojectandincludingthatinyourapplication,itwillincludethecompatibilitylibraryresourcesthatyourapplicationwillneed.

YouwillmanuallydosomethingsimilartowhatADTdidtoautomaticallyincludethev7appcompatlibraryintoyourproject.Tostart,youwillchooseFile Import,thenExistingAndroidCodeIntoWorkspace,thennavigatetotheextrasfolderwheretheAndroidSDKisonyourworkstation.Locatethev7gridlayoutormediarouterfolderandchoosethat.SeeFigure12-1.

Page 283: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure12-1.Importingthev7mediaroutercompatibilitylibrary

ClickFinishandyouwillgetanewlibraryproject.Ifyouchosetocreatealibraryprojectforv7mediarouter,youwillseethatitismissingsomefunctionalitysoithaserrors.Youneedtoaddinthev7appcompatlibrarytoclearthatup.Right-clickthemediarouterlibraryprojectinEclipseandchooseProperties.InthelistontheleftchooseAndroid.NowclicktheAdd…buttonintheLibrarysection.SeeFigure12-2.

Page 284: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure12-2.Addingappcompat_v7tothev7mediaroutercompatibilitylibrary

Selecttheappcompat_v7libraryandclickOK.Thatshouldclearuptheerrorsinmediarouter.Nowwhenyouwanttoincludemediarouterinyourapplicationproject,simplyfollowthesameprocedurebutright-clickyourapplicationproject,andwhenyouclicktheAdd…buttonforLibrary,chosethemediarouterlibrary.

WithAndroidStudio,addingav7compatibilitylibraryisjustaseasy.Bydefault,ifyoucreateanewprojectwithaminimumSDKvaluelessthanyourtargetSDK,youwillverylikelygetthev7appcompatlibraryaddedinautomatically.Youcancheckthisbylookingforthefollowinglineintheapp’sbuild.gradleconfigurationfileinthedependenciessection:compile'com.android.support:appcompat-v7:22.0.0'

Therefore,toaddoneoftheotherv7libraries,youwouldinsertanothersimilarcompilelinetothedependenciessection,butusetheappropriatenamesuchascardviewormediarouter.

Includingthev8SupportLibraryIfyouwanttousethev8renderscriptcompatibilitylibrary,andyoudevelopwithEclipse,yousimplyaddthefollowingthreelinestotheapplicationproject’sproject.propertiesfileregardlessofthetargetversionofyourapplication:

renderscript.target=22renderscript.support.mode=truesdk.buildtools=22.1.1

Atthetimeofthiswriting,theonlineAndroiddocumentationsaysthatyoushoulduseatargetof18andabuildtoolsof18.1.0.However,usingtheoldvaluesgeneratesanerror

Page 285: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

sayingtouseanewerversionofbuildtools.IfyouseeerrorsintheEclipseConsoleregardingversionnumbers,tryusingalaterversionasindicatedbytheerror.

IfyoudevelopwithAndroidStudio,toincludev8renderscriptyouwouldedittheapp’sbuild.gradlefileandaddtheselineswithinthedefaultConfigsection:

renderscriptTargetApi22renderscriptSupportModeEnabledtrue

Withinyourcode,makesureyouimportfromandroid.support.v8.renderscriptratherthanandroid.renderscript.IfyouaremodifyinganexistingRenderScriptapplicationforthev8library,makesuretocleanyourproject;theJavafilesthataregeneratedfromyour.rsfilesneedtoberegeneratedtoalsousethev8library.YoucannowuseRenderScriptasusualanddeployyourapplicationtoolderversionsofAndroid.

Includingthev13SupportLibraryToincludethev13compatibilitylibraryintoyourapplicationusingEclipse,navigatetotheSDKextrasdirectoryandfindthev13jarfile.Copythisfiletothe/libsdirectoryofyourapplicationproject.Oncethev13jarfileisinplace,right-clickittopullupthemenu,andthenchooseBuildPath AddtoBuildPath.There’sagoodchanceyoualreadyhavethev4andv7appcompatlibrariesinyourapplicationcourtesyofADT.Youmaychoosetogetridofthoseifyoudon’tneedthefunctionalityfromeitherone.Forexample,iftheminimumSDKforyourapplicationisv11,youcanusethenativeActionBarclasswithouttheneedforthev7appcompatsupportlibrary.

Thev13jarfilecontainsmanyofthesameclassesasv4,soyoudon’twanttocauseanyproblemsbyhavingthesameclassesintwice.Ifyou’regoingtohaveallthreelibrariesinyourapplication(i.e.,v4,v7,andv13),thenatleastensurethatv13isorderedbeforev4.ThiscanbedoneintheConfigureBuildPathdialogbox.

Ifyou’reusingAndroidStudio,justmakesuretheSDKManagerhasdownloadedtheSupportRepository,thenaddthefollowingcompilelinetotheapp’sbuild.gradlefilejustlikeyoudoforv7libraries:

compile'com.android.support:support-v13:22.0.0'

Includingthev17SupportLibraryFinally,includingthev17compatibilitylibraryisdonethesamewayasforthev13supportlibrary.

IncludingJustthev4SupportLibraryIfyoureallymusthavethev4supportlibraryandnoneoftheothers,youwouldfollowthesameprocedureasforthev13library.

Page 286: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RetrofittinganAppwiththeAndroidSupportLibraryTogetabetterfeelforhowthisallworks,you’regoingtobringbackafragmentappyouworkedoninChapter8andwillmakeitworkforolderversionsofAndroidthatdon’tnativelysupportfragments.

UseFile Import,chooseGeneral,thenExistingProjectsintoWorkspace.NavigatetotheShakespeareInstrumentedprojectfromChapter8andchoosethat.Check“Copyprojectsintoworkspace”beforehittingFinish.

Nowyou’regoingtoretrofitthisapplicationtoworkonversionsofAndroidlowerthanAPIversion11.Thefollowingworkswhenyoudon’tneedresourcesfromthecompatibilitylibrary,sinceitworriesonlyaboutcopyingintheJARfile.

1. Right-clickyourprojectandchooseAndroidTools AddSupportLibrary….AcceptthelicenseandclickOK.

2. NowgointoMainActivity.javaandchangethebaseclassfromActivitytoFragmentActivity.Youneedtofixtheimportlinefromandroid.app.Activitytoandroid.support.v4.app.FragmentActivity.AlsofixtheimportsforFragment,FragmentManager,andFragmentTransactiontousetheonesfromthesupportlibrary.

3. FindthemethodcallsforgetFragmentManager()andchangethesetogetSupportFragmentManager().DothisalsoforDetailsActivity.java.

4. ForDetailsFragment.java,changetheimportforFragmenttotheoneforthesupportlibraryFragment(i.e.,android.support.v4.app.Fragment).

5. InTitlesFragment.java,changetheimportforListFragmenttotheoneforthesupportlibraryListFragment(i.e.,android.support.v4.app.ListFragment).

ThenewerversionsofAndroidusedifferentanimatorsfromoldAndroid.YoumayneedtofixanimationsinMainActivity.javaintheshowDetails()method.PickoneofthecommentedoutcallstosetCustomAnimations(),thenplaywiththeinandoutanimations.AnythingthatreliesonanObjectAnimatorclasswillnotworkonolderdevicessincethisclasswasintroducedwithAPIversion11(i.e.,Honeycomb3.0).ItwillcompilebutsincethatclasshasnotbeenimplementedinolderAndroidandhasnotbeenincludedinthecompatibilitylibraries,youwillgetaruntimeexception.Inotherwords,avoidR.animator.TryusingR.animinstead.Youcancopyintoyourprojectanim

Page 287: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

resourcefilesthatyou’dliketouse,oryoucantryreferringtoandroid.R.animfiles.

NowyoucangointoAndroidManifest.xmlandchangetheminSdkVersionfrom11to8.Thatshouldbeallyouneedtodo.TryrunningthisapplicationonaFroyodeviceoremulator.Ifallwentwellyoushouldnowbeseeingafragment-basedapplicationrunningonapre–Android3.0OS.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://developer.android.com/tools/support-library/index.html:TheAndroidDeveloper’sGuideontheSupportLibrarypackage.

http://developer.android.com/tools/support-library/features.html:Androiddocumentationonthemainfeaturesofeachcompatibilitylibrary.

http://developer.android.com/tools/support-library/setup.html:Androiddocumentationonsettingupacompatibilitylibraryforyourproject,forbothEclipseandAndroidStudio.Atthetimeofthiswriting,thesepageswerenotascurrentasthischapter.However,thingschange.Ifyouexperiencetrouble,checktheonlinedocumentationorcontactthebook’sauthors.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedabouttheAndroidcompatibilitylibraries:

Togetyourapplicationworkingonthebroadestarrayofdevices,usethecompatibilitylibrariesandcodetotheirAPIsratherthanthelatestandgreatestAPIs.

Thev7supportlibrariescomewithresourcesthatmustbeincludedinyourapplicationfortheAPIstoworkproperly.

Page 288: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter13

ExploringPackages,Processes,Threads,andHandlersInthebookthusfar,wehavefocusedontheessentialsofhowtoprogramfortheAndroidplatform.InthischapterwewanttogounderthehoodabittoaddresstheprocessandthreadingmodelforAndroidprograms.Thisdiscussionwillleadustosigningpackages,sharingdatabetweenpackages,usingcompile-timelibraries,thenatureofAndroidcomponentsandhowtheyusethreads,andfinallytheneedforhandlersandhowonecancodehandlers.

Asyougothroughthischapter,keepinmindthattheword“package”isoverloaded.SometimesitreferstotheJavalanguagepackage,andsometimesitreferstotheAPKfilesthatAndroidapplicationsaredeployedas.

UnderstandingPackagesandProcessesWewillstartwithAndroidpackagesandtheprocessmodel.WhenyoudevelopanapplicationinAndroid,youendupwithan.apkfile.Yousignthis.apkfileanddeployittothedevice.Each.apkfileisuniquelyidentifiedbyauniquejava-language-stylepackagename,asshowninthemanifestfileshowninListing13-1.

Listing13-1.ProvidingaPackageNameintheManifestFile

<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.testapp"...>...restofthexmlnodes</manifest>

Ifyouwerethedeveloperofthispackage,nooneotherthanyoucouldupdatethisapplicationonceitisdeployed.TheAndroidapplicationpackagenameisreservedforyou.Thistie-uphappenswhenyousignandregisteryourappwithvariousapppublishers.SochoosethisAndroidapplicationpackagenameverysimilartothewaythatJavapackagesarenamed.Thisneedstobeuniqueintheworld.Onceyoupublishtheapp,youcannotchangethispackagename,asthisdefinesyourapplication’sidentity.

Androidusesthepackagenameasthenameoftheprocessthatrunsthecomponentsofthispackage.AndroidalsoallocatesauniqueuserIDforthisprocesstorununder.ThisuserIDisessentiallytheuserIDfortheunderlyingLinuxOS.AsthisuserIDisdeterminedatthetimeoftheinstallonaparticulardevice,itwillbedifferentoneachdevicewhereyourappisinstalled.Youcandiscoverthisinformationbylookingatthe

Page 289: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

detailsoftheinstalledpackagethroughthedevelopertoolsintheAndroidEmulator.Forexample,apackagedetailscreenfortheinstalledbrowserapplicationlookslikeFigure13-1.(Pleasenotethatthisimageortoolwhereyoulookthisupmayvaryfromreleasetorelease.TheimageinFigure13-1istakenfromthedevelopertoolsapplicationontheAndroidEmulator.)

Figure13-1.Androidpackagedetails

Figure13-1showsthenameoftheprocessasindicatedbytheJavapackagenameinthemanifestfileandtheuniqueuserIDallocatedtothispackage.AnyresourcescreatedbythisprocessorpackagewillbesecuredunderthatLinuxuserID.Thisscreenalsoliststhecomponentsinsidethispackage.Examplesofcomponentsareactivities,services,andbroadcastreceivers.DonotethatthisimagemayvarydependingontheAndroidrelease.Throughthesettingsofthedeviceortheemulator,youcanalsouninstallthepackagesothatitcanberemoved.

Becauseaprocessistiedtoapackagename,andapackagenameistiedtoitssignature,signaturesplayaroleinsecuringthedatabelongingtoapackage.Apackageistypicallysignedwithaself-signedPKI(PublicKeyInfrastructure)certificate.Acertificate

Page 290: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

identifieswhotheauthorofthepackageis.Thesecertificatesneednotbeissuedbyacertificateauthority.Thismeanstheinformationinthecertificateisnotapprovedorvalidatedbyanyauthority.ThismeansonecancreateacertificatethatsaysthattheirnameisGoogle.Theonlyassuranceisthatthispackagenameisreservedtothatuserifnoonehadclaimeditinthemarketplacebefore,andanysubsequentupdatestothatpackagearegivenonlytothatuser(identifiedbythatcertificate).AllassetsthatareinstalledorcreatedthroughthispackagebelongtotheuserwhoseIDisassignedtothepackage.Ifyourintentionistoallowasetofcooperatingapplicationsthatdependonacommonsetofdata,youhaveanoptiontoexplicitlyspecifyauserIDthatisuniquetoyouandcommonforyourneeds.ThisshareduserIDisalsodefinedinthemanifestfile,similartothedefinitionofapackagename.Listing13-2showsanexample.

Listing13-2.SharedUserIDDeclaration

<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.somepackage"sharedUserId="com.androidbook.mysharedusrid"...>...therestofthexmlnodes</manifest>

MultipleapplicationscanspecifythesameshareduserIDiftheysharethesamesignature(signedwiththesamePKIcertificate).HavingashareduserIDallowsmultipleapplicationstosharedataandevenruninthesameprocess.ToavoidtheduplicationofashareduserID,useaconventionsimilartonamingaJavaclass.HerearesomeexamplesofshareduserIDsfoundintheAndroidsystem:

"android.uid.system""android.uid.phone"

NoteAsharedIDmustbespecifiedasarawstringandnotastringresource.

Asanoteofcaution,ifyouareplanningtouseshareduserIDs,therecommendationistousethemfromthestart.Otherwise,theydon’tworkwellwhenyouupgradeyourapplicationfromanonshareduserIDtoonewithasharedID.OneofthecitedreasonsisthatAndroidwillnotrunchownontheoldresourcesbecauseoftheuserIDchange.

ACodePatternforSharingDataThissectionexplorestheopportunitieswhentwoapplicationswanttoshareresourcesanddatathroughtheuseofashareduserID.Theresourcesanddataofeachpackageareownedandprotectedbythatpackage’scontextduringruntime.Youneedaccesstothecontextofthepackagefromwhichyouwanttosharetheresourcesordata.

YoucanusethecreatePackageContext()APIonanyexistingcontextobject(such

Page 291: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

asyouractivity)togetareferencetothetargetcontextthatyouwanttointeractwith.Listing13-3providesanexample.

Listing13-3.UsingthecreatePackageContext()API

//Usetheappropriatetry/catchtodetecterrors//IdentifypackageyouwanttouseStringtargetPackageName="com.androidbook.samplepackage1";

//Decideonanappropriatecontextflagintflag=Context.CONTEXT_RESTRICTED;

//Getthetargetcontextthroughoneofyouractivities//NeedtocatchNameNotFoundExceptionActivitymyContext=......;ContexttargetContext=myContext.createPackageContext(targetPackageName,flag);

//UsecontexttoresolvefilepathsResourcesres=targetContext.getResources();Filepath=targetContext.getFilesDir();

Noticehowweareabletogetareferencetothecontextofagivenpackagenamesuchascom.androidbook.samplepackage1.ThistargetContextinListing13-3isidenticaltothecontextthatispassedtothetargetapplicationwhenthatapplicationislaunched.Asthenameofthemethodindicates(inits“create”prefix),eachcallreturnsanewcontextobject.However,thedocumentationassuresusthatthisreturnedcontextobjectisdesignedtobelightweight,meaningitdoesn’tconsumealotofmemoryandisoptimizedtoreferthetargetpackage’sresources,assets,andcode.

ThisAPIisapplicableregardlessofwhetherbothcontextsshareauserID.IfyousharetheuserID,itiswellandgood.Ifyoudon’tshareauserID,thetargetapplicationwouldneedtodeclareitsresourcesaccessibletooutsideusers.

TheCONTEXT_RESTRICTEDflagindicatesthatyouareinterestedinjustloadingtheresourcesandtheassetsandnotthecode.Sousingthisflagallowsthesystemtodetectifthelayoutscontainreferencestocallbackcode.Exampleofacallbackwouldbeabuttoninalayoutreferringtoamethodthatwouldbecalled.Thiscallbackcodeexistsinthesourcecontext.So,youwouldwantthesystemtothrowanexceptionsothatyoucandetectthatconditionorignorethatparticularXMLtag.Inessence,youaretellingthesystemthatyouareusingthecontextinarestrictedsenseandthetargetcontextisfreetomakesuitableassumptionsbasedonthatflag.Thebottomlineappearstobethatifyouareinterestedinnotusingthecodefromthetargetcontext,usethisflag.

CONTEXT_INCLUDE_CODEallowsyoutoloadJavaclassesatruntimefromthetargetcontextintoyourprocessandcallthatcode.Documentationindicatesthatyoumayreceiveasecurityexceptionifitisnotsafetoloadthecode.However,itisnotclearunderwhatcircumstancesthecodeisconsideredunsafe.Oneeducatedguessisthatthetarget

Page 292: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

contextdoesnothaveashareduserIDasthatofthesourcecontext.YoucanovercomethisrestrictionbyalsospecifyingtheCONTEXT_IGNOR_SECURITYalongwiththeCONTEXT_INCLUDE_CODE.Thesetwoflagstogetherloadthetargetcontextcodeintothesourcecontextcodeallthetime,ignoringevenifthetargetcontextbelongstoadifferentuser.Althoughcodeisborrowedandrunsintheclientprocess,itwillnothavepermissionstothetargetcontextdata.So,besurewhatthatcodedoeswhenletlooseonyourdata.Thisapproachisoftenusedforutilitycodethatcanbeshared.

UnderstandingLibraryProjectsAswetalkthroughsharingcodeandresources,onequestionworthaskingis,willtheideaofa“library”projecthelp?StartingwithADT0.9.7Eclipseplug-in,Androidsupportstheideaoflibraryprojects.Theapproachtobuildinglibrarieshasbeenchangingabitsincethen,whilethecentralidearemainsinallrecentreleases.

AlibraryprojectisacollectionofJavacodeandresourcesthatlookslikearegularAndroidprojectbutneverendsupinan.apkfilebyitself.Instead,thecodeandresourcesofalibraryprojectbecomepartofanotherprojectandgetcompiledintothatmainproject’s.apkfile.Aslibrariesarepurelyacompile-timeconcept,eachdevelopmenttoolmaycraftthisfacilitydifferently.

Herearesomeadditionalfactsabouttheselibraryprojects:

Alibraryprojectcanhaveitsownpackagenamedistinctfromthemainapplication.

AlibraryprojectcanuseotherJARfiles.

EclipseADTwillcompilethelibraryJavasourcefilesintoaJARfilethatisthencompiledwiththeapplicationproject.

ExceptfortheJavafiles(whichbecomeajarfile),therestofthefilesbelongingtoalibraryproject(suchasresources)arekeptwiththelibraryproject.Thepresenceofthelibraryprojectisrequiredinordertocompiletheapplicationprojectthatincludesthatlibraryasadependency.

StartingwithSDKTools15.0,theresourceIDsgeneratedforlibraryprojectsintheirrespectiveR.javafilesarenotfinal.(Thisisexplainedlaterinthechapter.)

BoththelibraryprojectandthemainprojectcanaccesstheresourcesfromthelibraryprojectthroughtheirrespectiveR.javafiles.ThismeanstheIDnamesareduplicatedandavailableinbothR.javafiles.

IfyouwouldliketodistinguishresourceIDsbetweenthetwoprojects(libraryandmain),youcanusedifferentresourceprefixes,suchaslib_forthelibraryprojectresources.

Amainprojectcanreferenceanynumberoflibraryprojects.

Page 293: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Components,suchasanactivity,ofalibraryneedtobedefinedinthetargetmainprojectmanifestfile.Whenthisisdone,thecomponentnamefromthelibrarypackagemustbefullyqualifiedwiththelibrarypackagename.

Itisnotnecessarytodefinethecomponentsinalibrarymanifestfile,althoughitmaybeagoodpracticetoknowquicklywhatcomponentsitsupports.

CreatingalibraryprojectstartswithcreatingaregularAndroidprojectandthenchoosingtheIsLibraryflaginitspropertieswindow.

Youcansetthedependentlibraryprojectsforamainprojectthroughtheprojectpropertiesscreenaswell.

Clearly,beingalibraryproject,anynumberofmainprojectscanincludealibraryproject.

Onelibraryprojectcannotreferenceanotherlibraryprojectasofthereleases(Android4.4,API19,SDKTools19,ADT22.3),althoughthereseemstobeadesiretobeabletodosoinfuturereleases.

Tocreatealibraryproject,youstartbycreatingaregularAndroidproject.Oncetheprojectissetup,right-clicktheprojectnameandclickthepropertiescontextmenutoshowthepropertiesdialogforthelibraryproject.ThisdialogisshowninFigure13-2.(TheavailablebuildtargetsinthisfiguremayvarywithyourversionoftheAndroidSDK.)SimplyselectIsLibraryfromthisdialogtosetupthisprojectasalibraryproject.

Page 294: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure13-2.Designatingaprojectasalibraryproject

Youcanusethefollowingprojectpropertiesdialog(seeFigure13-3)toindicatethatamainprojectdependsonthelibraryprojectthatwascreatedearlier.

Page 295: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure13-3.Declaringalibraryprojectdependency

NoticetheAddbuttoninthedialog.YoucanusethistoaddthelibraryinFigure13-3asareference.Youdon’tneedtodoanythingelse.

Oncethelibraryprojectissetupasadependencyforthemainapplicationproject,thelibraryprojectappearsasacompiledJARfileintheapplicationprojectunderthenodeAndroidDependencies.

Androiddoesn’tpackageR.classfilesfromthelibrariesintheirrespectivejarfiles.Instead,itreliesonthesourceR.javafilethatisre-createdandmadeavailableinthemainapplicationprojectforeachofthelibraries.ThatmeansyouhaveanR.javafileforeachofthelibrariesinthegensubdirectoryofthemainproject.

Toavoidhard-codedconstantsbeinginthecompiledsourcecodeofthelibraries,AndroidcreatesthelibraryR.javafilessuchthatalltheconstantsinthatfilearenon-final.Duringthefinalcompilationofthemainproject,newconstantvaluesareallocatedsothattheseconstantvaluesareuniqueacrossallthelibrariesandthemainproject.Hadwegivenfinalconstantvaluesduringlibrarycompilation,thenthosenumberscouldcollidebetweenlibraries.AllocationofIDsuniquelyforagivensetofnamesmustbedoneonetime.OncethesenumbersareallocatedtotheIDsduringthecompileofthemainproject,theycan

Page 296: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

becomefinalinthatmainproject.

ThereisanimplicationtiedtothefactthatIDsinthelibrary’sR.javafilearenotfinal.ItiscommontouseaswitchstatementtorespondtomenuitemsbasedonamenuitemID.ThislanguageconstructwillfailatcompiletimewhendoneinthelibrarycodeiftheIDsarenotfinal.Thisisbecausethecasestatementinaswitchclausehastobeanumericalconstantnumber.

So,theswitchstatementinListing13-4willnotcompileunlesstheIDs(suchasR.id.menu_item_1)areactualliteralnumbersorstaticfinals.

Listing13-4.SampleswitchStatementtoDemonstrateNon-FinalVariables

switch(menuItem.getItemId()){caseR.id.menu_item_1:Statement1;break;case0x7778888://asanexampleforR.id.menu_item_2:statement;statement;break;default:statement;statement;}

BecausetheIDsaredefinedasnon-finalforlibraryprojects,weareforcedtouseif/elsestatementsinsteadofswitch/caseclauses.Becausethesameconstantsre-createdfromthelibrary’sR.javafilesarefinal,youcanusefreelytheswitchclauseinyourfinalproject.

Asyoucansee,libraryprojectsarecompile-timeconstructs.Clearly,anyresourcesthatbelongtothelibrarygetabsorbedandmergedintothemainproject.Thereisnotaquestionofsharingatruntime,becausethereisjustonepackagefilewiththenameofthemainpackage.Inshort,librariesofferawaytoshareresourcesbetweenrelatedprojectsatcompiletime.

UnderstandingComponentsandThreadsWestartedoffthischapterestablishingthateachpackagerunsinitsownprocess.Wewillnowexplaintheorganizationofthreadswithinthisprocess.Thiswillleadustowhyweneedhandlerstooffloadtheworkfromthemainthreadandalsotocommunicatewiththemainthread.

MostcodeinanAndroidapplicationrunsinthecontextofacomponentsuchasanactivityoraservice.Mostofthetime,thereisonlyonethreadrunninginanAndroidprocess,calledthemainthread.Wewilltalkabouttheimplicationsofsharingthismainthreadamongvariouscomponents.Primarily,thiscanleadtoApplicationNotResponding

Page 297: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(ANR)messages(the“A”standsfor“application”andnot“annoying”).Wewillshowyouhowyoucanusehandlers,messages,andthreadstobreakthedependencyonthemainthreadwhenlong-runningoperationsareneeded.

AnAndroidprocesshasfourprimarycomponenttypes:Activity,Service,ContentProvider,andaBroadcastReceiver.MostcodeyouwriteinanAndroidapplicationispartofoneofthesecomponentsorcalledbyoneofthesecomponents.EachofthesecomponentsgetsitsownXMLnodeunderanapplicationnodespecificationintheAndroidprojectmanifestfile.Torecall,herearethesenodesinListing13-5:

Listing13-5.HowComponentsAreDeclaredintheManifestFile

<manifest…><application><activity/><service/><receiver/><provider/></application></manifest>

Withsomeexceptions(suchasexternalprocesscallstocontentproviders),Androidusesthesamethreadtoprocess(orrunthrough)codeinthesecomponents.Thisthreadiscalledthemainthreadoftheapplication.Whenthesecomponentsarecalled,thecallcanbeeitherasynchronouscall,suchaswhenyoucallacontentproviderfordata,oradeferredonethroughamessagequeue,suchaswhenyouinvokefunctionalitybycallingastartserviceorshowadialog.

Figure13-4describestherelationshipbetweenthreadsandthesefourcomponents.ThisdiagramshowshowthreadsweavethroughtheAndroidframeworkanditscomponents.Thediagramdoesnotindicatetheorderinwhichathreadmightweavethroughthevariouscomponents.Thediagramismerelyshowingthattheprocessingcontinuesfromonecomponenttoanotherinasequentialfashion.

Page 298: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure13-4.Androidcomponentsandthreadingframework

AsindicatedinFigure13-4,themainthreaddoestheheavylifting.Itrunsthroughallthecomponentsbyusingamessagequeue.Asyouselectmenusorbuttonsonthedevicescreen,thedevicewilltranslatetheseactionsasmessagesanddropthemontothemainqueueoftheprocessthatisinfocus.Themainthreadsitsinaloopandprocesseseachmessage.Ifanymessagetakesmorethanfivesecondsorso,AndroidthrowsanANRmessage.

Similarly,inresponsetoamenuitem,ifyouweretoinvokeabroadcastmessage,Androidagaindropsamessageonthemainqueueofthepackageprocessfromwhichtheregisteredreceiveristobeinvoked.Themainthreadwillcomearoundtothatmessageatalatertimetoinvokethereceiver.Themainthreaddoestheworkforabroadcastreceiveraswell.Ifthemainthreadisbusyrespondingtoamenuaction,thebroadcastreceiverwillhavetowaituntilthemainthreadgetsfreedup.

Thesameistruewithaservice.WhenyoustartalocalservicewithActivity.startServicefromamenuitem,amessageisdroppedontothemainqueue,andthemainthreadwillcomearoundtoprocessitviatheservicecode.

Callstoalocalcontentproviderareslightlydifferent.Acontentproviderstillrunsonthemainthreadforalocalcall,butacalltoitissynchronousanddoesnotusemessagequeues.

Youmayask,“WhyisitimportantwhethermostcodeinanAndroidapplicationrunsonthemainthreadorotherwise?”ThisisimportantbecausethemainthreadhastheresponsibilitytogetbacktoitsqueuesothatUIeventsarerespondedto.Asaconsequence,youshouldnotholdupthemainthread.Ifthereissomethingthatisgoingto

Page 299: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

takelongerthanfiveseconds,youshouldgetthatdoneinaseparatethreadordeferitbyaskingthemainthreadtocomebacktoitwhenitisfreedupfromotherprocessing.Whenexternalclientsorcomponentsoutsideoftheprocessmakeacalltothecontentproviderfordata,thenthatcallisallocatedathreadfromathreadpool.Thesameistruewithexternalclientsconnectingtoservices.

Let’slookatwhathandlersareandhowtheyfunctioninthenextsection.

UnderstandingHandlersWehavebrieflyreferredtotheideaofdeferringworkonamainthreadifneeded.Thisisdonethroughhandlers.HandlersareextensivelyusedthroughoutAndroidsothatthemainUIthreadisnotheldup.Theyalsoplayaroleincommunicatingwiththemainthreadfromotherspawnedworkerthreads.

Ahandlerisamechanismtodropamessageonthemainqueue(moreprecisely,thequeueattachedtothethreadonwhichthehandlerisinstantiated)sothatthemessagecanbeprocessedatalaterpointintimebythatcirculatingthread.Themessagethatisdroppedhasaninternalreferencepointingtothehandlerthatdroppedit.

Whenthemainthreadgetsaroundtoprocessingthatmessage,itinvokesthehandlerthatdroppedthemessagethroughacallbackmethodonthehandlerobject.ThiscallbackmethodiscalledhandleMessage.Figure13-5presentsthisrelationshipbetweenhandlers,messages,andthemainthread.

Page 300: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure13-5.Handler,message,messagequeuerelationship

Figure13-5illustratesthekeyplayersthatworktogetherwhenwetalkabouthandlers:mainthread,mainthreadqueue,handler,andamessage.Outofthesefour,wearenotexposedtothemainthreadorthequeuedirectly.Weprimarilydealwiththehandlerobjectandthemessageobject.Evenbetweenthesetwo,thehandlerobjectcoordinatesmostofthework.

Althoughahandlerallowsustodropamessageontothequeue,itisthemessageobjectthatactuallyholdsareferencebacktothehandler.Themessageobjectalsoholdsadatastructurethatcanbepassedbacktothehandler.

Workingwithahandlerandmessagesisbestunderstoodthroughanexample.Fortheexample,wewillhaveamenuitemthatinvokesafunction,andthatfunction,inturn,performsanactionfivetimesatone-secondintervalsandreportsbacktotheinvokingactivityeachtime.

Ifwedidn’tmindholdingupthemainthread,wecouldhavecodedthisscenariolikethepseudocodeinListing13-6.

Page 301: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing13-6.HoldingUptheMainThreadwithaSleepMethod

publicclassSomeActivity{....othermethodsvoidrespondToMenuItem(){//ProvethatweareonthemainthreadUtils.logThreadSignature();//simulateanoperationthattakeslongerthan5secondsfor(inti=0;i<6;i++){sleepFor(1000);//putmainthreadtosleepfor1secdosomething();SomeTextView.setText("didsomething.Counter:"+Integer.toString(i));}}}

Thiswillsatisfytherequirementoftheusecase.However,ifwedothis,weareholdingupthemainthread,andweareguaranteedtohaveanANR.WecanuseahandlertoavoidtheANRinthepreviousexample.PseudocodetodothisviaahandlerwilllooklikeListing13-7.

Listing13-7.InstantiatingaHandlerfromtheMainThread

voidrespondToMenuItem(){SomeHandlerDerivedFromHandlermyHandler=newSomeHandlerDerivedFromHandler();myHandler.doDeferredWork();//invokeafunctionin1secintervals//notethatdoDeferredWork()isnotpartoftheSDK//wewillshowyouthecodeforthisshortly}

Now,thecallrespondToMenuItem()willallowthemainthreadtogobacktoitsloop.Theinstantiatedhandlerknowsthatitisinvokedonthemainthreadandhooksitselfuptothequeue.ThemethoddoDeferredWork()willscheduleworksothatthemainthreadcangetbacktothisworkonceitisfree.

Toinvestigatethisprotocol,let’sseetheactualsourcecodeforaproperhandler.ThecodeinListing13-8inthenextsectiondemonstratesthishandler,whichiscalledDeferWorkHandler.InthepreviouspseudocodeofListing13-7,theindicatedhandlerSomeHandlerDerivedFromHandlerisequivalenttothisDeferWorkHandler.Similarly,theindicatedmethoddoDeferredWork()(ofListing13-7)isimplementedontheDeferWorkHandlerinListing13-8.

Listing13-8.DeferWorkHandlerSourceCode

Page 302: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicclassDeferWorkHandlerextendsHandler{//Keeptrackofhowmanytimeswesentthemessageprivateintcount=0;

//Aparentdriveractivitywecanusetoinformofstatus.privateTestHandlersDriverActivityparentActivity=null;

//Duringconstructionwetakeintheparentdriveractivity.publicDeferWorkHandler(TestHandlersDriverActivityinParentActivity){parentActivity=inParentActivity;}//Callbackmethodthatgetscalledbythemainthread

@OverridepublicvoidhandleMessage(Messagemsg){

//UsethemessageobjecttogettoitsdataStringpm=newString("messagecalled:"+count+":"+msg.getData().getString("message"));//youcanaccesstheparentactivityandinvokeUIcallsonithereparentActivity.someControl.somemethod();//exampleonly

//logictoinvokeitselfmultipletimesifneededif(count>5){return;}count++;//incrementcountsendTestMessage(1);//reinvokeagainbysendingamessage}//methodcalledbytheclient

publicvoiddoDeferredWork(){count=0;sendTestMessage(1);}//PreparingandsendingthemessagepublicvoidsendTestMessage(longinterval){Messagem=this.obtainMessage();prepareMessage(m);this.sendMessageDelayed(m,interval*1000);}publicvoidprepareMessage(Messagem){Bundleb=newBundle();

Page 303: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

b.putString("message","HelloWorld");m.setData(b);return;}}

Let’slookatthekeyaspectsofthissourcecode.Thefirstisthatthehandlerisderivedfromthebaseclasshandler.Intheconstructorofthehandler,weuseapointertotheparentactivitysothatwecanusetheUIcontrolsoftheactivitytoreportwhatneedstobereportedortoactupon.Thenwecodeamethod(doDeferredWork)toencapsulatewhatthishandlerisexpectedtodoforus.NoticethatthedoDeferredWork( )isnotanoverriddenmethodandyoucancallthismethodwhatevernamethatyouwouldlike.ItisinthismethodthatyouworkwithmessagestoeventuallycalltheoverriddenhandleMessage( ).Also,itisinthishandleMessage( )thatyouactuallyputtherealcodethatisoriginallydeferredfromthemainthread.

Thebasehandleroffersaseriesofmethodstosendmessagestothequeuetoberespondedtolater.ThesemethodsareusedinthedoDeferredWork( ).sendMessage()andsendMessageDelayed()aretwoexamplesofthesesendmethods.sendMessageDelayed(),whichweusedintheexample,allowsustodropamessageonthemainqueuewithagivenamountoftimedelay.sendMessage(),incontrast,dropsthemessageimmediatelytobeprocessedwhenthemainthreadgetsaroundtoit.

WhenyoucallsendMessage()orsendMessageDelayed(),youwillneedaninstanceofthemessageobject.Itisbestthatyouaskthehandlertogiveittoyou,becausewhenthehandlerreturnsthemessageobject,ithidesitselfinthebellyofthemessage.Thatway,whenthemainthreadcomesalong,itknowswhichhandlertocallbasedsolelyonthemessage.InListing13-8,themessageisobtainedusingthefollowingcode:

Messagem=this.obtainMessage();

Thevariablethisreferstoisthehandlerobjectinstance.Asthenameindicates,themethoddoesnotcreateanewmessagebutinsteadgetsonefromaglobalmessagepool.Atalaterpoint,oncethismessageisprocessed,itwillberecycled.ThemethodobtainMessage()hasthevariationsshowninListing13-9.

Listing13-9.ConstructingaMessageThroughaHandler

obtainMessage();obtainMessage(intwhat);obtainMessage(intwhat,Objectobject);obtainMessage(intwhat,intarg1,intarg2)obtainMessage(intwhat,intarg1,intarg2,Objectobject);

Eachmethodvariationsetsthecorrespondingfieldsonthemessageobject.Therearesomerestrictionsontheobjectargumentwhenthemessagecrossesprocessboundaries.Insuchcases,itneedstobeParcelable.Itismuchsaferandcompatibleinsuchcasesto

Page 304: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

usethesetData()methodexplicitlyonthemessageobject,whichtakesaBundle.InListing13-8,wehaveusedsetData().Youareencouragedtousearg1orarg2insteadifwhatyouareintendingtopassaresimpleindicatorsthatcanbeaccommodatedwithintegervalues.

Theargumentwhat(inListing13-9)allowsyoutodequeuemessageorenquireiftherearemessagesofthistypeinthequeue.Seetheoperationsonthehandlerclassformoredetails.

Onceweobtainamessagefromthehandler,wecanoptionallymodifythedatacontentsofthatmessage.Inourexample,wehaveusedthesetData()functionbypassingitaBundleobject.Afterwehavecategorizedoridentifiedthedataofthemessage,wecansendthemessagetothequeuethroughsendMessage()orsendMessageDelayed().Whenthesemethodsarecalled,themainthreadwillreturntoattendingthequeue.

Oncethemessagesaredeliveredtothequeue,thehandlersitsandwaits(figurativelyspeaking)untilthemainthreadretrievesthosemessagesandcallsthehandler’shandleMessage().

Ifyouwanttoseethishandlerandmainthreadinteractionmoreclearly,youcanwritealogcatmessagewhenyouaresendingthemessageandinthehandleMessage()callback.YouwillnoticethetimestampsdifferasthemainthreadwouldhavetakenafewmoremillisecondstocomebacktothehandleMessage()method.

Inourexample,eachhandleMessage(),afterprocessingonemessage,sendsanothermessagetothequeuesothatitcanbecalledagain.Itdoesthisfivetimes,andwhenthecounterreachesfive,itquitssendingmessagestothequeue.Thisisonewaytobreakuptheworkintomultiplechunks,althoughtherearebetterwaystodothiseitherthroughaworkerthreadorthroughaclassAsyncTask.TheessentialAsyncTaskiscoveredinthenextchapter.Let’scovertheexplicitworkerthreadsoptionbrieflynow.

UsingWorkerThreadsWhenweuseahandlerliketheoneintheprevioussection,thecodeisstillexecutedonthemainthread.EachcalltohandleMessage()stillshouldreturnwithinthetimestipulationsofthemainthread(inotherwords,eachmessageinvocationshouldcompleteinlessthanfivesecondstoavoidApplicationNotResponding).Ifyourgoalistoextendthattimeofexecutionfurther,youwillneedtostartaseparatethread,keepthethreadrunninguntilitfinishesthework,andallowforthatsubthreadtoreportbacktothemainactivity,whichisrunningonthemainthread.Thistypeofasubthreadisoftencalledaworkerthread.

Itisano-brainertostartaseparatethreadwhilerespondingtoamenuitem.However,theclevertrickistoallowtheworkerthreadtopostamessagetothequeueofthemainthreadthatsomethingishappeningandthatthemainthreadshouldlookatitwhenitgetstothatmessage.ItisalsoanerrortocallUImethodsonanon-UIthread.So,youwillneedthis

Page 305: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

handlerthatistiedtothemainthreadtocallUImethodsfromaworkerthread.

Areasonablesolutionthatinvolvesaworkerthreadisasfollows:

1. Createahandlerinthemainthreadwhilerespondingtothemenuitem.Keepitaside.

2. Createaseparatethread(aworkerthread)thatdoestheactualwork.Passthehandlerfromstep1totheworkerthread.Thishandlerallowstheworkerthreadtocommunicatewiththemainthread.

3. Theworkerthreadcodecannowdotheactualworkforlongerthanfivesecondsand,whiledoingit,cancallthehandlertosendstatusmessagestocommunicatewiththemainthread.

4. Thesestatusmessagesnowgetprocessedbythemainthread,becausethehandlerbelongedtothemainthread.Themainthreadcanprocessthesemessageswhiletheworkerthreadisdoingitswork.

Youcanseethesamplecodeforthisinteractioninthedownloadableprojectforthischapter.AnalternateandprobablymorestraightforwardwaytocommunicatewiththeUIthreadfromaworkerthreadistogetholdoftheactivitypointerandcallthemethodActivity.runOnUiThread(Runnableaction).OfcourseyouneedtocreateaRunnableobjectforcoordination.

ReferencesHerearesomeusefullinkstofurtherstrengthenyourunderstandingofthischapter:

http://developer.android.com/guide/publishing/app-signing.html:Amust-readforsigning.apkfiles.

http://developer.android.com/guide/developing/projects/projects-eclipse.html:PrimarySDKreferenceforAndroidlibraries.

http://developer.android.com/guide/topics/fundamentals.htmlSDKreferenceonAndroidcomponentlifecycles.

http://www.androidbook.com/item/3493:Alayman’sintroductiontowhatitmeanstosigndigitally.

http://www.androidbook.com/item/3279:OurresearchonunderstandingAndroidpackages.Youwillseehowtosign.apkfiles,furtherlinkstohowtosharedatabetweenpackages,moreonshareduserIDs,andinstructionstoinstallanduninstallpackages.

http://www.androidbook.com/item/3908:OurresearchnotesonallaspectsofAndroidlibrarysupport,includingolderscreenshots,newerscreenshots,usefulURLs,samplecode,and

Page 306: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

more.

http://android-developers.blogspot.com/2011/10/changes-to-library-projects-in-android.html:WhathaschangedinlibrariesatthetimeofAndroid4.0andthereasonsforthechange?Thisblogalsotalksaboutfuturedirectionsforworkingwithlibraries.

http://tools.android.com/tips/non-constant-fields:Insightfuldiscussionoftheroleofnon-finalvariablesandhowtheyaffectswitchstatements.

http://tools.android.com/knownissues:AndroiddocumentationofknownissuesintheSDKToolsandtheADTreleases.AlsonotethedomainnameofthisURL;thissiteisdedicatedtoallaspectsofAndroidtooling.

http://docs.oracle.com/javase/7/docs/technotes/tools/windows/keytool.htmlExcellentdocumentationonkeytool,jarsigner,andthesigningprocessitself.

http://www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforafilecalledProAndroid5_Ch13_TestAndroidLibraries.zip.ThisZIPfilecontainstwoprojects:onealibraryandtheotherthatusesthislibrary.AlsotakealookataprojectcalledProAndroid5_Ch13_TestHandlers.zip,whichcontainsthecodetoworkwithhandlersincludingworkerthreads.

SummaryThischaptergaveyouaquickrun-downonhowpackages,processes,components,andthreadsinteractinanAndroidapplication.Thischapterhasalsodocumentedthelibrarysupportforsharingassetsbetweenmultipleapplications.Thischapteralsohasintroducedhandlers,akeyconceptintheAndroidSDK.Inthenextchapter,wewillgivedetailedcoverageofAsyncTask,whichcombinestheworkerthreadsandhandlersintoasimplerprogrammingabstractiontouse.

Page 307: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter14

BuildingandConsumingServicesTheAndroidplatformprovidesacompletesoftwarestack.Thismeansyougetanoperatingsystemandmiddleware,aswellasworkingapplications(suchasaphonedialer).Alongsideallofthis,youhaveanSDKthatyoucanusetowriteapplicationsfortheplatform.Thusfar,we’veseenthatwecanbuildapplicationsthatdirectlyinteractwiththeuserthroughauserinterface.Wehavenot,however,discussedbackgroundservicesorthepossibilitiesofbuildingcomponentsthatruninthebackground.

Inthischapter,wearegoingtofocusonbuildingandconsumingservicesinAndroid.Firstwe’lldiscussconsumingHTTPservices,andthenwe’llcoveranicewaytodosimplebackgroundtasks,andfinallywe’lldiscussinterprocesscommunication—thatis,communicationbetweenapplicationsonthesamedevice.

ConsumingHTTPServicesAndroidapplicationsandmobileapplicationsingeneralaresmallappswithalotoffunctionality.Oneofthewaysthatmobileappsdeliversuchrichfunctionalityonsuchasmalldeviceisthattheypullinformationfromvarioussources.Forexample,mostAndroidsmartphonescomewiththeMapsapplication,whichprovidessophisticatedmappingfunctionality.We,however,knowthattheapplicationisintegratedwiththeGoogleMapsAPIandotherservices,whichprovidemostofthesophistication.

Thatsaid,itislikelythattheapplicationsyouwritewillalsoleverageinformationfromotherapplicationsandAPIs.AcommonintegrationstrategyistouseHTTP.Forexample,youmighthaveaJavaservletavailableontheInternetthatprovidesservicesyouwanttoleveragefromoneofyourAndroidapplications.HowdoyoudothatwithAndroid?Interestingly,theAndroidSDKshipswithavariationofApache’sHttpClient(http://hc.apache.org/httpcomponents-client-ga/),whichisuniversallyused.TheAndroidversionhasbeenmodifiedforAndroid,buttheAPIsareverysimilartotheAPIsintheApacheversion.

TheApacheHttpClientisacomprehensiveHTTPclient.ItoffersfullsupportfortheHTTPprotocol.Inthissection,wewilldiscussusingtheHttpClienttomakeHTTPGETandHTTPPOSTcalls.IfyouareworkingwithRESTfulservices,youwouldprobablyusetheotherHTTPoperationsaswell(PUT,DELETE,etc.).

UsingtheHttpClientforHTTPGETRequestsHere’soneofthegeneralpatternsforusingtheHttpClient:

1. CreateanHttpClient(orgetanexistingreference).

Page 308: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

2. InstantiateanewHTTPmethod,suchasPostMethodorGetMethod.

3. SetHTTPparameternames/values.

4. ExecutetheHTTPcallusingtheHttpClient.

5. ProcesstheHTTPresponse.

Listing14-1showshowtoexecuteanHTTPGETusingtheHttpClient.

NoteWegiveyouaURLattheendofthechapterthatyoucanusetodownloadprojectsfromthischapter.ThiswillallowyoutoimporttheseprojectsintoyourIDEdirectly.Also,becausethecodeattemptstousetheInternet,youwillneedtoaddandroid.permission.INTERNETtoyourmanifestfilewhenmakingHTTPcallsusingHttpClient.

Alsonotethatinthefollowingexamples,allwebservicescallsshouldbeputintobackgroundthreadssoasnottoblockthemainUIthread.Seelaterinthischapter,aswellasChapter15,foranexcellentdeep-diveonhowtodothat.Forthepurposesofthischapter,thosedetailsareexcludedtohelpwithunderstandingservices.

Listing14-1.UsingHttpClientandHttpGet:HttpGetDemo.java

publicclassHttpGetDemoextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

BufferedReaderin=null;try{

HttpClientclient=newDefaultHttpClient();HttpGetrequest=newHttpGet("http://code.google.com/android/");HttpResponseresponse=client.execute(request);

in=newBufferedReader(newInputStreamReader(response.getEntity().getContent()));

StringBuffersb=newStringBuffer("");Stringline="";StringNL=System.getProperty("line.separator");while((line=in.readLine())!=null){sb.append(line+NL);

Page 309: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}in.close();

Stringpage=sb.toString();System.out.println(page);}catch(Exceptione){e.printStackTrace();}finally{if(in!=null){try{in.close();}catch(IOExceptione){e.printStackTrace();}}}}}

TheHttpClientisabletoconsumethevariousHTTPrequesttypes,suchasHttpGet,HttpPost,andsoon.Listing14-1usestheHttpClienttogetthecontentsofthehttp://code.google.com/android/URL.TheactualHTTPrequestisexecutedwiththecalltoclient.execute().Afterexecutingtherequest,thecodereadstheentireresponseintoastringobject.NotethattheBufferedReaderisclosedinthefinallyblock,whichalsoclosestheunderlyingHTTPconnection.

ForourexampleweembeddedtheHTTPlogicinsideofanactivity,butwedon’tneedtobewithinthecontextofanactivitytouseHttpClient.YoucanuseitfromwithinthecontextofanyAndroidcomponentoruseitaspartofastand-aloneclass.Infact,youshouldn’tuseHttpClientdirectlywithinanactivity,becauseawebcallcouldtakeawhiletocompleteandcauseanApplicationNotResponding(ANR)pop-up.We’llcoverthattopiclaterinthischapter.Fornowwe’regoingtocheatalittlesowecanfocusonhowtomakeHttpClientcalls.

ThecodeinListing14-1executesanHTTPrequestwithoutpassinganyHTTPparameterstotheserver.Youcanpassname/valueparametersaspartoftherequestbyappendingname/valuepairstotheURL,asshowninListing14-2.

Listing14-2.AddingParameterstoanHTTPGETRequest

HttpGetrequest=newHttpGet("http://somehost/Upload.aspx?one=value1&two=value2");client.execute(request);

WhenyouexecuteanHTTPGET,theparameters(namesandvalues)oftherequestarepassedaspartoftheURL.Passingparametersthiswayhassomelimitations.Namely,thelengthofaURLshouldbekeptbelow2,048characters.Ifyouhavemorethanthisamount

Page 310: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ofdatatosubmit,youshoulduseHTTPPOSTinstead.ThePOSTmethodismoreflexibleandpassesparametersaspartoftherequestbody.

UsingtheHttpClientforHTTPPOSTRequests(aMultipartExample)MakinganHTTPPOSTcallisverysimilartomakinganHTTPGETcall(seeListing14-3).ThisexampleiscalledSimpleHTTPPost.

Listing14-3.MakinganHTTPPOSTRequestwiththeHttpClient

HttpClientclient=newDefaultHttpClient();HttpPostrequest=newHttpPost("http://www.androidbook.com/akc/display");List<NameValuePair>postParameters=newArrayList<NameValuePair>();postParameters.add(newBasicNameValuePair("url","DisplayNoteIMPURL"));postParameters.add(newBasicNameValuePair("reportId","4788"));postParameters.add(newBasicNameValuePair("ownerUserId","android"));postParameters.add(newBasicNameValuePair("aspire_output_format","embedded-xml"));UrlEncodedFormEntityformEntity=newUrlEncodedFormEntity(postParameters);request.setEntity(formEntity);HttpResponseresponse=client.execute(request);

ThecodeinListing14-3wouldreplacethethreelinesinListing14-1wheretheHttpGetisused.Everythingelsecouldstaythesame.TomakeanHTTPPOSTcallwiththeHttpClient,youhavetocalltheexecute()methodoftheHttpClientwithaninstanceofHttpPost.WhenmakingHTTPPOSTcalls,yougenerallypassURL-encodedname/valueformparametersaspartoftheHTTPrequest.TodothiswiththeHttpClient,youhavetocreatealistthatcontainsinstancesofNameValuePairobjectsandthenwrapthatlistwithaUrlEncodedFormEntityobject.TheNameValuePairwrapsaname/valuecombination,andtheUrlEncodedFormEntityclassknowshowtoencodealistofNameValuePairobjectssuitableforHTTPcalls(generallyPOSTcalls).AfteryoucreateaUrlEncodedFormEntity,youcansettheentitytypeoftheHttpPosttotheUrlEncodedFormEntityandthenexecutetherequest.

InListing14-3,wecreatedanHttpClientandtheninstantiatedtheHttpPostwiththeURLoftheHTTPendpoint.Next,wecreatedalistofNameValuePairobjectsandpopulateditwithseveralname/valueparameters.WethencreatedaUrlEncodedFormEntityinstance,passingthelistofNameValuePairobjectsto

Page 311: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

itsconstructor.Finally,wecalledthesetEntity()methodofthePOSTrequestandthenexecutedtherequestusingtheHttpClientinstance.

HTTPPOSTisactuallymuchmorepowerfulthanthis.WithanHTTPPOST,wecanpasssimplename/valueparameters,asshowninListing14-3,aswellascomplexparameterssuchasfiles.HTTPPOSTsupportsanotherrequest-bodyformatknownasamultipartPOST.WiththistypeofPOST,youcansendname/valueparametersasbefore,alongwitharbitraryfiles.Unfortunately,theversionofHttpClientshippedwithAndroiddoesnotdirectlysupportmultipartPOST.Toachievethisgoalinthepast,we’verecommendedthatyougrabthreeotherlibraries:ApacheCommonsIO,Mime4j,andHttpMime.

NowwerecommendthatyoudownloadtheIonlibrary,whichhastwodependencies.Allthreejarfilescanbefoundatthesetwosites:

https://github.com/koush/ion#jars(ionandandroidasync)

https://code.google.com/p/google-gson/downloads/list(gson)

Listing14-4demonstratesamultipartPOSTusingAndroid.ThisexampleiscalledMultipartHTTPPost.

Listing14-4.MakingaMultipartPOSTCall

publicclassTestMultipartPostextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

try{Ion.with(this,"http://www.androidbook.com/akc/update/PublicUploadTest").setMultipartParameter("field1","Thisisfieldnumber1").setMultipartParameter("field2","Field2isshorter").setMultipartFile("datafile",newFile(Environment.getExternalStorageDirectory()+"/testfile.txt")).asString().setCallback(newFutureCallback<String>(){@OverridepublicvoidonCompleted(Exceptione,Stringresult){System.out.println(result);}});

Page 312: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}catch(Exceptione){//DosomethingaboutexceptionsSystem.out.println("Gotexception:"+e);}}}

NoteThemultipartexampleusesseveral.jarfilesthatarenotincludedaspartoftheAndroidruntime.Toensurethatthe.jarfileswillbepackagedaspartofyour.apkfile,youneedtoaddthemasexternal.jarfilesinEclipse.Todothis,right-clickyourprojectinEclipse,selectProperties,chooseJavaBuildPath,selecttheLibrariestab,andthenselectAddExternalJARs.

Followingthesestepswillmakethe.jarfilesavailableduringcompiletimeaswellasruntime.

ToexecuteamultipartPOSTusingtheIonlibrary,yousimplyputtogethertheappropriatecallstobuildaURL,addparameters,definethereturntype,andsetupacallbackmethod.ThiswillrunasynchronouslyandthecallbackwillbeinvokedontheUIthreadoncearesponseisreceivedfromthewebserver.Intheexample,theresultstringiswrittentoLogCat.YourapplicationisprobablygoingtoreceivebackaJsonObjectwhichthecallbackwouldthenprocess.ButrealizethattheresponsefromthewebserverhasalreadybeenconvertedintoaJsonObjectforyou,makingtheprocessinginthecallbackthatmucheasier.Listing14-4addsthreepartstotherequest:twostringpartsandatextfile.Torunthisexampleyourselfyouwillneedtoputatestfile.txtfileontotheexternalstorageareaofyourdeviceoremulator.

Finally,ifyouarebuildinganapplicationthatrequiresyoutopassamultipartPOSTtoawebresource,you’lllikelyhavetodebugthesolutionusingadummyimplementationoftheserviceonyourlocalworkstation.Whenyou’rerunningapplicationsonyourlocalworkstation,normallyyoucanaccessthelocalmachinebyusinglocalhostorIPaddress127.0.0.1.WithAndroidapplications,however,youwillnotbeabletouselocalhost(or127.0.0.1)becausethedeviceoremulatorwillbeitsownlocalhost.Youdon’twanttopointthisclienttoaserviceontheAndroiddevice;youwanttopointtoyourworkstation.Torefertoyourdevelopmentworkstationfromtheapplicationrunninginthedeviceoremulator,you’llhavetouseyourworkstation’sIPaddressintheURL.

SOAP,JSON,andXMLParsersWhataboutSOAP?TherearelotsofSOAP-basedwebservicesontheInternet,buttodate,GooglehasnotprovideddirectsupportinAndroidforcallingSOAPwebservices.GoogleinsteadprefersREST-likewebservices,seeminglytoreducetheamountofcomputingrequiredontheclientdevice.However,thetradeoffisthatthedevelopermustdomoreworktosenddataandtoparsethereturneddata.Ideally,youwillhavesome

Page 313: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

optionsforhowyoucaninteractwithyourwebservices.SomedevelopershaveusedthekSOAP2developerkittobuildSOAPclientsforAndroid.Wewon’tbecoveringthatapproach,butit’soutthereifyou’reinterested.

NoteTheoriginalkSOAP2sourceislocatedhere:http://ksoap2.sourceforge.net/.Theopensourcecommunityhas(thankfully!)contributedaversionofkSOAP2forAndroid,andyoucanfindoutmoreaboutithere:http://code.google.com/p/ksoap2-android/.

Oneapproachthat’sbeenusedsuccessfullyistoimplementyourownservicesontheInternet,whichcantalkSOAP(orwhatever)tothedestinationservice.ThenyourAndroidapplicationonlyneedstotalktoyourservices,andyounowhavecompletecontrol.Ifthedestinationserviceschange,youmightbeabletohandlethatwithouthavingtoupdateandreleaseanewversionofyourapplication.You’donlyhavetoupdatetheservicesonyourserver.Asidebenefitofthisapproachisthatyoucouldmoreeasilyimplementapaidsubscriptionmodelforyourapplication.Ifauserletstheirsubscriptionlapse,youcanturnthemoffatyourserver.

AndroiddoeshavesupportforJavaScriptObjectNotation(JSON).Thisisafairlycommonmethodofpackagingdatabetweenawebserverandaclient.TheJSONparsingclassesmakeitveryeasytounpackdatafromaresponsesoyourapplicationcanactonit.OrdigdeeperintotheGsonpackagereferencedearlierinthischapter.GsonisaJSONJavalibraryfromGoogle,anditsmainbenefitishoweasyitistoparseJSONinputintoJavaobjects,andviceversa.It’salsoveryfast.

AndroidalsohasacoupleofXMLparsersthatyoucanusetointerprettheresponsesfromtheHTTPcalls;therecommendedoneisXMLPullParser.

DealingwithExceptionsDealingwithexceptionsispartofanyprogram,butsoftwarethatmakesuseofexternalservices(suchasHTTPservices)mustpayadditionalattentiontoexceptionsbecausethepotentialforerrorsismagnified.ThereareseveraltypesofexceptionsthatyoucanexpectwhilemakinguseofHTTPservices.Thesearetransportexceptions,protocolexceptions,andtimeouts.Youshouldunderstandwhentheseexceptionscouldoccur.

Transportexceptionscanoccurduetoanumberofreasons,butthemostlikelyscenariowithamobiledeviceispoornetworkconnectivity.Protocolexceptions(e.g.,ClientProtocolException)areexceptionsattheHTTPprotocollayer.Theseincludeauthenticationerrors,invalidcookies,andsoon.Youcanexpecttoseeprotocolexceptionsif,forexample,youhavetosupplylogincredentialsaspartofyourHTTPrequestbutfailtodoso.Timeouts,withrespecttoHTTPcalls,comeintwoflavors:connectiontimeoutsandsockettimeouts.Aconnectiontimeout(e.g.,ConnectTimeoutException)canoccuriftheHttpClientisnotabletoconnecttotheHTTPserver—if,forexample,theserverisnotavailable.Asockettimeout(e.g.,SocketTimeoutException)canoccuriftheHttpClientfailstoreceivearesponse

Page 314: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

withinadefinedtimeperiod.Inotherwords,theHttpClientwasabletoconnecttotheserver,buttheserverfailedtoreturnaresponsewithintheallocatedtimelimit.

Nowthatyouunderstandthetypesofexceptionsthatmightoccur,howdoyoudealwiththem?Fortunately,theHttpClientisarobustframeworkthattakesmostoftheburdenoffyourshoulders.Infact,theonlyexceptiontypesthatyou’llhavetoworryaboutaretheonesthatyou’llbeabletomanageeasily.TheHttpClienttakescareoftransportexceptionsbydetectingtransportissuesandretryingrequests(whichworksverywellwiththistypeofexception).Protocolexceptionsareexceptionsthatcangenerallybeflushedoutduringdevelopment.Timeoutsarethemostlikelyexceptionsthatyou’llhavetodealwith.Asimpleandeffectiveapproachtodealingwithbothtypesoftimeouts—connectiontimeoutsandsockettimeouts—istowraptheexecute()methodofyourHTTPrequestwithatry/catchandthenretryifafailureoccurs.

WhenusingtheHttpClientaspartofareal-worldapplication,youneedtopaysomeattentiontomultithreadingissuesthatmightcomeup.Let’sdelveintothesenow.

AddressingMultithreadingIssuesTheexampleswe’veshownsofarcreatedanewHttpClientforeachrequest.Inpractice,however,youcouldcreateoneHttpClientfortheentireapplicationandusethatforallofyourHTTPcommunication.It’spossibletoassociateaconnectionpoolwiththisHttpClient,whichyou’llnowsee.WithoneHttpClientservicingallofyourHTTPrequests,youshouldpayattentiontomultithreadingissuesthatcouldsurfaceifyoumakesimultaneousrequeststhroughthesameHttpClient.Fortunately,theHttpClientprovidesfacilitiesthatmakethiseasy—allyouhavetodoiscreatetheDefaultHttpClientusingaThreadSafeClientConnManager,asshowninListing14-5.ThisexampleprojectisHttpSingleton.

Listing14-5.CreatinganHttpClientforMultithreading:CustomHttpClient.java

publicclassCustomHttpClient{privatestaticHttpClientcustomHttpClient;

/**AprivateConstructorpreventsinstantiation*/privateCustomHttpClient(){}

publicstaticsynchronizedHttpClientgetHttpClient(){if(customHttpClient==null){HttpParamsparams=newBasicHttpParams();HttpProtocolParams.setVersion(params,HttpVersion.HTTP_1_1);HttpProtocolParams.setContentCharset(params,HTTP.DEFAULT_CONTENT_CHARSET);HttpProtocolParams.setUseExpectContinue(params,

Page 315: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

true);HttpProtocolParams.setUserAgent(params,System.getProperty("http.agent")//Couldalsohaveusedthefollowingwhichisbrowser-orientedasopposedto//device-oriented://newWebView(getApplicationContext()).getSettings().getUserAgentString());

ConnManagerParams.setTimeout(params,1000);

HttpConnectionParams.setConnectionTimeout(params,5000);HttpConnectionParams.setSoTimeout(params,10000);

SchemeRegistryschReg=newSchemeRegistry();schReg.register(newScheme("http",PlainSocketFactory.getSocketFactory(),80));schReg.register(newScheme("https",SSLSocketFactory.getSocketFactory(),443));ClientConnectionManagerconMgr=newThreadSafeClientConnManager(params,schReg);

customHttpClient=newDefaultHttpClient(conMgr,params);}returncustomHttpClient;}

publicObjectclone()throwsCloneNotSupportedException{thrownewCloneNotSupportedException();}}

IfyourapplicationneedstomakemorethanafewHTTPcalls,youshouldcreateanHttpClientthatservicesallyourHTTPrequests.Thesimplestwaytodothisistocreateasingletonclassthatcanbeaccessedfromanywhereintheapplication,aswe’veshownhere.ThisisafairlystandardJavapatterninwhichwesynchronizeaccesstoagettermethod,andthatgettermethodreturnstheoneandonlyHttpClientobjectforthesingleton,creatingitthefirsttimeasnecessary.

Now,takealookatthegetHttpClient()methodofCustomHttpClient.ThismethodisresponsibleforcreatingoursingletonHttpClient.Wesetsomebasicparameters,sometimeoutvalues,andtheschemesthatourHttpClientwillsupport

Page 316: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(thatis,HTTPandHTTPS).NoticethatwhenweinstantiatetheDefaultHttpClient(),wepassinaClientConnectionManager.TheClientConnectionManagerisresponsibleformanagingHTTPconnectionsfortheHttpClient.BecausewewanttouseasingleHttpClientforalltheHTTPrequests(requeststhatcouldoverlapifwe’reusingthreads),wecreateaThreadSafeClientConnManager.

WealsoshowyouasimplerwayofcollectingtheresponsefromtheHTTPrequest,usingaBasicResponseHandler.ThecodeforouractivitythatusesourCustomHttpClientisinListing14-6.

Listing14-6.UsingOurCustomHttpClient:HttpActivity.java

publicclassHttpActivityextendsActivity{privateHttpClienthttpClient;@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

httpClient=CustomHttpClient.getHttpClient();getHttpContent();}

publicvoidgetHttpContent(){try{HttpGetrequest=newHttpGet("http://www.google.com/");Stringpage=httpClient.execute(request,newBasicResponseHandler());System.out.println(page);}catch(IOExceptione){//covers://ClientProtocolException//ConnectTimeoutException//ConnectionPoolTimeoutException//SocketTimeoutExceptione.printStackTrace();}}}

Forthissampleapplication,wedoasimpleHTTPgetoftheGooglehomepage.WealsouseaBasicResponseHandlerobjecttotakecareofrenderingthepageasabig

Page 317: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

String,whichwethenwriteouttoLogCat.Asyoucansee,addingaBasicResponseHandlertotheexecute()methodisveryeasytodo.

YoumaybetemptedtotakeadvantageofthefactthateachAndroidapplicationhasanassociatedApplicationobject.Bydefault,ifyoudon’tdefineacustomapplicationobject,Androidusesandroid.app.Application.Here’stheinterestingthingabouttheapplicationobject:therewillalwaysbeexactlyoneapplicationobjectforyourapplication,andallofyourcomponentscanaccessit(usingtheglobalcontextobject).ItispossibletoextendtheApplicationclassandaddfunctionalitysuchasourCustomHttpClient.However,inourcasethereisreallynoreasontodothiswithintheApplicationclassitself,andyouwillbemuchbetteroffnotmessingwiththeApplicationclasswhenyoucansimplycreateaseparatesingletonclasstohandlethistypeofneed.

FunwithTimeoutsThereareotherterrificadvantagestosettingupasingleHttpClientforourapplicationtouse.Wecanmodifythepropertiesofitinoneplace,andeveryonecantakeadvantageofit.Forexample,ifwewanttosetupcommontimeoutvaluesforourHTTPcalls,wecandothatwhencreatingourHttpClientbycallingtheappropriatesetterfunctionsagainstourHttpParamsobject.PleaserefertoListing14-5andthegetHttpClient()method.Noticethattherearethreetimeoutswecanplaywith.Thefirstisatimeoutfortheconnectionmanager,anditdefineshowlongweshouldwaittogetaconnectionoutoftheconnectionpoolmanagedbytheconnectionmanager.Inourexample,wesetthisto1second.Abouttheonlytimewemighteverhavetowaitisifallconnectionsfromthepoolareinuse.Thesecondtimeoutvaluedefineshowlongweshouldwaittomakeaconnectionoverthenetworktotheserverontheotherend.Here,weusedavalueof2seconds.Andlastly,wesetasockettimeoutvalueto4secondstodefinehowlongweshouldwaittogetdatabackforourrequest.

Correspondingtothethreetimeoutsdescribedpreviously,wecouldgetthesethreeexceptions:ConnectionPoolTimeoutException,ConnectTimeoutException,orSocketTimeoutException.AllthreeoftheseexceptionsaresubclassesofIOException,whichwe’veusedinourHttpActivityinsteadofcatchingeachsubclassexceptionseparately.

Ifyouinvestigateeachoftheparameter-settingclassesthatweusedingetHttpClient(),youmightdiscoverevenmoreparametersthatyouwouldfinduseful.

We’vedescribedforyouhowtosetupanHttpClientwithapoolofconnectionsforuseacrossyourapplication.Andtheimplicationisthateverytimeyouneedtouseaconnection,thevarioussettingswillapplytoyourparticularneeds.Butwhatifyouwantdifferentsettingsforaparticularmessage?Thankfully,there’saneasywaytodothataswell.WeshowedyouhowtouseanHttpGetoranHttpPostobjecttodescribetherequesttobemadeacrossthenetwork.InasimilarwaytohowwesetHttpParamsonourHttpClient,youcansetHttpParamsonbothHttpGetandHttpPost

Page 318: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

objects.ThesettingsyouapplyatthemessagelevelwilloverridethesettingsattheHttpClientlevelwithoutchangingtheHttpClientsettings.Listing14-7showswhatthismightlooklikeifwewantedtohaveasockettimeoutof1minuteinsteadof4secondsforoneparticularrequest.YouwouldusetheselinesinplaceofthelinesinthetryblockofgetHttpContent()inListing14-6.

Listing14-7.OverridingtheSocketTimeoutattheRequestLevel

HttpGetrequest=newHttpGet("http://www.google.com/");HttpParamsparams=request.getParams();HttpConnectionParams.setSoTimeout(params,60000);//1minuterequest.setParams(params);Stringpage=httpClient.execute(request,newBasicResponseHandler());System.out.println(page);

UsingtheHttpURLConnectionAndroidprovidesanotherwaytodealwithHTTPservices,andthatisusingthejava.net.HttpURLConnectionclass.ThisisnotunliketheHttpClientclasseswe’vejustcovered,butHttpURLConnectiontendstorequiremorestatementstogetthingsdone.HttpURLConnectionisalsonotthreadsafe.Ontheotherhand,thisclassismuchsmallerandlightweightthanHttpClient,soyoucansimplycreatetheonesyouneed.StartingwiththeGingerbreadrelease,itisalsofairlystable,soyoushouldconsideritforappsonmorerecentdeviceswhenyoujustneedbasicHTTPfeaturesandyouwantacompactapplication.

UsingtheAndroidHttpClientAndroid2.2introducedanewsubclassofHttpClientcalledAndroidHttpClient.TheideabehindthisclassistomakethingseasierforthedeveloperofAndroidappsbyprovidingdefaultvaluesandlogicappropriateforAndroidapps.Forexample,thetimeoutvaluesfortheconnectionandthesocket(thatis,operation)defaultto20secondseach.TheconnectionmanagerdefaultstotheThreadSafeClientConnManager.Forthemostpart,itisinterchangeablewiththeHttpClientweusedinthepreviousexamples.Thereareafewdifferences,though,thatyoushouldbeawareof:

TocreateanAndroidHttpClient,youinvokethestaticnewInstance()methodoftheAndroidHttpClientclass,likethis:

AndroidHttpClienthttpClient=AndroidHttpClient.newInstance("my-http-agent-string");

Page 319: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

NoticethattheparametertothenewInstance()methodisanHTTPagentstring.Youmostlikelydon’twanttohardcodethis,soyouhavetwooptionsasfollows,whichunfortunatelycanreturndifferentstrings.Thesecondoneisprobablytheoneyouwanttouseasitlooksmorelikewhatabrowserwouldsend(atleastinourexperiments).

//Thefirstoptionisadevice-levelagentstringStringhttpAgent=System.getProperty("http.agent");//Thissecondoptionlookslikeabrowser’sagentstringhttpAgent=newWebView(context).getSettings().getUserAgentString();

Ofcourse,youarealsofreetobuildyourownagentstringusinganythingavailabletoyourapp;it’stheserverthat’sgoingtoparseittobetterunderstandthedevice,andifyoucontroltheserver,youcanusewhatevervaluesyousentfromtheapp.

Whenexecute()iscalledonthisclient,youmustbeinathreadseparatefromthemainUIthread.Thismeansthatyou’llgetanexceptionifyousimplyattempttoreplaceourpreviousHttpClientwithanAndroidHttpClient.ItisbadpracticetomakeHTTPcallsfromthemainUIthread,soAndroidHttpClientwon’tletyou.We’llbecoveringthreadingissuesinthenextsection.

Youmustcallclose()ontheAndroidHttpClientinstancewhenyouaredonewithit.Thisissomemorycanbefreedupproperly.

Therearesomehandystaticmethodsfordealingwithcompressedresponsesfromaserver,including

modifyRequestToAcceptGzipResponse(HttpRequestrequest)

getCompressedEntity(byte[]data,ContentResolverresolver)

getUngzippedContent(HttpEntityentity)

Onceyou’veacquiredaninstanceoftheAndroidHttpClient,youcannotmodifyanyparametersettingsinit,norcanyouaddanyparametersettingstoit(suchastheHTTPprotocolversion,forexample).YouroptionsaretooverridesettingswithintheHttpGet

Page 320: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

objectasshownpreviouslyortonotusetheAndroidHttpClient.

ThisconcludesourdiscussionofusingHTTPserviceswiththeHttpClient.ForagreattutorialonusingHttpClientandtheseotherconcepts,pleasecheckouttheApachesiteathttp://hc.apache.org/httpcomponents-client-ga/tutorial/html/.

We’veshownyouhowtooperatewithHTTP-basedservices.Butwhatifwewantedtorunsomebackgroundprocessingthatlastedlongerthanashortwhile,orwhatifwewantedtoinvokesomenon-UIfunctionalitythatexistsinanotherAndroidapplication?Fortheseneeds,Androidprovidesservices.Wewilldiscussthemnext.

UsingAndroidServicesAndroidsupportstheconceptofservices.Servicesarecomponentsthatruninthebackground,withoutauserinterface.YoucanthinkofthesecomponentsassimilartoWindowsservicesorUnixdaemons.Similartothesetypesofservices,Androidservicescanbealwaysavailablebutdon’thavetobeactivelydoingsomething.Moreimportant,Androidservicescanhavelifecyclesseparatefromactivities.Whenanactivitypauses,stops,orgetsdestroyed,theremaybesomeprocessingthatyouwanttocontinue.Servicesaregoodforthattoo.

Androidsupportstwotypesofservices:localservicesandremoteservices.Alocalserviceisaservicethatisonlyaccessibletotheapplicationthatishostingit,anditisnotaccessiblefromotherapplicationsrunningonthedevice.Generally,thesetypesofservicessimplysupporttheapplicationthatishostingtheservice.Aremoteserviceisaccessiblefromotherapplicationsonthedeviceinadditiontotheapplicationhostingtheservice.RemoteservicesdefinethemselvestoclientsusingAndroidInterfaceDefinitionLanguage(AIDL).We’regoingtotalkaboutbothofthesetypesofservices,althoughinthenextfewchapters,we’regoingdeepintolocalservices.Therefore,wewillintroducethemherebutnotspendthatmuchtimeonthem.We’llcoverremoteservicesinmoredetailinthischapter.

UnderstandingServicesinAndroidTheAndroidServiceclassisawrapperofsortsforcodethathasservice-likebehavior.However,aServiceobjectdoesnotcreateitsownthreadsautomatically.ForaServiceobjecttousethreads,thedevelopermustmakeithappen.Thismeansthatwithoutaddingthreadingtoaservice,thecodeoftheservicewillrunonthemainthread.Ifourserviceisperformingoperationsthatwillcompletequickly,thiswon’tbeaproblem.Ifourservicemightrunforawhile,wedefinitelywanttoinvolvethreading.KeepinmindthereisnothingwrongwithusingAsyncTaskstodothreadingwithinservices.

Androidsupportstheconceptofaservicefortworeasons:

First,toallowyoutoimplementbackgroundtaskseasily.

Page 321: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Second,toallowyoutodointerprocesscommunicationbetweenapplicationsrunningonthesamedevice.

ThesetworeasonscorrespondtothetwotypesofservicesthatAndroidsupports:localservicesandremoteservices.Anexampleofthefirstcasemightbealocalserviceimplementedaspartofane-mailapplication.Theservicecouldhandlethesendingofanewe-mailtothee-mailserver,completewithattachmentsandretries.Asthiscouldtakeawhiletocomplete,aserviceisanicewayofwrappingupthatfunctionalitysothemainthreadcankickitoffandgetbacktotheuser.Plus,ifthee-mailactivitygoesaway,youstillwantthesente-mailstobedelivered.Anexampleofthesecondcase,aswe’llseelater,isalanguagetranslationapplication.Supposeyouhaveseveralapplicationsrunningonadevice,andyouneedaservicetoaccepttextthatneedstobetranslatedfromonelanguagetoanother.Ratherthanrepeatthelogicineveryapplication,youcouldwritearemotetranslationserviceandhavetheapplicationstalktotheservice.

AlocalservicegetsinitializedeitherbyaclientbindingtoitusingbindService(),orbyaclientstartingitusingstartService().RemoteservicesaretypicallyalwaysinitializedwithbindService().Aboundservicegetsinstantiatedwhenthefirstclientbindstoit,anddestroyedwhenthelastclientunbindsfromit.Asclientscomeinandoutoftheforeground,theycanbindandunbindasneeded,toensurethattheserviceisn’trunningunnecessarily.Thishelpstopreservebatterylife.However,itisunwisetobindinonResume()andunbindinonPause()becausethatcouldcausealotofunnecessarystartingandstoppingoftheservice.It’sbettertobindandunbindinonCreate()andonDestroy(),orinonStart()andonStop().BindingisonlyallowedfromanApplicationContext,anActivity,anotherService,oraContentProvider.ThatmeansnotfromFragmentsandnotfromBroadcastReceivers.

WhenaserviceisinsteadstartedwithstartService(),itwillremainrunninguntilitisstopped,eitherbyaclientorbytellingitselftostop.Foralocalservicethatwantstoperformworkinthebackground,considerinstantiatingitwithstartService()soitcanremainrunningeveniftheactivitythatstarteditgoesaway.TechnicallyaBroadcastReceivercanstartaserviceusingstartService(),sincetheservicecanthencontinuetoexistoncetheshort-livedBroadcastReceiverterminates.Ifyoudocreateaservicethatwillruninthebackgroundevenwhentheactivitieshavegoneaway,youmaywanttoimplementonBind()forwhentheuserwantstoregaincontroloftheservice.Anewactivitycouldbindtotheexistingserviceandthencallservicemethodsonit.

Thereareexamplesoflocalservicesthatdonotcreatebackgroundthreads,butthismaynotbeveryusefulinpractice.Aservicedoesnotinherentlycreateanythreads,socodeofaservicewillbydefaultrunonthemainUIthread.Theremaynotbeanyrealadvantagetowrappingthiscodeinaservicethen,sinceyoucouldjustcallmethodsofaclasstoexecutethatlogic.Itismorecommonforalocalservicetohaveitsownthreadsofexecution,whichcanbestartedeitherwhenthefirstclientbindstoit,orbecauseofastartService()command.

Now,wecanbeginadetailedexaminationofthetwotypesofservices.Wewillstartbytalkingaboutlocalservicesandthendiscussremoteservices.Asmentionedbefore,localservicesareservicesthatarecalledonlybytheapplicationthathoststhem.Remote

Page 322: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

servicesareservicesthatsupportaremoteprocedurecall(RPC)mechanism.Theseservicesallowexternalclients,onthesamedevice,toconnecttotheserviceanduseitsfacilities.Therearetwomainwaysofcallingremoteservices:usinganAIDLinterfaceandusingaMessenger.Bothwillbecovered.

NoteThesecondtypeofserviceinAndroidisknownbyseveralnames:remoteservice,AIDL-supportingservice,AIDLservice,externalservice,andRPCservice.Thesetermsallrefertothesametypeofservice—onethat’smeanttobeaccessedremotelybyotherapplicationsrunningonthedevice.

UnderstandingLocalServicesLocalservicesareservicesthataregenerallystartedviaContext.startService().Oncestarted,thesetypesofserviceswillcontinuetorununtilaclientcallsContext.stopService()ontheserviceortheserviceitselfcallsstopSelf().NotethatwhenContext.startService()iscalledandtheservicehasnotalreadybeencreated,thesystemwillinstantiatetheserviceandcalltheservice’sonStartCommand()method.KeepinmindthatcallingContext.startService()aftertheservicehasbeenstarted(thatis,whileitexists)willnotresultinanotherinstanceoftheservice,butwillreinvoketherunningservice’sonStartCommand()method.Hereareacoupleofexamplesoflocalservices:

Aservicetomonitorsensordatafromthedeviceanddoanalysis,issuingalertsifacertainconditionisrealized.Thisservicemightrunconstantly.

Atask-executorservicethatletsyourapplication’sactivitiessubmitjobsandqueuethemforprocessing.Thisservicemightonlyrunforthedurationoftheoperationtosubmitthejob.

Listing14-8demonstratesalocalservicebyimplementingaservicethatexecutesbackgroundtasks.We’llendupwithfourartifactsrequiredtocreateandconsumetheservice:BackgroundService.java(theserviceitself),main.xml(alayoutfilefortheactivity),MainActivity.java(anactivityclasstocalltheservice),andAndroidManifest.xml.Listing14-8onlycontainsBackgroundService.java.We’lldissectthiscodefirstandthenmoveontotheotherthree.

Listing14-8.ImplementingaLocalService:BackgroundService.java

publicclassBackgroundServiceextendsService{privatestaticfinalStringTAG="BackgroundService";privateNotificationManagernotificationMgr;privateThreadGroupmyThreads=newThreadGroup("ServiceWorker");

@Override

Page 323: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonCreate(){super.onCreate();

Log.v(TAG,"inonCreate()");notificationMgr=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);displayNotificationMessage("BackgroundServiceisrunning");}

@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){super.onStartCommand(intent,flags,startId);

intcounter=intent.getExtras().getInt("counter");Log.v(TAG,"inonStartCommand(),counter="+counter+",startId="+startId);

newThread(myThreads,newServiceWorker(counter),"BackgroundService").start();

returnSTART_STICKY;}

classServiceWorkerimplementsRunnable{privateintcounter=-1;publicServiceWorker(intcounter){this.counter=counter;}

publicvoidrun(){finalStringTAG2="ServiceWorker:"+Thread.currentThread().getId();//dobackgroundprocessinghere…we'lljustsleep…try{Log.v(TAG2,"sleepingfor10seconds.counter="+counter);Thread.sleep(10000);Log.v(TAG2,"...wakingup");}catch(InterruptedExceptione){

Page 324: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.v(TAG2,"...sleepinterrupted");}}}

@OverridepublicvoidonDestroy(){Log.v(TAG,"inonDestroy().Interruptingthreadsandcancellingnotifications");myThreads.interrupt();notificationMgr.cancelAll();super.onDestroy();}

@OverridepublicIBinderonBind(Intentintent){Log.v(TAG,"inonBind()");returnnull;}

privatevoiddisplayNotificationMessage(Stringmessage){

PendingIntentcontentIntent=PendingIntent.getActivity(this,0,newIntent(this,MainActivity.class),0);

Notificationnotification=newNotificationCompat.Builder(this).setContentTitle(message).setContentText("Touchtoturnoffservice").setSmallIcon(R.drawable.emo_im_winking).setTicker("Startingup!!!")//.setLargeIcon(aBitmap).setContentIntent(contentIntent).setOngoing(true).build();

notificationMgr.notify(0,notification);}}

ThestructureofaServiceobjectissomewhatsimilartoanactivity.ThereisanonCreate()methodwhereyoucandoinitialization,andanonDestroy()whereyoudocleanup.Servicesdon’tpauseorresumethewayactivitiesdo,sowedon’tuseonPause()oronResume()methods.Inthisexample,wewon’tbebindingtothe

Page 325: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

localservice,butbecauseServicerequiresanimplementationoftheonBind()method,weprovideonethatsimplyreturnsnull.It’sworthmentioningthatyoucouldhavealocalservicethatimplementsonBind()anddoesnotuseonStartCommand().

GoingbacktoouronCreate()method,wedon’tneedtodomuchexcepttonotifytheuserthatthisservicehasbeencreated.WedothisusingtheNotificationManager.You’veprobablynoticedthenotificationbaratthetopleftofanAndroidscreen.Bypullingdownonthis,theusercanviewmessagesofimportance,andbytouchingnotificationscanactonthenotifications,whichusuallymeansreturningtosomeactivityrelatedtothenotification.Withservices,becausetheycanberunning,oratleastexisting,inthebackgroundwithoutavisibleactivity,therehastobesomewayfortheusertogetbackintouchwiththeservice,perhapstoturnitoff.Therefore,wecreateaNotificationobject,populateitwithaPendingIntent,whichwillgetusbacktoourcontrolactivity,andpostit.ThisallhappensinthedisplayNotificationMessage()method.NotethatourNotificationobjectneedstoexistaslongasourserviceexists,soweusesetOngoing(true)tokeepitinthenotificationslistuntilweclearitourselvesfromourservice’sonDestroy()method.ThemethodweusedinonDestroy()toclearournotificationiscancelAll()ontheNotificationManager.

There’sanotherthingyouneedtohaveforthisexampletowork.You’llneedtocreateadrawablenamedemo_im_winkingandplaceitwithinyourproject’sdrawablefolder.AgoodsourceofdrawablesforthisdemonstrationpurposeistolookundertheAndroidplatformfolderatAndroidSDK/platforms/<version>/data/res/drawable,where<version>istheversionyou’reinterestedin.Unfortunately,youcan’treliablyrefertoAndroidsystemdrawablesfromyourcode,soyou’llneedtocopywhatyouwantovertoyourproject’sdrawablesfolder.Ifyouchooseadifferentdrawablefileforyourexample,justgoaheadandrenametheresourceIDintheconstructorfortheNotification.

WhenanintentissentintoourserviceusingstartService(),onCreate()iscalledifnecessary,andouronStartCommand()methodiscalledtoreceivethecaller’sintent.Inourcase,we’renotgoingtodoanythingspecialwithit,excepttounpackthecounteranduseittostartabackgroundthread.Inareal-worldservice,wewouldexpectanydatatobepassedtousviatheintent,andthiscouldincludeURIs,forexample.NoticetheuseofaThreadGroupwhencreatingtheThread.Thiswillprovetobeusefullaterwhenwewanttogetridofourbackgroundthreads.AlsonoticethestartIdparameter.ThisissetforusbyAndroidandisauniqueidentifieroftheservicecallssincethisservicewasstarted.

OurServiceWorkerclassisatypicalrunnableandiswheretheworkhappensforourservice.Inourparticularcase,we’resimplyloggingsomemessagesandsleeping.We’realsocatchinganyinterruptionsandloggingthem.Onethingwe’renotdoingismanipulatingtheuserinterface.We’renotupdatinganyviewsforexample.Becausewe’renotonthemainthreadanymore,wecannottouchtheUIdirectly.TherearewaysforourServiceWorkertoeffectchangesintheuserinterface,andwe’llgetintothosedetailsinthenextfewchapters.

Page 326: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThelastitemtopayattentiontoinourBackgroundServiceistheonDestroy()method.Thisiswhereweperformthecleanup.Forourexample,wewanttogetridofthethreadswecreatedearlier,ifanyarestillaround.Ifwedon’tdothis,theycouldsimplyhangaroundandtakeupmemory.Second,wewanttogetridofournotificationmessage.Becauseourserviceisgoingaway,there’snolongeranyneedfortheusertogettotheactivitytogetridofit.Inareal-worldapplication,however,wemightwanttokeepourworkersworking.Ifourserviceissendinge-mails,wecertainlydon’twanttosimplykilloffthethreads.Ourexampleisoverlysimple,becauseweimplythroughtheuseoftheinterrupt()methodthatyoucaneasilykilloffbackgroundthreads.Inreality,however,themostyoucandoisinterrupt.Thiswon’tnecessarilykilloffathread,though.Therearedeprecatedmethodsforkillingthreads,butyoushouldnotusethese.Theycancausememoryandstabilityproblemsforyouandyourusers.Interruptingworksinourexample,becausewe’redoingsleeps,whichcanbeinterrupted.

It’sworthwhiletakingalookattheThreadGroupclassbecauseitprovideswaysforyoutogetaccesstoyourthreads.WecreatedasingleThreadGroupobjectwithinourserviceandthenusedthatwhencreatingourindividualthreads.WithinouronDestroy()methodoftheservice,wesimplyinterrupt()ontheThreadGroup,anditissuesaninterrupttoeachthreadintheThreadGroup.

Sothereyouhavethemakingsofasimplelocalservice.Beforeweshowyouthecodeforouractivity,Listing14-9showstheXMLlayoutfileforouruserinterface.

Listing14-9.ImplementingaLocalService:main.xml

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/startBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="StartService"android:onClick="doClick"/><Buttonandroid:id="@+id/stopBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="StopService"android:onClick="doClick"/></LinearLayout>

We’regoingtoshowtwobuttonsontheuserinterface,onetodostartService()andtheothertodostopService().WecouldhavechosentouseaToggleButton,butthenyouwouldnotbeabletocallstartService()multipletimesinarow.Thisisan

Page 327: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

importantpoint.Thereisnotaone-to-onerelationshipbetweenstartService()andstopService().WhenstopService()iscalled,theserviceobjectwillbedestroyed,andallthreadscreatedfromallstartService()callsshouldalsogoaway.Now,let’slookatthecodeforouractivityinListing14-10.

Listing14-10.ImplementingaLocalService:MainActivity.java

publicclassMainActivityextendsActivity{privatestaticfinalStringTAG="MainActivity";privateintcounter=1;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}

publicvoiddoClick(Viewview){switch(view.getId()){caseR.id.startBtn:Log.v(TAG,"Startingservice…counter="+counter);Intentintent=newIntent(MainActivity.this,BackgroundService.class);intent.putExtra("counter",counter++);startService(intent);break;caseR.id.stopBtn:stopService();}}

privatevoidstopService(){Log.v(TAG,"Stoppingservice…");if(stopService(newIntent(MainActivity.this,BackgroundService.class)))Log.v(TAG,"stopServicewassuccessful");elseLog.v(TAG,"stopServicewasunsuccessful");}

@OverridepublicvoidonDestroy(){stopService();

Page 328: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

super.onDestroy();}}

OurMainActivitylooksalotlikeotheractivitiesyou’veseen.There’sasimpleonCreate()tosetupouruserinterfacefromthemain.xmllayoutfile.There’sadoClick()methodtohandlethebuttoncallbacks.Inourexample,we’recallingstartService()whentheStartServicebuttonispressed,andwe’recallingstopService()whentheStopServicebuttonispressed.Whenwestarttheservice,wewanttopassinsomedata,whichwedoviatheintent.WechosetopassthedataintheExtrasbundle,butwecouldhaveaddeditusingsetData()ifwehadaURI.Whenwestoptheservice,wechecktoseethereturnresult.Itshouldnormallybetrue,butiftheservicewasnotrunning,wecouldgetareturnoffalse.Last,whenouractivitydies,wewanttostoptheservice,sowealsostoptheserviceinouronDestroy()method.There’sonemoreitemtodiscuss,andthat’stheAndroidManifest.xmlfile,whichweshowinListing14-11.

Listing14-11.ImplementingaLocalService:AndroidManifest.xml

<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.services.simplelocal"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="8"/><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><activityandroid:name=".MainActivity"android:label="@string/app_name"android:launchMode="singleTop"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity><serviceandroid:name="BackgroundService"/></application>

</manifest>

Inadditiontoourregular<activity>tagsinthemanifestfile,wenowhavea<service>tag.Becausethisisalocalservicethatwe’recallingexplicitlyusingtheclassname,wedon’tneedtoputmuchintothe<service>tag.Allthatisrequiredisthenameofourservice.Butthereisoneotherthingtopointoutaboutthismanifestfile.Our

Page 329: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

servicecreatesanotificationsothattheusercangetbacktoourMainActivityif,forexample,theuserpressedtheHomekeyonMainActivitywithoutstoppingtheservice.

TheMainActivityisstillthere;it’sjustnotvisible.OnewaytogetbacktotheMainActivityistoclickthenotificationthatourservicecreated.ThenotificationmanagerdeliversourintentbacktoourapplicationandwouldnormallycauseanewinstanceofMainActivitytohandlethenewintent.Topreventthisfromhappening,wesetanattributeinourmanifestfileforMainActivitycalledandroid:launchMode,andwesetittosingleTop.ThiswillhelpensurethattheexistinginvisibleMainActivitywillbebroughtforwardanddisplayed,ratherthancreatinganotherMainActivity.

Whenyourunthisapplication,youwillseeourtwobuttons.ByclickingtheStartServicebutton,youwillbeinstantiatingtheserviceandcallingonStartCommand().OurcodelogsseveralmessagestoLogCat,soyoucanfollowalong.GoaheadandclickStartServiceseveraltimesinarow,evenquickly.Youwillseethreadscreatedtohandleeachrequest.You’llalsonoticethatthevalueofcounterispassedalongthroughtoeachServiceWorkerthread.WhenyoupresstheStopServicebutton,ourservicewillgoaway,andyou’llseethelogmessagesfromourMainActivity’sstopService()method,fromourBackgroundService’sonDestroy()method,andpossiblyfromServiceWorkerthreadsiftheygotinterrupted.

Youshouldalsonoticethenotificationmessagewhentheservicehasbeenstarted.Withtheservicerunning,goaheadandpresstheBackbuttonfromourMainActivityandnoticethatthenotificationmessagedisappears.Thismeansourservicehasgoneawayalso.TorestartourMainActivity,clickStartServicetogettheservicegoingagain.Now,presstheHomebutton.OurMainActivitydisappearsfromview,butthenotificationremains,meaningourserviceisstillinexistence.Goaheadandclickthenotification,andyou’llagainseeourMainActivity.

Notethatourexampleusesanactivitytointerfacewiththeservice,butanycomponentinyourapplicationcanusetheservice.Thisincludesotherservices,activities,genericclasses,andsoon.Alsonotethatourservicedoesnotstopitself;itreliesontheactivitytodothatforit.Therearesomemethodsavailabletoaservicetoallowtheservicetostopitself,namelystopSelf()andstopSelfResult().Obviously,ifwehavemultipleclientsforthisservice,wewouldn’twanttheservicetobestoppedbyoneiftheothersarestillusingit.Forastartedservicewithmultipleclients,itismorelikelyyou’dputlogicintheserviceitselftodecidewhentheservicecanorshouldbestopped,andtheservicewoulduseoneofthestop*()methodstodothat.

OurBackgroundServiceisatypicalexampleofaservicethatisusedbythecomponentsoftheapplicationthatishostingtheservice.Inotherwords,theapplicationthatisrunningtheserviceisalsotheonlyconsumer.Becausetheservicedoesnotsupportclientsfromoutsideitsprocess,theserviceisalocalservice.ThecriticalmethodsofalocalserviceareonCreate(),onStartCommand(),onBind(),stop*(),andonDestroy().

Page 330: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

There’sanotheroptionwithalocalservice,andthatisforthecasewhereyou’llonlyhaveoneinstanceoftheservicewithonebackgroundthread.Inthiscase,intheonCreate()methodoftheBackgroundService,wecouldcreateathreadthatdoestheservice’sheavylifting.WecouldcreateandstartthethreadinonCreate()ratherthanonStartCommand().WecoulddothisbecauseonCreate()iscalledonlyonce,andwewantthethreadtobecreatedonlyonceduringthelifeoftheservice.Onethingwewouldn’thaveinonCreate(),though,isthecontentoftheintentpassedbystartService().Ifweneedthat,wemightaswellusethepatternasdescribedpreviously,andwe’djustknowthatonStartCommand()shouldbecalledonlyonce.

Androidhasyetanotherwaytoimplementalocalservicethatincludesabackgroundthreadautomatically:theIntentService.AsubclassofService,IntentServicereceivestheincomingIntentfromastartService()call,createsabackground(worker)threadforyou,andinvokesthecallbackonHandleIntent(Intentintent).Ifanotherintentisdeliveredtothisservicebeforetheworkerthreadhascompletedtheearlierintent,thenewintentwillsitandwaituntilthepreviousintenthasbeenprocessed,atwhichtimethenextintentinthequeuewillgetpassedtotheonHandleIntent()method.Whenallintentsfromtheinboundqueuehavecompletedprocessing,theservicewillstopitself(noneedforyoutodothat).

Thisconcludesourintroductiontolocalservices.Rememberthatwe’llgetintomoredetailsoflocalservicesinsubsequentchapters.Let’smoveontoAIDLservices—themorecomplicatedtypeofservice.

UnderstandingAIDLServicesIntheprevioussection,weshowedyouhowtowriteanAndroidservicethatisconsumedbytheapplicationthathoststheservice.Now,wearegoingtoshowyouhowtobuildaservicethatcanbeconsumedbyotherprocessesviaremoteprocedurecall(RPC).AswithmanyotherRPC-basedsolutions,inAndroidyouneedaninterfacedefinitionlanguage(IDL)todefinetheinterfacethatwillbeexposedtoclients.IntheAndroidworld,thisIDLiscalledAndroidInterfaceDefinitionLanguage(AIDL).Tobuildaremoteservice,youdothefollowing:

1. WriteanAIDLfilethatdefinesyourinterfacetoclients.TheAIDLfileusesJavasyntaxandhasan.aidlextension.UsethesamepackagenameinsideyourAIDLfileasthepackageforyourAndroidproject.

2. AddtheAIDLfiletoyourEclipseprojectunderthesrcdirectory.TheAndroidEclipseplug-inwillcalltheAIDLcompilertogenerateaJavainterfacefromtheAIDLfile(theAIDLcompileriscalledaspartofthebuildprocess).

3. Implementaservice,andreturntheinterfacefromtheonBind()method.

4. AddtheserviceconfigurationtoyourAndroidManifest.xml

Page 331: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

file.Thesectionsthatfollowshowyouhowtoexecuteeachstep.

DefiningaServiceInterfaceinAIDLTodemonstrateanexampleofaremoteservice,wearegoingtowriteastock-quoterservice.Thisservicewillprovideamethodthattakesatickersymbolandreturnsthestockvalue.TowritearemoteserviceinAndroid,thefirststepistodefinetheserviceinterfacedefinitioninanAIDLfile.Listing14-12showstheAIDLdefinitionofIStockQuoteService.ThisfilegoesintothesameplaceasaregularJavafilewouldforyourStockQuoteServiceproject.

Listing14-12.TheAIDLDefinitionoftheStock-QuoterService

//ThisfileisIStockQuoteService.aidlpackagecom.androidbook.services.stockquoteservice;interfaceIStockQuoteService{doublegetQuote(Stringticker);}

TheIStockQuoteServiceacceptsthestock-tickersymbolasastringandreturnsthecurrentstockvalueasadouble.WhenyoucreatetheAIDLfile,theAndroidEclipseplug-inrunstheAIDLcompilertoprocessyourAIDLfile(aspartofthebuildprocess).IfyourAIDLfilecompilessuccessfully,thecompilergeneratesaJavainterfacesuitableforRPCcommunication.NotethatthegeneratedfilewillbeinthepackagenamedinyourAIDLfile—com.androidbook.services.stockquoteserviceinthiscase.

Listing14-13showsthegeneratedJavafileforourIStockQuoteServiceinterface.ThegeneratedfilewillbeputintothegenfolderofourEclipseproject.

Listing14-13.TheCompiler-GeneratedJavaFile

/**Thisfileisauto-generated.DONOTMODIFY.*Originalfile:C:\\android\\StockQuoteService\\src\\com\\androidbook\\services\\stockquoteservice\\IStockQuoteService.aidl*/packagecom.androidbook.services.stockquoteservice;importjava.lang.String;importandroid.os.RemoteException;importandroid.os.IBinder;importandroid.os.IInterface;importandroid.os.Binder;importandroid.os.Parcel;publicinterfaceIStockQuoteServiceextendsandroid.os.IInterface{

Page 332: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/**Local-sideIPCimplementationstubclass.*/publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.androidbook.services.stockquoteservice.IStockQuoteService{privatestaticfinaljava.lang.StringDESCRIPTOR="com.androidbook.services.stockquoteservice.IStockQuoteService";/**Constructthestubatattachittotheinterface.*/publicStub(){this.attachInterface(this,DESCRIPTOR);}/***CastanIBinderobjectintoanIStockQuoteServiceinterface,*generatingaproxyifneeded.*/publicstaticcom.androidbook.services.stockquoteservice.IStockQuoteService

asInterface(android.os.IBinderobj){if((obj==null)){returnnull;}android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);if(((iin!=null)&&(iininstanceofcom.androidbook.services.stockquoteservice.IStockQuoteService))){return((com.androidbook.services.stockquoteservice.IStockQuoteService)iin);}returnnewcom.androidbook.services.stockquoteservice.IStockQuoteService.Stub.Proxy(obj);}publicandroid.os.IBinderasBinder(){returnthis;}@OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException{switch(code){

Page 333: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

caseINTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);returntrue;}caseTRANSACTION_getQuote:{data.enforceInterface(DESCRIPTOR);java.lang.String_arg0;_arg0=data.readString();double_result=this.getQuote(_arg0);reply.writeNoException();reply.writeDouble(_result);returntrue;}}returnsuper.onTransact(code,data,reply,flags);}privatestaticclassProxyimplementscom.androidbook.services.stockquoteservice.IStockQuoteService{privateandroid.os.IBindermRemote;Proxy(android.os.IBinderremote){mRemote=remote;}publicandroid.os.IBinderasBinder(){returnmRemote;}publicjava.lang.StringgetInterfaceDescriptor(){returnDESCRIPTOR;}publicdoublegetQuote(java.lang.Stringticker)throwsandroid.os.RemoteException{android.os.Parcel_data=android.os.Parcel.obtain();android.os.Parcel_reply=android.os.Parcel.obtain();double_result;try{_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(ticker);mRemote.transact(Stub.TRANSACTION_getQuote,_data,_reply,0);_reply.readException();

Page 334: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

_result=_reply.readDouble();}finally{_reply.recycle();_data.recycle();}return_result;}}staticfinalintTRANSACTION_getQuote=(IBinder.FIRST_CALL_TRANSACTION+0);}publicdoublegetQuote(java.lang.Stringticker)throwsandroid.os.RemoteException;}

Notethefollowingimportantpointsregardingthegeneratedclasses:

TheinterfacewedefinedintheAIDLfileisimplementedasaninterfaceinthegeneratedcode(thatis,thereisaninterfacenamedIStockQuoteService).

AstaticabstractclassnamedStubextendsandroid.os.BinderandimplementsIStockQuoteService.Notethattheclassisanabstractclass.

AninnerclassnamedProxyimplementstheIStockQuoteServicethatproxiestheStubclass.

TheAIDLfilemustresideinthepackagewherethegeneratedfilesaresupposedtobe(asspecifiedintheAIDLfile’spackagedeclaration).

Now,let’smoveonandimplementtheAIDLinterfaceinaserviceclass.

ImplementinganAIDLInterfaceIntheprevioussection,wedefinedanAIDLfileforastock-quoterserviceandgeneratedthebindingfile.Now,wearegoingtoprovideanimplementationofthatservice.Toimplementtheservice’sinterface,weneedtowriteaclassthatextendsandroid.app.ServiceandimplementstheIStockQuoteServiceinterface.Theclasswearegoingtowritewe’llcallStockQuoteService.Toexposetheservicetoclients,ourStockQuoteServicewillneedtoprovideanimplementationoftheonBind()method,andwe’llneedtoaddsomeconfigurationinformationtotheAndroidManifest.xmlfile.Listing14-14showsanimplementationoftheIStockQuoteServiceinterface.ThisfilealsogoesintothesrcfolderoftheStockQuoteServiceproject.

Page 335: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing14-14.TheIStockQuoteServiceServiceImplementation

publicclassStockQuoteServiceextendsService{privatestaticfinalStringTAG="StockQuoteService";publicclassStockQuoteServiceImplextendsIStockQuoteService.Stub{@OverridepublicdoublegetQuote(Stringticker)throwsRemoteException{Log.v(TAG,"getQuote()calledfor"+ticker);return20.0;}}

@OverridepublicvoidonCreate(){super.onCreate();Log.v(TAG,"onCreate()called");}

@OverridepublicvoidonDestroy(){super.onDestroy();Log.v(TAG,"onDestroy()called");}

@OverridepublicIBinderonBind(Intentintent){Log.v(TAG,"onBind()called");returnnewStockQuoteServiceImpl();}}

TheStockQuoteService.javaclassinListing14-14resemblesthelocalBackgroundServicewecreatedearlier,butwithouttheNotificationManager.TheimportantdifferenceisthatwenowimplementtheonBind()method.RecallthattheStubclassgeneratedfromtheAIDLfilewasanabstractclassandthatitimplementedtheIStockQuoteServiceinterface.Inourimplementationoftheservice,wehaveaninnerclassthatextendstheStubclasscalledStockQuoteServiceImpl.Thisclassservesastheremote-serviceimplementation,andaninstanceofthisclassisreturnedfromtheonBind()method.Withthat,wehaveafunctionalAIDLservice,althoughexternalclientscannotconnecttoityet.

Page 336: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Toexposetheservicetoclients,weneedtoaddaservicedeclarationintheAndroidManifest.xmlfile,andthistime,weneedanintentfiltertoexposetheservice.Listing14-15showstheservicedeclarationfortheStockQuoteService.The<service>tagisachildofthe<application>tag.

Listing14-15.ManifestDeclarationfortheIStockQuoteService

<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.services.stockquoteservice"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><serviceandroid:name="StockQuoteService"><intent-filter><actionandroid:name="com.androidbook.services.stockquoteservice.IStockQuoteService"/></intent-filter></service></application><uses-sdkandroid:minSdkVersion="4"/></manifest>

Aswithallservices,wedefinetheservicewewanttoexposewitha<service>tag.ForanAIDLservice,wealsoneedtoaddan<intent-filter>withan<action>entryfortheserviceinterfacewewanttoexpose.

Withthisinplace,wehaveeverythingweneedtodeploytheservice.WhenyouarereadytodeploytheserviceapplicationfromEclipse,justgoaheadandchooseRunAsthewayyouwouldforanyotherapplication.EclipsewillcommentintheConsolethatthisapplicationhasnoLauncher,butitwilldeploytheappanyway,whichiswhatwewant.Let’snowlookathowwewouldcalltheservicefromanotherapplication(onthesamedevice,ofcourse).

CallingtheServicefromaClientApplicationWhenaclienttalkstoaservice,theremustbeaprotocolorcontractbetweenthetwo.WithAndroid,thecontractisinourAIDLfile.Sothefirststepinconsumingaserviceistotaketheservice’sAIDLfileandcopyittoyourclientproject.WhenyoucopytheAIDLfiletotheclientproject,theAIDLcompilercreatesthesameinterface-definitionfilethatwascreatedwhentheservicewasimplemented(intheservice-implementationproject).Thisexposestotheclientallofthemethods,parameters,andreturntypesontheservice.Let’screateanewprojectandcopytheAIDLfile:

Page 337: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

1. CreateanewAndroidprojectnamedStockQuoteClient.Useadifferentpackagename,suchascom.androidbook.stockquoteclient.UseMainActivityfortheCreateActivityfield.

2. CreateanewJavapackageinthisprojectnamedcom.androidbook.services.stockquoteserviceinthesrcdirectory.

3. CopytheIStockQuoteService.aidlfilefromtheStockQuoteServiceprojecttothisnewpackage.Notethatafteryoucopythefiletotheproject,theAIDLcompilerwillgeneratetheassociatedJavafile.

Theserviceinterfacethatyouregenerateservesasthecontractbetweentheclientandtheservice.ThenextstepistogetareferencetotheservicesowecancallthegetQuote()method.Withremoteservices,wehavetocallthebindService()methodratherthanthestartService()method.Listing14-16showsanactivityclassthatactsasaclientoftheIStockQuoteServiceservice.Listing14-17containsthelayoutfilefortheactivity.

Listing14-16showsourMainActivity.javafile.Realizethatthepackagenameoftheclientactivityisnotthatimportant—youcanputtheactivityinanypackageyou’dlike.However,theAIDLartifactsthatyoucreatearepackage-sensitivebecausetheAIDLcompilergeneratescodefromthecontentsoftheAIDLfile.

Listing14-16.AClientoftheIStockQuoteServiceService

publicclassMainActivityextendsActivity{privatestaticfinalStringTAG="StockQuoteClient";privateIStockQuoteServicestockService=null;privateToggleButtonbindBtn;privateButtoncallBtn;

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

bindBtn=(ToggleButton)findViewById(R.id.bindBtn);callBtn=(Button)findViewById(R.id.callBtn);}

publicvoiddoClick(Viewview){switch(view.getId()){caseR.id.bindBtn:if(((ToggleButton)view).isChecked()){

Page 338: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

bindService(newIntent(IStockQuoteService.class.getName()),serConn,Context.BIND_AUTO_CREATE);}else{unbindService(serConn);callBtn.setEnabled(false);}break;caseR.id.callBtn:callService();break;}}

privatevoidcallService(){try{doubleval=stockService.getQuote("ANDROID");Toast.makeText(MainActivity.this,"Valuefromserviceis"+val,Toast.LENGTH_SHORT).show();}catch(RemoteExceptionee){Log.e("MainActivity",ee.getMessage(),ee);}}

privateServiceConnectionserConn=newServiceConnection(){

@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){Log.v(TAG,"onServiceConnected()called");stockService=IStockQuoteService.Stub.asInterface(service);bindBtn.setChecked(true);callBtn.setEnabled(true);}

@OverridepublicvoidonServiceDisconnected(ComponentNamename){Log.v(TAG,"onServiceDisconnected()called");bindBtn.setChecked(false);callBtn.setEnabled(false);stockService=null;

Page 339: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}};

protectedvoidonDestroy(){Log.v(TAG,"onDestroy()called");if(callBtn.isEnabled())unbindService(serConn);super.onDestroy();}}

TheactivitydisplaysourlayoutandgrabsareferencetotheCallServicebuttonsowecanproperlyenableitwhentheserviceisrunninganddisableitwhentheserviceisstopped.WhentheuserclickstheBindbutton,theactivitycallsthebindService()method.Similarly,whentheuserclicksUnBind,theactivitycallstheunbindService()method.NoticethatthreeparametersarepassedtothebindService()method:anIntentwiththenameoftheAIDLservice,aServiceConnectioninstance,andaflagtoautocreatetheservice.

Listing14-17.TheIStockQuoteServiceServiceClientLayout

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<ToggleButtonandroid:id="@+id/bindBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textOff="Bind"android:textOn="Unbind"android:onClick="doClick"/>

<Buttonandroid:id="@+id/callBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="CallService"android:enabled="false"android:onClick="doClick"/></LinearLayout>

Withaboundservice,suchasanAIDLservice,youneedtoprovideanimplementationoftheServiceConnectioninterface.Thisinterfacedefinestwomethods:onecalledbythesystemwhenaconnectiontotheservicehasbeenestablishedandonecalledwhentheconnectiontotheservicehasbeendestroyed.Inouractivityimplementation,wedefinetheServiceConnectionfortheIStockQuoteService.Whenwecallthe

Page 340: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

bindService()method,wepassinthereferencetothis(i.e.,serConn).Whentheconnectiontotheserviceisestablished,theonServiceConnected()callbackisinvoked,andwethenobtainareferencetotheIStockQuoteServiceusingtheStubandenabletheCallServicebutton.

NotethatthebindService()callisanasynchronouscall.Itisasynchronousbecausetheprocessorservicemightnotberunningandthusmighthavetobecreatedorstarted.Andwecannotwaitonthemainthreadfortheservicetostart.BecausebindService()isasynchronous,theplatformprovidestheServiceConnectioncallback,soweknowwhentheservicehasbeenstartedandwhentheserviceisnolongeravailable.TheseServiceConnectioncallbackswillrunonthemainthreadthough,sothey’llhaveaccesstotheUIcomponentsifnecessary.

PleasenoticetheonServiceDisconnected()callback.Thisdoesnotgetinvokedwhenweunbindfromtheservice.ItisinvokediftheservicecrashesorifAndroiddecidestokilltheservice,forexampleifmemoryisgettinglow.Ifthiscallbackfires,weshouldnotthinkthatwe’restillconnected,andwemightneedtoreinvokethebindService()call.ThatiswhywechangethestatusofourbuttonsintheUIwhenthiscallbackisinvoked.Butnoticewesaid“wemightneedtoreinvokethebindService()call.”AndroidcouldrestartourserviceforusandinvokeouronServiceConnected()callback.Youcantrythisyourselfbyrunningtheclient,bindingtotheservice,andusingDDMStodoaStopontheStockQuoteServiceapplication.

Whenyourunthisexample,watchthelogmessagesinLogCattogetafeelforwhatisgoingonbehindthescenes.

Inourserviceexamplesthusfar,wehavestrictlydealtwithpassingsimpleJavaprimitivetypes.Androidservicesactuallysupportpassingcomplextypes,too.Thisisveryuseful,especiallyforAIDLservices,becauseyoumighthaveanopen-endednumberofparametersthatyouwanttopasstoaservice,andit’sunreasonabletopassthemallassimpleprimitives.Itmakesmoresensetopackagethemascomplextypesandthenpassthemtotheservice.

Let’sseehowwecanpasscomplextypestoservices.

PassingComplexTypestoServicesPassingcomplextypestoandfromservicesrequiresmoreworkthanpassingJavaprimitivetypes.Beforeembarkingonthiswork,youshouldgetanideaofAIDL’ssupportfornonprimitivetypes:

AIDLsupportsStringandCharSequence.

AIDLallowsyoutopassotherAIDLinterfaces,butyouneedtohaveanimportstatementforeachAIDLinterfaceyoureference(evenifthereferencedAIDLinterfaceisinthesamepackage).

AIDLallowsyoutopasscomplextypesthatimplementtheandroid.os.Parcelableinterface.Youneedtohavean

Page 341: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

importstatementinyourAIDLfileforthesetypes.

AIDLsupportsjava.util.Listandjava.util.Map,withafewrestrictions.TheallowabledatatypesfortheitemsinthecollectionincludeJavaprimitive,String,CharSequence,andandroid.os.Parcelable.YoudonotneedimportstatementsforListorMap,butyoudoneedthemfortheParcelables.

Nonprimitivetypes,otherthanString,requireadirectionalindicator.Directionalindicatorsincludein,out,andinout.inmeansthevalueissetbytheclient,outmeansthevalueissetbytheservice,andinoutmeansboththeclientandservicesetthevalue.Androidavoidsserializingthevaluesifthey’renotflowingintheindicateddirection,whichhelpsoverallperformance.

TheParcelableinterfacetellstheAndroidruntimehowtoserializeanddeserializeobjectsduringthemarshallingandunmarshallingprocess.Listing14-18showsaPersonclassthatimplementstheParcelableinterface.

Listing14-18.ImplementingtheParcelableInterface

//ThisfileisPerson.javapackagecom.androidbook.services.stock2;importandroid.os.Parcel;importandroid.os.Parcelable;

publicclassPersonimplementsParcelable{privateintage;privateStringname;publicstaticfinalParcelable.Creator<Person>CREATOR=newParcelable.Creator<Person>(){publicPersoncreateFromParcel(Parcelin){returnnewPerson(in);}

publicPerson[]newArray(intsize){returnnewPerson[size];}};

publicPerson(){}

privatePerson(Parcelin){readFromParcel(in);}

Page 342: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

@OverridepublicintdescribeContents(){return0;}

@OverridepublicvoidwriteToParcel(Parcelout,intflags){out.writeInt(age);out.writeString(name);}

publicvoidreadFromParcel(Parcelin){age=in.readInt();name=in.readString();}

publicintgetAge(){returnage;}

publicvoidsetAge(intage){this.age=age;}

publicStringgetName(){returnname;}

publicvoidsetName(Stringname){this.name=name;}}

Togetstartedonimplementingthis,createanewAndroidProjectinEclipsecalledStockQuoteService2.ForCreateActivity,useanameofMainActivity,anduseapackageofcom.androidbook.services.stock2.ThenaddthePerson.javafilefromListing14-18tothecom.androidbook.services.stock2packageofournewproject.

TheParcelableinterfacedefinesthecontractforthemarshallingandunmarshallingofobjects.UnderlyingtheParcelableinterfaceistheParcelcontainerobject.TheParcelclassisafastserialization/deserializationmechanismspeciallydesignedforinterprocesscommunicationwithinAndroid.Theclassprovidesmethodsthatyouusetoflattenyourmemberstothecontainerandtoexpandthemembersbackfromthecontainer.Toproperlyimplementanobjectforinterprocesscommunication,wehavetodothefollowing:

Page 343: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

1. ImplementtheParcelableinterface.ThismeansthatyouimplementwriteToParcel()andreadFromParcel().Thewritemethodwillwritetheobjecttotheparcel,andthereadmethodwillreadtheobjectfromtheparcel.Notethattheorderinwhichyouwritepropertiesmustbethesameastheorderinwhichyoureadthem.

2. AddastaticfinalpropertytotheclasswiththenameCREATOR.Thepropertyneedstoimplementtheandroid.os.Parcelable.Creator<T>interface.

3. ProvideaconstructorfortheParcelablethatknowshowtocreatetheobjectfromtheParcel.

4. DefineaParcelableclassinan.aidlfilethatmatchesthe.javafilecontainingthecomplextype.TheAIDLcompilerwilllookforthisfilewhencompilingyourAIDLfiles.AnexampleofaPerson.aidlfileisshowninListing14-19.ThisfileshouldbeinthesameplaceasPerson.java.

NoteSeeingParcelablemighthavetriggeredthequestion,whyisAndroidnotusingthebuilt-inJavaserializationmechanism?ItturnsoutthattheAndroidteamcametotheconclusionthattheserializationinJavaisfartooslowtosatisfyAndroid’sinterprocess-communicationrequirements.SotheteambuilttheParcelablesolution.TheParcelableapproachrequiresthatyouexplicitlyserializethemembersofyourclass,butintheend,yougetamuchfasterserializationofyourobjects.

AlsorealizethatAndroidprovidestwomechanismsthatallowyoutopassdatatoanotherprocess.Thefirstistopassabundletoanactivityusinganintent,andthesecondistopassaParcelabletoaservice.Thesetwomechanismsarenotinterchangeableandshouldnotbeconfused.Thatis,theParcelableisnotmeanttobepassedtoanactivity.Ifyouwanttostartanactivityandpassitsomedata,useaBundle.ParcelableismeanttobeusedonlyaspartofanAIDLdefinition.

Listing14-19.AnExampleofaPerson.aidlFile

//ThisfileisPerson.aidlpackagecom.androidbook.services.stock2;parcelablePerson;

Youwillneedan.aidlfileforeachParcelableinyourproject.Inthiscase,wehavejustoneParcelable,whichisPerson.Youmaynoticethatyoudon’tgetaPerson.javafilecreatedinthegenfolder.Thisistobeexpected.Wealreadyhavethisfilefromwhenwecreateditpreviously.

Now,let’susethePersonclassinaremoteservice.Tokeepthingssimple,wewill

Page 344: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

modifyourIStockQuoteServicetotakeaninputparameteroftypePerson.TheideaisthatclientswillpassaPersontotheservicetotelltheservicewhoisrequestingthequote.ThenewIStockQuoteService.aidllookslikeListing14-20.

Listing14-20.PassingParcelablestoServices

//ThisfileisIStockQuoteService.aidlpackagecom.androidbook.services.stock2;importcom.androidbook.services.stock2.Person;

interfaceIStockQuoteService{StringgetQuote(inStringticker,inPersonrequester);}

ThegetQuote()methodnowacceptstwoparameters:thestock’stickersymbolandaPersonobjecttospecifywhoismakingtherequest.NotethatwehavedirectionalindicatorsontheparametersbecausetheparametersincludenonprimitivetypesandthatwehaveanimportstatementforthePersonclass.ThePersonclassisalsointhesamepackageastheservicedefinition(com.androidbook.services.stock2).

TheserviceimplementationnowlookslikeListing14-21,withtheMainActivitylayoutinListing14-22.

Listing14-21.TheStockQuoteService2Implementation

packagecom.androidbook.services.stock2;//ThisfileisStockQuoteService2.java

importandroid.app.Notification;importandroid.app.NotificationManager;importandroid.app.PendingIntent;importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;importandroid.os.RemoteException;

publicclassStockQuoteService2extendsService{privateNotificationManagernotificationMgr;

publicclassStockQuoteServiceImplextendsIStockQuoteService.Stub{publicStringgetQuote(Stringticker,Personrequester)throwsRemoteException{return"Hello"+requester.getName()+"!Quotefor"+ticker+"is20.0";

Page 345: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}}

@OverridepublicvoidonCreate(){super.onCreate();

notificationMgr=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);

displayNotificationMessage("onCreate()calledinStockQuoteService2");}

@OverridepublicvoidonDestroy(){displayNotificationMessage("onDestroy()calledinStockQuoteService2");//ClearallnotificationsfromthisservicenotificationMgr.cancelAll();super.onDestroy();}

@OverridepublicIBinderonBind(Intentintent){displayNotificationMessage("onBind()calledinStockQuoteService2");returnnewStockQuoteServiceImpl();}

privatevoiddisplayNotificationMessage(Stringmessage){PendingIntentcontentIntent=PendingIntent.getActivity(this,0,newIntent(this,MainActivity.class),0);

Notificationnotification=newNotificationCompat.Builder(this).setContentTitle("StockQuoteService2").setContentText(message).setSmallIcon(R.drawable.emo_im_happy).setTicker(message)//.setLargeIcon(aBitmap).setContentIntent(contentIntent).setOngoing(true)

Page 346: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

.build();

notificationMgr.notify(R.id.app_notification_id,notification);}}

Listing14-22.TheStockQuoteService2Layout

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Thisiswheretheservicecouldaskforhelp."/></LinearLayout>

Thedifferencesbetweenthisimplementationandthepreviousonearethatwebroughtbackthenotifications,andwenowreturnthestockvalueasastringandnotadouble.ThestringreturnedtotheusercontainsthenameoftherequesterfromthePersonobject,whichdemonstratesthatwereadthevaluesentfromtheclientandthatthePersonobjectwaspassedcorrectlytotheservice.

Thereareafewotherthingsthatneedtobedonetomakethiswork:

1. Findtheemo_im_happy.pngimagefilefromunderAndroidSDK/platforms/android-19/data/res/drawable-mdpi,andcopyittothe/res/drawabledirectoryofourproject.Orchangethenameoftheresourceinthecode,andputwhateverimageyouwantinthedrawablesfolder.

2. Addanew<itemtype=“id”name=“app_notification_id”/>tagtothe/res/values/strings.xmlfile.

3. WeneedtomodifytheapplicationintheAndroidManifest.xmlfileasshowninListing14-23.

Listing14-23.Modified<application>inAndroidManifest.xmlFileforStockQuoteService2

<?xmlversion="1.0"encoding="utf-8"?><manifest

Page 347: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

xmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.services.stock2"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="8"/><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><activityandroid:name=".MainActivity"android:label="@string/app_name"android:launchMode="singleTop"><intent-filter><actionandroid:name="android.intent.action.MAIN"/></intent-filter></activity><serviceandroid:name="StockQuoteService2"><intent-filter><actionandroid:name="com.androidbook.services.stock2.IStockQuoteService"/></intent-filter></service></application>

</manifest>

WhileitisOKtousethedotnotationforourandroid:name=”.MainActivity”attribute,itisnotOKtousedotnotationinsideofour<action>taginsidetheservice’s<intent-filter>tag.Weneedtospellitout;otherwise,ourclientwillnotfindtheservicespecification.

Last,we’llusethedefaultMainActivity.javafilethatsimplydisplaysabasiclayoutwithasimplemessage.Weshowedyouearlierhowtolaunchtotheactivityfromanotification.Thisactivitywouldservethatpurposealsoinreallife,butforthisexample,we’llkeepthatpartsimple.Nowthatwehaveourserviceimplementation,let’screateanewAndroidprojectcalledStockQuoteClient2.Usecom.daveforthepackageandMainActivityfortheactivityname.ToimplementaclientthatpassesthePersonobjecttotheservice,weneedtocopyeverythingthattheclientneedsfromtheserviceprojecttotheclientproject.Thereneedstobeanewsrcpackagecalledcom.androidbook.services.stock2toreceivethesecopiedfiles.Inourpreviousexample,allweneededwastheIStockQuoteService.aidlfile.WealsoneedtocopythePerson.javaandPerson.aidlfiles,becausethePersonobjectisnowpartoftheinterface.Afteryoucopythesethreefilestothecom.androidbook.services.stock2srcpackageoftheclientproject,modifymain.xmlaccordingtoListing14-24,andmodifyMainActivity.javaaccordingtoListing14-25.Orsimplyimportthisprojectfromthesourcecodeonourwebsite.

Page 348: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing14-24.Updatedmain.xmlforStockQuoteClient2

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">

<ToggleButtonandroid:id="@+id/bindBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textOff="Bind"android:textOn="Unbind"android:onClick="doClick"/><Buttonandroid:id="@+id/callBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="CallService"android:enabled="false"android:onClick="doClick"/></LinearLayout>

Listing14-25.CallingtheServicewithaParcelable

packagecom.dave;//ThisfileisMainActivity.javaimportcom.androidbook.services.stock2.IStockQuoteService;importcom.androidbook.services.stock2.Person;

publicclassMainActivityextendsActivity{

protectedstaticfinalStringTAG="StockQuoteClient2";privateIStockQuoteServicestockService=null;privateToggleButtonbindBtn;privateButtoncallBtn;

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

bindBtn=(ToggleButton)findViewById(R.id.bindBtn);callBtn=(Button)findViewById(R.id.callBtn);}

publicvoiddoClick(Viewview){switch(view.getId()){

Page 349: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

caseR.id.bindBtn:if(((ToggleButton)view).isChecked()){bindService(newIntent(IStockQuoteService.class.getName()),serConn,Context.BIND_AUTO_CREATE);}else{unbindService(serConn);callBtn.setEnabled(false);}break;caseR.id.callBtn:callService();break;}}

privatevoidcallService(){try{Personperson=newPerson();person.setAge(47);person.setName("Dave");Stringresponse=stockService.getQuote("ANDROID",person);Toast.makeText(MainActivity.this,"Valuefromserviceis"+response,Toast.LENGTH_SHORT).show();}catch(RemoteExceptionee){Log.e("MainActivity",ee.getMessage(),ee);}}

privateServiceConnectionserConn=newServiceConnection(){

@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){Log.v(TAG,"onServiceConnected()called");stockService=IStockQuoteService.Stub.asInterface(service);bindBtn.setChecked(true);callBtn.setEnabled(true);}

@Override

Page 350: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonServiceDisconnected(ComponentNamename){Log.v(TAG,"onServiceDisconnected()called");bindBtn.setChecked(false);callBtn.setEnabled(false);stockService=null;}};

protectedvoidonDestroy(){if(callBtn.isEnabled())unbindService(serConn);super.onDestroy();}}

Thisisnowreadytorun.Remembertosendovertheservicetothedeviceoremulatorbeforeyousendovertheclienttorun.TheuserinterfaceshouldlooklikeFigure14-1.

Figure14-1.UserinterfaceofStockQuoteClient2

Let’stakealookatwhatwe’vegot.Asbefore,webindtoourservice,andthenwecaninvokeaservicemethod.TheonServiceConnected()methodiswherewegettoldthatourserviceisrunning,sowecanthenenabletheCallServicebuttonsothebuttoncaninvokethecallService()method.Asshown,wecreateanewPersonobjectandsetitsAgeandNameproperties.Wethenexecutetheserviceanddisplaytheresultfromtheservicecall.TheresultlookslikeFigure14-2.

Figure14-2.ResultfromcallingtheservicewithaParcelable

Noticethatwhentheserviceiscalled,yougetanotificationinthestatusbar.Thisiscomingfromtheserviceitself.WebrieflytouchedonNotificationsearlierasawayforaservicetocommunicatetotheuser.Normally,servicesareinthebackgroundanddonotdisplayanysortofUI.Butwhatifaserviceneedstointeractwiththeuser?Whileit’stemptingtothinkthataservicecaninvokeanactivity,aserviceshouldneverinvokeanactivitydirectly.Aserviceshouldinsteadcreateanotification,andthenotificationshouldbehowtheusergetstothedesiredactivity.Thiswasshowninourlastexercise.We

Page 351: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

definedasimplelayoutandactivityimplementationforourservice.Whenwecreatedthenotificationwithintheservice,wesettheactivityinthenotification.Theusercantouchthenotification,anditwilltaketheusertoouractivitythatispartofthisservice.Thiswillallowtheusertointeractwiththeservice.

Notificationsaresavedsothatyoucangettothembypullingdownfromthestatusbartoseethem.NotethefactthatwereusethesameIDforeverymessage.Thismeansthatweareupdatingtheoneandonlynotificationeverytime,ratherthancreatingnewnotificationentries.Therefore,ifyougototheNotificationsscreeninAndroidafterclickingBind,CallAgain,andUnbindafewtimes,youwillonlyseeonemessageinNotifications,anditwillbethelastonesentbyStockQuoteService2.IfweuseddifferentIDs,wecouldhavemultiplenotificationmessages,andwecouldupdateeachoneseparately.Notificationscanalsobesetwithadditionaluser“prompts”suchassound,lights,and/orvibration.

Itisalsousefultoseetheartifactsoftheserviceprojectandtheclientthatcallsit(seeFigure14-3).

Figure14-3.Theartifactsoftheserviceandtheclient

Figure14-3showstheEclipseprojectartifactsfortheservice(left)andtheclient(right).NotethatthecontractbetweentheclientandtheserviceconsistsoftheAIDLartifactsand

Page 352: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theParcelableobjectsexchangedbetweenthetwoparties.ThisisthereasonthatweseePerson.java,IStockQuoteService.aidl,andPerson.aidlonbothsides.BecausetheAIDLcompilergeneratestheJavainterface,stub,proxy,andsoonfromtheAIDLartifacts,thebuildprocesscreatestheIStockQuoteService.javafileontheclientsidewhenwecopythecontractartifactstotheclientproject.Nowyouknowhowtoexchangecomplextypesbetweenservicesandclients.Let’sbrieflytouchonanotherimportantaspectofcallingservices:synchronousversusasynchronousserviceinvocation.

Allofthecallsthatyoumakeonservicesaresynchronous.Thisbringsuptheobviousquestion:Doyouneedtoimplementallofyourservicecallsinaworkerthread?Notnecessarily.Onmostotherplatforms,it’scommonforaclienttouseaservicethatisacompleteblackbox,sotheclientwouldhavetotakeappropriateprecautionswhenmakingservicecalls.WithAndroid,youwilllikelyknowwhatisintheservice(generallybecauseyouwrotetheserviceyourself),soyoucanmakeaninformeddecision.Ifyouknowthatthemethodyouarecallingisdoingalotofheavylifting,youshouldconsiderusingasecondarythreadtomakethecall.Ifyouaresurethatthemethoddoesnothaveanybottlenecks,youcansafelymakethecallontheUIthread.Ifyouconcludethatit’sbesttomaketheservicecallwithinaworkerthread,youcancreatethethreadandthencalltheservice.YoucanthencommunicatetheresulttotheUIthread.

MessengersandHandlersThereisonemorewaytocommunicatewithaserviceinAndroid,andthatiswithMessengersandHandlers.ThismechanismisbuiltontopofAIDLservices,butwithoutyouhavingtoseeordealwithAIDL.LikeAIDLservices,youuseitwhentheserviceisinaseparateprocessfromtheclient.BoththeclientandtheservicewillimplementaMessengerandaHandler,andproceedtosendmessagesbackandforth.Youdon’tneedtospecifyany.aidlfiles;everythingiscodedinyourJavaclasses.Thisisafairlycommonwaytodointer-processservicecallsonAndroid,andissignificantlyeasierthanmessingwithAIDLyourself.

Here’saquickoverviewofhowitworks.Theclientbindstotheservice,andsetsupaMessengerandHandlertoreceiveresponsesfromtheservice.AcallbackwithintheHandlertakescareofmessagessentbackbytheservice.TheclientalsocreatesaMessengertosendmessagestotheservice.Ontheserviceside,there’sasimilarMessengerandHandlertoreceivetheincomingmessagesfromclients.AmessagecominginfromaclientincludesaMessengertouseforanyrepliestothatclient.Therefore,theservicecreatesonlyoneMessengerwhileaclientcreatestwo.Theclientsideisasynchronous,withtheserviceresponsecominglater.AproblemwiththeservicecallgeneratesaRemoteExceptionthattheclientcancaptureandactupon.

Let’sseeanexampleofhowthisworks.Thissampleapplicationhastwoparts:aMessengerClientandaMessengerService.Theywillrunasseparateprocessesonadevice.Theclientwilluseanon-UIfragmenttocontaintheserviceclientconnection.Thismeanstheclientactivitycangoawayandberecreatedduetoaconfigurationchange,andtheunderlyingserviceconnectionremainsinplace.Thisisapreferredwaytoconnect

Page 353: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

toaservicefromanactivitysinceyoudon’twanttohavetoreconstructtheserviceclientconnectionjustbecausethedevicehasbeenrotatedforexample.Listing14-26showsthesignificantcodefromMessengerService.javatosetuptheHandlerandMessenger.Forafulllisting,refertotheMessengerServicesourceprojectforthischapter.

Listing14-26.Messenger/Handler-BasedServiceCode

publicclassMessengerServiceextendsService{NotificationManagermNM;ArrayList<Messenger>mClients=newArrayList<Messenger>();intmValue=0;publicstaticfinalintMSG_REGISTER_CLIENT=1;publicstaticfinalintMSG_UNREGISTER_CLIENT=2;publicstaticfinalintMSG_SET_SIMPLE_VALUE=3;publicstaticfinalintMSG_SET_COMPLEX_VALUE=4;publicstaticfinalStringTAG="MessengerService";/***Handlerofincomingmessagesfromclients.*/classIncomingHandlerextendsHandler{@OverridepublicvoidhandleMessage(Messagemsg){switch(msg.what){caseMSG_REGISTER_CLIENT:mClients.add(msg.replyTo);Log.v(TAG,"Registeringclient");break;caseMSG_UNREGISTER_CLIENT:mClients.remove(msg.replyTo);Log.v(TAG,"Unregisteringclient");break;caseMSG_SET_SIMPLE_VALUE:mValue=msg.arg1;Log.v(TAG,"Receivingarg1:"+mValue);showNotification("Receivedarg1:"+mValue);for(inti=mClients.size()-1;i>=0;i--){try{mClients.get(i).send(Message.obtain(null,MSG_SET_SIMPLE_VALUE,mValue,0));}catch(RemoteExceptione){//Theclientisdead.Removeitfromthelist;//wearegoingthroughthelistfrombacktofront

Page 354: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//sothisissafetodoinsidetheloop.mClients.remove(i);}}break;caseMSG_SET_COMPLEX_VALUE:BundlemBundle=msg.getData();Log.v(TAG,"Receivingbundle:");if(mBundle!=null){showNotification("Gotcomplexmsg:myDouble="+mBundle.getDouble("myDouble"));for(Stringkey:mBundle.keySet()){Log.v(TAG,""+key);}}break;default:Log.v(TAG,"Gotsomeothermessage:"+msg.what);super.handleMessage(msg);}}}

//TargetforclientstosendmessagestoIncomingHandler.finalMessengermMessenger=newMessenger(newIncomingHandler());

@OverridepublicvoidonCreate(){mNM=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);

//Displayanotificationaboutusstarting.Log.v(TAG,"Serviceisstarting");showNotification(getText(R.string.remote_service_started));}

@OverridepublicvoidonDestroy(){//Cancelthepersistentnotification.mNM.cancel(R.string.remote_service_started);

//Telltheuserwestopped.

Page 355: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Toast.makeText(this,R.string.remote_service_stopped,Toast.LENGTH_SHORT).show();}

/***Whenbindingtotheservice,wereturnaninterfacetoourmessenger*forsendingmessagestotheservice.*/@OverridepublicIBinderonBind(Intentintent){returnmMessenger.getBinder();}

/***Showanotificationwhilethisserviceisrunning.Notethat*wedon'tincludeanintentsincewe'rejustaservicehere.The*servicestopswhentheclienttellsitto.*/privatevoidshowNotification(CharSequencetext){Notificationnotification=newNotificationCompat.Builder(this).setContentTitle("MessengerService").setContentText(text).setSmallIcon(android.R.drawable.ic_dialog_info).setTicker(text).setOngoing(true).build();

mNM.notify(R.string.remote_service_started,notification);}

}

Inthissample,clientsregisterwiththeservice,unregisterwiththeservice,sendasimplemessage,orsendacomplexmessage.Whenaclientregisters,theserviceremembersitbysavingthepassed-inclientMessenger(i.e.,msg.replyTo)inmClients.Ifasimplemessageisreceived,theservicesendsacopyofthereceivedargumentvaluetoallknownclients.NoticehowrepliesaresenttoeachclientusingtheMessengersinmClientsthatcamefromeachclient.TheMessage’swhatfieldisjustaninttoindicatewhatserviceoperationisbeingcalled.Baseduponthewhatoperation,theservicewillextracttheappropriatearguments.SinceaMessageobjecthastwointargumentsavailable,thesimplecaseusesjustoneofthoseMessagefields.Whenmorecomplexdatamustbesent,aBundleobjectiscreated,populated,andattachedtotheMessagefortransmissiontothe

Page 356: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

service.

Beawarethataservicehasa1MBbufferforpasseddata(inandout)forallin-processservicecalls,soyou’llwanttokeepMessagedatatoaminimum.Iftherearealotofsimultaneousservicecalls,youcouldexceedthebufferandgetaTransactionTooLargeException.

Ontheclientside,there’saMainActivityandaClientFrag(thenon-UIfragment).Forsimplicity’ssaketheactivityprovidestheUItotheuserwithoutusingaUIfragment.Listing14-27showstheMainActivity.Forafulllistingoftheproject,pleaseseetheMessengerClientprojectforthischapter.

Listing14-27.Messenger/Handler-BasedClientActivityCode

publicclassMainActivityextendsFragmentActivityimplementsISampleServiceClient{

protectedstaticfinalStringTAG="MessengerClient";privateTextViewmCallbackText;privateClientFragclientFrag;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

mCallbackText=(TextView)findViewById(R.id.callback);

//Getanon-UIfragmenttohandletheserviceinterface.//Ifouractivitygetsdestroyedandrecreated,thefragment//willstillbearoundandwejustneedtore-fetchit.if((clientFrag=(ClientFrag)getSupportFragmentManager().findFragmentByTag("clientFrag"))==null){updateStatus("CreatingaclientFrag.Noserviceyet.");clientFrag=ClientFrag.getInstance();getSupportFragmentManager().beginTransaction().add(clientFrag,"clientFrag").commit();}else{updateStatus("FoundexistingclientFrag,willuseit");}}

Page 357: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoiddoClick(Viewview){switch(view.getId()){caseR.id.startBtn:clientFrag.doBindService();break;caseR.id.stopBtn:clientFrag.doUnbindService();break;caseR.id.simpleBtn:clientFrag.doSendSimple();break;caseR.id.complexBtn:clientFrag.doSendComplex();break;}}

@OverridepublicvoidupdateStatus(Stringstatus){mCallbackText.setText(status);}}

Noticehowthere’snomentionofaserviceinthisactivity,justaTextView,buttons,andaclientfragment.TheupdateStatus()methodisasaresultoftheISampleServiceClientinterfacethatthisactivityimplements,andallitneedstodoissetthetextintheUIaspassedin.Thebuttonssimplyinvokeamethodoftheclientfragment.Inarealapplication,therewouldbemorebusinessandUIlogicinthisactivityorinotherfragmentsthatareseparatefromtheservicecall.

Theclientfragmentiswherethefunis.Listing14-28showsthecodefromtheclientfragment.

Listing14-28.Messenger/Handler-BasedClientFragmentCode

publicclassClientFragextendsFragment{privatestaticfinalStringTAG="MessengerClientFrag";staticprivateClientFragmClientFrag=null;//applicationcontextwillbeusedtobindtotheservicebecause//fragmentscan'tbindandactivitiescangoaway.privateContextappContext=null;

//Messengerforsendingtoservice.MessengermService=null;//Flagindicatingwhetherwehavecalledbindontheservice.

Page 358: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

booleanmIsBound;

//Instantiationmethodfortheclientfragment.Wejustwantone//andweusesetRetainInstance(true)soithangsaroundduring//configurationchanges.publicstaticClientFraggetInstance(){if(mClientFrag==null){mClientFrag=newClientFrag();mClientFrag.setRetainInstance(true);}returnmClientFrag;}

//HandlerforresponsemessagesfromtheserviceclassIncomingHandlerextendsHandler{@OverridepublicvoidhandleMessage(Messagemsg){switch(msg.what){caseMessengerService.MSG_SET_SIMPLE_VALUE:updateStatus("Receivedfromservice:"+msg.arg1);break;default:break;}super.handleMessage(msg);}}

//NeedaMessengertoreceiveresponses.Sendthiswiththe//Messagestotheservice.finalMessengermMessenger=newMessenger(newIncomingHandler());

privateServiceConnectionmConnection=newServiceConnection(){publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){//Thisiscalledwhentheconnectionwiththeservicehasbeen//established,givingustheserviceobjectwecanuseto//interactwiththeservice.Weare

Page 359: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

communicatingwithour//servicethroughaMessenger,sogetaclient-side//representationofthatfromtherawserviceobject.mService=newMessenger(service);updateStatus("Attached.");

//Wewanttomonitortheserviceforaslongasweare//connectedtoit.Thisisnotstrictlynecessary.You//donotneedtoregisterwiththeservicebeforeusing//it.Butifthisfailedyou'dhaveanearlywarning.try{Messagemsg=Message.obtain(null,MessengerService.MSG_REGISTER_CLIENT);msg.replyTo=mMessenger;mService.send(msg);}catch(RemoteExceptione){//Inthiscasetheservicehascrashedbeforewecouldeven//doanythingwithit;wecancountonsoonbeing//disconnected(andthenreconnectedifitcanberestarted)//sothereisnoneedtodoanythinghere.Log.e(TAG,"Couldnotestablishaconnectiontotheservice:"+e);}}

publicvoidonServiceDisconnected(ComponentNameclassName){//Thisiscalledwhentheconnectionwiththeservicehasbeen//unexpectedlydisconnected—thatis,itsprocesscrashed.mService=null;updateStatus("Disconnected.");}};

publicvoiddoBindService(){//Establishaconnectionwiththeservice.Weusethe

Page 360: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Stringname//oftheservicesinceitexistsinaseparateprocessandwedo//notwanttorequiretheservicejarintheclient.Wealsograb//theapplicationcontextandbindtheservicetothatsincethe//activitycontextcouldgoawayonaconfigurationchangebutthe//applicationcontextwillalwaysbethere.appContext=getActivity().getApplicationContext();if(mIsBound=appContext.bindService(newIntent("com.androidbook.messengerservice.MessengerService"),mConnection,Context.BIND_AUTO_CREATE)){updateStatus("Boundtoservice.");}else{updateStatus("Bindattemptfailed.");}}

publicvoiddoUnbindService(){if(mIsBound){//Ifwehavereceivedtheservice,andhenceregisteredwith//it,thennowisthetimetounregister.Notethatthe//replyTovalueisonlyusedbytheservicetounregister//thisclient.Noresponsemessagewillcomebacktotheclient.if(mService!=null){try{Messagemsg=Message.obtain(null,MessengerService.MSG_UNREGISTER_CLIENT);msg.replyTo=mMessenger;mService.send(msg);}catch(RemoteExceptione){//Thereisnothingspecialweneedtodoiftheservice//hascrashed.}}

Page 361: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Detachourexistingconnection.appContext.unbindService(mConnection);mIsBound=false;updateStatus("Unbound.");}}

//Ifyoucansimplifyandsendonlyoneortwointegers,this//istheeasywaytodoit.publicvoiddoSendSimple(){try{Messagemsg=Message.obtain(null,MessengerService.MSG_SET_SIMPLE_VALUE,this.hashCode(),0);mService.send(msg);updateStatus("Sendingsimplemessage.");}catch(RemoteExceptione){Log.e(TAG,"Couldnotsendasimplemessagetotheservice:"+e);}}

//Ifyouhavemorecomplexdata,throwitintoaBundleand//addittotheMessage.CanalsopassParcelablesifyoulike.publicvoiddoSendComplex(){try{Messagemsg=Message.obtain(null,MessengerService.MSG_SET_COMPLEX_VALUE);BundlemBundle=newBundle();mBundle.putString("stringArg","Thisisastringtopass");mBundle.putDouble("myDouble",1138L);mBundle.putInt("myInt",42);msg.setData(mBundle);mService.send(msg);updateStatus("Sendingcomplexmessage.");}catch(RemoteExceptione){Log.e(TAG,"Couldnotsendacomplexmessagetotheservice:"+e);}}

privatevoidupdateStatus(Stringstatus){//MakesurethelateststatusisupdatedintheGUI,

Page 362: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

which//ishandledbytheparentactivity.ISampleServiceClientuiContext=(ISampleServiceClient)getActivity();if(uiContext!=null){uiContext.updateStatus(status);}}}

Theclientfragmentcodeisfairlystraightforward.WhentheuserclickstheBindServicebutton,theclientfragmentbindstotheremoteserviceandsetsuptheServiceConnection.Bindingisdonefromtheapplicationcontext.Thisispreferredbecausefragmentscan’tbindservices,butactivitiesandapplicationscan.However,becausetheactivitycouldgoawayduringaconfigurationchange,it’sbettertobindtotheapplicationwhichwillalwaysbethere.WhentheServiceConnectiongetsconnected,anoutgoingMessengerissetuptosendtheMSG_REGISTER_CLIENTregisterclientmessagetotheservice.Theclientdoesnotwaitforareplyfromtheservicebutdoesgobacktowaitingfortheuser’snextinteraction.ThispreventsthedreadedANRpop-up.PressingSendSimplecreatesasimplemessageandsendsit.

Forasimplemessage,theservicedoesareplymessagewhichisreceivedbytheclient’shandlerandprocessed.AlltheclienthandlerdoesisupdatetheTextViewwiththevaluereceivedfromtheservice.Noticethattheclientfragmentusestheparentactivity’sISampleServiceClientinterfacetocallanappropriatemethodtoupdatetheUI.Thisisbecausetheclientfragmentisnon-UIandwewouldprefernottoembedUIlogicwithinit.Aninterfacekeepstheclientfragmentseparatefromtheactivityandmakesiteasytolettheactivitygoawayandcomebackduringaconfigurationchange.PressingSendComplexcreatesamessagewithabundlecontainingseveraldifferentvalues,whichissenttotheservice.Theservicewillusethedoublevalueinanotificationtoprovethatthevaluewasproperlytransmittedfromclienttoservice.Theservicedoesnotsendareplymessageforthecomplexmessage.

Onethingtobeawareofwiththismechanismforinter-processservicecalls:theservice’shandlerisworkingfromaqueueofincomingmessagesandisthereforesingle-threadedbydefault.Therewillnotbemultiplethreadsprocessingtheincomingservicemessagesunlessyoucreatesomeyourself.Sincetheclientisnotblockingonareplyfromtheservice,aclientapplicationwouldnotcrashiftheservicetookawhiletorespondtoamessage.However,itwouldbesomethingtokeepinmindifyou’llhavemultipleclientsoftheservice.AIDLservicescanmoreeasilyhandlerequestssimultaneously,soitmightbeabetterchoiceifyouneedmorepredictableresponsetimes.

Ifyourclientissendingmessagestomultipleservices,youcoulduseasingleMessenger/Handlerpairtoprocessreplymessagesfromthoseservices.YoujusthavetoputthatsameMessengerintoeachoutboundMessageandeachserviceshouldreplyback.

Theotherthingtobeawareofisthattheclienthasnoguaranteethattheservicewilleverrespond.TherearenotimeoutsinherentinaMessenger/Handlerinteraction.YouwillbenotifiedthroughonServiceDisconnected()iftheservicedies,butnotifithangs

Page 363: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ortakestoolong.Therefore,tobesurethattheservicerespondsinatimelyfashion,theclientcouldchoosetosetatimer,oranalarmtowakeitupagain.Ifthereplycomesbackbeforethetimer/alarmgoesoff,theclienthandlercouldclearit.Ifthetimer/alarmwakesuptheclient,itmeanstheservicetooktoolongandtheclientcouldthentakeappropriateaction.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch14_Services.zip.ThisZIPfilecontainsallprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoyourIDEfromoneoftheseZIPfiles.

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/:GreattutorialsonusingtheHttpClientclasses,includingauthenticationandtheuseofcookies.

http://developer.android.com/guide/components/bound-services.html:AndroidDeveloperGuideonBoundServices.

SummaryThischapterwasallaboutservices,specifically:

WetalkedaboutconsumingexternalHTTPservicesusingtheApacheHttpClient.

WithregardtousingtheHttpClient,weshowedyouhowtodoHTTPGETcallsandHTTPPOSTcalls.

WealsoshowedyouhowtodomultipartPOSTs.

YoulearnedthatSOAPcanbedonefromAndroid,butit’snotthepreferredwaytocallwebservices.

WetalkedabouthowyoucouldsetupanInternetproxytomanageaSOAPserviceonyourapplication’sbehalffromaserversomewhere,soyourapplicationcanuseRESTfulservicestoyourproxyandkeeptheapplicationsimpler.

Wethencoveredexceptionhandlingandthelikelytypesofexceptionsthatyourapplicationislikelytoexperience(timeoutsmostly).

Page 364: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

YousawhowtousetheThreadSafeClientConnManagertoshareacommonHttpClientinsideyourapplication.

Youlearnedhowtocheckandsettimeoutvaluesforconnectionstothenetwork.

Wecoveredacoupleofoptionsformakingconnectionstowebservices,includingHttpURLConnectionandAndroidHttpClient.

Weexplainedthedifferencebetweenlocalservicesandremoteservices.Localservicesareservicesthatareconsumedbythecomponents(suchasactivities)inthesameprocessastheservice.Remoteservicesareserviceswhoseclientsareoutsidetheprocesshostingtheservices.

Youlearnedthateventhoughaserviceismeanttobeonaseparatethread,itisstilluptothedevelopertocreateandmanagethebackgroundthreadsassociatedwithservices.

Youdiscoveredhowtostartandstoplocalservices,andhowtocreateandbindtoaremoteservice.

YousawhowtheNotificationManagerisusedtotrackrunningservices.

Wecoveredhowtopassdatatoaservice,usingParcelablesforthecomplextypes.

YoulearnedhowtouseMessengersandHandlerstocallremoteservices.

Page 365: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter15

AdvancedAsyncTaskandProgressDialogsInChapter13,wecoveredhandlersandworkerthreadstorunlong-runningtaskswhilethemainthreadkepttheUIhouseinorder.AndroidSDKhasrecognizedthisasapatternandabstractedthehandlerandthreaddetailsintoautilityclasscalledAsyncTask.YoucanuseAsyncTasktoruntasksthattakelongerthanfivesecondsinthecontextofUI.(Wewillcoverhowtorunreallylong-runningtasks,rangingfromminutestoevenhours,through“Long-RunningReceiversandServices”inChapter16.)

ThischapterwillstartwiththebasicsofanAsyncTaskandmovetothecodeneededtopresentprogressdialogsandprogressbarsthatshowthestatusofanAsyncTaskcorrectlyevenifthedevicechangesitsconfiguration.Let’sstartbyintroducingtheAsyncTaskthroughpseudocodeinListing15-1.

Listing15-1.UsagePatternforanAsyncTaskbyanActivity

publicclassMyActivity{voidrespondToMenuItem(){//menuhandlerperformALongTask();}voidperformALongTask(){//usinganAsyncTask

//DerivefromanAsyncTask,andInstantiatethisAsyncTaskMyLongTaskmyLongTask=newMyLongTask(...CallBackObjects…);myLongTask.execute(...someargs…);//starttheworkonaworkerthread//havethemainthreadgetbacktoitsUIbusiness}

//HearbackfromtheAsyncTaskvoidsomeCallBackFromAsyncTask(SomeParameterizedTypex){

//AlthoughinvokedbytheAsyncTaskthiscoderunsonthemainthread.//reportbacktotheuseroftheprogress}}

UseofanAsyncTaskstartswithextendingfromAsyncTaskfirstliketheMyLongTaskinListing15-1.OnceyouhavetheAsyncTaskobjectinstantiated,youcancallexecute()methodonthatobject.Theexecute()methodinternallystartsaseparatethreadtodotheactualwork.TheAsyncTaskimplementationwillinturn

Page 366: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

invokeanumberofcallbackstoreportthebeginningofthetask,theprogressofthetask,andtheendofthetask.Listing15-2showspseudocodetoextendanAsyncTaskandthemethodsthatneedtobeoverridden.(Pleasenotethatthisispseudocodeandnotintendedtobecompiled.The@overrideannotationisaddedtoexplicitlystatethattheyareoverriddenfromthebaseclass.)

Listing15-2.ExtendinganAsyncTask:AnExample

publicclassMyLongTaskextendsAsyncTask<String,Integer,Integer>{

//...constructorsstuff//Callingexecute()willresultincallingallofthesemethods@Override

voidonPreExecute(){}//Runsonthemainthread

//Thisiswhereyoudoalltheworkandrunsontheworkerthread@Override

IntegerdoInBackground(String…params){}

//Runsonthemainthreadagainonceitfinishes@Override

voidonPostExecute(Integerresult){}

//Runsonthemainthread@Override

voidonProgressUpdate(Integer…progressValuesArray){}

//....othermethods}

execute()methodinListing15-1iscalledonthemainthread.ThiscallwilltriggeraseriesofmethodsinListing15-2,startingwithonPreExecute().TheonPreExecute()iscalledonthemainthreadaswell.Youcanusethismethodtosetupyourenvironmenttoexecutethetask.Youcanalsousethismethodtosetupadialogboxorinitiateaprogressbartoindicatetotheuserthattheworkhasstarted.AfterthecompletionoftheonPreExecute(),execute()methodwillreturnandthemainthreadoftheactivitycontinueswithitsUIresponsibilities.Bythattimetheexecute()wouldhavespawnedanewworkerthreadsothatdoInBackground()methodisscheduledtobeexecutedonthatworkerthread.YouwilldoallyourheavyliftinginthisdoInBackground()method.Asthismethodrunsonaworkerthread,themainthreadisnotaffectedandyouwillnotgetthe“applicationnotresponding”message.FromthedoInBackground()methodyouhaveafacility(youwillseethisshortly)tocalltheonProgressUpdate()toreporttheprogress.ThisonProgressUpdate()methodrunsonthemainthreadsothatyoucanaffecttheUIonthemainthread.

EssentialsofaSimpleAsyncTaskLet’sgetintothedetailsofextendingtheAsyncTask.TheAsyncTaskclassuses

Page 367: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

genericstoprovidetypesafetytoitsmethods,includingtheoverriddenmethods.Youcanseethesegenericswhenyoulookatthepartialdefinition(Listing15-3)oftheAsyncTaskclass.(PleasenotethatListing15-3isanextremelypruned-downversionoftheAsyncTaskclass.It’sreallyjusttheelementsofitsinterfacemostcommonlyusedbyclientcode.)

Listing15-3.AQuickLookattheAsyncTaskClassDefinition

publicclassAsyncTask<Params,Progress,Result>{

//AclientwillcallthismethodAsyncTask<Params,Progress,Result>execute(Params…params);

//Doyourworkhere.FrequentlytriggersonProgressUpdate()ResultdoInBackGround(Params…params);

//Callback:AftertheworkiscompletevoidonPostExecute(Resultresult);

//Callback:AstheworkisprogressingvoidonProgressUpdate(Progress…progressValuesArray);

}

StudyingListing15-3,youcanseethattheAsyncTask(throughgenerics)needsthefollowingthreeparameterizedtypes(Params,Progress,andResult)whenyouextendit.Let’sexplainthesetypesbriefly:

Params(Thetypeofparameterstotheexecute()method):WhenextendingAsyncTask,youwillneedtoindicatethetypeofparametersthatyouwillpasstotheexecute()method.IfyousayyourParamstypeisString,thentheexecute()methodwillexpectanynumberofstringsseparatedbycommasinitsinvocationsuchasexecute(s1,s2,s3)orexecute(s1,s2,s3,s4,s5).

Progress(Parametertypestotheprogresscallbackmethod):ThistypeindicatesthearrayofvaluespassedbacktothecallerwhilereportingprogressthroughthecallbackonProgressUpdate(Progress…progressValuesArray).Theabilitytopassanarrayofprogressvaluesallowssituationswheremultipleaspectsofataskcanbemonitoredandreportedon.Forexample,thisfeaturecouldbeusedifanAsyncTaskisworkingonmultiplesubtasks.

Result(TypeusedtoreporttheresultthroughonPostExecute()method):ThistypeindicatesthetypeofthereturnvaluethatissentbackasthefinalresultfromtheexecutionthroughthecallbackonPostExecute(Result

Page 368: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

finalResult).

KnowingnowtheneededgenerictypesforanAsyncTask,supposewedecideonthefollowingparametersforourspecificAsyncTask:Params:AString,Result:Anint,Progress:AnInteger.Then,wecandeclareanextendedAsyncTaskclassasshowninListing15-4.

Listing15-4.ExtendingtheGenericAsyncTaskThroughConcreteTypes

publicclassMyLongTaskextendsAsyncTask<String,Integer,Integer>

{//...otherconstructorsstuff//...othermethods//ConcretemethodsbasedontheparameterizedtypesprotectedIntegerdoInBackground(String…params);protectedvoidonPostExecute(Integerresult);protectedvoidonProgressUpdate(Integer…progressValuesArray);

//....othermethods}

NoticehowthisconcreteclassinListing15-4,MyLongTask,hasdisambiguatedthetypenamesandarrivedatfunctionsignaturesthataretypesafe.

ImplementingYourFirstAsyncTaskLet’snowlookatasimple,butcomplete,implementationofMyLongTask.WehaveamplycommentedthecodeinListing15-5inlinetoindicatewhichmethodsrunonwhichthread.AlsopayattentiontotheconstructorofMyLongTaskwhereitreceivesobjectreferencesofthecallingcontext(usuallyanactivity)andalsoaspecificsimpleinterfacesuchasIReportBacktologprogressmessages.

TheIReportBackinterfaceisnotcriticaltoyourunderstandingbecauseitismerelyawrappertoalog.SameistruewiththeUtilsclassaswell.Youcanseetheseadditionalclassesinbothofthedownloadableprojectsforthischapter.TheURLforthedownloadableprojectsisinthereferencessectionattheendofthischapter.Listing15-5showsthecompletecodeforMyLongTask.

Listing15-5.CompleteSourceCodeforImplementinganAsyncTask

//ThefollowingcodeisinMyLongTask.java(ProAndroid5_Ch15_TestAsyncTask.zip)//Usemenuitem:TestAsync1toinvokethiscodepublicclassMyLongTaskextendsAsyncTask<String,Integer,Integer>

{IReportBackr;//aninterfacetoreportbacklog

Page 369: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

messagesContextctx;//TheactivitytostartadialogpublicStringtag=null;//DebugtagProgressDialogpd=null;//Tostart,report,andstopaprogressdialog

//ConstructornowMyLongTask(IReportBackinr,ContextinCtx,StringinTag){r=inr;ctx=inCtx;tag=inTag;}//RunsonthemainuithreadprotectedvoidonPreExecute(){

Utils.logThreadSignature(this.tag);pd=ProgressDialog.show(ctx,"title","InProgress…",true);}//Runsonthemainuithread.TriggeredbypublishProgresscalledmultipletimesprotectedvoidonProgressUpdate(Integer…progress){

Utils.logThreadSignature(this.tag);Integeri=progress[0];r.reportBack(tag,"Progress:"+i.toString());}protectedvoidonPostExecute(Integerresult){

//RunsonthemainuithreadUtils.logThreadSignature(this.tag);r.reportBack(tag,"onPostExecuteresult:"+result);pd.cancel();}//Runsonaworkerthread.Mayevenbeapooliftherearemoretasks.protectedIntegerdoInBackground(String…strings){

Utils.logThreadSignature(this.tag);for(Strings:strings){Log.d(tag,"Processing:"+s);}for(inti=0;i<3;i++){Utils.sleepForInSecs(2);publishProgress(i);//thiscallsonProgressUpdate}return1;//thisvalueisthenpassedtotheonPostExecuteasinput}}

WewillgointothedetailsofeachofthemethodshighlightedinListing15-5after

Page 370: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

coveringbrieflyhowaclientwouldmakeuseof(orcall)MyLongTask.

CallinganAsyncTaskOncewehavetheclassMyLongTaskimplemented,aclientwillutilizethisclassasshowninListing15-6.

Listing15-6.CallinganAsyncTask

//YouwillfindthisclassAsyncTester.java(ProAndroid5_Ch15_TestAsyncTask.zip)//Usemenuitem:TestAsync1toinvokethiscodevoidrespondToMenuItem(){//Aninterfacetologsomemessagesbacktotheactivity//Seedownloadableprojectifyouneedthedetails.IReportBackreportBackObject=this;Contextctx=this;//activityStringtag="Task1";//debugtag

//InstantiateandexecutethelongtaskMyLongTaskmlt=newMyLongTask(reportBackObject,ctx,tag);

mlt.execute("String1","String2","String3");

}

Noticehowtheexecute()methodiscalledinListing15-6.BecausewehaveindicatedoneofthegenerictypesasaStringandthattheexecute()methodstakesavariablenumberofargumentsforthistype,wecanpassanynumberofstringstotheexecute()method.IntheexampleinListing15-6,wehavepassedthreestringarguments.Youcanpassmoreorlessasyouneed.

Oncewecalltheexecute()methodontheAsyncTask,thiswillresultinacalltotheonPreExecute()methodfollowedbyacalltothedoInBackground()method.ThesystemwillalsocalltheonPostExecute()callbackoncethedoInBackground()methodfinishes.RefertoListing15-5forhowthesemethodsareimplemented.

UnderstandingtheonPreExecute( )CallbackandProgressDialogGoingbacktoMyLongTaskimplementationinListing15-5,intheonPreExecute()methodwestartedaprogressdialogtoindicatethatthetaskisinprogress.Figure15-1showsanimageofthatdialog.(UsemenuitemTestAsync1toinvokethisviewfromprojectdownloadProAndroid5_Ch15_TestAsyncTask.zip.)

Page 371: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure15-1.AsimpleprogressdialoginteractingwithanAsyncTask

Thecodesegment(takenfromListing15-5)thatshowstheprogressdialogisreproducedinListing15-7.

Listing15-7.ShowinganIndeterminateProgressDialog

pd=ProgressDialog.show(ctx,"title","InProgress…",true);

Thevariablepdwasalreadydeclaredintheconstructor(seeListing15-5).ThiscallinListing15-7willcreateaprogressdialoganddisplayitasshowninFigure15-1.Thelastargumenttotheshow()methodinListing15-7indicatesifthedialogisindeterminate(whetherthedialogcanestimatebeforehandhowmuchworkthereis).Wewillcoverthedeterministiccaseinalatersection.

NoteShowingprogressofanAsyncTaskreliablyisquiteinvolved.Thisisbecauseanactivitycancomeandgo,becauseofeitheraconfigurationchangeoranotherUItakingprecedence.Wewillcoverthisessentialneedandsolutionslaterinthechapter.

Page 372: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UnderstandingthedoInBackground( )MethodAllthebackgroundworkcarriedoutbytheAsyncTaskisdoneinthedoInBackground()method.ThismethodisorchestratedbytheAsyncTasktorunonaworkerthread.Asaresult,thisworkisallowedtotakemorethanfiveseconds,unliketheworkdoneonamainthread.

InourexamplefromListing15-5,inthedoInBackground()methodwesimplyretrieveeachoftheinputstringstothetaskasiftheyareanarray.Inthismethoddefinitionwehaven’tdefinedanexplicitstringarray.However,thesingleargumenttothisfunctionisdefinedasavariable-lengthargument,asshowninListing15-8.

Listing15-8.doInBackground()MethodSignature

protectedIntegerdoInBackground(String…strings)

Javathentreatstheargumentasifitisanarrayinsidethefunction.SoinourcodeinthedoInBackground()method,wereadeachofthestringsandlogthemtoindicatethatweknowwhattheyare.Wethenwaitlongenoughtosimulatealong-runningoperation.Becausethismethodisrunninginaworkerthread,wehavenoaccesstotheUIfunctionalityofAndroidfromthisworkerthread.Forinstance,youwon’tbeabletoupdateanyViewsdirectlyevenifyouhaveaccesstothemfromthisthread.YoucannotevensendaToastfromhere.Thenexttwomethodsallowustoovercomethis.

TriggeringonProgressUpdate( )throughpublishProgress( )InthedoInBackground()method,youcantriggeronProgressUpdate()bycallingthepublishProgress()method.ThetriggeredonProgressUpdate()methodthenrunsonthemainthread.ThisallowstheonProgressUpdate()methodtoupdateUIelementssuchasViewsappropriately.YoucanalsosendaToastfromhere.InListing15-5,wesimplylogamessage.Oncealltheworkisdone,wereturnfromthedoInBackground()methodwitharesultcode.

UnderstandingtheonPostExecute( )MethodTheresultcodefromthedoInBackground()methodisthenpassedtotheonPostExecute()callbackmethod.Thiscallbackisalsoexecutedonthemainthread.Inthismethod,wetelltheprogressdialogtoclose.Beingonthemainthread,youcanaccessanyUIelementsinthismethodwithnorestrictions.

UpgradingtoaDeterministicProgressDialogInthepreviousexampleinListing15-5,weusedaprogressdialog(Figure15-1)thatdoesn’ttelluswhatportionoftheworkiscomplete.Thisprogressdialogiscalledan

Page 373: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

indeterminateprogressdialog.Ifyousettheindeterminatepropertytofalseonthisprogressdialog,youwillseeaprogressdialogthattracksprogressinsteps.ThisisshowninFigure15-2.(Usemenuitem“TestAsync2”toinvokethisviewfromprojectdownloadProAndroid5_Ch15_TestAsyncTask.zip.)

Figure15-2.Aprogressdialogshowingexplicitprogress,interactingwithanAsyncTask

Listing15-9showstheprevioustaskfromListing15-5rewrittentochangethebehavioroftheprogressdialogtoadeterministicprogressdialog.WehavealsoaddedanonCancelListenertoseeifweneedtocancelthetaskoncancellingthedialog.AusercanclickthebackbuttoninFigure15-2tocancelthedialog.KeyportionsofthecodearegiveninListing15-9(forthefullcode,seethedownloadfileProAndroid5_Ch15_TestAsyncTask.zip).

Listing15-9.ALongTaskUtilizingaDeterministicProgressDialog

//FollowingcodeisinMyLongTask1.java(ProAndroid5_Ch15_TestAsyncTask.zip)//Usemenuitem:TestAsync2toinvokethiscode

Page 374: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicclassMyLongTask1extendsAsyncTask<String,Integer,Integer>implementsOnCancelListener{//..othercodetakenfromListing15-5//AlsorefertothejavaclassMyLongTask1.javainthedownloadableproject//forfullcodelisting.protectedvoidonPreExecute(){//....othercodepd=newProgressDialog(ctx);pd.setTitle("title");pd.setMessage("InProgress…");pd.setCancelable(true);pd.setOnCancelListener(this);pd.setIndeterminate(false);pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);pd.setMax(5);pd.show();}publicvoidonCancel(DialogInterfaced){r.reportBack(tag,"CancelCalled");this.cancel(true);}//..othercodetakenfromListing15-5}

NoticehowwehavepreparedtheprogressdialoginListing15-9.Inthiscasewehaven’tusedthestaticmethodshow(),incontrasttowhatwedidinListing15-5,ontheprogressdialog.Instead,weexplicitlyinstantiatedtheprogressdialog.Thevariablectxstandsforthecontext(oractivity)inwhichthisUIprogressdialogoperates.Thenweindividuallysetthepropertiesonthedialog,includingitsdeterministicorindeterminatebehavior.ThemethodsetMax()indicateshowmanystepstheprogressdialoghas.Wehavealsopassedtheselfreference(theAsyncTaskitself)asalistenerwhencancelistriggered.Inthecancelcallback,weexplicitlyissueacancelontheAsyncTask.Thecancel()methodwilltrytostoptheworkerthreadifwecallitwiththebooleanargumentoffalse.Abooleanargumentoftruewillforce-stoptheworkerthread.

AsyncTaskandThreadPoolsConsiderthecodeinListing15-10,whereamenuitemisinvokingtwoAsyncTasksoneaftertheother.

Listing15-10.InvokingTwoLong-RunningTasks

voidrespondToMenuItem(){

Page 375: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MyLongTaskmlt=newMyLongTask(this.mReportTo,this.mContext,"Task1");mlt.execute("String1","String2","String3");

MyLongTaskmlt1=newMyLongTask(this.mReportTo,this.mContext,"Task2");mlt1.execute("String1","String2","String3");}

Hereweareexecutingtwotasksonthemainthread.Youmayexpectthatboththetasksgetstartedclosetoeachother.Thedefaultbehavior,however,isthatthesetasksrunsequentiallyusingasinglethreaddrawnoutofapoolofthreads.Ifyouwantaparallelexecution,youcanusetheexecuteOnExecutor()methodontheAsyncTask.SeeSDKdocsfordetailsonthismethod.AlsoaspertheSDKdocumentation,itisnotvalidtocalltheexecute()methodmorethanonceonasingleAsyncTask.Ifyouwantthatbehavior,youhavetoinstantiateanewtaskandcalltheexecute()methodagain.

IssuesandSolutionsforCorrectlyShowingtheProgressofanAsyncTaskIfyourprimarygoalwiththischapteristolearnjusttheessentialsofAsyncTask,thenwhatwehavecoveredsofarissufficient.However,therearesomeissueswhenanAsyncTaskispairedwithaprogressdialogasshowninthepreviouslistingssofar.OneofthoseissuesisthatanAsyncTaskwilllosethecorrectactivityreferencewhenthedeviceisrotated,therebyalsolosingitsreferencetotheprogressdialog.Theotherissueisthattheprogressdialogweusedearlierinthecodeisnotamanageddialog.Let’sunderstandtheseissuesnow.

DealingwithActivityPointersandDeviceRotationTheactivitypointerthatisheldbytheAsyncTaskbecomesstalewhentheactivityisre-createdbecauseofaconfigurationchange.ThisisbecauseAndroidhascreatedanewactivityandtheoldactivityisnolongershownonthescreen.Soholdingontotheoldactivityanditscorrespondingdialogisbadforacoupleofreasons.ThefirstisthattheuserisnotseeingthatactivityordialogthattheAsyncTaskistryingtoupdate.ThesecondreasonisthattheoldactivityneedstobegarbagecollectedandyouarestoppingitfromgettinggarbagecollectedbecausetheAsyncTaskisholdingontoitsreference.IfyouweretobesmartanduseaJavaweakreferencefortheoldactivity,thenyouwouldn’tleakmemorybutyouwouldgetanullpointerexception.Thecaseofstalepointeristruenotonlyoftheactivitypointerbutanyotherpointerthatindirectlypointstotheactivity.

Therearetwowaystoaddressthestaleactivityreferenceissue.Therecommendedwayistouseheadlessretainedfragments.(FragmentsarecoveredinChapter8.Retainedfragmentsarefragmentsthatstayaroundwhiletheactivityisre-createdduetoa

Page 376: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

configurationchange.Thesefragmentsarealsocalledheadlessbecausetheydon’tnecessarilyhavetoholdanyUI.)Anotherwaytosolvethestaleactivitypointersistousetheretainedobjectscallbackfromtheactivity.Wewillpresentbothoftheseapproachesforaddressingthestaleactivitypointerissue.

DealingwithManagedDialogsEvenifweareabletosolvethestaleactivityreferenceissueandreestablishtheconnectivitytothecurrentactivity,thereisaflawinthewayprogressdialogswereusedsofarinthischapter.WehaveinstantiatedaProgressDialogdirectly.AProgressDialogcreatedinthismannerisnota“managed”dialog.Ifitisnotamanageddialog,theactivitywillnotre-createthedialogwhenthedeviceundergoesrotationoranyotherconfigurationchange.So,whenthedevicerotatestheAsyncTaskisstillrunninguninterruptedbutthedialogwillnotshowup.Thereareacoupleofwaystosolvethisproblemaswell.TherecommendedwayisnottouseprogressdialogsbutinsteaduseanembeddedUIcontrolintheactivityitself,suchasaprogressbar.Becauseaprogressbarispartoftheactivityviewhierarchy,thehopeisthatitwillbere-created.Althoughaprogressbarsoundsgood,therearetimeswhenamodalprogressdialogmakesmoresense.Forexample,thatwouldbethecaseifyoudon’twanttheusertointeractwithanyotherpartoftheactivitywhiletheAsyncTaskisrunning.Inthosecases,weseelittlecontradictioninusingfragmentdialogsinsteadofprogressbars.

It’stimewestepintothesolutionstodealwiththeactivityreferencesissuesandthemanageddialogsissue.Wewillpresentthreedifferentsolutions.Thefirstoneusesretainedobjectsandfragmentdialogs.Thesecondoneusesheadlessretainedfragmentsandfragmentdialogs.Thethirdsolutionusesheadlessretainedfragmentsandprogressbars.

TestingScenariosforaWell-BehavedProgressDialogOfthethreesolutionswehaveinthischapter,whicheveryouusetocorrectlydisplayaprogressdialogforanAsyncTask,thesolutionshouldworkinallofthefollowingtestscenarios:

1. Withoutanorientationchangetheprogressdialogmuststart,showitsprogress,end,andalsocleanupthereferencetotheAsyncTask.Thismustworkrepeatedlytoshowthattherearenovestigesleftfromthepreviousrun.

2. Thesolutionshouldhandletheorientationchangeswhilethetaskisinthemiddleofitsexecution.Therotationshouldre-createthedialogandshowprogresswhereitleftoff.ThedialogshouldproperlyfinishandcleanuptheAsyncTaskreference.Thismustworkrepeatedlytoshowthattherearenovestigesleftbehind.

3. Thebackshouldbedisabledwhenthetaskstartstorun.

4. GoingHomeshouldbeallowedevenwhenthetaskisinthemiddle

Page 377: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ofexecution.

5. GoingHomeandrevisitingtheactivityshouldshowthedialogandcorrectlyreflectthecurrentprogress,andtheprogressshouldneverbelessthantheonebefore.

6. GoingHomeandrevisitingtheactivityalsoshouldworkwhenthetaskfinishesbeforereturning.ThedialogshouldbeproperlydismissedandtheAsyncTaskreferenceremoved.

ThissetoftestcasesshouldalwaysbeperformedforallactivitiesdealingwithAsyncTasks.Nowthatwehavelaidouthoweachsolutionshouldsatisfy,let’sstartwiththefirstsolution,theonethatusesretainedobjectsandfragmentdialogs.

UsingRetainedObjectsandFragmentDialogsInthisfirstsolution,let’sshowyouhowtouseretainedobjectsandfragmentdialogsfordisplayingprogresscorrectlyforanAsyncTask.Thissolutioninvolvesthefollowingsteps:

1. TheactivitymustkeeptrackofanexternalobjectthroughitsonRetainNonConfigurationInstance()callback.Thisexternalobjectmuststickaroundanditsreferencevalidatedastheactivityisclosedandbroughtback.Thatiswhythisobjectisreferredtoasaretainedobject.ThisretainedobjectcaneitherbetheAsyncTaskobjectitselforanintermediateobjectthatholdsareferencetotheAsyncTask.Let’scallthatarootretainedactivity-dependentobject(orarootRADO).Itiscalleda“root”becausetheonRetainNonConfigurationInstance()canuseonlyoneretainedobjectreference.

2. ArootRADOthenwillhaveapointertotheAsyncTaskandcansetandresettheactivitypointeronAsyncTaskastheactivitycomesandgoes.So,thisrootRADOactsasanintermediarybetweentheactivityandtheAsyncTask.

3. TheAsyncTaskthenwillinstantiateafragmentprogressdialoginsteadofaplainnon-managedprogressdialog.TheAsyncTaskwillusetheactivitypointerthatissetbytherootRADOtoaccomplishthis,asyouwillneedanactivitytocreateafragmentincludingafragmentdialog.

4. Theactivitywillre-createthedialogfragmentasitrotatesandkeepsitsstateproperlybecausedialogfragmentsaremanaged.TheAsyncTaskcanproceedtoincrementprogressonthefragmentdialogaslongastheactivityissetandavailable.Notethatthisdialogfragmentisnot,byitself,aretainedfragment.Itgetsre-createdaspartoftheactivitylifecycle.

Page 378: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

5. ThefragmentdialogcanfurtherdisallowthecancelonitsothattheusercannotgobacktotheactivityfromthedialogwhiletheAsyncTaskisinprogress.

6. However,ausercangoHomebytappingHomeanduseotherapps.Thiswillpushouractivity,andthedialogwithit,intothebackground.Thismustbehandled.Whentheuserreturnstotheactivityorapp,thedialogcancontinuetoshowtheprogress.TheAsyncTaskmustknowhowtodismissthefragmentdialogifthetaskfinisheswhiletheactivityishidden.Beingafragmentdialog,dismissingthisdialogthrowsaninvalidstateexceptioniftheactivityisnotintheforeground.So,theAsyncTaskhastowaituntiltheactivityisreopenedandintherightstatetodismissthedialog.

ExploringCorrespondingKeyCodeSnippetsWewillpresentnowthekeypiecesofcodethatareusedtoimplementtheoutlinedapproach.TherestoftheimplementationcanbefoundinthedownloadableprojectProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zipforthischapter.Asallsolutionsforthisproblemrequirethedialogtobeafragmentdialog,sothatthedialogcanbemanaged,Listing15-11presentsthesourcecodeofthisfragmentdialogfirst.

Listing15-11.EncapsulatingaProgressDialoginaDialogFragment

//ThefollowingcodeisinProgressDialogFragment.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)/***ADialogFragmentthatencapsulatesaProgressDialog.*Thisisnotexpectedtobearetainedfragmentdialog.*Getsre-createdasactivityrotatesfollowinganyfragmentprotocol.*/publicclassProgressDialogFragmentextendsDialogFragment{

privatestaticStringtag="ProgressDialogFragment";ProgressDialogpd;//WillbesetbyonCreateDialog

//ThisgetscalledfromADOssuchasretainedfragments//typicallydonewhenactivityisattachedbacktotheAsyncTaskprivateIFragmentDialogCallbacksfdc;publicvoidsetDialogFragmentCallbacks(IFragmentDialogCallbacks

infdc){

Log.d(tag,"attachingdialogcallbacks");fdc=infdc;}

//Thisisadefaultconstructor.Calledbytheframework

Page 379: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

allthetime//forreintroduction.publicProgressDialogFragment(){

//Shouldbesafeformetosetcancelableasfalse;//wonderifthatiscarriedthroughrebirth?this.setCancelable(false);}//Onewayfortheclienttoattachinthebeginningwhenthefragmentisreborn.//ThereattachmentisdonethroughsetFragmentDialogCallbacks//Thisisashortcut.Yourcompilerifenabledforlintmaythrowanerror.//YoucanusethenewInstancepatternandsetbundle(seethefragmentschapter)publicProgressDialogFragment(IFragmentDialogCallbacksinfdc){

this.fdc=infdc;this.setCancelable(false);}/***Thiscangetcalledmultipletimeseachtimethefragmentis*re-created.Sostoringthedialogreferenceinalocalvariableshouldbesafe*/@OverridepublicDialogonCreateDialog(BundlesavedInstanceState){

Log.d(tag,"InonCreateDialog");pd=newProgressDialog(getActivity());pd.setTitle("title");pd.setMessage("InProgress…");pd.setIndeterminate(false);pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);pd.setMax(15);returnpd;}//Calledwhenthedialogisdismissed.Ishouldtellmycorrespondingtask//tocloseordotherightthing!Thisisdonethroughcallbacktofdc//fdc:fragmentdialogcallbackscouldbetheTask,orActivityortherootRADO//SeeListing15-12toseehowFDCisimplementedbythetask@OverridepublicvoidonDismiss(DialogInterfacedialog){

super.onDismiss(dialog);

Page 380: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.d(tag,"Dialogdismissed");if(fdc!=null){fdc.onDismiss(this,dialog);}}@OverridepublicvoidonCancel(DialogInterfacedialog){

super.onDismiss(dialog);Log.d(tag,"Dialogcancelled");if(fdc!=null){fdc.onCancel(this,dialog);}}//willbecalledbyaclientlikethetaskpublicvoidsetProgress(intvalue){

pd.setProgress(value);}}

CodeinListing15-11showshowtowraparegularnon-managedProgressDialoginamanagedfragmentdialog.WeextendaDialogFragmentandoverrideitsonCreateDialog()toreturntheProgressDialogobject.Inadditiontothatbasicfeature,weaddedtheabilitytomonitorwhentheprogressdialoggetsdismissedorcancelled.WealsoprovideasetProgress()methodonthewrappedclasstocallthesetProgress()ontheinternalProgressDialog.YoucanseethesourcecodefortheIFragmentDialogCallbacksinthedownloadableproject(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip),asitisnotthatcriticaltounderstandingthisfragmentprogressdialog.

Let’sseenowhowanAsyncTaskcancreateandcontrolthisfragmentprogressdialog.Listing15-12presentsthepseudocodefortheAsyncTaskinordertoaidthisunderstanding.Forthecompletesourcecode,refertodownloadableproject.

Listing15-12.PseudocodeforanAsyncTaskThatUsesaFragmentProgressDialog

//ThefollowingcodeisinMyLongTaskWithRADO.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanstartthistaskthroughmenuitem:FlipDialogwithADOspublicclassMyLongTaskWithRADOextendsAsyncTask<String,Integer,Integer>implementsIRetainedADO,IFragmentDialogCallbacks{//....othercode@OverridepublicvoidonPreExecute(){

//....othercode//gettheactivityasitwouldhavebeensetbytherootRADO

Page 381: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Activityact=this.getActivity();

//CreatetheprogressdiaolgProgressDialogFragmentpdf=newProgressDialogFragment();//theshowmethodwilladdandcommitthefragmentdialogpdf.show(act.getFragmentManager(),this.PROGRESS_DIALOG_FRAGMENT_TAG_NAME);}@OverridepublicvoidonProgressUpdate(){

//ifactivityisavailable,getthefragmentdialogfromit//callsetProgress()onit//otherwiseignoretheprogress}@OverridepublicvoidonPostExecute(){

//ifactivityisinagoodstate//dismissthedialogandtelltherootRADOtodropthepointertotheAsyncTask//ifnotrememberitthroughaflagtocloseitwhenyoucomeback}@Overridepublicvoidattach(){

//calledwhentheactivityisback//checktoseeifyouaredone//ifsodismissthedialogandremoveyourselffromtheRADO//ifnotcontinuetoupdatetheprogress}}

BecausethisAsyncTaskimplementstheideaofaretainedactivity-dependentobject(IRetainedADO),itknowswhentheactivityisavailableandwhenitisnot.Italsoknowsthestateoftheactivity,suchaswhethertheUIisreadyornot.Althoughittakessomecodetoimplementactivity-dependentobjects(ADOs),itisnotahardconcept.WeleaveittoyouduetospaceconsiderationstolookintothedownloadableprojectProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zipandseehowthisisdone.

ThisAsyncTaskinListing15-12alsotakesoverthemanagementofitsfragmentdialogsothatitactslikeacohesiveunitandtherebydoesn’tcontaminatethemainactivitywiththedetailsofthisAsyncTask.AnotherkeydetailinListing15-12iswhathappenswhenthedialogisdismissedastheAsyncTaskfinishes.Atthisinstantiftheactivityishidden,ornotthereduetorotation,itisimportanttodismissthedialogwhentheactivityisre-created.Inordertodothis,theonPostExecute()remembersthelaststateoftheAsyncTaskwhetheritisdoneorinprogress.ThisAsyncTaskthenwaitsforthe

Page 382: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

attach()method,whichgetscalledwhentheUIreadyactivityisreattachedtothisADO.Onceintheattach()method,theAsyncTaskcanthendismissthefragmentdialog.

YoucandownloadtheprojectnamedProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zipandseehowtheinteractionpresentedinListing15-12isfullyrealized.

Thisparticularapproachofusingretainedobjectsisabitinvolvedwhencomparedtousingretainedfragmentsinstead.ButithastheeleganceofsolvingitinamoregenericformusingtheideaofADOs,betheyfragmentsorotherwise.Wehavelinksinthereferencesectionthatoutlinethisideaandprovidebackground.Withthat,let’sturnourattentiontotherecommendedideaofretainedfragmentsinoursecondsolution.

UsingRetainedFragmentsandFragmentDialogsInthesecondsolution,wewillstickwiththefragmentdialogsbutwewilluseheadlessretainedfragmentsinsteadofsimpleretainedobjects.Androidhasdeprecatedtheretainedobjectsinfavorofretainedfragments.InAndroidaretainedobjectisjustanobjectandhasnoin-builtabilitytotrackthestateoftheactivity.(ThisiswhywehadtoinventtheframeworkofADOsontop.)ThisdeficiencyisnottherewiththeintroductionoffragmentsinlaterreleasesofAndroid.AlthoughfragmentsaretightlywovenintothefabricofUI,theycanexistwithoutUIaswell.Thesearecalledheadlessfragments.Inadditiontobeingabletotrackthestateoftheactivity,fragmentscanalsoberetained,muchlikeretainedobjects.

OutliningtheRetainedFragmentsApproachTheapproachinthissolutionistouseaheadlessretainedfragmentasananchortocommunicatebetweentheactivityandtheAsyncTask.Herearethekeyaspectsofthisapproach:

1. Continuetouseafragmentprogressdialog,asinthesolutionbefore.

2. HavetheactivitycreateaheadlessretainedfragmentwhichthenholdsapointertotheAsyncTask.Thisheadlessretainedfragmenttakestheplaceoftheretainedobjectintheprevioussolution.Beingaretainedfragment,thefragmentobjectsticksaroundwhiletheactivityisre-createdwithanewpointer.TheAsyncTaskthenalwaysreliesontheretainedfragmenttoretrievethemostcurrentactivitypointer.

3. TheAsyncTaskreliesontheheadlessretainedfragmenttobeinformedoftheactivitystatetoaccomplishallofthetestcasesindicatedintheprevioussolution.

ExploringCorrespondingKeyCodeSnippets

Page 383: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Wehavealreadyshownyouthecodeforthefragmentdialogduringtheprevioussolution.Aswecontinuetousethesameobjectinthissolution,wewillfocusontheretainedfragmentandalsohowtheAsyncTaskusesthefragmentdialogthroughtheretainedfragment.

Inthesampleprogram(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)wehaveprovidedinthedownload,wecalledtheretainedfragmentAsyncTesterFragment.Listing15-13showsthepseudocodeforthisclass,whichdemonstrates,amongotherthings,whatmakesthisclassaheadlessfragment.

Listing15-13.PseudocodeforaHeadlessFragment

//ThefollowingcodeisinAsyncTesterFragment.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanstartthistaskthroughmenuitem:FlipDialogwithFragmentpublicclassAsyncTesterFragment

extendsFragment(oranotherobjectthatisderivedfromFragment){//NoneedtooverridethekeyonCreateView()method

//whichotherwisewouldhavereturnedaviewloadedfromalayout.//ThushavingnoViewmakesthisfragmentaheadlessfragment

//UsethisnametoregisterwiththeactivitypublicstaticStringFRAGMENT_NAME=“AsyncTesterRetainedFragment”;

//Localvariablefortheasynctask.Youcanuseamenutostartworkonthistask//NullifythisreferencewhentheasynctaskfinishesMyLongTaskWithFragmentDialogtaskReference;

//Haveaninitmethodtohelpwithinheritancepublicvoidinit(arg1,arge2,etc){super.init(arg1,…);//ifthereisonesetArguments(….);//orpassthebundletothesuperinit}publicstaticAsyncTesterFragmentnewInstance(arg1,arg2,…){AsyncTesterFragmentf=newAsyncTesterFragment();f.init(arg1,arg2,…);}//havemorestaticmethodstocreatethefragment,locatethefragmentetc.

Page 384: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

TherearethreethingsworthmentioningaboutthecodeinListing15-13.BynotoverridingtheonCreateView(),thisfragmentbecomesaheadlessfragment.Becauseafragmentgetsre-createdusingitsdefaultconstructor,wefollowedthenewInstance()patternandalsoextendedthatpatterntouseinit()methodswhichcanbevirtualandinherited.ThislatterapproachisusefulifyouareextendingtheFragmentclassinadeeperhierarchy.

Listing15-14showsastaticmethodonthisAsyncTesterFragmentobjectthatcancreatethisfragment,makeitretainitsstate,andthenregisteritwiththeactivity.

Listing15-14.RegisteringaFragmentasaRetainedFragment

//ThefollowingcodeisinAsyncTesterFragment.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanstartthistaskthroughmenuitem:FlipDialogwithFragmentpublicstaticAsyncTesterFragmentcreateRetainedAsyncTesterFragment(Activityact){AsyncTesterFragmentfrag=AsyncTesterFragment.newInstance();frag.setRetainInstance(true);

FragmentManagerfm=act.getFragmentManager();FragmentTransactionft=fm.beginTransaction();ft.add(frag,AsyncTesterFragment.FRAGMENT_TAG);ft.commit();returnfrag;}

Oncethisretainedfragmentisavailablewiththeactivity,itcanberetrievedanytimeandaskedtostartanAsyncTask.Listing15-15showsthepseudocodefortheAsyncTaskthatisabletointeractwiththisretainedfragmenttocontrolthefragmentdialog

Listing15-15.AnAsyncTaskThatUsesaFragmentDialogThroughaRetainedFragment

//ThefollowingcodeisinMyLongTaskWithFragment.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanstartthistaskthroughmenuitem:FlipDialogwithFragmentpublicclassMyLongTaskWithFragmentextendsAsyncTask<String,Integer,Integer>{//...othercode//ThefollowingreferencepassedinandsetfromtheconstructorAsyncTesterFragmentretainedFragment;

//....othercode@OverrideprotectedvoidonPreExecute(){

Page 385: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

....othercode//gettheactivityfromtheretainedfragmentActivityact=retainedFragment.getActivity();//CreatetheprogressdialogProgressDialogFragmentpdf=newProgressDialogFragment();//theshowmethodwilladdandcommitthefragmentdialogpdf.show(act.getFragmentManager(),this.PROGRESS_DIALOG_FRAGMENT_TAG_NAME);}@OverrideprotectedvoidonProgressUpdate(){//ifactivityisavailable,getthefragmentdialogfromit,callsetProgress()onit//otherwiseignoretheprogress}@OverrideprotectedvoidonPostExecute(){//ifactivityisinagoodstate//dismissthedialogandtelltherootRADOtodropthepointertotheAsyncTask//ifnotrememberitthroughaflagtocloseitwhenyoucomeback}@Overridepublicvoidattach(){//calledwhentheactivityisback.checktoseeifthistaskisdone//ifsodismissthedialogandremoveyourselffromtheretainedfragment//ifnotcontinuetoupdatetheprogress}@OverrideprotectedIntegerdoInBackground(String…strings){//Dotheactualworkherewhichoccursonaseparatethread}}

ThisAsyncTaskinListing15-15behavesmuchliketheAsyncTaskthatusedtheretainedobject.Oncethistaskknowshowtogetaccesstotheprogressdialogfragmentfromtheretainedfragment,itisprettystraightforwardtosettheprogressonit.Asbefore,thistaskalsoneedstoknowwhentheactivityisreattachedincasethetaskisdonebeforehand.Ifthishappens,theAsyncTaskneedstorememberthisandclosethedialogonreattach.ThepseudocodeinListing15-15satisfiesallthetestconditionssetforthearlier.

Thisconcludesoursecondsolution.Let’sshiftnowtothethirdsolution,wherewewilluseaprogressbarinsteadofaprogressdialogtoshowtheprogressofanAsyncTask.

Page 386: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UsingRetainedFragmentsandProgressBarsAndroidSDKdocumentationonProgressDialog(http://developer.android.com/guide/topics/ui/dialogs.html)isrecommendingthatweuseaProgressBarinanumberofscenariosinsteadasabetterpractice.Thepurportedreasonisthataprogressbarislessintrusive,asitallowsinteractionwithotherareasoftheactivity.Aprogressbar,likeaprogressdialog,canbeindeterminateorfixedinduration.Itcanalsobeacontinuouslyrevolvingcircleorahorizontalbar.YoucanfindthesemodesbylookingupthedocsforProgressBar.Listing15-16givesaquickrundownofasamplingofProgressBarstylesinalayoutfile.

Listing15-16.DifferentWaystoStyleaProgressBarinaLayoutFile

//Thefollowingcodeisinspb_show_progressbars_activity_layout.xml//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanseetheseprogressbarsthroughmenuitem:ShowProgressbars<!--Aregularprogressbar-Alargespinningcircle--><ProgressBarandroid:id="@+id/tpb_progressBar1"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@android:color/background_light"/>

<!--Smallspinningcircle--><ProgressBarandroid:id="@+id/tpb_progressBar4"style="?android:attr/progressBarStyleSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@android:color/background_light"/>

<!--HorizontalindefiniteProgressbar:aline--><ProgressBarandroid:id="@+id/tpb_progressBar3"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:indeterminate="true"/>

<!--HorizontalfixeddurationProgressbar:aline--><ProgressBarandroid:id="@+id/tpb_progressBar3"style="?android:attr/progressBarStyleHorizontal"

Page 387: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:layout_width="match_parent"android:layout_height="wrap_content"android:indeterminate="false"android:max="50"android:progress="10"/>

Figure15-3showshowtheprogressbarlayoutsshowninListing15-16lookwhenloadedintoanactivity.Eachtypeofprogressbarislabeledtoindicateitsmodeorbehavior.(UsemenuitemShowProgressBarstoinvokethisviewfromprojectdownloadProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip.)

Figure15-3.AsamplingofprogressbarsinAndroid

OutliningtheProgressBarApproachTheapproachtoreporttheprogressofanAsyncTaskthroughaprogressbarissimilartothepreviousapproachthatusedaretainedheadlessfragmentandafragmentprogressdialog.

1. Asintheprevioussolution,havetheactivitycreateaheadlessretainedfragmentthatholdsapointertotheAsyncTask.

2. Embedtheprogressbarintheactivitylayout.AsyncTaskwillgettothisprogressbarthroughtheheadlessretainedfragment.

3. TheAsyncTaskreliesontheheadlessretainedfragmenttobe

Page 388: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

informedoftheactivitystatetoaccomplishallofthetestcasesindicatedearlier.

WalkingThroughCorrespondingKeyCodeSnippetsLet’swalkthroughthekeycodesnippetsthatyouwouldneedtomakethissolutionwork.Let’sbeginwiththelocalvariablestheAsyncTaskholdstointeractwiththeretainedfragmentandtheactivity(Listing15-17).

Listing15-17.LocalVariablesofanAsyncTasktoWorkwithaProgressBar

//ThefollowingcodeisinMyLongTaskWithProgressBar.java//(ProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip)//Youcanstartthistaskthroughmenuitem:TestProgressBarpublicclassMyLongTaskWithProgressBarextendsAsyncTask<String,Integer,Integer>implementsIWorkerObject{publicStringtag=null;//DebugtagprivateMonitoredFragmentretainedFragment;//ReferencetotheretainedfragmentintcurProgress=0;//Totrackcurrentprogress....

Listing15-18showshowtheAsyncTaskinitializestheprogressbarwhenitstarts.

Listing15-18.InitializingaProgressBar

//PartofMyLongTaskWithProgressBar.javaprivatevoidshowProgressBar(){Activityact=retainedFragment.getActivity();ProgressBarpb=(ProgressBar)act.findViewById(R.id.tpb_progressBar1);pb.setProgress(0);pb.setMax(15);pb.setVisibility(View.VISIBLE);}

Listing15-19showshowtheAsyncTasksetstheprogressontheprogressbarafterlocatingit.

Listing15-19.SettingProgressonaProgressBar

//PartofMyLongTaskWithProgressBar.javaprivatevoidsetProgressOnProgressBar(inti){this.curProgress=i;ProgressBarpbar=getProgressBar();if(pbar==null){

Page 389: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.d(tag,"Activityisnotavailabletosetprogress");return;}pbar.setProgress(i);}

ThemethodgetProgressBar()thatlocatestheactivityisquitesimple;youjustusethefind()methodtolocatetheProgressBarview.Iftheactivityisnotavailableduetodevicerotation,theProgressBarreferencewillbenullandwewillignoresettingtheprogress.Listing15-20showshowtheAsyncTaskclosestheprogressbar.

Listing15-20.ClosingtheProgressBaronAsyncTaskCompletion

//PartofMyLongTaskWithProgressBar.javaprivatevoidcloseProgressBar(){ProgressBarpbar=getProgressBar();if(pbar==null){Log.d(tag,"Sorryprogressbarisnulltocloseit!");return;}//Dismissthedialogpbar.setVisibility(View.GONE);detachFromParent();}

OncetheProgresBarisremovedfromtheview,thecodeinListing15-20informstheretainedfragmentthatitcanletgooftheAsyncTaskpointershoulditbeholdingit.Dependingonhowtheretainedfragmentholdsthispointer,thisstepmayormaynotbeneeded.Butitisagoodpracticetotelltheparentitnolongerneedstoholdontoareferencethatitdoesn’tneedanymore.So,Listing15-21showshowtheAsyncTaskinformstheparentthatitnolongerneedstoholdapointertotheAsyncTask.

Listing15-21.InformingClients,LiketheRetainedFragment,oftheCompletionofAsyncTask

//TotellthecalledobjectthatI,theAsyncTask,havefinished//TheActivityorretainedfragmentcanactasaclienttothisAsyncTask//AsyncTaskisimaginedtobeaWorkerObjectandhenceunderstandstheIWorkerObjectClient

//MyLongTaskWithProgressBarimplementsIWorkerObject//AsyncTesterFragmentimplementstheIWorkerObjectClient

//CodebelowistakenfromMyLongTaskWithProgressBar.java//ThisimplementstheIWorkerObjectcontract

Page 390: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IWorkerObjectClientclient=null;intworkerObjectPassbackIdentifier=-1;

publicvoidregisterClient(IWorkerObjectClientwoc,intinWorkerObjectPassbackIdentifier){client=woc;this.workerObjectPassbackIdentifier=inWorkerObjectPassbackIdentifier;}privatevoiddetachFromParent(){if(client==null){Log.e(tag,"Youhavefailedtoregisteraclient.");return;}//clientisavailableclient.done(this,workerObjectPassbackIdentifier);}

AddressingKeyDifferenceswiththeProgressBarSolutionTherearesomeunexpecteddifferencesyoumustbeawareofwhenweuseaprogressbarinsteadofaprogressdialog.

Initially,inthelayoutfile,visibilityoftheprogressbarissettoGONEsothatitrepresentsthestatethattheAsyncTaskhasnotevenstarted.OncetheAsyncTaskstartsitwillsetthevisibilitytoVISIBLEandsubsequentlysettheprogressasitgoesalong.However,whentheactivityisre-created,thestatemanagementoftheactivityrequiresthatthecontrolisvisiblecomingoutoftheonCreate()method.BecauseinthelayoutthevisibilityissettobeGONE,theactivitywillnotrestoretheprogressbarstateandyouwillnotseetheprogressbarwhenthedeviceisrotated.Becauseofthis,theAsyncTaskneedstotakeoverthecontrolofthisprogressbarstatemanagementandreinitializeitproperlywhentheactivityisreattached.Listing15-22showshowwedothisintheAsyncTaskcode.

Listing15-22.ManagingtheProgressBarStatefromtheAsyncTask

//TakenfromMyLongTaskWithProgressBar.java//OnactivitystartpublicvoidonStart(Activityact){//dismissdialogifneededif(bDoneFlag==true){Log.d(tag,"OnmystartInoticeIwasdoneearlier");closeProgressBar();return;}Log.d(tag,"Iamreattached.Iamnotdone");setProgressBarRightOnReattach();

Page 391: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}privatevoidsetProgressBarRightOnReattach(){ProgressBarpb=getProgressBar();pb.setMax(15);pb.setProgress(curProgress);pb.setVisibility(View.VISIBLE);}

TheonStart()methodinListing15-22iscalledbytheretainedfragmentontheAsyncTaskwhentheactivityisreattachedtotheretainedfragmentandthefragmentdetectsthattheactivity’sUIisreadytobeused.

Anotherdifferencewhenusingaprogressbaristhebehaviorofthebackbutton.Unlikeaprogressdialog,fortheactivity,youmaywanttoallowthebackbutton.Asthebackbuttoncompletelyremovestheactivity,youmaywanttotakethisopportunitytocancelthetask.ThereleaseResources()methodinListing15-23iscalledbytheretainedfragmentwhenitdetectsthattheactivityisnotgoingtobebackbymonitoringtheisFinishing()flagintheonDestroy()method.

Listing15-23.CancellingtheAsyncTaskonActivityBack

//TakenfromMyLongTaskWithProgressBar.javapublicvoidreleaseResources(){cancel(true);//cancelthetaskdetachFromParent();//removemyself}

AllthreesolutionsoutlinedinthislatterpartofthechapterwillworktocorrectlyshowtheprogressofanAsyncTask.TheSDK-recommendedapproachistousetheProgressBarastherightUIcomponenttodisplaytheprogress.Ourpreferenceforquicktasksthattakejustasecondortwoistousetheprogressbarsaswell.Forataskthattakesalittlelonger—andyoudon’twanttheusertodisturbthestateoftheUI—thenusetheProgressDialoginconjunctionwithaheadlessretainedfragment.Whenyoursolutionsrequireadeephierarchyofobjects,thenuseoftheADOframeworkcouldcomehandyirrespectiveofwhetheryouusethemthroughretainedfragmentsorthroughtheretainedobjects.YoucanseeallofthesolutionsoutlinedherefullyimplementedinthedownloadableprojectProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.zip.

TherearefurtherconsiderationsiftheAsyncTaskweredoingupdatesandchangingstate.Ifthatisthecase,youmaywanttouseabackgroundservicesothatitcanberestartediftheprocessistobereclaimedandrestartedlater.Theapproachespresentedhereareadequateforquick-tomedium-levelreadsasyouareexpectingtheusertowait.However,forlonger-timereadsorwrites,youmaywanttoadaptaservice-basedsolution.

References

Page 392: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thefollowingreferenceswillhelpyoulearnmoreaboutthetopicsdiscussedinthischapter:

http://developer.android.com/reference/android/os/AsyncTask.htmlAkeyresourcethatdefinitivelydocumentsthebehaviorofAsyncTask.

http://www.shanekirk.com/2012/04/asynctask-missteps/:Anotherlookatawell-behavedAsyncTask.

http://www.androidbook.com/item/3536:ResearchnotesonAsyncTaskthatwegatheredinpreparingthischapter.

http://www.androidbook.com/item/3537:AndroidusesJavagenericsofteninitsAPI.ThisURLdocumentsafewbasicsonJavagenericstogetyoustarted.

http://www.androidbook.com/fragments:Asthischapterhasdemonstrated,toworkwithanAsyncTaskauthoritativelyyouneedtoknowalotaboutactivitylifecycle,fragments,theirlifecycle,headlessfragments,configurationchanges,fragmentdialogs,AsyncTask,ADOs,andmore.ThisURLhasanumberofarticlesfocusingonalltheseareas.

http://www.androidbook.com/item/4660:ADOisanabstractionthatoneofourauthorsespousedasahandytooltodealwithconfigurationchange.ThisURLdocumentswhatADOsareandhowtheycouldbeused,anditalsoprovidesapreliminaryimplementation.

http://www.androidbook.com/item/4674:ThisURLdocumentsthebackground,helpfulURLs,codesnippets,andhelpfulhintstoworkwithaProgressBar.

http://www.androidbook.com/item/4680:ThisURLhasagoodbitofresearchonactivitylifecycleintheeventofconfigurationchanges.

http://www.androidbook.com/item/4665:Itisquitehardtowriteprogramsthatworkwellwhendevicesrotate.ThisURLoutlinessomebasictestcasesyoumustsuccessfullyrunforvalidatingAsyncTask.

http://www.androidbook.com/item/4673:ThisURLsuggestsanenhancedpatternforconstructinginheritedfragments.

http://www.androidbook.com/item/4629:Thebestwaytounderstandafragment,includingaretainedfragment,istostudyitscallbacksdiligently.ThisURLprovidesdocumentedsamplecodeforalltheimportantcallbacksofafragment.

Page 393: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

http://www.androidbook.com/item/4668:Thebestwaytounderstandanactivitylifecycleisstudyitscallbacksdiligently.ThisURLprovidesdocumentedsamplecodeforalltheimportantactivitycallbacks.

http://www.androidbook.com/item/3634:ThisURLoutlinesourresearchonfragmentdialogs.

http://www.androidbook.com/proandroid5/projects:AlistofdownloadableprojectsfromthisbookisatthisURL.Forthischapter,lookforazipfilenamedProAndroid5_Ch15_TestAsyncTask.zipandalsoProAndroid5_Ch15_TestAsyncTaskWithConfigChanges.Thelatterzipfileistheonethatimplementsthethreeproposedsolutionsforawell-behavedAsyncTask.

SummaryInthischapter,inadditiontocoveringAsyncTask,wehaveintroducedyoutoprogressdialogs,progressbars,headlessretainedfragments,andADOs.Readingthischapter,younotonlyunderstoodAsyncTaskbutalsogottoapplyyourunderstandingofactivitylifecycleandadeepunderstandingoffragments.Wehavealsodocumentedasetofkeytestcasesthatmustbesatisfiedforawell-behavedAndroidapplication.

Page 394: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter16

BroadcastReceiversandLong-RunningServicesAbroadcastreceiverisanothercomponentinanAndroidprocess,alongwithactivities,contentproviders,andservices.Abroadcastreceiverisacomponentthatcanrespondtoabroadcastmessagesentbyaclient.Thismessageismodeledasanintent.Further,abroadcastmessage(intent)canberespondedtobymorethanonereceiver.

AclientcomponentsuchasanactivityoraserviceusesthesendBroadcast(intent)method,availableontheContextclass,tosendabroadcast.ReceivingcomponentsofthebroadcastintentwillneedtoinheritfromaBroadcastReceiverclassavailableintheAndroidSDK.Thesebroadcastreceiversneedtoberegisteredinthemanifestfilethroughareceivercomponenttagtoindicatethatthereceiverisinterestedinrespondingtoacertaintypeofbroadcastintent.

SendingaBroadcastListing16-1showssamplecodethatsendsabroadcastevent.Thiscodecreatesanintentwithauniqueintentactionstring,putsanextrafieldcalledmessageonit,andcallsthesendBroadcast()method.Puttingtheextraontheintentisoptional.

Listing16-1.BroadcastinganIntent

//Thiscodeisinclass:TestBCRActivity.java//Project:TestBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zipprivatevoidtestSendBroadcast(Activityactivity){//CreateanintentwithauniqueactionstringStringuniqueActionString="com.androidbook.intents.testbc";IntentbroadcastIntent=newIntent(uniqueActionString);

//Allowstandalonecross-processesthathavebroadcastreceivers//inthemtobestartedeventhoughtheyareinstoppedstate.broadcastIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);

broadcastIntent.putExtra("message","Helloworld");activity.sendBroadcast(broadcastIntent);}

Page 395: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

InListing16-1,theactionisanarbitraryidentifierthatsuitsyourneeds.Tomakethisactionstringunique,youmaywanttouseanamespacesimilartoaJavapackage.Also,wewilltalkaboutthecross-processFLAG_INCLUDE_STOPPED_PACKAGESlaterinthischapterinthesectioncalled“Out-of-ProcessReceivers.”

CodingaSimpleReceiverListing16-2showsabroadcastreceiverthatcanrespondtothebroadcastedintentfromListing16-1.

Listing16-2.SampleBroadcastReceiverCode

//ThisclassisinTestBroadcastReceiverprojectinthedownload//Thedownloadforthischapteris:ProAndroid5_Ch16_TestReceivers.zippublicclassTestReceiverextendsBroadcastReceiver{privatestaticfinalStringtag="TestReceiver";@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.d("TestReceiver","intent="+intent);Stringmessage=intent.getStringExtra("message");Log.d(tag,message);}}

Creatingabroadcastreceiverisquitesimple.ExtendtheBroadcastReceiverclassandoverridetheonReceive()method.Weareabletoseetheintentinthereceiverandextractthemessagefromit.Nextweneedtoregisterthebroadcastreceiverinthemanifestfileasareceiver.

RegisteringaReceiverintheManifestFileListing16-3showshowyoucandeclareareceiverastherecipientoftheintentwhoseactioniscom.androidbook.intents.testbc.

Listing16-3.AReceiverDefinitionintheManifestFile

<!--Infilename:AndroidManifest.xmlProject:TestBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zip--><manifest><application>...

Page 396: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<activity>...</activity>...<receiverandroid:name=".TestReceiver"><intent-filter><actionandroid:name="com.androidbook.intents.testbc"/></intent-filter></receiver>...</application></manifest>

Thereceiverelementisachildnodeoftheapplicationelementliketheothercomponentnodessuchasanactivity.

Withthereceiver(Listing16-2)anditsregistrationinthemanifestfile(Listing16-3)available,youcaninvokethereceiverusingtheclientcodeinListing16-1.WehaveincludedareferencetothedownloadableZIPfileProAndroid5_Ch16_TestReceivers.zipforthischapterattheendofthischapter.ThisZIPfilehastwoprojects.ThecodereferencedsofarisintheprojectTestBroadcastReceiver.

AccommodatingMultipleReceiversTheideaofabroadcastisthattherecouldbemorethanonereceiver.Let’sreplicateTestReceiver(seeListing16-2)asTestReceiver2andseeifbothcanrespondtothesamebroadcastmessage.ThecodeforTestReceiver2ispresentedinListing16-4.

Listing16-4.SourcecodeforTestReceiver2

//Filename:TestReceiver2.java//Project:TestBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicclassTestReceiver2extendsBroadcastReceiver{privatestaticfinalStringtag="TestReceiver2";@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.d(tag,"intent="+intent);Stringmessage=intent.getStringExtra("message");Log.d(tag,message);}}

AddthisreceivertoyourmanifestfileasshowninListing16-5.

Listing16-5.TestReceiver2DefinitionintheManifestFile

Page 397: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<!--Infilename:AndroidManifest.xmlProject:TestBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zip--><receiverandroid:name=".TestReceiver2"><intent-filter><actionandroid:name="com.androidbook.intents.testbc"/></intent-filter></receiver>

Now,ifyoufireofftheeventasinListing16-1,bothreceiverswillbecalled.

WehaveindicatedinChapter13thatthemainthreadrunsallthebroadcastreceiversthatbelongtoasingleprocess.Youcanprovethisbyprintingoutthethreadsignatureineachofthereceivers,includingthemainlineinvokingcode.Youwillseethesamethreadrunningthroughthiscodesequentially.ThesendBroadcast()queuesthebroadcastmessageandletsthemainthreadgetbacktoitsqueue.Responsetothisqueuedmessagebyareceiveriscarriedoutbythesamemainthreadinorder.Whentherearemultiplereceivers,itisnotgooddesigntorelyontheorderofexecutionastowhichreceiverisinvokedfirst.

WorkingwithOut-of-ProcessReceiversTheintentionofabroadcastismorelikelythattheprocessrespondingtoitisanunknownoneandseparatefromtheclientprocess.Youcanprovethisbyreplicatingoneofyourreceiverspresentedsofarandcreatingaseparate.apkfilefromit.ThenwhenyoufireofftheeventfromListing16-1,youwillseethatboththein-processreceivers(thosethatareinthesameprojector.apkfile)andout-of-processreceivers(thosethatareinaseparate.apkfile)areinvoked.YouwillalsoseethroughtheLogCatmessagesthatthein-processandout-of-processreceiversrunintheirrespectivemainthreads.

However,afterAPI12(Android3.1)therearesomewrinklesaroundbroadcastreceiversthatareinexternalprocesses.ThisisduetothelaunchmodeladaptedbytheSDKforsecurityconcerns.Youcanreadaboutthismoreinoneofthereferencelinksprovidedforthischapter.Withthischangeanapplicationwheninstalledwillbeinastoppedstate.Intentsthatcanstartcomponentscannowspecifytotargetthoseapplicationsthatareonlyinstartedstate.Bydefaulttheoldbehaviorpersists.However,forbroadcastintentsthesystemautomaticallyaddsaflagtoexcludeapplicationsthatareinstoppedstate.Toovercomethepreviouspoint,onecanexplicitlysetanintentflagonthebroadcastintenttoincludethosestoppedapplicationsasvalidtargets.ThisiswhatyouseeincodeListing16-1.

Wehaveincludedanadditionalseparatestand-aloneprojectcalledStandaloneBroadcastReceiverinthechapter’sdownloadableZIPfileProAndroid5_Ch16_TestReceivers.ziptotestthisconcept.Totryit,youhave

Page 398: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

todeployboththeinvokingprojectTestBroadcastReceiverandthestand-alonereceiver’sprojectStandloneBroadcastReceiverontheemulator.YoucanthenusetheTestBroadcastReceiverprojecttosendthebroadcasteventandmonitortheLogCatforthereceiversrespondingfromtheStandaloneBroadcastReceiver.

UsingNotificationsfromaReceiverBroadcastreceiversoftenneedtocommunicatetotheuseraboutsomethingthathappenedorasastatus.Thisisusuallydonebyalertingtheuserthroughanotificationiconinthesystem-widenotificationbar.Wewillnowshowyouhowtocreateanotificationfromabroadcastreceiver,sendit,andviewitthroughthenotificationmanager.

MonitoringNotificationsThroughtheNotificationManagerAndroidshowsiconsofnotificationsasalertsinthenotificationarea.ThenotificationareaislocatedatthetopofdeviceinastripthatlookslikeFigure16-1.ThelookandplacementofthenotificationareamaychangebasedonwhetherthedeviceisatabletoraphoneandmayattimesalsochangebasedonAndroidrelease.

Figure16-1.Androidnotificationiconstatusbar

ThenotificationareashowninFigure16-1iscalledthestatusbar.Itcontainssystemindicatorssuchasbatterystrength,signalstrength,andsoon.Whenwedeliveranotification,thenotificationwillappearasaniconintheareashowninFigure16-1.ThenotificationiconisillustratedinFigure16-2.

Figure16-2.Statusbarshowinganotificationicon

Thenotificationiconisanindicatortotheuserthatsomethingneedstobeobserved.Toseethefullnotification,youhavetoholdafingerontheiconanddragthetitlestripshowninFigure16-2downlikeacurtain.Thiswillexpandthenotificationarea,asshowninFigure16-3.

Page 399: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure16-3.Expandednotificationview

IntheexpandedviewofthenotificationinFigure16-3,yougettoseethedetailssuppliedtothenotification.Youcanclickthenotificationdetailtofireofftheintenttobringupthefullapplicationtowhichthenotificationbelongs.Youcanusethisviewtoclearnotifications.Alsodependingonthedeviceandreleasetheremaybealternatewaysofopeningthenotifications.Let’sseenowhowtogenerateanotificationiconliketheoneshowninFigures16-2and16-3.

SendingaNotificationWhenyoucreateanotificationobject,itneedstohavethefollowingelements:

Anicontodisplay

Page 400: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Tickertextlike“helloworld”

Thetimewhenitisdelivered

Onceyouhaveanotificationobjectconstructed,yougetthenotificationmanagerreferencebyaskingthecontextforasystemservicenamedContext.NOTIFICATION_SERVICE.Thenyouaskthenotificationmanagertosendthenotification.Listing16-6hasthesourcecodeforabroadcastreceiverthatsendsthenotificationshowninFigures16-2and16-2.

Listing16-6.AReceiverThatSendsaNotification

//Filename:NotificationReceiver.java//Project:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicclassNotificationReceiverextendsBroadcastReceiver{privatestaticfinalStringtag="NotificationReceiver";@OverridepublicvoidonReceive(Contextcontext,Intentintent){

Log.d(tag,"intent="+intent);Stringmessage=intent.getStringExtra("message");Log.d(tag,message);this.sendNotification(context,message);}privatevoidsendNotification(Contextctx,Stringmessage){//Getthenotificationmanager

Stringns=Context.NOTIFICATION_SERVICE;NotificationManagernm=(NotificationManager)ctx.getSystemService(ns);//PrepareNotificationObjectDetails

inticon=R.drawable.robot;CharSequencetickerText="Hello";longwhen=System.currentTimeMillis();//Gettheintenttofirewhenthenotificationisselected

Intentintent=newIntent(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.google.com"));PendingIntentpi=PendingIntent.getActivity(ctx,0,intent,0);//Createthenotificationobjectthroughthebuilder

Notificationnotification=newNotification.Builder(ctx).setContentTitle("title").setContentText(tickerText).setSmallIcon(icon).setWhen(when).setContentIntent(pi)

Page 401: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

.setContentInfo("AddtionalInformation:ContentInfo").build();//Sendnotification

//Thefirstargumentisauniqueidforthisnotification.//Thisidallowsyoutocancelthenotificationlater//Thisidalsoallowsyoutoupdateyournotification//bycreatinganewnotificationandresendingitagainstthatid//Thisidisuniquewithinthisapplicationnm.notify(1,notification);}}

Thecontentviewofanotificationisdisplayedwhenthenotificationisexpanded.ThisiswhatyouseeinFigure16-2.ThecontentviewneedstobeaRemoteViewsobject.However,wedon’tpassacontentviewdirectly.BasedontheparameterspassedtotheBuilderobject,theBuilderobjectcreatesanappropriateRemoteViewsobjectandsetsitonthenotification.TheBuilderinterfacealsohasamethodtodirectlysetthecontentviewasawholeifneeded.

Thestepsfordirectlyusingremoteviewsforacontentviewofanotificationareasfollows:

1. Createalayoutfile.

2. CreateaRemoteViewsobjectusingthepackagenameandthelayoutfileID.

3. CallsetContent()ontheNotification.Builderobjectbeforecallingthebuild()methodtocreatethenotificationobject,whichisthensenttothenotificationmanager.

Keepinmindthatonlyalimitedsetofcontrolsmayparticipateinaremoteview,suchasFrameLayout,LinearLayout,RelativeLayout,AnalogClock,Button,Chronometer,ImageButton,ImageView,ProgressBar,TextView.

ThecodeinListing16-6createsanotificationusingtheBuilderobjecttosettheimplicitcontentview(throughtitleandtext)andtheintenttofire(inourcase,thisintentisthebrowserintent).AnewnotificationcanbecreatedtoberesentthroughthenotificationmanagerinordertoupdatethepreviousinstanceofitusingtheuniqueIDofthenotification.TheIDofthenotification,whichissetto1inListing16-6,isuniquewithinthisapplicationcontext.Thisuniquenessallowsustocontinuouslyupdatewhatishappeningtothatnotificationandalsocancelitifneeded.

Youmayalsowanttolookatthevariousflagsavailablewhilecreatinganotification,suchasFLAG_NO_CLEARandFLAG_ONGOING_EVENT,tocontrolthepersistenceofthesenotifications.YoucanusethefollowingURLtochecktheseflags:

Page 402: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

http://developer.android.com/reference/android/app/Notification.html

StartinganActivityinaBroadcastReceiverAlthoughyou’readvisedtousethenotificationmanagerwhenauserneedstobeinformed,Androiddoesallowyoutospawnanactivityexplicitly.YoucandothisbyusingtheusualstartActivity()methodbutwiththefollowingflagsaddedtotheintentthatisusedastheargumenttothestartActivity():

Intent.FLAG_ACTIVITY_NEW_TASK

Intent.FLAG_FROM_BACKGROUND

Intent.FLAG_ACTIVITY_SINGLE_TOP

ExploringLong-RunningReceiversandServicesSofar,wehavecoveredthehappypathofbroadcastreceiverswheretheexecutionofabroadcastreceiverisunlikelytotakemorethan10seconds.Theproblemspaceisabitcomplicatedifwewanttoperformtasksthattakelongerthan10seconds.

Tounderstandwhy,let’sreviewafewfactsaboutbroadcastreceivers:

Abroadcastreceiver,likeothercomponentsofanAndroidprocess,runsonthemainthread.HenceholdingupthecodeinabroadcastreceiverwillholdupthemainthreadandwillresultinANR.Thetimelimitonabroadcastreceiveris10secondscomparedto5secondsforanactivity.Itisabitofareprieve,butnotverymuch.

Theprocesshostingthebroadcastreceiverwillstartandterminatealongwiththebroadcastreceiverexecution.Hencetheprocesswillnotstickaroundafterthebroadcastreceiver’sonReceive()methodreturns.Ofcourse,thisisassumingthattheprocesscontainsonlythebroadcastreceiver.Iftheprocesscontainsothercomponents,suchasactivitiesorservices,thatarealreadyrunning,thenthelifetimeoftheprocesstakesthesecomponentlifecyclesintoaccountaswell.

Unlikeaserviceprocess,abroadcastreceiverprocesswillnotgetrestarted.

Ifabroadcastreceiverweretostartaseparatethreadandreturntothemainthread,Androidwillassumethattheworkiscompleteandwillshutdowntheprocesseveniftherearethreadsrunning,bringingthosethreadstoanabruptstop.

Androidautomaticallyacquiresapartialwakelockwheninvokinga

Page 403: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

broadcastserviceandreleasesitwhenitreturnsfromtheserviceinthemainthread.AwakelockisamechanismandanAPIclassavailableintheSDKtokeepthedevicefromgoingtosleeportowakeitupifitisalreadyasleep.

Giventhesepredicates,howcanweexecutelonger-runningcodeinresponsetoabroadcastevent?

UnderstandingLong-RunningBroadcastReceiverProtocolTheanswerliesinresolvingthefollowing:

WewillclearlyneedaseparatethreadsothatthemainthreadcangetbackandavoidANRmessages.

TostopAndroidfromkillingtheprocessandhencetheworkerthread,weneedtotellAndroidthatthisprocesscontainsacomponent,suchasaservice,withalifecycle.Soweneedtocreateorstartthatservice.Theserviceitselfcannotdirectlydotheworkformorethan5secondsbecausethathappensonthemainthread,sotheserviceneedstostartaworkerthreadandletthemainthreadgo.

Forthedurationoftheworkerthread’sexecution,weneedtoholdontothepartialwakelocksothatthedevicewon’tgotosleep.Apartialwakelockwillallowthedevicetoruncodewithoutturningonthescreenandsoon,whichallowsforlongerbatterylife.

Thepartialwakelockmustbeobtainedinthemainlinecodeofthereceiver;otherwise,itwillbetoolate.Forexample,youcannotdothisintheservice,becauseitmaybetoolatebetweenthestartService()beingissuedbythebroadcastreceiverandtheonStartCommand()ofaservicethatbeginsexecution.

Becausewearecreatingaservice,theserviceitselfcanbebroughtdownandbroughtbackupbecauseoflow-memoryconditions.Ifthishappens,weneedtoacquirethewakelockagain.

WhentheworkerthreadstartedbytheonStartCommand()methodoftheservicecompletesitswork,itneedstotelltheservicetostopsothatitcanbeputtobedandnotbroughtbacktolifebyAndroid.

Itisalsopossiblethatmorethanonebroadcasteventcanoccur.Giventhat,weneedtobecautiousabouthowmanyworkerthreadsweneedtospawn.

Giventhesefacts,therecommendedprotocolforextendingthelifeofabroadcastreceiverisasfollows:

Page 404: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

1. Geta(static)partialwakelockintheonReceive()methodofthebroadcastreceiver.Thepartialwakelockneedstobestatictoallowcommunicationbetweenthebroadcastreceiverandtheservice.Thereisnootherwayofpassingareferenceofthewakelocktotheservice,astheserviceisinvokedthroughadefaultconstructorthattakesnoparameters.

2. Startalocalservicesothattheprocesswon’tbekilled.

3. Intheservice,startaworkerthreadtodothework.DonotdotheworkintheonStart()methodoftheservice.Ifyoudo,youarebasicallyholdingupthemainthreadagain.

4. Whentheworkerthreadisdone,telltheservicetostopitselfeitherdirectlyorthroughahandler.

5. Havetheserviceturnoffthestaticwakelock.

UnderstandingIntentServiceRecognizingtheneedforaservicetonotholdupthemainthread,AndroidhasprovidedautilitylocalserviceimplementationcalledIntentServicetooffloadworktoaworkerthreadsothatthemainthreadcanbereleasedafterschedulingtheworktothesubthread.Underthisscheme,whenyoucallstartService()onanIntentService,theIntentServicewillqueuethatrequesttoasubthreadusingalooperandahandlersothataderivedmethodoftheIntentServiceiscalledtodotheactualworkonasingleworkerthread.

HereiswhattheAPIdocumentationforIntentServicesays:

IntentService is a base class for Services that handle asynchronous requests(expressed as Intents) on demand. Clients send requests throughstartService(Intent)calls;theserviceisstartedasneeded,handleseachIntentinturnusingaworkerthread,andstopsitselfwhenitrunsoutofwork.This“workqueue processor” pattern is commonly used to offload tasks from anapplication'smainthread.TheIntentServiceclassexiststosimplifythispatternand takecareof themechanics.Touse it, extend IntentServiceand implementonHandleIntent(Intent). IntentServicewill receive the Intents, launchaworkerthread,andstoptheserviceasappropriate.Allrequestsarehandledonasingleworker thread—they may take as long as necessary (and will not block theapplication'smainloop),butonlyonerequestwillbeprocessedatatime.

ThisideaisdemonstratedusingasimpleexampleinListing16-7.YouextendtheIntentServiceandprovidewhatyouwanttodointheonHandleIntent()method.

Listing16-7.UsingIntentService

//YoucanseefileTest30SecBCRService.javaforexample//Project:StandaloneBroadcastReceiver,Download:

Page 405: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ProAndroid5_Ch16_TestReceivers.zippublicclassMyServiceextendsIntentService{publicMyService(){super("some-java-package-like-name-used-for-debugging");}protectedvoidonHandleIntent(Intentintent){//logthreadsignatureifyouwanttoseethatitisrunningonaseparatethread//Ex:Utils.logThreadSignature("MyService");//dotheworkinthissubthread//andreturn}}

Onceyouhaveaservicelikethis,youcanregisterthisserviceinthemanifestfileanduseclientcodetoinvokethisserviceascontext.startService(newIntent(context,MyService.class)).ThiswillresultinacalltoonHandleIntent()inListing16-7.YouwillnoticethatifyouweretousethecommentedoutmethodUtils.logThreadSignature()inListing16-7inyouractualcode,itwillprinttheIDoftheworkerthreadandnotthemainthread.YoucanseetheUtilsclassintheprojectanddownloadreferenceslistedinthecommentssectionofListing16-7.

ExtendingIntentServiceforaBroadcastReceiverFromtheperspectiveofabroadcastreceiver,anIntentServiceisawonderfulthing.Itletsusexecutelong-runningcodewithoutblockingthemainthread.Notonlythat,beingaservice,anIntentServiceprovidesaprocessthatkeepsrunningwhenthebroadcastcodereturns.SocanweusetheIntentServicefortheneedsofalong-runningoperation?Yesandno.

Yes,becausetheIntentServicedoestwothings:First,itkeepstheprocessrunningbecauseitisaservice.Second,itletsthemainthreadgoandavoidsrelatedANRmessages.

Tounderstandthe“no”answer,youneedtounderstandwakelocksabitmore.Whenabroadcastreceiverisinvokedthroughanalarmmanager,thedevicemaynotbeon.Sothealarmmanagerpartiallyturnsonthedevice(justenoughtorunthecodewithoutanyUI)bymakingacalltothepowermanagerandrequestingawakelock.Thewakelockgetsreleasedassoonasthebroadcastreceiverreturns.

ThisleavestheIntentServiceinvocationwithoutawakelock,sothedevicemaygotosleepbeforetheactualcoderuns.However,IntentService,beingageneral-purposeextensiontoaservice,itdoesnotacquireawakelock.Soweneedfurtherprops

Page 406: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ontopofanIntentService.Weneedanabstraction.

MarkMurphyhascreatedavariantoftheIntentServicecalledWakefulIntentServicethatkeepsthesemanticsofusinganIntentServicebutalsoacquiresthewakelockandreleasesitproperlyunderavarietyofconditions.Youcanlookathisimplementationathttp://github.com/commonsguy/cwac-wakeful.

ExploringLong-RunningBroadcastServiceAbstractionWakefulIntentServiceisagoodabstraction.However,wewanttogoastepfurthersothatourabstractionparallelsthemethodofextendingIntentServiceasinListing16-7anddoeseverythingthatanIntentServicedoesbutalsoprovidesfewmorebenefits:

PasstheoriginalintentthatwaspassedtothebroadcastreceivertotheoverriddenmethodonHandleIntent.Thisallowsustolargelyhidethebroadcastreceiver,simulatingaprogrammingexperiencethataserviceisstartedinresponsetoabroadcastmessage.Thisisreallythegoalforthisabstractionwhilesomeextrasarethrownin.

Acquireandreleasewakelocks(similartoWakefulIntentService).

Dealwithaservicebeingrestarted.

Allowauniformwaytodealwiththewakelockformultiplereceiversandmultipleservicesinthesameprocess.

WewillcallthisabstractclassALongRunningNonStickyBroadcastService.Asthenamesuggests,wewantthisservicetoallowforlong-runningwork.Itwillalsobespecificallybuiltforabroadcastreceiver.Thisservicewillalsobenonsticky(wewillexplainthisconceptlaterinthechapter,butbriefly,thisindicatesthatAndroidwillnotstarttheserviceiftherearenomessagesinthequeue).ToallowforthebehaviorofanIntentService,itwillextendtheIntentServiceandoverridetheonHandleIntentmethod.

Combiningtheseideas,theabstractALongRunningNonStickyBroadcastServiceservicewillhaveasignaturethatlookslikeListing16-8.

Listing16-8.Long-RunningServiceAbstractIdea

publicabstractclassALongRunningNonStickyBroadcastServiceextendsIntentService{//...otherimplementationdetails

Page 407: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//thefollowingmethodwillbecalledbytheonHandleIntentofIntentService//thisiswheretheactualworkhappensinthisderivedabstractclassprotectedabstractvoidhandleBroadcastIntent(IntentbroadcastIntent);

//...otherimplementationdetails

}

TheimplementationdetailsforthisALongRunningNonStickyBroadcastServiceareatouchinvolved,andwewillcoverthemsoonafterweexplainwhywearegoingafterthistypeofservice.Wewanttodemonstratefirsttheutilityandsimplicityofhavingit.

OncewehavethisabstractclassofListing16-8,theMyServiceexampleinListing16-7canberewrittenasinListing16-9.

Listing16-9.Long-RunningServiceSampleUsage

publicclassMyServiceextendsALongRunningNonStickyBroadcastService{//..otherimplementationdetailsprotectedvoidhandleBroadcastIntent(IntentbroadcastIntent){//Youcanusethefollowingmethodtoseewhichthreadrunsthiscode//Utils.logThreadSignature("MyService");//dotheworkhere//andreturn}//..otherimplementationdetails}

ThesimplicityofListing16-9isthatthiscodeisinvokedassoonasaclientfiresoffabroadcastintent.Especiallythefactthatyouarereceivingdirectly,unmodified,thesameintentthatinvokedthebroadcastreceiver.Itisasifthebroadcastreceiverhasdisappearedfromthesolution.

Asyoucansee,youcanextendthisnewlong-runningserviceclass(justlikeIntentServiceandWakefulIntentService)andoverrideasinglemethodanddoverylittletonothinginthebroadcastreceiver.Yourworkwillbedoneinaworkerthread(thankstoIntentService)withoutblockingthemainthread.

Listing16-9isasimpleexampledemonstratingtheconcept.Let’sturntoamorecompleteimplementationthatimplementsalong-runningservicethatcanrunfor60secondsinresponsetoabroadcastevent(provingthatwecanrunformorethan10secondsandavoidanANRmessage).WewillcallthisserviceappropriatelyTest60SecBCRService(BCRstandsforbroadcastreceiver),anditsimplementationisshowninListing16-10.

Listing16-10.SourcecodeforTest60SecBCRService

Page 408: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Filename:Test30SecBCRService.java//Project:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicclassTest60SecBCRServiceextendsALongRunningNonStickyBroadcastService{publicstaticStringtag="Test60SecBCRService";//RequiredbyIntentServicetopasstheclassnamefordebugneedspublicTest60SecBCRService(){super("com.androidbook.service.Test60SecBCRService");}/*Performlong-runningoperationsinthismethod.*Thisisexecutedinaseparatethread.*/@OverrideprotectedvoidhandleBroadcastIntent(IntentbroadcastIntent){//UtilsclassisinthedownloadprojectmentionedUtils.logThreadSignature(tag);Log.d(tag,"Sleepingfor60secs");//Usethethreadtosleepfor60secondsUtils.sleepForInSecs(60);Stringmessage=broadcastIntent.getStringExtra("message");Log.d(tag,"Jobcompleted");Log.d(tag,message);}}

Asyoucansee,thiscodesuccessfullysimulatesdoingworkfor60secondsandstillavoidstheANRmessage.TheutilitymethodsinListing16-10areself-explanatoryandavailableinthedownloadprojectsforthischapter.TheprojectnameanddownloadfilenameareinthecommentssectionofthecodeinListing16-10.

DesigningALong-RunningReceiverOncewehavethelong-runningserviceinListing16-10,weneedtobeabletoinvoketheservicefromabroadcastreceiver.Againwearegoingafteranabstractiontohidethebroadcastreceiverasmuchaspossible.

Thefirstgoalofalong-runningbroadcastreceiveristodelegatetheworktothelong-runningservice.Todothis,thelong-runningreceiverwillneedtheclassnameofthelong-runningservicetoinvokeit.Thesecondgoalistoacquireawakelock.Thethirdgoalistotransfertheoriginalintentthatthebroadcastreceiverisinvokedontotheservice.WewilldothisbystickingtheoriginalintentasaParcelableintheintentextras.Wewilluseoriginal_intentasthenameforthisextra.Thelong-runningservicethenextractsoriginal_intentandpassesittotheoverriddenmethodofthelong-runningservice

Page 409: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(youwillseethislaterintheimplementationofthelong-runningservice).Thisfacilitythusgivestheimpressionthatthelong-runningserviceisindeedanextensionofthebroadcastreceiver.

Letusabstractoutthesethreethingsandprovideabaseclass.Theonlybitofinformationthislong-runningreceiverabstractionneedsisthenameofthelong-runningserviceclass(LRSClass)throughanabstractmethodcalledgetLRSClass().

Puttingtheseneedstogether,sourcecodefortheimplementationoftheabstractclassALongRunningReceiverisinListing16-11.

Listing16-11.ALongRunningReceiverAbstraction

//Filename:ALongRunningReceiver.java//Project:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicabstractclassALongRunningReceiverextendsBroadcastReceiver{privatestaticfinalStringtag="ALongRunningReceiver";@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.d(tag,"Receiverstarted");//LightedGreenRoomabstractstheAndroidWakeLock//tokeepthedevicepartiallyon.//Inshortthisisequivalenttoturningon//oracquiringthewakelock.LightedGreenRoom.setup(context);startService(context,intent);Log.d(tag,"Receiverfinished");}privatevoidstartService(Contextcontext,Intentintent){IntentserviceIntent=newIntent(context,getLRSClass());serviceIntent.putExtra("original_intent",intent);context.startService(serviceIntent);}/**Overridethismethodtoreturnthe*"class"objectbelongingtothe*nonstickyserviceclass.*/publicabstractClassgetLRSClass();}

Intheprecedingbroadcastreceivercode,youseereferencestoaclasscalledLightedGreenRoom.Thisisawrapperaroundastaticwakelock.Inadditiontobeingawakelock,thisclasstriestocatertoworkingwithmultiplereceivers,multipleservices,

Page 410: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

etc.,sothatallwaki-nessisproperlycoordinated.Forthepurposeofunderstanding,youcantreatitasifitisastaticwakelock.ThisabstractioniscalledaLightedGreenRoombecauseitisaimedatsavingpowerforthedevicelikethevarious“green”movements.Furthermoreitiscalled“Lighted”becauseitstartsoffbeing“lighted”firstasthebroadcastreceiverturnsitonassoonasitiskickedoff.Thelastservicetouseitwillturnitoff.

Oncethereceiverabstractionisavailable,you’llneedareceiverthatworkshandinhandwiththe60-secondlong-runningserviceinListing16-11.SuchareceiverisprovidedinListing16-12.

Listing16-12.ASampleLong-RunningBroadcastReceiver,Test60SecBCR

//Filename:Test60SecBCR.java//Project:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicclassTest60SecBCRextendsALongRunningReceiver{@OverridepublicClassgetLRSClass(){Utils.logThreadSignature("Test60SecBCR");returnTest60SecBCRService.class;}}

JustliketheserviceabstractioninListings16-10and16-11,thecodeinListing16-12usesanabstractionforthebroadcastreceiver.ThereceiverabstractionstartstheserviceindicatedbytheserviceclassreturnedbythegetLRSClass()method.

Thusfar,wehavedemonstratedwhyweneededthetwoimportantabstractionstoimplementlong-runningservicesinvokedbybroadcastreceivers:

ALongRunningNonStickyBroadcastService(Listing16-8)

ALongRunningReceiver(Listing16-11)

AbstractingaWakeLockwithLightedGreenRoomAsmentionedearlier,theprimarypurposeoftheLightedGreenRoomabstractionistosimplifytheinteractionwiththewakelock,andawakelockisusedtokeepthedeviceonduringbackgroundprocessing.Youreallydon’tneedthedetailsoftheimplementationoftheLightedGreenRoom,butmerelyitsinterfaceandthecallsthataremadeagainstit.JustkeepinmindthatitisathinwrapperaroundtheAndroidSDKwakelock.Initssimplestimplementation,itcanjustbeassimpleasturningthewakelockon(acquire)andoff(release).Listing16-13showshowawakelockisusedtypicallyasstatedintheSDK.

Listing16-13.PsuedocodeforworkingwiththeWakeLockAPI

//Getaccesstothepowermanagerservice

Page 411: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PowerManagerpm=

(PowerManager)inCtx.getSystemService(Context.POWER_SERVICE);

//GetholdofawakelockPowerManager.WakeLockwl=pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,tag);

//Acquirethewakelockwl.acquire();

//dosomework//whilethisworkisbeingdonethedevicewillbeonpartially

//releasetheWakelockwl.release();

Giventhisinteraction,thebroadcastreceiverissupposedacquirethelock,andwhenthelong-runningserviceisfinished,itneedstoreleasethelock.Assaidearlierthereisnogoodwaytopassthewakelockvariabletotheservicefromthebroadcastreceiver.Theonlywaytheserviceknowsaboutthiswakelockistouseastaticorapplication-levelvariable.

Anotherdifficultyinacquiringandreleasingawakelockisthereferencecount.Asabroadcastreceiverisinvokedmultipletimes,iftheinvocationsoverlap,therearegoingtobemultiplecallstoacquirethewakelock.Similarly,therearegoingtobemultiplecallstorelease.Ifthenumberofacquireandreleasecallsdon’tmatch,wewillendupwithawakelockthatatworstkeepsthedeviceonforfarlongerthanneeded.Also,whentheserviceisnolongerneededandthegarbagecollectionruns,ifthewakelockcountsaremismatched,therewillbearuntimeexceptionintheLogCat.TheseissueshavepromptedustodoourbesttoabstractthewakelockasaLightedGreenRoomtoensureproperusage.Therewillbeoneoftheseobjectsperprocessthatkeepsawakelockandensuresitisturnedonandoffproperly.Theincludedprojecthasanimplementationforthisclass.Ifyoufindthatcodetoocomplicatedduetothenumberofconditionsittakesintoaccount,youcanjuststartwithasimplestaticvariableandturnitonandoffastheservicestartsandclosesandrefineittosuityourparticularconditions.

Areasonableapproachforthebroadcastreceiverandtheservicetocommunicatewitheachotheristhroughastaticvariable.InsteadofmakingWakeLockstatic,wehavemadetheentireLightedGreenRoomastaticinstance.However,everyothervariableinsideLightedGreenRoomstayslocalandnonstatic.

EverypublicmethodofLightedGreenRoomisalsoexposedasastaticmethodforconvenience.Wehaveusedtheconventionofnamingthesemethodsstartingwith“s_”.Youcanchoose,instead,togetridofthestaticmethodsanddirectlycallthesingleobjectinstanceofLightedGreenRoom.

Page 412: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ImplementingaLong-RunningServiceTopresentthelong-runningserviceabstraction,wehavetotakeonemoredetourtoexplainthelifetimeofaserviceandhowitrelatestotheimplementationofonStartCommand.Thisisthemethodthatisultimatelyresponsibleforstartingtheworkerthreadandthesemanticsofaservice.

WhenaserviceisstartedthroughstartService,theservicegetscreatedfirst,anditsonStartCommandmethodiscalled.Androidhasprovisionstokeepthisprocessinmemorysothattheservicecanbecompletedevenwhenservingmultipleincomingclientrequests.However,underdemandingmemoryconditions,AndroidmaychoosetoreclaimtheprocessandcalltheonDestroy()methodoftheservice.

NoteAndroidtriestocalltheonDestroy()methodforaservicetoreclaimitsresourceswhentheserviceisnotexecutingitsonCreate(),onStart(),oronDestroy()method,orinotherwordswhentheserviceisidle.

However,unlikeanactivitythatisshutdown,aserviceisscheduledtorestartagainwhenresourcesareavailableiftherearependingstartServiceintentsinthequeue.TheservicewillbewokenupandthenextintentdeliveredtoitviaonStartCommand().Ofcourse,onCreate()willbecalledwhentheserviceisbroughtback.

Becauseservicesareautomaticallyrestartediftheyarenotexplicitlystopped,itisreasonabletothinkthat,unlikeactivitiesandothercomponents,aservicecomponentisfundamentallyastickycomponent.

UnderstandingaNonstickyServiceAservicewillnotbeautomaticallyrestartedifaclientexplicitlycallsstopService.Dependingonhowmanyclientsarestillconnected,thisstopServicemethodcanmovetheserviceintoastoppedstate,atwhichtimetheservice’sonDestroymethodiscalledandtheservicelifecycleiscomplete.Onceaservicehasbeenstoppedlikethisbyitslastclient,theservicewillnotbebroughtback.

Thisprotocolworkswellwheneverythinghappensasperdesign,wherestartandstopmethodsarecalledandexecutedinsequenceandwithoutamiss.PriortoAndroid2.0,deviceshaveseenalotofserviceshangingaroundandclaimingresourceseventhoughtherewasnoworktobedone,meaningAndroidbroughttheservicesbackintomemoryeventhoughtherewerenomessagesinthequeue.ThiswouldhavehappenedwhenstopServicewasnotinvokedeitherbecauseofanexceptionorbecausetheprocesswastakenoutbetweenonStartCommandandstopService.

Android2.0introducedasolutionsothatwecanindicatetothesystem,iftherearenopendingintents,thatitshouldn’tbotherrestartingtheservice.Thisisdonebyreturningthenonstickyflag(Service.START_NOT_STICKY)fromonStartCommand.

However,nonstickyisnotreallythatnonsticky.Evenifwemarktheserviceasnonsticky,

Page 413: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

iftherearependingintents,Androidwillbringtheservicebacktolife.Thissettingappliesonlywhentherearenopendingintents.

UnderstandingaStickyServiceWhatdoesitmeanforaservicetobereallystickythen?Thestickyflag(Service.START_STICKY)meansthatAndroidshouldrestarttheserviceeveniftherearenopendingintents.Whentheserviceisrestarted,callonCreateandonStartCommandwithanullintent.Thiswillgivetheserviceanopportunity,ifneedbe,tocallstopSelfifthatisappropriate.Theimplicationisthataservicethatisstickyneedstodealwithnullintentsonrestarts.

UnderstandingRedeliverIntentsOptionLocalservicesinparticularfollowapatternwhereonStartandstopSelfarecalledinpairs.AclientcallsonStart.Theservice,whenitfinishesthatwork,callsstopSelf.Ifaservicetakes,say,30minutestocompleteatask,itwillnotcallstopSelffor30minutes.Meanwhile,theserviceisreclaimedduetolow-memoryconditionsandhigher-priorityjobs.Ifweusethenonstickyflag,theservicewillnotwakeup,andwewouldneverhavecalledstopSelf.

Manytimes,thisisOK.However,ifyouwanttomakesurewhetherthesetwocallshappenforsure,youcantellAndroidnottounqueuethestarteventuntilstopSelfiscalled.Thisensuresthatwhentheserviceisreclaimed,thereisalwaysapendingeventunlessthestopSelfiscalled.Thisiscalledredelivermode,anditcanbeindicatedinreplytotheonStartCommandmethodbyreturningtheService.START_REDELIVER_INTENTflag.

CodingaLong-RunningServiceNowthatyouhavethebackgroundonIntentService,service-startflags,andthelightedgreenroom,we’rereadytotakealookatthelong-runningserviceinListing16-14.

Listing16-14.ALong-RunningServiceAbstraction

//Filename:ALongRunningNonStickyBroadcastService.java//Project:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zippublicabstractclassALongRunningNonStickyBroadcastServiceextendsIntentService{publicstaticStringtag="ALongRunningBroadcastService";//Thisiswhatyouoverridetodoyourwork

protectedabstractvoidhandleBroadcastIntent(IntentbroadcastIntent);

Page 414: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicALongRunningNonStickyBroadcastService(Stringname){super(name);}/**Thismethodcanbeinvokedundertwocircumstances*1.Whenabroadcastreceiverissuesa"startService"*2.whenandroidrestartsthisserviceduetopending"startService"intents.**Incase1,thebroadcastreceiverhasalready*setupthe"lightedgreenroom"andtherebygottenthewakelock**Incase2,weneedtodothesame.*/@OverridepublicvoidonCreate(){super.onCreate();

//Setupthegreenroom//Thesetupiscapableofgettingcalledmultipletimes.LightedGreenRoom.setup(this.getApplicationContext());

//Itispossiblethatmorethanoneserviceofthistypeisrunning.//Knowingthenumberwillallowustocleanupthewakelocksinondestroy.LightedGreenRoom.s_registerClient();}@OverridepublicintonStartCommand(Intentintent,intflag,intstartId){//CalltheIntentService"onstart"super.onStart(intent,startId);

//TellthegreenroomthereisavisitorLightedGreenRoom.s_enter();

//markthisasnonsticky//Means:Don'trestarttheserviceifthereareno//pendingintents.returnService.START_NOT_STICKY;}/*

Page 415: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

*NotethatthismethodcallrunsinasecondarythreadsetupbytheIntentService.**OverridethismethodfromIntentService.*Retrievetheoriginalbroadcastintent.*Callthederivedclasstohandlethebroadcastintent.*finallytellthelightedroomthatyouareleaving.*ifthisisthelastvisitorthenthelock*willbereleased.*/@OverridefinalprotectedvoidonHandleIntent(Intentintent){try{IntentbroadcastIntent=intent.getParcelableExtra("original_intent");handleBroadcastIntent(broadcastIntent);}finally{//releasethewakelockifyouarethelastoneLightedGreenRoom.s_leave();}}/*IfAndroidreclaimsthisprocess,thismethodwillreleasethelock*irrespectiveofhowmanyvisitorsthereare.*/@OverridepublicvoidonDestroy(){super.onDestroy();//Doanycleanup,ifneeded,whenaservicenolongerneedsawakelockLightedGreenRoom.s_unRegisterClient();}}

ThisclassextendsIntentServiceandgetsallthebenefitsofaworkerthreadassetupbyIntentService.Inaddition,itspecializestheIntentServicefurthersothatitissetupasanonstickyservice.Fromadeveloper’sperspective,theprimarymethodtofocusonistheabstracthandleBroadcastIntent()method.Listing16-15showsyouhowtosetupthereceiverandthecorrespondingserviceinthemanifestfile.

Listing16-15.TheLong-RunningReceiverandServiceDefinition

<!--Infilename:AndroidManifest.xmlProject:StandaloneBroadcastReceiver,Download:ProAndroid5_Ch16_TestReceivers.zip

Page 416: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

--><manifest…>......<application….><receiverandroid:name=".Test60SecBCR"><intent-filter><actionandroid:name="com.androidbook.intents.testbc"/></intent-filter></receiver><serviceandroid:name=".Test60SecBCRService"/></application>.....<uses-permissionandroid:name="android.permission.WAKE_LOCK"/></manifest>

Noticethatyouwillneedthewakelockpermissiontorunthislong-runningreceiverabstraction.Completesourcecodeforallofthereceiversandlong-runningservicesisavailableinthedownloadableprojectsforthischapter.Listing16-15bringsouttheessenceofthelong-runningservicesinvokedbyabroadcastreceiver.ThisabstractionstatesthatyouwriteacoupleoflinestocreateareceiverliketheTest60SecBCR(Listing16-12),andthenwriteajavamethodsimilartotheoneincodeTest60SecBCRService(Listing16-10).Giventhereceiverandthejavamethodthatyouwanttorunforalongtime,youcanexecutethatmethodinresponsetothebroadcastevent.ThisabstractionensuresthatthemethodthencanrunaslongasittakeswithoutproducinganARM.Theabstractiontakescareofa)keepingtheprocessalive,b)callingtheservice,c)takingcareofthewakelock,andd)transferringthebroadcastintenttotheservice.Intheendthisabstractionsimulates“callingamethodthatcanexecutewithouttimelimits”fromabroadcastevent.

AdditionalTopicsinBroadcastReceiversDuetospacelimitations,wearenotabletocoverallaspectsofbroadcastreceiversinthisbook.Onetopicwehaven’tcoveredatallisthesecurityopportunitiesavailabletorestrictbothsendingandreceivingbroadcasts.Youcanusetheexportattributeonareceivertoallowwhetheritcanbeinvokedfromexternalprocessesornot.Youcanalsoenableordisableareceivereitherthroughthemanifestfileorprogrammatically.WehavealsonotcoveredamethodcalledsendOrderBroadcastthatfacilitatescallingbroadcastreceiversinanorderincludingchainingthem.YoucanreadupontheseaspectsfromthemainAPIdocsfortheBroadcastReceiverclass.

Furthermore,inversion4oftheAndroidsupportlibrarySDKthereisaclasscalledLocalBroadcastManagerthatisusedtooptimizecallstobroadcastreceiversthatarestrictlylocal.Beinglocal,allsecuritylimitationsneednotbeconsidered.AspertheSDK,thereisalsosystem-leveloptimizationforwhenthisclassisused.

Page 417: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Alsoinversion4oftheAndroidsupportlibrarySDK,thereisaclasscalledWakefulBroadcastReceiverthatencapsulatessomeofthesameconceptsthatwehavecoveredforlong-runningserviceneeds.

ReferencesHerearehelpfulreferencestothetopicsthatarecoveredinthischapter:

http://developer.android.com/reference/android/content/BroadcastReceiver.htmlTheBroadcastReceiverAPI.YouwillfindatthislinkmoreaboutorderedbroadcastsandabouttheBroadcastReceiverlifecycle.Thisisanexcellentresource.

http://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.htmlAndroidAPIreference.

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.htmlAndroidAPIreference.

http://developer.android.com/reference/android/app/Service.htmlTheServiceAPI.Thisreferenceisespeciallygoodtohavewhileworkingwithlong-runningservices.

http://developer.android.com/reference/android/app/NotificationManager.htmlTheNotificationManagerAPI.

http://developer.android.com/reference/android/app/Notification.htmlTheNotificationAPI.Youwillseeherethevariousoptionsavailableforworkingwithanotification,suchascontentviewsandsoundeffects.

http://developer.android.com/reference/android/widget/RemoteViews.htmlTheRemoteViewsAPI.RemoteViewsareusedtoconstructcustomdetailedviewsofnotifications.

http://www.androidbook.com/item/3514:Authors’researchonlong-runningservices.

http://www.androidbook.com/item/3482:Authors’researchonbroadcastreceivers.Thisnotealsoexplainshowtostartanactivityfromareceiver.

http://www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsfromthisbook.Forthischapter,lookforaZIPfilenamedProAndroid5_Ch16_TestReceivers.zip.ThisZIPfilehastwoprojects:TestBroadcastReceiverandStandaloneBroadcastReceiver.Thelatterisdependentontheformer,soinstalltheminthatorder.Thesourcecodesnippetsin

Page 418: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thischapterareannotatedwiththeirfilenamesandinwhatprojectstheyareavailable.

SummaryInthischapter,wehavecoveredbroadcastreceivers,notificationmanagers,andtheroleofserviceabstractioninputtingbroadcastreceiverstotheirbestuse.Wealsohavegivenapracticalabstractiontosimulatelongrunningbroadcastservicesoutofbroadcastreceivers.

Page 419: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter17

ExploringtheAlarmManagerInAndroidanintentobjectisusedtostartaUIactivity,abackgroundservice,orabroadcastreceiver.Normallytheseintentsaretriggeredbyuseractions.InAndroidyoucanalsousealarmstotriggerbroadcastintents,mindyou,onlybroadcastintents.Theinvokedbroadcastreceiversthencanchoosetostartanactivityoraservice.

InthischapteryouwilllearnaboutthealarmmanagerAPI.AlarmmanagerAPIisusedtoscheduleabroadcastintenttogooffataparticulartime.Wewillrefertothisprocessofschedulingabroadcastintentataparticulartimeassettinganalarm.

Wewillalsoshowyouhowtoschedulealarmsthatrepeatatregularintervals.Wewillshowyouhowtocancelalarmsthatarealreadyset.

Whenanintentobjectisstoredtobeusedatalatertime,itiscalledapendingintent.Asalarmmanagersusependingintentsallthetimeyouwillgettoseetheusageandintricaciesofpendingintentsaswellinthischapter.

SettingUpaSimpleAlarmWewillstartthechapterwithsettinganalarmataparticulartimeandhavingitcallabroadcastreceiver.Oncethebroadcastreceiverisinvoked,youcanusetheinformationfromChapter16toperformbothsimpleandlong-runningoperationsinthatbroadcastreceiver.

GettingaccesstothealarmmanagerissimpleandisshowninListing17-1.

Listing17-1.GettingAccesstoanAlarmManager

//Infilename:SendAlarmOnceTester.javaAlarmManageram=(AlarmManager)

anyContextObject.getSystemService(Context.ALARM_SERVICE);

ThevariableanyContextObjectreferstoacontextobject.Forexample,ifyouareinvokingthiscodefromanactivitymenu,thecontextvariablewillbetheactivity.Tosetthealarmforaparticulardateandtime,youwillneedaninstanceintimeidentifiedbyaJavaCalendarobject.Listing17-2showsautilityfunctionthatgivesyouacalendarobjectforsomespecifiedtimeinstantafterthecurrenttime.

Listing17-2.AFewUsefulCalendarUtilities

//Infilename:Utils.javapublicclassUtils{publicstaticCalendargetTimeAfterInSecs(intsecs){

Page 420: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Calendarcal=Calendar.getInstance();cal.add(Calendar.SECOND,secs);returncal;}}

Inthedownloadableprojectforthischapter,youwillseelotmorecalendar-basedutilitiestoarriveatatimeinstanceinanumberofways.Now,weneedareceivertosetagainstthealarmthatweareplanningtoset.AsimplereceiverisshowninListing17-3.

Listing17-3.TestReceivertoTestAlarmBroadcasts

//Infilename:TestReceiver.javapublicclassTestReceiverextendsBroadcastReceiver{privatestaticfinalStringtag="TestReceiver";@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.d(tag,"intent="+intent);Stringmessage=intent.getStringExtra("message");Log.d(tag,message);}}

Youwillneedtoregisterthisreceiverinthemanifestfileusingthe<receiver>tag,asshowninListing17-4.ReceiversarecoveredindetailinChapter16.

Listing17-4.RegisteringaBroadcastReceiver

<!--Infilename:AndroidManifest.xml--><receiverandroid:name=".TestReceiver"/>

InAndroidanalarmisreallyabroadcastintentthatisscheduledforalatertime.Whatreceivercomponentthisintentshouldinvokeisexplicitly(throughitsclassname)specifiedintheintent.Listing17-5showsanintentthatcanbeusedtoinvokethebroadcastreceiverthatwehadinListing17-3.

Listing17-5.CreatinganIntentPointingtoTestReceiver

//Infilename:SendAlarmOnceTester.javaIntentintent=newIntent(mContext,TestReceiver.class);intent.putExtra("message","SingleShotAlarm");

Wealsohaveanopportunitytoloadtheintentwith“extras”whilecreatingthisintent.Becauseanalarmmanagerstoresanintentforalateruse,weneedtocreateapendingintentoutofthisintentofListing17-5.Listing17-6showshowtocreateapendingintentfromastandardintent.

Listing17-6.CreatingaPendingIntent

//Infilename:SendAlarmOnceTester.javaPendingIntentpendingIntent=

Page 421: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PendingIntent.getBroadcast(mContext,//context,oractivity,orservice1,//requestid,usedfordisambiguatingthisintentintent,//intenttobedelivered0);//pendingintentflags

NoticethatwehaveaskedthePendingIntentclasstoconstructapendingintentthatissuitableforabroadcastexplicitly.TheothervariationsofcreatingapendingintentarelistedinListing17-7:

Listing17-7.MultipleAPIsforCreatingaPendingIntent

//usefultostartanactivityPendingIntentactivityPendingIntent=PendingIntent.getActivity(..args..);//usefultostartaservicePendingIntentservicePendingIntent=PendingIntent.getService(..args..);

InListing17-7,argumentstothemethodsgetActivity()andgetService()aresimilartotheargumentstothegetBroadcast()methodinListing17-6.Notethatalarmsrequireabroadcastpendingintentandnotanactivitypendingintentoraservicependingintent.

Wewilldiscusstherequestidargument,whichwesetto1inListing17-6,ingreaterdetaillaterinthechapter.Briefly,itisusedtoseparatetwointentobjectsthatareequalinallotherrespects.

Pendingintentflagshavelittleornoinfluenceonthealarmmanager.Recommendationistousenoflagsatallanduse0fortheirvalues.Theseintentflagsaretypicallyusefulincontrollingthelifetimeofthependingintent.However,inthiscase,thelifetimeismaintainedbythealarmmanager.Forexample,tocancelapendingintent,youaskthealarmmanagertocancelit.

OncewehavethetimeinstanceinmillisecondsasaCalendarobjectandthependingintentpointingtothereceiver,wecansetupanalarmbycallingtheset()methodofthealarmmanager.ThisisshowninListing17-8.

Listing17-8.UsingtheAlarmManagerset()Method

//Infilename:SendAlarmOnceTester.javaCalendarcal=Utils.getTimeAfterInSecs(30);//...othercodethatgetsthependingintentetcam.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),pendingIntent);

Thefirstargumenttotheset()methodindicatesthewakeupnatureofthealarmandalsothereferenceclockthatwearegoingtobeusingforthealarm.Possiblevaluesforthis

Page 422: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

argumentareAlarmManager.RTC_WAKEUP,AlarmManager.RTC,AlarmManager.ELAPSED_REALTIME,AlarmManager.ELAPSED_REALTIME_WAKEUP.

Theelapsedwordintheseconstantsreferstothetimeinmillisecondssincethedeviceisrecentlybooted.So,itreferstothedeviceclock.TheRTCtimereferstothehumanclock/timethatyouseeonthedevicewhenyoucheckyourclockonthedevice.TheWAKEUPwordintheseconstantsreferstothenatureofthealarm,suchaswhetherthealarmshouldwakeupthedeviceorjustdeliveritatthefirstopportunitywhenthedeviceeventuallywakesup.Takentogether,theRTC_WAKEUPindicatestheuseofreal-timeclockandthedeviceshouldwakeup.TheconstantELAPSED_REALTIMEmeansusethedeviceclockanddon’twakeupthedevice;instead,deliverthealarmatthefirstopportunity.

WhenthismethodofListing17-8iscalled,thealarmmanagerwillinvoketheTestReceiverinListing17-3,30secondsafterthecalendartimewhenthemethodwascalledandalsowakesupthedeviceifitisasleep.

SettingOffanAlarmRepeatedlyLet’snowconsiderhowwecansetanalarmthatgoesofrepeatedly;seeListing17-9.

Listing17-9.SettingaRepeatingAlarm

publicvoidsendRepeatingAlarm(){Calendarcal=Utils.getTimeAfterInSecs(30);

//GetanintenttoinvokethereceiverIntentintent=newIntent(this.mContext,TestReceiver.class);intent.putExtra("message","RepeatingAlarm");

intrequestid=2;PendingIntentpi=this.getDistinctPendingIntent(intent,requestid);//Schedulethealarm!AlarmManageram=(AlarmManager)this.mContext.getSystemService(Context.ALARM_SERVICE);

am.setRepeating(AlarmManager.RTC_WAKEUP,

cal.getTimeInMillis(),5*1000,//5secsrepeatpi);}

protectedPendingIntentgetDistinctPendingIntent(Intentintent,int

requestId){

Page 423: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PendingIntentpi=PendingIntent.getBroadcast(mContext,//context,oractivityrequestId,//requestidintent,//intenttobedelivered0);returnpi;}

KeyelementsofthecodeinListing17-9arehighlighted.ArepeatingalarmissetbyinvokingthesetRepeating()methodonthealarmmanagerobject.Theprimaryinputtothismethodisapendingintentpointingtoareceiver.WehaveusedthesameintentthatwascreatedinListing17-5,theonepointingtotheTestReceiver.However,whenwemakeapendingintentoutoftheintentinListing17-5,wealtertheuniquerequestcodetoavalueof2.Ifwedon’tdothis,wewillseeabitofoddbehaviorwhichweshallexplainnow.Sayweintendtoinvokethesamereceiverthroughtwodifferentalarms:onealarmthatgoesoffonlyonceandanotheralarmthatgoesoffrepeatedly.Becausebothalarmstargetthesamereceivertheyneedtobeusinganintentthatpointstothesamereceiver.Twointentsthatpointtothesamereceiver,withoutanyotherdifferencebetweenthem,isconsideredthesameintent.So,whenwetellthealarmmanagertosetthealarmonintent1asaone-timealarmandthensetthealarmonintent2asarepeatedalarm,wemightbeundertheimpressionthattheyaretwodifferentalarms.Internally,however,bothalarmspointtothesameintentvalue,asintent1andintent2arethesameintheirvalues.Thisiswhyanalarmispracticallythesameasitsintentonwhichitisset(especiallybyvalue).Asaresult,thelateralarmoverridesthefirstalarmiftheintentsareequivalent.

Again,twointentsareconsideredthesameiftheyhavethesameaction,type,data,categories,orclass.Theextrasarenotincludedinfiguringouttheuniquenessofintents.Further,twopendingintentsareconsideredthesameiftheirunderlyingintentsarethesameandtherequestIDsmatch.BecausewecanusetherequestIDtodistinguishtwopendingintents,thecodeinListing17-8overcomesthesimilarityofsourceintentsbyusingtherequestidargument.ThisrequestidargumenttothePendingIntentAPIwillseparateonependingintentfromtheotherpendingintentwhenallelsematches.

Thisallshouldmakesenseifyouweretoseethependingintent(byvaluenotbyitsJavaobjectreference)itselfasthealarmonwhichyouaresettingdifferenttimes.

CancellinganAlarmCodeinListing17-10isusedtocancelanalarm.

Listing17-10.CancellingaRepeatingAlarm

publicvoidcancelRepeatingAlarm(){//Getanintentthatwasoriginally//usedtoinvokeTestReceiverclassIntentintent=newIntent(this.mContext,

Page 424: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TestReceiver.class);

//Tocancel,extraisnotnecessarytobefilledin//intent.putExtra("message","RepeatingAlarm");

PendingIntentpi=this.getDistinctPendingIntent(intent,2);

//Cancelthealarm!AlarmManageram=(AlarmManager)

this.mContext.getSystemService(Context.ALARM_SERVICE);am.cancel(pi);}

Tocancelanalarm,wehavetoconstructapendingintentfirstandthenpassittothealarmmanagerasanargumenttothecancel()method.However,youmustpayattentiontomakesurethatthePendingIntentisconstructedtheexactsamewaywhensettingthealarm,includingtherequestcodeandtargetedreceiver.

Inconstructingthecancelintent,youcanignoretheintentextrasfromtheoriginalintent(Listing17-10),becauseintentextrasdon’tplayaroleintheuniquenessofanintent,andhencecancellingthatintent.

UnderstandingExactnessofAlarmsPriortoAPI19,Androidfiredthealarmsascloseaspossibletothespecifiedtime.SinceAPI19,alarmsthatareclosetoeachotherarebundledforbatterylife.Ifyouneedtheolderbehavior,thereisaversionofset()methodcalledsetExact().ThereisalsoamethodcalledsetWindow()thatallowsroomforefficienciesandalsoallowsaguaranteedwindow.Similarly,themethodsetRepeating()isnowinexact.UnlikethesetExact()method,thereisnoexactversionforsetRepeating().Ifyouhavesuchaneed,youhavetousethesetExact()andrepeatityourselfmultipletimes.

UnderstandingPersistenceofAlarmsAnothernoteonalarmsisthattheyarenotsavedacrossdevicereboots.Thismeansyouwillneedtosavethealarmsettingsandpendingintentsinapersistentstoreandreregisterthembasedondevicerebootbroadcastactions,andpossiblytime-changebroadcastactions(e.g.,intent.ACTION_BOOT_COMPLETED,intent.ACTION_TIME_CHANGED,intent.ACTION_TIMEZONE_CHANGED).

References

Page 425: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thefollowingreferenceswillhelpyoulearnmoreaboutthetopicsdiscussedinthischapter:

http://developer.android.com/reference/android/app/AlarmManager.htmlThealarmmanagerAPI.Youwillseeheresignaturesformethodslikeset,setRepeating,andcancel.

http://developer.android.com/reference/android/app/PendingIntent.htmlHowtoconstructapendingintent.Don’tpaytoomuchattentiontothependingintentflags;theyarenotthatcriticaltothealarmmanager.

http://androidbook.com/item/1040:Quickexamplesandreferencesforworkingwithdateandtimeclasses.

http://androidbook.com/item/3503:Ourresearchonalarmmanagers.

http://androidbook.com/proandroid5/projects:Alistofdownloadableprojectsfromthisbook.Forthischapter,lookforaZIPfilenamedProAndroid5_Ch17_TestAlarmManager.zip.

SummaryThischapterexploredtheAlarmManagerAPI,whichyouusetosetupandcancelalarms.Thischaptershowedyouhowtoconnectanalarmtoabroadcastservice.Thischapteralsoshowedyouhowalarmsarecloselyrelatedtointents.

Page 426: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter18

Exploring2DAnimationAnimationallowsanobjectonascreentochangeitscolor,position,size,ororientationovertime.AnimationcapabilitiesinAndroidarepractical,fun,andsimple.Theyareusedfrequentlyinapplications.

Android2.3andpriorreleasessupportthreetypesofanimation:frame-by-frameanimation,whichoccurswhenaseriesofframesisdrawnoneaftertheotheratregularintervals;layoutanimation,whereyouanimatethelayoutoftheviewsinsideacontainersuchaslistsandtables;andviewanimation,inwhichanyviewcanbeanimated.Inlayoutanimationthefocusisnotanygivenviewbutthewayviewscometogethertoformthecompositelayout.Android3.0enhancedanimationbyextendingittoanyJavapropertyincludingthepropertiesofUIelements.Wewillcoverthepre-2.3featuresfirstandthencoverthe3.0featuresrightafter.Bothfeaturesareapplicablebasedonyourusecase.

ExploringFrame-by-FrameAnimationFrame-by-frameanimationiswhereaseriesofimagesareshowninsuccessionatquickintervalssothatthefinaleffectisthatofanobjectmovingorchanging.Figure18-1showsasetofcircleseachwithaballatadifferentposition.Withafewoftheseimages(whicharetheframes)youcanuseanimationtohavetheballgoingaroundthecircle.

Figure18-1.Exampleimageframesforanimation

EachcircleinFigure18-1isaseparateimage.Givetheimageabasenameofcolored_ballandstoreeightoftheseimagesinthe/res/drawablesubdirectorysothatyoucanaccessthemusingtheirresourceIDs.Thenameofeachimagewillhavethepatterncolored-ballN,whereNisthedigitrepresentingtheimagenumber.TheanimationactivityweareplanningwilllooklikeFigure18-2.

Page 427: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure18-2.Aframe-by-frameanimationtestharness

PrimarycontrolinFigure18-2istheanimationviewshowingtheballplacedonanoval/circle.Buttonatthetopisusedtostartandstoptheanimation.Thereisadebugscratchpadatthetoptologevents.Listing18-1showsthelayoutusedtocreatetheactivityinFigure18-2.

Listing18-1.XMLLayoutFilefortheFrameAnimationExample

<?xmlversion="1.0"encoding="utf-8"?><!--filename:/res/layout/frame_animations_layout.xmlDownload:ProAndroid5_ch18_TestFrameAnimation.zip--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:id="@+id/textViewId1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="DebugScratchPad"/><Buttonandroid:id="@+id/startFAButtonId"android:layout_width="fill_parent"

Page 428: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:layout_height="wrap_content"android:text="StartAnimation"/><ImageViewandroid:id="@+id/animationImage"android:layout_width="fill_parent"android:layout_height="wrap_content"/></LinearLayout>

Thefirstcontrolisthedebug-scratchtextcontrol,whichisasimpleTextView.Youthenaddabuttontostartandstoptheanimation.ThelastviewistheImageView,whichisusedtoplaytheanimation.

InAndroid,frame-by-frameanimationisimplementedthroughtheclassAnimationDrawable.ThisclassisaDrawable.Theseobjectsarecommonlyusedasbackgroundsforviews.AnimationDrawable,inadditiontobeingaDrawable,cantakealistofotherDrawableresources(likeimages)andrenderthematspecifiedintervals.TousethisAnimationDrawableclass,startwithasetofDrawableresources(forexample,asetofimages)placedinthe/res/drawablesubdirectory.YouwillthenconstructanXMLfilethatdefinestheAnimationDrawableusingalistoftheseimages(seeListing18-2).ThisXMLfileneedstobeplacedinthe/res/drawablesubdirectoryaswell.

Listing18-2.XMLFileDefiningtheListofFramestoBeAnimated

<!--filename:/res/drawable/frame_animation.xmlDownload:ProAndroid5_ch18_TestFrameAnimation.zip--><animation-listxmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot="false"><itemandroid:drawable="@drawable/colored_ball1"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball2"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball3"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball4"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball5"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball6"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball7"android:duration="50"/><itemandroid:drawable="@drawable/colored_ball8"android:duration="50"/></animation-list>

Page 429: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Eachframepointstooneofthecolored-ballimagesyouhaveassembledthroughtheirresourceIDs.Theanimation-listtaggetsconvertedintoanAnimationDrawableobjectrepresentingthecollectionofimages.YouthenneedtosetthisAnimationDrawableasabackgroundresourceforourImageViewcontrolintheactivitylayout.AssumingthatthefilenameforthisXMLfileisframe_animation.xmlandthatitresidesinthe/res/drawablesubdirectory,youcanusethefollowingcodetosettheAnimationDrawableasthebackgroundoftheImageView:

view.setBackgroundResource(R.drawable.frame_animation);//SeeListing18-3

Withthiscode,AndroidrealizesthattheresourceIDR.drawable.frame_animationisanXMLresourceandaccordinglyconstructsasuitableAnimationDrawableJavaobjectforitbeforesettingitasthebackground.Oncethisisset,youcanaccessthisAnimationDrawableobjectbydoingagetontheviewobjectlikethis:

ObjectbackgroundObject=view.getBackground();AnimationDrawablead=(AnimationDrawable)backgroundObject;

OnceyouhavetheAnimationDrawableobject,youcanuseitsstart()andstop()methodstostartandstoptheanimation.Herearetwootherimportantmethodsonthisobject:

setOneShot(boolean);addFrame(drawable,duration);

ThesetOneShot(true)methodrunstheanimationonceandthenstops.TheaddFrame()methodaddsanewframeusingaDrawableobjectandsetsitsdisplayduration.ThefunctionalityoftheaddFrame()methodresemblesthatoftheXMLtagandroid:drawableinListing18-2.Putthisalltogethertogetthecompletecodeforourframe-by-frameanimationactivityofFigure18-1.

Listing18-3.CompleteCodefortheFrame-by-FrameAnimationTestHarness

//filename:FrameAnimationActivity.java//Download:ProAndroid5_ch18_TestFrameAnimation.zippublicclassFrameAnimationActivityextendsActivity{

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.frame_animations_layout);this.setupButton();}privatevoidsetupButton(){Buttonb=(Button)this.findViewById(R.id.startFAButtonId);

Page 430: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

b.setOnClickListener(newButton.OnClickListener(){publicvoidonClick(Viewv){animate();}});}privatevoidanimate(){ImageViewimgView=(ImageView)findViewById(R.id.animationImage);imgView.setVisibility(ImageView.VISIBLE);imgView.setBackgroundResource(R.drawable.frame_animation);

AnimationDrawableframeAnimation=(AnimationDrawable)imgView.getBackground();if(frameAnimation.isRunning()){frameAnimation.stop();}else{frameAnimation.stop();frameAnimation.start();}}}//eof-class

animate()methodinListing18-3locatestheImageViewintheactivityandsetsitsbackgroundtotheAnimationDrawableidentifiedbytheresourceR.drawable.frame_animation.ThisanimationresourceIDpointstotheearlieranimationdefinitioninListing18-3.TherestofthecodeinthemethodretrievesthisAnimationDrawableobjectandcallsanimationmethodsonthatobject.InthesameListing18-3,Start/Stopbuttonissetupsothatifanimationisrunning,thebuttoncouldstopit;ifanimationisnotrunning,thebuttoncouldstartit.IfyousettheoneshotattributeintheanimationdefinitioninListing18-2totrue,theanimationstopsafteronce.

ExploringLayoutAnimationLayoutAnimationisusedtoanimatetheviewsinanAndroidlayout.YoucanusethistypeofanimationforexamplewithcommonlayoutcontrolslikeListViewandGridView.Unlikeframe-by-frameanimation,layoutanimationisnotachievedthroughrepeatingframesbutbychangingthetransformationmatrixofaview.EveryviewinAndroidhasatransformationmatrixthatmapstheviewtothescreen.Bychangingthismatrixyoucanaccomplishscaling,rotation,andmovement(translation)oftheview.Thistypeofanimationthatreliesonchangingpropertiesandredrawinganimageisreferredtoastweeninganimation.EssentiallyLayoutAnimationistweeninganimationofthetransformationmatrixoftheviewsinalayout.ALayoutAnimationthatisspecifiedonalayoutisappliedtoalltheviewsinthatlayout.

Page 431: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thesearethetweeninganimationtypesthatcanbeappliedtoalayout:

Scaleanimation:Usedtomakeaviewsmallerorlargereitheralongthexaxis,ontheyaxis,oronboth.Youcanalsospecifythepivotpointaroundwhichyouwanttheanimationtotakeplace.

Rotateanimation:Usedtorotateaviewaroundapivotpointbyacertainnumberofdegrees.

Translateanimation:Usedtomoveaviewalongthexaxisortheyaxis.

Alphaanimation:Usedtochangethetransparencyofaview.

TheseanimationsaredefinedasXMLfilesinthe/res/animsubdirectory.Listing18-4showsascaleanimationdeclaredinanXMLfile.

Listing18-4.AScaleAnimationDefinedinanXMLFileat/res/anim/scale.xml

<setxmlns:android="http://schemas.android.com/apk/res/android"android:interpolator="@android:anim/accelerate_interpolator"><scaleandroid:fromXScale="1"android:toXScale="1"android:fromYScale="0.1"android:toYScale="1.0"android:duration="500"android:pivotX="50%"android:pivotY="50%"android:startOffset="100"/></set>

ParametersintheanimationXMLshavea“from”anda“to”flavortoindicatestartandendvaluesofthatproperty.Otherpropertiesofananimationalsoincludeanimationdurationandatimeinterpolator.InterpolatorsdeterminetherateofchangeoftheanimatedargumentsuchasscaleinListing18-4duringanimation.Wewillcoverinterpolatorsshortly.XMLfileinListing18-4canbeassociatedwithalayouttoanimatethatlayout’sconstituentviews.

NoteAnimationsliketheScaleanimationinListing18-4arerepresentedasJavaclassesintheandroid.view.animationpackage.JavadocumentationfortheseclassesdescribesnotonlyJavamethodsbutalsotheallowedXMLargumentsforeachtypeofanimation.

WecanusetheListViewinFigure18-3totestanumberoflayoutanimations.Thisactivityiswhatyouseewhenyourunthesampleprojectforthischapter.ProAndroid5_ch18_TestLayoutAnimation.zip

Page 432: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure18-3.TheListViewtobeAnimated

ThelayoutforthisactivityisinListing18-5.

Listing18-5.ListViewXMLLayoutFile

<?xmlversion="1.0"encoding="utf-8"?><!--filename:/res/layout/list_layout.xmlproject:ProAndroid5_ch18_TestLayoutAnimation.zip--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><ListViewandroid:id="@+id/list_view_id"android:layout_width="fill_parent"android:layout_height="fill_parent"/></LinearLayout>

Listing18-5showsasimpleLinearLayoutwithasingleListViewinit.Theactivitycodetoshowthelayoutfrom18-5asFigure18-3isinListing18-6.

Listing18-6.Layout-AnimationActivityCode

Page 433: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//filename:LayoutAnimationActivity.java//project:ProAndroid5_ch18_TestLayoutAnimation.zippublicclassLayoutAnimationActivityextendsActivity{

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.list_layout);setupListView();}privatevoidsetupListView(){String[]listItems=newString[]{"Item1","Item2","Item3","Item4","Item5","Item6",};ArrayAdapter<String>listItemAdapter=newArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);ListViewlv=(ListView)this.findViewById(R.id.list_view_id);lv.setAdapter(listItemAdapter);}}

Let’sseenowhowtoapplyscaleanimationfromListing18-4tothisListView.TheListViewrequiresanotherXMLfilethatactsasamediatorbetweenitselfandthescaleanimationinListing18-4.ThisisbecausetheanimationsdefinedinListing18-4aregenericandapplytoanyview.Ontheotherhandalayoutisacollectionofviews.SothemediatorlayoutanimationXMLfileinListing18-7reusesthegenericanimationXMLfileandspecifiestheadditionalattributesthatareapplicabletoacollectionofviews.ThismediatorlayoutanimationXMLfileisshowninListing18-9.

Listing18-7.Layout-ControllerXMLFile

<?xmlversion="1.0"encoding="utf-8"?><!--filename:/res/anim/list_layout_controller.xml(ProAndroid5_ch18_TestLayoutAnimation.zip)--><layoutAnimationxmlns:android="http://schemas.android.com/apk/res/android"

android:delay="100%"android:animationOrder="reverse"android:animation="@anim/scale"/>

ThisXMLfileneedstobein/res/animsubdirectory.ThisXMLfilespecifiesthattheanimationinthelistshouldproceedinreverse,andtheanimationforeachitemshouldstartwitha100%delaywithrespecttothetotalanimationduration.A100%durationensuresthattheanimationofoneitemiscompletebeforetheanimationofthenextitemstarts.Youcanchangethispercentagetosuittheneedsofyouranimation.Anythingless

Page 434: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

than100%willresultinanoverlappinganimationofitems.ThismediatorXMLfilealsoreferstotheindividualanimationfile,scale.xml(Listing18-4)throughtheresourcereference@anim/scale.Listing18-8showshowtoattachtheanimationofListing18-4totheactivitylayoutofListing18-5viathemediatorofListing18-7.

Listing18-8.TheUpdatedCodeforthelist_layout.xmlFile

<?xmlversion="1.0"encoding="utf-8"?><!--filename:/res/layout/list_layout.xml(ProAndroid5_ch18_TestLayoutAnimation.zip)--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><ListViewandroid:id="@+id/list_view_id"android:persistentDrawingCache="animation|scrolling"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layoutAnimation="@anim/list_layout_controller"/></LinearLayout>

InListing18-8android:layoutAnimationisthetagthatpointstothemediatingXMLfileofListing18-7,whichinturnpointstothescale.xmlofListing18-5.InListing18-8AndroidSDKdocsrecommendsettingthepersistentDrawingCachetagonthelistviewtooptimizeforanimationandscrolling.IfyouweretoruntheapplicationProAndroid5_ch18_TestLayoutAnimation.zip,youwouldseethescaleanimationtakeeffectontheindividuallistitemsastheactivitygetsloaded.Wehavesettheanimationdurationto500mssothatscalechangecanbeobservedaseachlistitemisdrawn.

Withthissampleprogramyoucanexperimentwithdifferentanimationtypes.YoucantryalphaanimationwiththecodeinListing18-9.

Listing18-9.Thealpha.xmlFiletoTestAlphaAnimation

<?xmlversion="1.0"encoding="utf-8"?><!--file:/res/anim/alpha.xml(ProAndroid5_ch18_TestLayoutAnimation.zip)--><alphaxmlns:android="http://schemas.android.com/apk/res/android"

android:interpolator="@android:anim/accelerate_interpolator"android:fromAlpha="0.0"android:toAlpha="1.0"android:duration="1000"/>

Alphaanimationcontrolsfading(ofcolor).InListing18-9alphaanimationcolorgoes

Page 435: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

frominvisibletofullintensityin1second.Don’tforgettochangethemediatorXMLfile(seeListing18-7)topointtothenewanimationfileifyouintendtousethesamemediatorfile.

Listing18-10showsananimationthatcombinesachangeinpositionwithachangeincolorgradient.

Listing18-10.CombiningTranslateandAlphaAnimationsThroughanAnimationSet

<?xmlversion="1.0"encoding="utf-8"?><!--file:/res/anim/alpha_translate.xml(ProAndroid5_ch18_TestLayoutAnimation.zip)--><setxmlns:android="http://schemas.android.com/apk/res/android"

android:interpolator="@android:anim/accelerate_interpolator"><translateandroid:fromYDelta="-100%"android:toYDelta="0"android:duration="500"/><alphaandroid:fromAlpha="0.0"android:toAlpha="1.0"android:duration="500"/></set>

NoticetwoanimationsareintheanimationsetofListing18-10.Translateanimationwillmovethetextfromtoptobottominitscurrentlyallocateddisplayspace.Alphaanimationwillchangethecolorgradientfrominvisibletovisibleasthetextitemdescendsintoitsslot.Toseethisanimationinaction,changethelayoutAnimationmediatorXMLfilewithreferencetofilename@anim/alpha_translate.xml.Listing18-11showsthedefinitionforarotationanimation.

Listing18-11.RotateAnimationXMLFile

<!--file:/res/anim/rotate.xml(ProAndroid5_ch18_TestLayoutAnimation.zip)--><rotatexmlns:android="http://schemas.android.com/apk/res/android"

android:interpolator="@android:anim/accelerate_interpolator"android:fromDegrees="0.0"android:toDegrees="360"android:pivotX="50%"android:pivotY="50%"android:duration="500"/>

Listing18-11spinseachtextiteminthelistonefullcirclearoundthemidpointofthetextitem.Let’stalkabouttheinterpolatorsthatyouhaveseenusedintheanimationXMLfiles.

UnderstandingInterpolatorsInterpolatorstellhowapropertychangesovertimefromitsstartvaluetotheendvalue.Willthechangeoccurlinearlyorexponentially?Willthechangestartquicklyandslowdowntowardtheend?

AlphaanimationinListing18-9identifiestheinterpolatoras

Page 436: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

accelerate_interpolator.ThereisacorrespondingJavaobjectthatdefinesthebehaviorofthisinterpolator.Aswe’vespecifiedthisinterpolatorasaresourcereferenceinListing18-9,theremustbeafilecorrespondingtothe@anim/accelerate_interpolatorthatdescribeswhatthisJavaobjectisandwhatadditionalparametersitmighttake.Listing8-12showstheresourceXMLfiledefinitionpointedtobytheresourcereference@android:anim/accelerate_interpolator:

Listing18-12.AnInterpolatorDefinitionasanXMLResource

<accelerateInterpolatorxmlns:android="http://schemas.android.com/apk/res/android"factor="1"/>

YoucanseethisXMLfileinthesubdirectory/res/anim/accelerate_interpolator.xmlintherootAndroidSDKpackage.(Caution:Thisfilecouldlookdifferentlydependingontherelease.)TheaccelerateInterpolatorXMLtagcorrespondstotheJavaclassandroid.view.animation.AccelerateInterpolator.YoucanlookupthecorrespondingJavadocumentationtoseewhatXMLtagsareavailable.Thisinterpolator’sgoalistoprovideamultiplicationfactorgivenatimeintervalbasedonahyperboliccurve.ThesourcecodesnippetinListing18-13forthisinterpolatorillustratesthis.(Caution:ThiscodecouldlookdifferentdependingontheAndroidrelease.)

Listing18-13.SampleCodefromAccelerateInterpolatorintheCoreAndroidSDK

publicfloatgetInterpolation(floatinput){if(mFactor==1.0f){return(float)(input*input);}else{return(float)Math.pow(input,2*mFactor);}}

EveryinterpolatorimplementsthegetInterpolationmethoddifferently.IncaseoftheAccelerateInterpolator,iftheinterpolatorissetupintheresourcefilewithafactorof1.0,itwillreturnthesquareoftheinputateachinterval.Otherwise,itwillreturnapoweroftheinputthatisfurtherscaledbythefactoramount.Ifthefactoris1.5,youwillseeacubicfunctioninsteadofasquarefunction.

ThesupportedinterpolatorsincludeAccelerateDecelerateInterpolator,AccelerateInterpolator,CycleInterpolator,DecelerateInterpolator,LinearInterpolator,AnticipateInterpolator,AnticipateOvershootInterpolator,BounceInterpolator,andOvershootInterpolator.

Toseehowflexibletheseinterpolatorscanbe,takeaquicklookinListing18-14atthe

Page 437: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

BounceInterpolatorwhichbouncestheobject(thatis,movesitbackandforth)towardtheendoftheanimationcycle:

Listing18-14.BounceInterpolatorImplementationintheCoreAndroidSDK

publicclassBounceInterpolatorimplementsInterpolator{privatestaticfloatbounce(floatt){returnt*t*8.0f;}publicfloatgetInterpolation(floatt){t*=1.1226f;if(t<0.3535f)returnbounce(t);elseif(t<0.7408f)returnbounce(t-0.54719f)+0.7f;elseif(t<0.9644f)returnbounce(t-0.8526f)+0.9f;elsereturnbounce(t-1.0435f)+0.95f;}}

YoucanfindthebehaviorofthesevariousinterpolatorsdescribedatthefollowingURL:

http://developer.android.com/reference/android/view/animation/package-summary.html

JavadocumentationforeachoftheseclassesalsopointsouttheXMLtagsavailabletocontrolthem.

ExploringViewAnimationThroughviewanimationyoucananimateaviewbymanipulatingitstransformationmatrix.Atransformationmatrixislikealensthatprojectsaviewontothedisplay.Atransformationmatrixcanaffecttheprojectedviewsscale,size,position,andcolor.

Identitytransformationmatrixpreservestheoriginalview.Youstartwithanidentitymatrixandapplyaseriesofmathematicaltransformationsinvolvingsize,position,andorientation.Youthensetthefinalmatrixasthetransformationmatrixfortheviewyouwanttotransform.

Androidexposesthetransformationmatrixforaviewbyallowingregistrationofananimationobjectwiththatview.Theanimationobjectwillbepassedtothetransformationmatrix.

ConsiderFigure18-4asademonstrationofviewanimation.TheStartAnimationbuttonanimatesthelistviewtostartsmallinthemiddleofthescreenandgraduallyfillthefullspace.Listing18-15showstheXMLlayoutfileusedforthisactivity.

Page 438: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure18-4.AViewAnimationActivity

Listing18-15.XMLLayoutFilefortheView-AnimationActivity

<?xmlversion="1.0"encoding="utf-8"?><!--filen:at/res/layout/list_layout.xml(ProAndroid5_ch18_TestViewAnimation.zip)--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/btn_animate"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="StartAnimation"/><ListViewandroid:id="@+id/list_view_id"android:persistentDrawingCache="animation|scrolling"android:layout_width="fill_parent"android:layout_height="fill_parent"/></LinearLayout>

Page 439: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing18-16showstheactivitycodethatloadsthislayout.

Listing18-16.CodefortheView-AnimationActivity,BeforeAnimation

//filename:ViewAnimationActivity.java(ProAndroid5_ch18_TestViewAnimation.zip)publicclassViewAnimationActivityextendsActivity{

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.list_layout);setupListView();this.setupButton();}privatevoidsetupListView(){String[]listItems=newString[]{"Item1","Item2","Item3","Item4","Item5","Item6",};ArrayAdapter<String>listItemAdapter=newArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);ListViewlv=(ListView)this.findViewById(R.id.list_view_id);lv.setAdapter(listItemAdapter);}privatevoidsetupButton(){Buttonb=(Button)this.findViewById(R.id.btn_animate);b.setOnClickListener(newButton.OnClickListener(){publicvoidonClick(Viewv){//animateListView();}});}}

WiththiscodeyouwillseetheUIaslaidoutinFigure18-4.ToaddanimationtotheListViewshowninFigure18-4weneedaclassthatderivesfromandroid.view.animation.Animation.Listing18-17showsthisclass.

Listing18-17.CodefortheViewAnimationClass

//filename:ViewAnimation.javaproject:ProAndroid5_ch18_TestViewAnimation.zippublicclassViewAnimationextendsAnimation{

@Override

Page 440: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidinitialize(intwidth,intheight,intparentWidth,intparentHeight){super.initialize(width,height,parentWidth,parentHeight);setDuration(2500);setFillAfter(true);setInterpolator(newLinearInterpolator());}@OverrideprotectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){finalMatrixmatrix=t.getMatrix();matrix.setScale(interpolatedTime,interpolatedTime);}}

InListing18-7initializemethodisacallbackmethodwiththedimensionsoftheview.Animationparameterscanbeinitializedhere.Heretheanimationdurationissetto2.5seconds.WehavesettheanimationeffecttoremainintactaftertheanimationcompletesbysettingFillAftertotrue.We’vesetalinearinterpolator.Allofthesepropertiescomefromthebaseandroid.view.animation.Animationclass.

ThemainpartoftheanimationoccursintheapplyTransformationmethod.AndroidSDKcallsthismethodagainandagaintosimulateanimation.EverytimeAndroidcallsthemethod,interpolatedTimehasadifferentvalue.Thisvaluechangesfrom0to1dependingonwheretheanimationisinthe2.5-seconddurationthatyousetduringinitialization.WheninterpolatedTimeis1,theanimationisattheend.Ourgoalinthismethodistochangethetransformationmatrixthatisavailablethroughthetransformationobjectcalledt.Firstgetthematrixandchangesomethingaboutit.Whentheviewgetspainted,thenewmatrixwilltakeeffect.MethodsavailableontheMatrixobjectaredocumentedintheSDKat

http://developer.android.com/reference/android/graphics/Matrix.html

InListing18-17,thecodethatchangesthematrixis

matrix.setScale(interpolatedTime,interpolatedTime);

setScalemethodtakestwoparameters:thescalingfactorinthexdirectionandthescalingfactorintheydirection.BecauseinterpolatedTimegoesbetween0and1,youcanusethatvaluedirectlyasthescalingfactor.Atthestartoftheanimation,thescalingfactoris0inboththexandydirections.Halfwaythroughtheanimation,thisvaluewillbe0.5inbothxandydirections.Attheendofanimation,theviewwillbeatitsfullsizebecausethescalingfactorwillbe1inboththexandydirections.TheendresultofthisanimationisthattheListViewstartsouttinyandgrowstofullsize.Listing18-18showsthefunctionyouneedtoaddtheactivityclassinListing18-15andcallitfromthebuttonclick.

Page 441: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing18-18.CodefortheView-AnimationActivity,IncludingAnimation

privatevoidanimateListView(){ListViewlv=(ListView)this.findViewById(R.id.list_view_id);lv.startAnimation(newViewAnimation());}

NoteInthissectiononViewAnimationwearegoingtosuggestalternateimplementationsfortheViewAnimationclassofListing18-18.InthesuppliedprojecttherearevariationsofthisclassavailableasViewAnimation,ViewAnimation1,ViewAnimation2,andViewAnimation3.Codesnippetsinthesubsequentdiscussionswillindicateincommentswhichoftheseclassesholdthatcode.Thereisonlyonemenuiteminthesampleprojectforanimation.TotesteachvariationyouhavetoreplacetheViewAnimation()classinListing18-18withtherespectiveversionofitandreruntheprogramtoseethealteredanimation.

WhenyourunthecodewiththeViewAnimationclassasinListing18-17,youwillnoticesomethingodd.Insteadofuniformlygrowinglargerfromthemiddleofthescreen,theListViewgrowslargerfromthetop-leftcorner.Thisisbecausetheoriginformatrixoperationsisatthetop-leftcorner.Togetthedesiredeffect,youfirsthavetomovethewholeviewsothattheview’scentermatchestheanimationcenter(topleft).Then,youapplythematrixandmovetheviewbacktothepreviouscenter.TherewrittencodefromListing18-16fordoingthisisshowninListing18-19.

Listing18-19.ViewAnimationusingpreTranslateandpostTranslate

//filename:ViewAnimation1.javaproject:ProAndroid5_ch18_TestViewAnimation.zippublicclassViewAnimationextendsAnimation{

floatcenterX,centerY;publicViewAnimation(){}

@Overridepublicvoidinitialize(intwidth,intheight,intparentWidth,intparentHeight){super.initialize(width,height,parentWidth,parentHeight);centerX=width/2.0f;centerY=height/2.0f;setDuration(2500);setFillAfter(true);setInterpolator(newLinearInterpolator());}@OverrideprotectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){finalMatrixmatrix=t.getMatrix();

Page 442: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

matrix.setScale(interpolatedTime,interpolatedTime);matrix.preTranslate(-centerX,-centerY);matrix.postTranslate(centerX,centerY);}}

ThepreTranslateandpostTranslatemethodssetupamatrixbeforethescaleoperationandafterthescaleoperation.Thisisequivalenttomakingthreematrixtransformationsintandem.ConsiderthefollowingcodeinListing18-20

Listing18-20.StandardpatternforPreandPostTranslateofTransformationMatrices

matrix.setScale(interpolatedTime,interpolatedTime);matrix.preTranslate(-centerX,-centerY);matrix.postTranslate(centerX,centerY);

CodeinListing18-20isequivalentto

movetoadifferentcenterscaleitmovetotheoriginalcenter

Youwillseethispatternofpreandpostappliedoften.YoucanalsoaccomplishthisresultusingothermethodsontheMatrixclass,butthistechniqueiscommonasitissuccinct.

TheMatrixclassallowsyounotonlytoscaleaviewbutalsotomoveitaroundthroughtranslatemethodsorchangeitsorientationthroughrotatemethods.Youcanexperimentwiththesemethodsandseetheresultinganimations.Theanimationspresentedinthepreceding“LayoutAnimation”sectionareallimplementedinternallyusingthemethodsonthisMatrixclass.

UsingCameratoProvideDepthPerceptionin2DThegraphicspackageinAndroidprovidesanothertransformationmatrix–relatedfeaturethroughtheCameraclass.Thisclassprovidesdepthperceptiontoa2Dview.YoucantakeourListViewexampleandmoveitbackfromthescreenby10pixelsalongthezaxisandrotateitby30degreesaroundtheyaxis.Listing18-21isanexampleofmanipulatingthetransformationmatrixusingaCamera.

Listing18-21.UsingCameraObject

//filename:ViewAnimation2.javaproject:ProAndroid5_ch18_TestViewAnimation.zippublicclassViewAnimationextendsAnimation{

floatcenterX,centerY;Cameracamera=newCamera();publicViewAnimation(floatcx,floatcy){centerX=cx;centerY=cy;

Page 443: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}@Overridepublicvoidinitialize(intwidth,intheight,intparentWidth,intparentHeight){super.initialize(width,height,parentWidth,parentHeight);setDuration(2500);setFillAfter(true);setInterpolator(newLinearInterpolator());}@OverrideprotectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){finalMatrixmatrix=t.getMatrix();camera.save();camera.translate(0.0f,0.0f,(1300-1300.0f*interpolatedTime));camera.rotateY(360*interpolatedTime);camera.getMatrix(matrix);

matrix.preTranslate(-centerX,-centerY);matrix.postTranslate(centerX,centerY);camera.restore();}}

ThiscodeanimatestheListViewbyfirstplacingtheview1,300pixelsbackonthezaxisandthenbringingitbacktotheplanewherethezcoordinateis0.Whiledoingthis,thecodealsorotatestheviewfrom0to360degreesaroundtheyaxis.Thecamera.translate(x,y,z)methodinListing18-21tellsthecameraobjecttotranslatetheviewsuchthatwheninterpolatedTimeis0(atthebeginningoftheanimation),thezvaluewillbe1300.Astheanimationprogresses,thezvaluewillgetsmallerandsmalleruntiltheend,whentheinterpolatedTimebecomes1andthezvaluebecomes0.

Themethodcamera.rotateY(360*interpolatedTime)takesadvantageof3Drotationaroundanaxisbythecamera.Atthebeginningoftheanimation,thisvaluewillbe0.Attheendoftheanimation,itwillbe360.

Themethodcamera.getMatrix(matrix)takestheoperationsperformedontheCamerasofarandimposesthoseoperationsonthematrixthatispassedin.Oncethecodedoesthat,thematrixhasthetranslationsitneedstogettheendeffectofhavingaCamera.NowtheCameraobjectisnolongernecessarybecausethematrixhasalltheoperationsembeddedinit.Then,youdothepreandpostonthematrixtoshiftthecenterandbringitback.Attheend,yousettheCameratoitsoriginalstatethatwassavedearlier.WiththiscodeinListing18-21youwillseetheListViewarrivingfromthecenteroftheviewinaspinningmannertowardthefrontofthescreen.Asthisversion

Page 444: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ofViewAnimationtakesadditionalconstructionarguments,Listing18-22showshowtoinvokethisversionoftheAnimationView:

Listing18-22.ViewAnimationusingpreTranslateandpostTranslate

//filename:ViewAnimationActivity.java//project:ProAndroid5_ch18_TestViewAnimation.zipListViewlv=(ListView)this.findViewById(R.id.list_view_id);

floatcx=(float)(lv.getWidth()/2.0);floatcy=(float)(lv.getHeight()/2.0);lv.startAnimation(newViewAnimation(cx,cy));

Aspartofourdiscussionaboutviewanimation,weshowedyouhowtoanimateanyviewbyextendinganAnimationclassandthenapplyingittoaview.Inadditiontolettingyoumanipulatematrices(bothdirectlyandindirectlythroughaCameraclass),theAnimationclassalsoletsyoudetectvariousstagesinananimation.Wewillcoverthisnext.

ExploringtheAnimationListenerClassAndroidSDKhasalistenerinterface,AnimationListener,tomonitoranimationevents.Listing18-23demonstratestheseanimationeventsbyimplementingtheAnimationListenerinterface.

Listing18-23.AnImplementationoftheAnimationListenerInterface

//filename:ViewAnimationListener.java//project:ProAndroid5_ch18_TestViewAnimation.zippublicclassViewAnimationListenerimplementsAnimation.AnimationListener{

publicViewAnimationListener(){}publicvoidonAnimationStart(Animationanimation){Log.d("AnimationExample","onAnimationStart");}publicvoidonAnimationEnd(Animationanimation){Log.d("AnimationExample","onAnimationEnd");}publicvoidonAnimationRepeat(Animationanimation){Log.d("AnimationExample","onAnimationRepeat");}}

TheViewAnimationListenerclassinListing18-23justlogsmessages.CodeinListing18-24showshowtoattachananimationlistenertoanAnimationobject.

Listing18-24.AttachinganAnimationListenertoanAnimationObject

privatevoidanimateListView(){ListViewlv=(ListView)this.findViewById(R.id.list_view_id);

Page 445: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Initwidth,heightandassumingViewAnimationfromListing18-21ViewAnimationanimation=newViewAnimation(width,height);animation.setAnimationListener(newViewAnimationListener());lv.startAnimation(animation);}

NotesonTransformationMatricesAsyouhaveseeninthischapter,matricesarekeytotransformingviewsandanimations.Let’sexploresomekeymethodsoftheMatrixclass.

Matrix.reset():Resetsamatrixtoanidentitymatrix,whichcausesnochangetotheviewwhenapplied

Matrix.setScale(…args..):Changessize

Matrix.setTranslate(…args..):Changespositiontosimulatemovement

Matrix.setRotate(…args..):Changesorientation

Matrix.setSkew(…args..):Distortsaview

Thelastfourmethodshaveinputparameters.

Youcanmultiplymatricestogethertocompoundtheeffectofindividualtransformations.InListing18-25,considerthreematrices,m1,m2,andm3,whichareidentitymatrices:

Listing18-25.ViewAnimationusingpreTranslateandpostTranslate

m1.setScale(..scaleargs..);m2.setTranslate(..translateargs..)m3.setConcat(m1,m2)

Transformingaviewbym1andthentransformingtheresultingviewwithm2isequivalenttotransformingthesameviewbym3.Notethatm3.setConcat(m1,m2)isdifferentfromm3.setConcat(m2,m1).setConcat(matrix1,matrix2)multipliestwomatricesinthatgivenorder.

YouhavealreadyseenthepatternusedbythepreTranslateandpostTranslatemethodstoaffectmatrixtransformation.Infact,preandpostmethodsarenotuniquetotranslate,andyouhaveversionsofpreandpostforeveryoneofthesettransformationmethods.Ultimately,apreTranslatesuchasm1.preTranslate(m2)isequivalentto

m1.setConcat(m2,m1)

Inasimilarmanner,themethodm1.postTranslate(m2)isequivalentto

Page 446: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

m1.setConcat(m1,m2)

ConsiderthecodeinListing18-26

Listing18-26.PreandPostTranslatePattern

matrix.setScale(interpolatedTime,interpolatedTime);matrix.preTranslate(-centerX,-centerY);matrix.postTranslate(centerX,centerY);

ThecodeinthisListing18-26isequivalenttothecodeinListing18-27

Listing18-27.EquivalenceofPreandPostTranslatePattern

MatrixmatrixPreTranslate=newMatrix();matrixPreTranslate.setTranslate(-centerX,-centerY);

MatrixmatrixPostTranslate=newMatrix();matrixPostTranslate.setTranslate(centerX,centerY);

matrix.setConcat(matrixPreTranslate,matrix);matrix.setConcat(matrix,matrixPostTranslate);

ExploringPropertyAnimations:TheNewAnimationAPITheanimationAPIisoverhauledin3.0and4.0ofAndroid.Thisnewapproachtoanimationsiscalledpropertyanimation.ThepropertyanimationAPIisextensiveanddifferentenoughtorefertothepreviousanimationAPI(priorto3.x)asthelegacyAPIeventhoughthepreviousapproachisstillvalidandnotdeprecated.TheoldanimationAPIisinthepackageandroid.view.animation.ThenewanimationAPIisinthepackageandroid.animation.KeyconceptsinthenewpropertyanimationAPIare:

Animators

Valueanimators

Objectanimators

Animatorsets

Animatorbuilders

Animationlisteners

Propertyvalueholders

Typeevaluators

Viewpropertyanimators

Layouttransitions

Page 447: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AnimatorsdefinedinXMLfiles

Wewillcovermostoftheseconceptsintherestofthechapter.

UnderstandingPropertyAnimationThepropertyanimationapproachchangesthevalueofapropertyovertime.Thispropertycanbeanything,suchasastand-aloneinteger,afloat,oraspecificpropertyofanobjectsuchasaview.Forexample,youcanchangeanintvaluefrom10to200overatimeperiodof5secondsbyusingananimatorclasscalledValueAnimator(seeListing18-28).

Listing18-28.ASimpleValueAnimator

//file:TestBasicValueEvaluator.java(ProAndroid5_ch18_TestPropertyAnimation.zip)//Defineananimatortochangeanintvaluefrom10to200

ValueAnimatoranim=ValueAnimator.ofInt(10,200);

//setthedurationfortheanimationanim.setDuration(5000);//5seconds,default300ms

//Provideacallbacktomonitorthechangingvalueanim.addUpdateListener(newValueAnimator.AnimatorUpdateListener(){publicvoidonAnimationUpdate(ValueAnimatoranimation){Integervalue=(Integer)animation.getAnimatedValue();//thiscodegetscalledmanymanytimesfor5seconds.//Thevaluewillrangefrom10to200}});anim.start();

Theideaiseasytograsp.AValueAnimatorisamechanismtodosomethingevery10ms(thisisthedefaultframerate).Althoughthisisthedefaultframerate,dependingonthesystemloadyoumaynotgetcalledthatmanytimes.Fortheexamplegivenwecouldexpecttogetcalled500timesoveraspanof5seconds.Onanemulatorourtestsshowthatitmaybeasfewas10times.Howeverthelastcallwillbeclosetothe5-secondduration.

Inthecorrespondingcallbackthatiscalledforeveryframe(every10ms),youcanchoosetoupdateavieworanyotheraspecttoaffectanimation.InadditiontotheonAnimationUpdate,otherusefulcallbacksareavailableonthegeneralpurposeAnimator.AnimatorListenerinterface(Listing18-28)fromtheAndroidSDK

Page 448: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

whichcanbeattachedtotheValueAnimatorthroughitsbaseclassAnimator.SoonaValueAnimator,youcandoaddListener(Animator.AnimatorListenerlistener).SeeListing18-29.

Listing18-29.AnimatorListenerCallbackInterface

publicstaticinterfaceAnimator.AnimatorListener{abstractvoidonAnimationStart(Animatoranimation);abstractvoidonAnimationRepeat(Animatoranimation);abstractvoidonAnimationCancel(Animatoranimation);abstractvoidonAnimationEnd(Animatoranimation);}

YoucanusethesecallbacksinListing18-29tofurtheractonobjectsofinterestduringorafterananimation.

PropertyAnimationreliesontheavailabilityofanandroid.os.Looperonthethreadthatisinitiatingtheanimation.ThisisgenerallythecasefortheUIthread.ThecallbackshappenontheUIthreadaswellwhentheanimatingthreadisthemainthread.

AsyouuseValueAnimatorsandtheirlisteners,keepinmindthelifetimeoftheseobjects.EvenifyouletthereferenceofaValueAnimatorgofromyourlocalscope,theValueAnimatorwillliveonuntilitfinishestheanimation.IfyouweretoaddalistenerthenallthereferencesthatthelistenerholdsarealsovalidforthelifetimeoftheValueAnimator.

PlanningaTestBedforPropertyAnimationStartingwiththebasicideaofvalueanimators,Androidprovidesanumberofderivedwaystoanimateanyarbitraryobject,especiallyviews.Todemonstratethesemechanisms,wewilltakeasimpletextviewinalinearlayoutandanimateitsalphaproperty(simulatingtransparencyanimation)andalsothexandypositions(simulatingmovement).WewilluseFigure18-5asananchortoexplainpropertyanimationconcepts.

Page 449: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure18-5.ActivitytodemonstratePropertyanimations

EachbuttoninFigure18-5usesaseparatemechanismtoanimatethetextviewatthebottomofthefigure.Themechanismswewilldemonstrateareasfollows:

Button1:Usingobjectanimators,fadeoutandfadeinaviewalternativelyattheclickofabutton.

Button2:UsinganAnimatorSet,runafade-outanimationfollowedbyfade-inanimationinasequentialmanner.

Button3:UseanAnimatiorSetBuilderobjecttotiemultipleanimationstogetherina“before,”“after,”or“with”relationship.Usethisapproachtorunthesameanimationasbutton2.

Button4:DefineanXMLfileforbutton2’ssequenceanimationandattachittothetextviewforthesameanimationaffect.

Page 450: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Button5:UsingaPropertyValuesHolderobject,animatemultiplepropertiesofthetextviewinthesameanimation.Wewillchangethexandyvaluestomovethetextviewfrombottomrighttotopleft.

Button6:UseViewPropertyAnimatortomovethetextviewfrombottomrighttotopleft(sameanimationasbutton5).

Button7:UseaTypeEvaluatoroncustompointobjectstomovethetextviewfrombottomrighttotopleft(sameanimationasbutton5).

Button8:Usekeyframestoaffectmovementandalsoalphachangesonthetextview(sameanimationasbutton5,butstaggered).

ConstructingtheactivityinFigure18-5isstraightforward.YoucanseethelayoutforthisactivityandtheactivitycodeinthedownloadprojectfileProAndroid5_ch18_TestPropertyAnimation.zip.Let’sstartwiththefirstbutton.

AnimatingViewswithObjectAnimatorsThefirstbuttoninFigure18-5(Fadeout:Animator)invokesthetoggleAnimation(View)methodthatisinListing18-30.

Listing18-30.BasicViewAnimationwithObjectAnimators

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtoggleAnimation(ViewbtnView){

ButtontButton=(Button)btnView;//Thebuttonwehavepressed//m_tv:isthepointertothetextview//Animatethealphafromcurrentvalueto0thiswillmakeitinvisibleif(m_tv.getAlpha()!=0){ObjectAnimatorfadeOut=ObjectAnimator.ofFloat(m_tv,"alpha",0f);fadeOut.setDuration(5000);fadeOut.start();tButton.setText("FadeIn");}//Animatethealphafromcurrentvalueto1thiswillmakeitvisibleelse{ObjectAnimatorfadeIn=ObjectAnimator.ofFloat(m_tv,"alpha",1f);fadeIn.setDuration(5000);fadeIn.start();

Page 451: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

tButton.setText("Fadeout");}}

ThecodeinListing18-30firstexaminesthealphavalueofthetextview.Ifthisvalueisgreaterthan0,thenthecodeassumesthatthetextviewisvisibleandrunsafade-outanimation.Attheendofthefade-outanimation,thetextviewwillbeinvisible.Ifthealphavalueofthetextviewis0,thenthecodeassumesthetextviewisinvisibleandrunsafade-inanimationtomakethetextviewvisibleagain.

TheObjectAnimatorcodeinListing18-30isreallysimple.AnObjectAnimatorisobtainedonthetextview(m_tv)usingthestaticmethodofFloat().Thefirstargumenttothismethodisanobject(m_tv).ThesecondargumentisthepropertynameoftheobjectthatyouwanttheObjectAnimatortomodifyoranimate.Inthecaseofthetextviewm_tvthispropertynameisalpha.Thetargetobjectneedstohaveapublicmethodtomatchthisname.Forapropertynamedalpha,thecorrespondingviewobjectneedstohavethefollowingsetmethod:

view.setAlpha(floatf);

ThethirdargumenttoofFloat()isthevalueofthepropertyattheendoftheanimation.Ifyouspecifyafourthargument,thenthethirdargumentisthestartingvalueandthefourthisthetargetvalue.Youcanpassmoreargumentsaslongastheyareallfloats.Theanimationwillusethosevaluesasintermediatevaluesintheanimationprocess.

Ifyouspecifyjustthe“to”value,thenthe“from”valueistakenfromthecurrentvaluebyusing

view.getAlpha();

Whenyouplaythisanimation,thetextviewwillgraduallydisappearfirst.ThecodeinListing18-30thenrenamesthebuttonto“Fadein.”Nowifyouclickthebuttonagain,whichisnowcalled“Fadein,”thesecondanimationinListing18-30isrun,andthetextviewwillappeargraduallyoveraperiodof5seconds.

AchievingSequentialAnimationwithAnimatorSetButton2inFigure18-5runstwoanimationsoneaftertheother:afade-outfollowedbyafade-in.Wecoulduseanimationlistenercallbackstowaitforthefirstanimationtofinishandthenstartthesecondanimation.ThereisanautomatedwaytorunanimationsintandemthroughtheclassAnimatorSettogetthesameeffect.Button2demonstratesthisinListing18-31.

Listing18-31.SequentialAnimationThroughanAnimatorSet

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidsequentialAnimation(ViewbView){

ObjectAnimatorfadeOut=ObjectAnimator.ofFloat(m_tv,"alpha",0f);

Page 452: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ObjectAnimatorfadeIn=ObjectAnimator.ofFloat(m_tv,"alpha",1f);AnimatorSetas=newAnimatorSet();as.playSequentially(fadeOut,fadeIn);as.setDuration(5000);//5secsas.start();}

InListing18-31,wehavecreatedtwoanimators:afade-outanimatorandafade-inanimator.Thenwecreatedananimatorsetandtellittoplaybothanimationssequentially.

YoucanalsochoosetoplayanimationstogetherusingananimatorsetbycallingthemethodplayTogether().Bothofthesemethods,playSequentially()andplayTogether(),cantakeavariablenumberofAnimatorobjects.

Whenyouplaythisanimation,thetextviewwillgraduallydisappearandthenreappear,muchliketheanimationyousawearlier.

SettingAnimationRelationshipswithAnimatorSet.BuilderAnimatorSetalsoprovidesabitmoreelaboratewaytolinkanimationsthroughautilityclasscalledAnimatorSet.Builder.Listing18-32demonstratesthis.

Listing18-32.UsinganAnimatorSetBuilder

//filename:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtestAnimationBuilder(Viewv){

ObjectAnimatorfadeOut=ObjectAnimator.ofFloat(m_tv,"alpha",0f);ObjectAnimatorfadeIn=ObjectAnimator.ofFloat(m_tv,"alpha",1f);AnimatorSetas=newAnimatorSet();//play()returnsthenestedclass:AnimatorSet.Builderas.play(fadeOut).before(fadeIn);as.setDuration(5000);//5secsas.start();}

TheplaymethodonanAnimatorSetreturnsaclasscalledAnimatorSet.Builder.Thisispurelyautilityclass.Themethodsonthisclassareafter(animator),before(animator),andwith(animator).Thisclassisinitializedwiththefirstanimatoryousupplythroughtheplaymethod.Everyothercallonthisobjectiswithrespecttothisoriginalanimator.ConsiderListing18-33:

Listing18-33.UsingAnimationSet.Builder

Page 453: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AnimatorSet.Builderbuilder=someSet.play(main_animator).before(animator1);

Withthiscodeanimator1willplayafterthemain_animator.Whenwesaybuilder.after(animator2),theanimationofanimator2willplaybeforemain_animator.Themethodwith(animator)playstheanimationstogether.

ThekeypointwithanAnimationBuilderisthattherelationshipestablishedviabefore(),after(),andwith()isnotchainedbutonlytiedtotheoriginalanimatorthatwasobtainedfromplay()method.Also,theanimationstart()methodisnotonthebuilderobjectbutontheoriginalanimatorset.WhenyouplaythisanimationthroughButton3,thetextviewwillgraduallydisappearandthenreappear,muchasinthepreviousanimation.

UsingXMLtoLoadAnimatorsItisonlytobeexpectedthattheAndroidSDKallowsanimatorstobedescribedinXMLresourcefiles.AndroidSDKhasanewresourcetypecalledR.animatortodistinguishanimatorresourcefiles.TheseXMLfilesarestoredinthe/res/animatorsubdirectory.Listing18-34isanexampleofananimatorsetdefinedinanXMLfile.

Listing18-34.AnAnimatorXMLResourceFile

<?xmlversion="1.0"encoding="utf-8"?><!--file:/res/animator/fadein.xml(ProAndroid5_ch18_TestPropertyAnimation.zip)--><setxmlns:android="http://schemas.android.com/apk/res/android"

android:ordering="sequentially"><objectAnimatorandroid:interpolator="@android:interpolator/accelerate_cubic"android:valueFrom="1"android:valueTo="0"android:valueType="floatType"android:propertyName="alpha"android:duration="5000"/><objectAnimatorandroid:interpolator="@android:interpolator/accelerate_cubic"android:valueFrom="0"android:valueTo="1"android:valueType="floatType"android:propertyName="alpha"android:duration="5000"/></set>

YouwillnaturallywonderwhatXMLnodesareavailableforyoutodefinetheseanimations.Asof4.0theallowedXMLtagsareasfollows:

animator:BindstoValueAnimator

objectAnimator:BindstoObjectAnimator

Page 454: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

set:BindstoAnimatorSet

YoucanseeabasicdiscussionofthesetagsatthefollowingAndroidSDKURL:

http://developer.android.com/guide/topics/graphics/prop-animation.html#declaring-xml

ThecompleteXMLreferencefortheanimationtagscanbefoundatthefollowingURL:

http://developer.android.com/guide/topics/resources/animation-resource.html#Property

OnceyouhavethisXMLfile,youcanplaythisanimationusingthemethodshowninListing18-35.

Listing18-35.LoadinganAnimatorXMLResourceFile

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidsequentialAnimationXML(ViewbView){

AnimatorSetset=(AnimatorSet)AnimatorInflater.loadAnimator(this,R.animator.fadein);set.setTarget(m_tv);set.start();}

NoticehowitisnecessarytoloadtheanimationXMLfilefirstfollowedbyexplicitlysettingtheobjecttoanimate.Inourcase,theobjecttoanimateisthetextviewrepresentedbym_tv.ThemethodinListing18-35iscalledbybutton4(FadeOut/FadeInXML).Whenthisanimationruns,thetextviewwillfadeoutfirstandthenreappearbyfadingin,justasinthepreviousalphaanimations.

UsingPropertyValuesHolderSofar,wehaveseenhowtoanimateasinglevalueinasingleanimation.TheclassPropertyValuesHolderletsusanimatemultiplevaluesduringtheanimationcycle.Listing18-36demonstratestheuseofthePropertyValuesHolderclass.

Listing18-36.UsingthePropertyValueHolderClass

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtestPropertiesHolder(Viewv){

//Getthecurrentcoordinatesofthetextview.//Thisallowsustoknowstartingandendingpositionstoanimatefloath=m_tv.getHeight();floatw=m_tv.getWidth();floatx=m_tv.getX();floaty=m_tv.getY();

Page 455: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Settheviewtothebottomrightasastartingpointm_tv.setX(w);m_tv.setY(h);

//fromtherightbottomanimate"x"toitsoriginalposition:topleftPropertyValuesHolderpvhX=PropertyValuesHolder.ofFloat("x",x);

//fromtherightbottomanimate"y"toitsoriginalpositionPropertyValuesHolderpvhY=PropertyValuesHolder.ofFloat("y",y);

//whenyoudonotspecifythefromposition,theanimationwilltakethecurrentposition//asthefromposition.

//Telltheobjectanimatortoconsiderboth//"x"and"y"propertiestoanimatetotheirrespectivetargetvalues.ObjectAnimatoroa=ObjectAnimator.ofPropertyValuesHolder(m_tv,pvhX,pvhY);

//setthedurationoa.setDuration(5000);//5secs

//hereisawaytosetaninterpolatoronanyanimatoroa.setInterpolator(newAccelerateDecelerateInterpolator());oa.start();}

APropertyValuesHolderclassholdsapropertynameanditstargetvalue.ThenyoucandefinemanyofthesePropertyValuesHolderswiththeirownpropertytoanimate.YoucansupplythissetofPropertyValuesHolderstotheobjectanimator.Theobjectanimatorwillthensetthesepropertiestotheirrespectivevaluesonthetargetobject.Witheachrefreshoftheanimation,allthevaluesfromeachPropertyValuesHolderwillbeappliedallatonce.Thisismoreefficientthanapplyingmultipleanimationsinparallel.

Button5inFigure18-5runsthecodeinListing18-36.Whenthisanimationruns,thetextviewwillemergefrombottomrightandmigratetowardthetopleftin5seconds.

UnderstandingViewPropertiesAnimationAndroidSDKhasanoptimizedapproachtoanimatevariouspropertiesofviews.ThisisdonethroughaclasscalledViewPropertyAnimator.Listing18-37usesthisclasstomovethetextviewfrombottomrighttotopleft.

Page 456: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing18-37.UsingaViewPropertyAnimator

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtestViewAnimator(Viewv){

//Remembercurrentboundariesfloath=m_tv.getHeight();floatw=m_tv.getWidth();floatx=m_tv.getX();floaty=m_tv.getY();

//Positiontheviewatbottomrightm_tv.setX(w);m_tv.setY(h);

//GetaViewPropertyAnimatorfromthetextviewViewPropertyAnimatorvpa=m_tv.animate();

//Setasmanytargetvaluesyouwanttosetvpa.x(x);vpa.y(y);

//Setdurationandinterpolatorsvpa.setDuration(5000);//2secsvpa.setInterpolator(newAccelerateDecelerateInterpolator());

//TheanimationautomaticallystartswhentheUIthreadgetstoit.//Noneedtoexplicitlycallthestartmethod.//vpa.start();}

ThestepstouseViewPropertyAnimatorareasfollows:

1. GetaViewPropertyAnimatorbycallingtheanimate()methodonaview.

2. UsetheViewPropertyAnimatorobjecttosetvariousfinalpropertiesofthatview,suchasx,y,scale,alpha,andsoon.

3. LettheUIthreadproceedbyreturningfromthefunction.Theanimationwillautomaticallystart.

Thisanimationisinvokedbybutton6.Whenthisanimationruns,thetextviewwillmigratefrombottomrighttotopleft.

UnderstandingTypeEvaluatorsAswehaveseen,anobjectanimatordirectlysetsaparticularvalueonatargetobjectwitheachanimationcycle.Thesevaluessofarhavebeensinglepointvaluessuchasfloats,ints,andsoon.Whathappensifyourtargetobjecthasapropertythatisanobjectitself?Thisiswheretypeevaluatorscomeintoplay.

Page 457: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Toillustratethisconsideraviewonwhichwewanttosettwovaluessuchas‘x’and‘y’.Listing18-35showshowweencapsulatearegularviewforwhichweknowhowtochangexandy.TheencapsulationwillallowtheanimationtocallonceforbothxandythroughthePointFabstractionavailableintheAndroidgraphicspackage.WewillprovideasetPoint(PointF)methodandthen,insidethatmethod,parseoutxandyandsetthemontheview.TakealookatListing18-38.

Listing18-38.AnimatingaViewThroughaTypeEvaluator

//file:AnimatableView.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicclassMyAnimatableView{

PointFcurPoint=null;Viewm_v=null;publicMyAnimatableView(Viewv){curPoint=newPointF(v.getX(),v.getY());m_v=v;}publicPointFgetPoint(){returncurPoint;}publicvoidsetPoint(PointFp){curPoint=p;m_v.setX(p.x);m_v.setY(p.y);}}

IncodeListing18-38TypeEvaluatorisahelperobjectthatknowshowtosetacompositevaluesuchasatwo-dimensionalorthree-dimensionalpointduringananimationcycle.Inascenarioinvolvingcompositefields(representedasanobject),anObjectAnimatorwilltakethestartingcompositevalue(likethePointFobjectwhichisacompositeofxandy),anendingcompositevalueandpassthemtoaTypeEvaluatorhelperobjecttogettheintermediateobjectvalue.Thiscompositevalueisthensetonthetargetobject.Listing18-39showshowaTypeEvlautorcalculatesthisintermediatevaluethroughitsevaluatemethod.

Listing18-39.CodingaTypeEvaluator

//file:MyPointEvaluator.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicclassMyPointEvaluatorimplementsTypeEvaluator<PointF>{

publicPointFevaluate(floatfraction,PointFstartValue,PointFendValue){PointFstartPoint=(PointF)startValue;PointFendPoint=(PointF)endValue;returnnewPointF(startPoint.x+fraction*(endPoint.x-startPoint.x),

Page 458: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

startPoint.y+fraction*(endPoint.y-startPoint.y));}}

FromListing18-39youcanseethatyouneedtoinheritfromtheTypeEvaluatorinterfaceandimplementtheevaluate()method.Inthismethod,youwillbepassedthefractionoftheanimation’stotalprogress.Youcanusethatfractiontoadjustyourintermediatecompositevalueandreturnitasatypedvalue.

Listing18-40showshowanObjectAnimatorusesMyAnimatableViewandtheMyPointEvaluatortoanimatecompositevaluesforaView.

Listing18-40.UsingaTypeEvaluator

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtestTypeEvaluator(Viewv){

floath=m_tv.getHeight();floatw=m_tv.getWidth();floatx=m_tv.getX();floaty=m_tv.getY();

PointFstartingPoint=newPointF(w,h);PointFendingPoint=newPointF(x,y);

//m_atv:Youwillneedthiscodeinyouractivityearlierasalocalvariable:MyAnimatableViewm_atv=newMyAnimatableView(m_tv);

ObjectAnimatorviewCompositeValueAnimator=ObjectAnimator.ofObject(m_atv,"point",newMyPointEvaluator(),startingPoint,endingPoint);

viewCompositeValueAnimator.setDuration(5000);viewCompositeValueAnimator.start();}

NoticeinListing18-40thattheObjectAnimatorisusingthemethodofObject()asopposedtoofFloat()orofInt().AlsonoticethatthestartingvalueandendingvaluefortheanimationarecompositevaluesrepresentedbytheclassPointF.ThegoaloftheobjectanimatorisnowtocomeupwithanintermediatevalueforPointFandthenpassittothemethodsetPoint(PointF)onthecustomclassMyAnimatableView.TheclassMyAnimatableViewcanaccordinglysettherespectiveindividualpropertiesonthecontainedtextview.ThisanimationinListing18-40usingtheTypeEvaluatorisinvokedbybutton7.Whenthisanimationruns,theviewwillmigratefrombottomrighttotopleft.

UnderstandingKeyFrames

Page 459: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Keyframesareusefulplacesduringananimationcycletoputkeytimemarkers(significantinstancesintime).Akeyframespecifiesaparticularvalueforapropertyatagivenmomentintime.Thekeymarker’stimeisbetween0(beginningofanimation)and1(endofanimation).Onceyougatherthesekey-framevalues,yousetthemagainstaparticularpropertysuchasalpha,x,ory.ThisassociationofkeyframestotheirrespectivepropertiesisdonethroughthePropertyValuesHolderclass.YouthentelltheObjectAnimatortoanimatetheresultingPropertyValuesHolder.Listing18-41demonstrateskey-frameanimation.

Listing18-41.AnimatingaViewUsingKeyFrames

//file:TestPropertyAnimationActivity.java(ProAndroid5_ch18_TestPropertyAnimation.zip)publicvoidtestKeyFrames(Viewv){

floath=m_tv.getHeight();floatw=m_tv.getWidth();floatx=m_tv.getX();floaty=m_tv.getY();

//Startframe:0.2,alpha:0.8Keyframekf0=Keyframe.ofFloat(0.2f,0.8f);

//Middleframe:0.5,alpha:0.2Keyframekf1=Keyframe.ofFloat(.5f,0.2f);

//endframe:0.8,alpha:0.8Keyframekf2=Keyframe.ofFloat(0.8f,0.8f);

PropertyValuesHolderpvhAlpha=PropertyValuesHolder.ofKeyframe("alpha",kf0,kf1,kf2);PropertyValuesHolderpvhX=PropertyValuesHolder.ofFloat("x",w,x);

//endframeObjectAnimatoranim=ObjectAnimator.ofPropertyValuesHolder(m_tv,pvhAlpha,pvhX);anim.setDuration(5000);anim.start();}

TheanimationinListing18-41isinvokedbybutton8.Whenthisanimationruns,youwillseethetextmovefromrighttoleft.When20%ofthetimehaspassed,alphawillchangeto80%.Thealphavaluewillreach20%athalfwayandchangebackto80%atthe80thpercentileoftheanimationtime.

UnderstandingLayoutTransitionsThepropertyanimationAPIalsoprovideslayout-basedanimationsthroughtheLayoutTransitionclass.ThisclassiswelldocumentedaspartofthestandardAPI

Page 460: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

JavadocatthefollowingURL.

http://developer.android.com/reference/android/animation/LayoutTransition.html

Wewillsummarizehereonlythekeypointsoflayouttransitions.Toenablelayouttransitionsonaviewgroup(mostlayoutsareviewgroups),youwillneedtousethecodeshowninListing18-42.

Listing18-42.SettingaLayoutTransition

viewgroup.setLayoutTransition(newLayoutTransition());

WiththecodeinListing18-42thelayoutcontainer(ViewGroup)willexhibitdefaulttransitionsasviewsareaddedandremoved.ALayoutTransitionobjecthasfourdifferentdefaultanimationsthatcovereachofthefollowingscenarios:

Addaview(animationfortheviewthatisappearingduetoanaddorashow)

Changeappearing(animationfortherestoftheitemsinthelayoutastheycouldchangetheirsizeorappearanceduetoanewitembeingadded)

Removeaview(animationfortheviewthatisdisappearingduetoaremoveorahide)

Changedisappearing(animationfortherestoftheitemsinthelayoutastheycouldtheirsizeorappearanceduetoanitembeingremoved)

Ifyouwantcustomanimatorsforeachofthesecases,youcansetthemontheLayoutTransitionobject.HereisanexampleinListing18-43.

Listing18-43.LayoutTransitionMethods

//HereishowyougetanewlayouttransitionLayoutTransitionlt=newLayoutTransition();

//YoucansetthislayouttransitiononalayoutsomeLayout.setLayoutTransition(lt);

//obtainadefaultanimatorifyouneedtorememberAnimatordefaultAppearAnimator=lt.getAnimator(APPEARING);

//createanewanimatorObjectAnimatorsomeNewObjectAnimator1,someOtherObjectAnimator2;

//setitasyourcustomanimatorfortheallowedsetofanimators

Page 461: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

lt.setAnimator(APPEARING,someNewObjectAnimator1);lt.setAnimator(CHANGE_APPEARING,someNewObjectAnimator1);lt.setAnimator(DISAPPEARING,someNewObjectAnimator1);lt.setAnimator(CHANGE_DISAPPEARING,someOtherObjectAnimator2);

Becausetheanimatoryousupplytoalayouttransitionappliestoeachview,theanimatorsareinternallyclonedbeforebeingappliedtoeachview.

ResourcesHerearesomeusefullinkstowhenyouareworkingwiththeAndroidAnimationAPI:

http://www.androidbook.com/item/3901:AuthorresearchnotesonAndroidpropertyanimations.

http://android-developers.blogspot.com/2011/02/animation-in-honeycomb.html:Akeyblogonpropertyanimations.

http://android-developers.blogspot.com/2011/05/introducing-viewpropertyanimator.html:Ablogonviewpropertyanimations.

http://developer.android.com/guide/topics/graphics/prop-animation.html:PrimarydocumentationonpropertyanimationsfromtheAndroidSDK.

http://developer.android.com/guide/topics/graphics/animation.htmlAndroiddocumentationlinkstoallanimationtypes,includingpropertyanimationsandold-styleanimations.

http://developer.android.com/reference/android/view/animation/package-summary.html:JavadocAPIfortheolderanimationpackageandroid.view.animation.

http://developer.android.com/guide/topics/resources/animation-resource.html:XMLtagsforvariousanimationtypes.

http://www.androidbook.com/proandroid5/projects:Downloadabletestprojectsforthischapter.ThenamesofthezipfilesareProAndroid5_ch18_TestFrameAnimation.zip,ProAndroid5_ch18_TestLayoutAnimation.zip,ProAndroid5_ch18_TestViewAnimation.zip,andProAndroid5_ch18_TestPropertyAnimation.zip.

Page 462: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SummaryInthischapterwehavecoveredframe-by-frameanimation,layoutanimation,viewanimation,interpolators,transformationmatrices,Camera,andvariouswaysofusingthenewpropertyanimationAPI.Allconceptsarepresentedwithworkingcodesnippetsandsupportedbyworkingdownloadableprojects.

Page 463: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter19

ExploringMapsandLocation-BasedServicesInthischapter,wearegoingtotalkaboutmapsandlocation-basedservices.Location-basedservicesformoneofthemoreexcitingpiecesoftheAndroidSDK.ThisportionoftheSDKprovidesAPIstoletapplicationdevelopersdisplayandmanipulatemaps,obtainreal-timedevice-locationinformation,andtakeadvantageofotherexcitingfeatures.WorkingwithmapschangedsignificantlywhenGoogleintroducedtheMapFragmentandversion2oftheGoogleMapsAPI.Thischapterwillgointodetailsofthenewwaysofcreatingmapsandmanipulatingthem.

Thelocation-basedservicesfacilityinAndroidsitsontwopillars:themappingandlocation-basedAPIs.ThemappingAPIsinAndroidprovidefacilitiesforyoutodisplayamapandmanipulateit.Forexample,youcanzoomandpan;youcanchangethemapmode(fromsatelliteviewtotrafficview,forexample);youcanaddmarkersandcustomdatatothemap;andsoon.TheotherendofthespectrumisGlobalPositioningSystem(GPS)dataandinformationaboutlocations,bothofwhicharehandledbythelocationpackage.

TheseAPIsoftenreachacrosstheInternettoinvokeservicesfromGoogleservers,viaGooglePlayServices(thelocaluberapplicationonthedevice).Therefore,youwillusuallyneedtohaveInternetconnectivityforthesetowork.Inaddition,GooglehasTermsofServicethatyoumustagreetobeforeyoucandevelopapplicationswiththeseGoogleservices.Readthetermscarefully;Googleplacessomerestrictionsonwhatyoucandowiththeservicedata.Forexample,youcanuselocationinformationforusers’personaluse,butcertaincommercialusesarerestricted,asareapplicationsinvolvingautomatedcontrolofvehicles.ThetermswillbepresentedtoyouwhenyousignupforaMapsAPIkey.

Inthischapter,we’llgothrougheachofthesepackages.We’llstartwiththemappingAPIsandshowyouhowtousemapswithyourapplications.Asyou’llsee,mappinginAndroidboilsdowntousingMapFragmentclassinadditiontothemappingAPIs,whichintegratewithGoogleMaps.Wewillalsoshowyouhowtoplacecustomdataontothemapsthatyoudisplayandhowtoshowthecurrentlocationofthedeviceonamap.Aftertalkingaboutmaps,we’lldelveintolocation-basedservices,whichextendthemappingconcepts.WewillshowyouhowtousetheAndroidGeocoderclassandtheLocationServicesservice.WewillalsotouchonthreadingissuesthatsurfacewhenyouusetheseAPIs.

UnderstandingtheMappingPackageAswementioned,themappingAPIsareoneofthecomponentsofAndroid’slocation-

Page 464: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

basedservices.Themappingpackagecontainsalmosteverythingyou’llneedtodisplayamaponthescreen,handleuserinteractionwiththemap(suchaszooming),displaycustomdataontopofthemap,andsoon.IntheoldversionofAndroidMaps,yourapplicationwouldtalkdirectlytotheGoogleMapsservicesforeverythingmap-related.Inthenewversion,yourapplicationmusttalktoGooglePlayServices,whichisalocalapponthedevice,providedaspartoftheoperatingsystem.YourappstillalsomakescallsovertheInternetfordata,butifGooglePlayServicesisnotpresentlocallyonthedevice,yourmapswillnotwork.Ifyouneedmapsondevicesthatdon’thaveGooglePlayServicesyou’llneedtoexploreoneoftheothermapspackagesavailableforAndroid(e.g.,MapQuest).

InorderforyourapplicationtotalktoGooglePlayServices,youwillneedtoincludetheGooglePlayServiceslibraryintoyourapplication.AndroidStudiodoesthisdifferentlythanEclipsewithADT.SeetheReferencessectionbelowforalinktoonlineinstructionsforthelatestwaytodothis.BeforeyouincludetheGooglePlayServiceslibraryinyourapplication,youmustfirstdownloaditthroughtheSDKManager.You’llfinditunderExtras.

YoumayhavenoticedthatyourAndroidSDKManagershowsGoogleAPIpackagesinadditiontotheAndroidSDKplatforms.Previously,youhadtobaseyourapplicationonaGoogleAPIspackageinordertousemaps,butthatisnolongertrue.Instead,theMapsAPIintegratestoGooglePlayServices,soyourapplicationcanbebasedonaregularAndroidpackage.However,totestamaps-basedappintheemulator,youwouldneedtobaseyouremulator’sAndroidVirtualDevice(AVD)onaGoogleAPIspackage.Moreontestingappslater.

Thefirststeptoworkingwiththemapspackageistodisplayamap.Todothat,you’lluseMapFragment(orSupportMapFragmentifyouwantbackwardscompatibilitywithversionsofAndroidpriortoAPI12,a.k.a.Honeycomb3.1).Usingthisclass,however,requiressomepreparationwork.Specifically,beforeyoucanuseGoogleMapsservices,you’llneedtogetaMapsAPIkeyfromGoogle.TheMapsAPIkeyenablesAndroidtointeractwithGoogleMapsservicestoobtainmapdata.ThenextsectionexplainshowtoobtainaMapsAPIkey.

ObtainingaMapsAPIKeyfromGoogleGooglewantstobeabletoidentifytheapplicationthatisconnectingtothemapservices.Itusesacombinationoftheapplicationpackageandthecertificateusedtosigntheapplication,togenerateaMapsAPIkeythattheapplicationmustthenusetorequestservice.TheMapsAPIkeycanbeusedacrossanumberofpairsofpackagesandcertificates.ThismeansyoucanusethesameMapsAPIkeyfordevelopmentandproduction;thepackagewouldbethesamebutthecertificatesareprobablydifferent.Intheoryyoucouldusethesamekeyacrossmultipleapplicationsbutthispracticeisdiscouraged.Youdon’twanttodothisanywaysinceGoogleimposescertainlimitsontheMapsAPIusageandbysharingaMapsAPIkeywithmultipleapplicationsyoucouldmoreeasilyexceedthelimit.

ToobtainaMapsAPIkey,youneedthecertificatethatyou’llusetosignyourapplication

Page 465: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(inthecaseofadevelopmentversionofyourapp,thedebugcertificate).You’llgettheSHA-1fingerprintofyourcertificate,andthenyou’llenterit,alongwithyourapplication’spackage,onGoogle’swebsitetogenerateanassociatedMapsAPIkey.

First,youmustlocateyourdebugcertificate,whichisgeneratedandmaintainedbyEclipse.YoucanfindtheexactlocationusingtheEclipseIDE.Ifyou’reusinganIDEotherthanEclipse,youjustneedtolocatethekeystorefilewherethecertificatesareheld.FromEclipse’sPreferencesmenu,gotoAndroid Build.Thedebugcertificate’slocationwillbedisplayedintheDefaultDebugKeystorefield,asshowninFigure19-1.

Figure19-1.Thedebugcertificate’slocation

ToextracttheSHA-1fingerprint,youcanrunthekeytoolwiththe–listoption,asshownhere:

keytool-list-aliasandroiddebugkey-keystore"FULLPATHOFYOURdebug.keystoreFILE"-storepassandroid-keypassandroid

Notethatthealiasyouwantfromthedebugstoreisandroiddebugkey.Similarly,thekeystorepasswordisandroid,andtheprivatekeypasswordisalsoandroid.Whenyourunthiscommand,thekeytoolprovidesthefingerprint(seeFigure19-2).

Page 466: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure19-2.Thekeytooloutputforthelistoption

You’llnoticethatthefingerprintdisplayedbythekeytoolcommandisthesameasdisplayedinthePreferencesscreenasshowninFigure19-1soyoucouldhavejustgottenitfromthatscreen.ButnowyouknowbothwaystoextractouttheSHA-1fingerprintforyourapplication.WhenyouusekeytooltoextractouttheSHA-1fingerprintfortheproductioncertificate,you’llusethekeystorefile,alias,andpasswordthatyousetupforyourproductioncertificate.

ThenextstepistogotoGoogle’sDeveloperConsoletoaddyourapplication,andfollowingthatyouenabletheMapsAPI.TheresultwillbeyourMapsAPIkeytoincludeinyourapplication.TheDeveloperConsoleishere,andyouwillneedaGoogleaccountinordertogetthere:

https://console.developers.google.com

Youwillneedtocreateanewproject.Aspartofcreatingthenewproject,youneedtoprovideaProjectNameandaProjectID.TheProjectIDwillbepre-populatedwithsomethingstrange-looking.Youcanputanyvalueyouwanthereaslongasitisunique.However,theProjectIDisjustforusebytheGoogleDeveloperConsole;ithasnothingtodowiththesourcecodeofyourapplication.Rememberthatyou’recreatingasampleprojectbasedonthecodeofthischapter’ssampleproject,sothatyoucangetaMapsAPIkeytoseeitwork.

ReadthroughtheTermsofService.Ifyouagreetotheterms,clickCreatetocreateyournewproject.ThissetsupabasictemplateofaprojectwithGoogle.Nextyou’regoingtoenabletheAPIsyouwant.Foramapsapplication,you’llchooseGoogleMapsAndroidAPIv2.Forthechapter’ssampleapplication,youalsowanttoincludetheGeocodingAPI.Youmightgetapop-upwindowcalled‘ConfigureAndroidKeyfor<yourappname>’.Ifyoudon’tgetapop-up,youcannavigatetotheAPIs&auth CredentialssectionofyourprojectintheDevelopersConsoleandgenerateanAPIkeythere.ThisiswhereyouneedtocopyandpasteinboththeSHA-1fingerprintoftheapplicationsigningcertificate,andthepackagenameoftheapplication,separatedbyasemicolon.Thepackagenameistheonefromyoursourcecode.Notethatyoucancopyinmorethanoneline,soifyouhavetheSHA-1fingerprintfromtheproductionapplicationsigningcertificate(whichistypicallydifferentfromtheandroiddebugkeyusedindevelopment),youcouldaddasecondlinefortheproductionapplication.

OnceyoupresstheCreatebuttononthisscreenyouwillgetanAPIkey.ThisiswhatyouwillincludeintheAndroidManifest.xmlfileofyourapplication.TheAPIkeyisactiveimmediately,soyoucanstartusingittoobtainmapdatafromGoogle.

AddingtheMapsAPIKeytoYourApplication

Page 467: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ToseehowtheMapsAPIkeyisaddedtothemanifestfile,seethebottomofListing19-1.

Listing19-1.AndroidManifest.xmlforaSimpleMapsApplication

<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.maps.whereami"android:versionCode="1"android:versionName="1.0">

<uses-sdkandroid:minSdkVersion="10"android:targetSdkVersion="19"/><uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-featureandroid:glEsVersion="0x00020000"android:required="true"/>

<applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme"><activityandroid:name="com.androidbook.maps.whereami.MainActivity"android:label="@string/app_name"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity><meta-dataandroid:name="com.google.android.gms.version"android:value="@integer/google_play_services_version"/><meta-dataandroid:name="com.google.android.maps.v2.API_KEY"

Page 468: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:value="AIzaSyBDs1ZQgu9X2A4TG1a7fPl-Ge_MKlyviKM"/></application></manifest>

Asyounodoubtnoticed,thereareotherelementswithinthemanifestfilethatmustbepresentforamapsapplicationtowork.The<meta-data>tagabovetheMapsAPIkeyisrequired,asarethepermissionsnearthetop.Technically,theACCESS_FINE_LOCATIONpermissionisnotneededtoshowmaps;itistheresolocationfunctionality(e.g.,GPS)willwork.GPSiscommonlyusedinmapsapplications.ACCESS_NETWORK_STATEandINTERNETpermissionsaretheresothemapsapplicationcandownloadmaptiledata(i.e.,themapgraphics)andtoknowwhattypeandstateofnetworkconnectiontheapplicationhas.TheWRITE_EXTERNAL_STORAGEpermissionistheresothemapsapplicationcancreatealocalcacheofmaptilefilesonthedevice’slocalstoragespace.Withoutcaching,amapsapplicationwouldlikelyspendalotoftimedownloadingmaptilesoverandoveragain,whichisnotonlyinefficientforyourapp,butitplacesanunwantedburdenontheGoogleserversanditcouldconsumealargeportionoftheuser’sdataplan.Andfinally,theglEsVersionfeatureispresentbecauserenderingmapsonthescreenusesOpenGL,sobyrequiringthefeature,theapplicationavoidsgettinginstalledondevicesthatcouldnotdisplaymaps.

Now,let’sstartplayingwithmaps.

UnderstandingMapFragmentThefoundationalbuildingblockofamapapplicationistheMapFragment.ThiswasintroducedinHoneycomb(Android3.1)andreplacedMapViewandMapActivityfunctionality.NowyoucanembedaMapFragmentinsideofaregularAndroidactivity.IfyouwantyourapplicationtorunondevicesrunninganolderversionofAndroid,youcanuseSupportMapFragmentandembeditinsideaFragmentActivity.TheMapFragmentcontainsthemapviewtodisplaymaps,ithandlesusergesturestomanipulatethemap,anditmanagesthebackgroundthreadsthattalktotheGoogleservicestoretrievemapdata.

MapFragmentisaverynicebundleoffunctionality,butit’snotallthatyouneedonyourdevicetomakemapswork.Fortunately,theintegrationwithGooglePlayServicesisallhandledforyou;allyouneedtodoismakeaspecialentryintoyourapp’sAndroidManifest.xmlfile,whichyousawintheprevioussection.

Thefirstsampleapplicationforthischapterwillsimplyshowamaptotheuserandlettheuserexplorethemap.

NoteNoteWegiveyouaURLattheendofthechapterthatyoucanusetodownloadprojectsfromthischapter.ThiswillallowyoutoimporttheseprojectsintoyourIDEdirectly.AlsonotethatifyouwanttotestthesesampleswithanAndroidemulator,makesuretheAndroidVirtualDevice(AVD)isbuiltwiththeGoogleAPIs.

Page 469: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PleaserefertothesampleprojectcalledWhereAmI.TheapplicationismadeupofaverybasicFragmentActivity,averysimplelayout,andaSupportMapFragment.Thesampleisusingthecompatibilityclasses,whichmeansitwillrunonGingerbreaddevicesaswellasthelatestmodels.IfyourapponlyneedstorunondevicesnewerthanHoneycomb3.0,youcouldusearegularactivityandaMapFragmentinstead.

Listing19-2showstheactivity.Allthat’sneededistosetupthelayoutand,ifneeded,createtheMapFragmentandinsertitintothelayout’scontainer(aFrameLayout).

Listing19-2.ABasicFragmentActivityforDisplayingaMap

publicclassMainActivityextendsFragmentActivity{privatestaticfinalStringMAPFRAGTAG="MAPFRAGTAG";privateMyMapFragmentmyMapFrag;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

if((myMapFrag=(MyMapFragment)getSupportFragmentManager().findFragmentByTag(MAPFRAGTAG))==null){myMapFrag=MyMapFragment.newInstance();getSupportFragmentManager().beginTransaction().add(R.id.container,myMapFrag,MAPFRAGTAG).commit();}}}

Iftheactivityisre-createdduetoanorientationchangeforexample,themapfragmentwillstillbeavailableandbeautomaticallyattachedtothenewactivitybyAndroid.Ifthemapfragmentisnotfound,itmeansthisisthefirsttimein,orthemapfragmenthasbeendestroyed,socreateanewoneandattachit.Itdoesn’tgetanyeasierthanthat.ThelayoutsourceisshowninListing19-3.ItissimplyaFrameLayoutwithanidof“container”thatfillstheavailablescreenspace.

Listing19-3.LayoutforSimpleMapDisplay(activity_main.xml)

<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.androidbook.maps.whereami.MainActivity"tools:ignore="MergeRootFrame"/>

Page 470: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Ifyouareincludingthemapfragmentwithotheritemsinyouruserinterface,youcansimplyusetheFrameLayoutwhereyouwantthemapfragmenttoappear,embeddedwithinotherlayouts.TheonlycoderemainingisthatoftheMapFragment,whichisshowninListing19-4.Figure19-3showswhattheusersees.

Listing19-4.CodefortheMapFragment

publicclassMyMapFragmentextendsSupportMapFragmentimplementsOnMapReadyCallback{privateGoogleMapmMap=null;

publicstaticMyMapFragmentnewInstance(){MyMapFragmentmyMF=newMyMapFragment();returnmyMF;}

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);getMapAsync(this);}

@OverridepublicvoidonActivityCreated(BundlesavedInstanceState){super.onActivityCreated(savedInstanceState);setRetainInstance(true);}

@OverridepublicvoidonResume(){super.onResume();doWhenMapIsReady();}

@OverridepublicvoidonPause(){super.onPause();if(mMap!=null)mMap.setMyLocationEnabled(false);}

@OverridepublicvoidonMapReady(GoogleMaparg0){mMap=arg0;doWhenMapIsReady();}

Page 471: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/*Wehavearaceconditionwherethefragmentcouldresume*beforeorafterthemapisready.Soweputallourlogic*forinitializingthemapintoacommonmethodthatis*calledwhenthefragmentisresumedorresumingandthe*mapisready.*/voiddoWhenMapIsReady(){if(mMap!=null&&isResumed())mMap.setMyLocationEnabled(true);}}

Figure19-3.AbasicMapFragmentdisplayingyourlocation

Arecentdevelopment(Dec2014)totheMapsAPIistheuseofacallbacktolettheapplicationknowwhenthemapisreadytobeactedupon.ThecallbackissetupusinggetMapAsync(),andtheonMapReady()callbackiscalledwhenthemapcanbe

Page 472: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

usedbytheapplication.InbetweencallinggetMapAsync()andinvokingtheonMapReady()callback,Androidissettingupcommunications,threads,etc.,forthemap.ThismeansthatthemapmayormaynotbereadywhenonResume()isinvoked,whichtellsthefragmentthattheUIisnowbeingshown.Therefore,theapplicationneedsaseparatemethodtoworkonthemapanditneedstobecalledbothbyonResume()andbyonMapReady().Forthissampleapplication,thedoWhenMapIsReady()methodfillsthatrole.Theapplicationwantstoshowtheuserthedevice’scurrentlocation,sothesetMyLocationEnabled()methodiscalledindoWhenMapIsReady().ButdoWhenMapIsReady()needstocheckthatthemapexistsandthatthefragmentisresumingorhasresumed.Wedon’tknowwhichwilloccurfirst,butbothmustbetruebeforeweenablelocationupdates.Thecurrentlocationupdatesaredisabledwhenthefragmentgoesoutofview(seeonPause()).TheonlyothercodelinetonoticeisthesetRetainInstance()methodcall.Sincethemapdoesnotneedtobedestroyedandre-createdforaconfigurationchangeoftheactivity,itmakessensetokeepthefragmentandreuseit,alongwiththethreadsandtilesandsoon.YoushouldrememberthataconfigurationchangewillcauseonPause()andonResume()tobeinvokedduringtheconfigchange.Thiswillcorrectlydisablelocationupdatesandre-enablethemduringonResume().

MapControls:MyLocation,Zoom,PanThereareacoupleofartifactsontheuserinterfacetonotice.FirstistheMyLocationbuttonintheupper-rightcorner.Whenyoufirststartthesampleappyouwillseeaveryhigh-levelviewoftheworld.Toshowthecurrentlocation,taptheMyLocationbutton.Thiswillrelocatethemaptothecurrentpositionandzoomin.Secondisthebluedot.Thebluedotrepresentswheretheappthinksyouare,andthecirclerepresentshowaccurateitthinksthislocationis.Thecirclemaygroworshrinkasthelocationinformationchanges.

Theusercanusepinchgestures(i.e.,squeezingtwofingersapartortogether)tozoominorout.Therearemoregesturesthattheusercandoonthemap.Byswiping,theusercanpanthemap;thatis,theycanmovethemaptoseenearbyareas.Usingtwofingersandarotationmove,theusercanrotatethemap.That’salotoffunctionalitythat’sautomaticfromsimplycreatingaMapFragment.

ThesemapcontrolsandmorearecontainedinanobjectoftheUiSettingsclass.Youcangetthemap’sUiSettingsbycallinggetUiSettings()ontheGoogleMapobject(i.e.,mMapinthesampleapp).Youcanthenmodifythesettingsprogrammatically.Forexample,youcouldenableacompasstobedisplayedonthemap,oryoucouldenable/disablethezoomplus/minuscontrolsoitisorisnotdisplayed.Thezoomplus/minuscontrolappearsinthelower-rightcornerandallowstheusertozoominoroutbytappingtheplusorminusbutton,respectively.

MapTypesThedefaultmaptypeisMAP_TYPE_NORMAL.ThisisthetypethatwasusedinFigure

Page 473: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

19-3.Itshowstheroadswiththebasicfeaturesofthelandsuchaswherewateris,wheregreenspaceis,andsomeplacesandbuildings.MAP_TYPE_SATELLITEshowsaphotographicsatelliteviewoftheground,sotheuserisabletoseeactualbuildings,cars,andevenpeople.MAP_TYPE_HYBRIDisacombinationofthesetwo;MAP_TYPE_TERRAINislikeanormalmapbutwithtopographicalfeaturesaddedsuchasmountainsandcanyons.ToreallyseetheeffectofMAP_TYPE_TERRAIN,zoominonaplacelikeBoulder,ColoradowithamapsettoTerrain.

YouusethesetMapType()methodofaGoogleMaptochangethetype.

AddingaTrafficLayerInthepreviousversionofAndroidMaps,trafficwastreatedlikethesatelliteandnormalmodesofmaps.WithAPIv2,trafficisenabledseparatelyusingthesetTrafficEnabled()methodofaGoogleMap.

MapTilesIt’shelpfultounderstandwhat’sgoingonwhenyourappdisplaysamap.Googlehascreatedmillionsofbasemaptilestorepresenttheearth’ssurface.Atthelowestzoomlevel(i.e.,zero)thereisonetiletoshowtheentireworld.Atzoomlevel1,therearefourtilesina2x2configuration.Atzoomlevel2,thereare16tilesina4x4configuration.Andsoonuptozoomlevel21.Dependingonwhatpartoftheworldyouwanttodisplay,andwhatthezoomlevelis,theGoogleMapobjectwillfetchandcachetheappropriatetiles.Pantotheside,andanyadditionaltileswillbefetchedanddisplayed.Panbacktowhereyouwereandyourappcanretrievemaptilesfromthecacheinsteadofmakingmoreroundtripstotheserver.

It’sinterestingtonotethatbasemaptilesforthenormaltypeofmapsarenotimages.Googlehasfiguredoutacompressedwaytodescribetheshapesandcolorswithinthetilesinsteadofjustsendingdownimagesforeachtile.Asaresult,normalmaptilesareveryefficientintermsofcachespaceaswellasnetworkbandwidth.Satellitetilesontheotherhandarenotascompressed,sincetheyareimages.

Nowyoucanunderstandwhysometimesamapsapplicationwillshowagraygridpatternandseemtofunctionbutwon’tshowstreetsandotheritems.TheGoogleMapobjecthasbeeninstantiated,anditknowsazoomlevelandwhereitissupposedtobedisplayingamap,butitisunabletoretrieveandrendertilestotheuser.ThisismostoftenduetoaninvalidMapsAPIkey,ortheAPIkeyhasnotbeensetupproperly.ButitcouldalsomeandifficultyinreachingtheGoogleMapsservers.However,ifmaptileshavebeencached,thosetilescanberenderedtotheuserevenifthetileserversatGoogleareunreachable.Therearetwounfortunatethingsaboutmaptilecaching.ThefirstisthattherearenoAPIcallstomanagethemaptilecache,eithertoforcemaptilestobecached,ortochangethesizeofthecache,ortoevicttilesfromthecache.YoujusthavetotrustthatGooglewilldotherightthing.Thesecondisthatmaptilesarecachedperapplication.SojustbecausetheGoogleMapsapplicationmayhavecachedtiles,yourapplicationdoesnothaveaccesstothosetiles.Yourapplicationcanonlyseethecachedtilesthatithascached.

Page 474: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AddingMarkerstoMapsUsuallyyou’llwanttoidentifypointsofinterestonamap,andthisisdoneusingMarkers.Thepointscouldbestationaryobjectslikeaddresses,landmarks,oraparkingspot.Buttheycouldalsobemovingobjectslikecars,planes,people,pets,storms,etc.Yougettochoosewhatthemarkerlookslikeandwhereitispositionedonamap.Andyoucanhavelotsofmarkersallatthesametime.We’regoingtomodifythesampleprogramfromabovetoincludeacoupleofmarkers.You’llseehowtoplacethem,andthenhowtomanipulatetheviewtomakesuretheuserseesthemarkers.

NowusethesampleprogramcalledWhereAmIMarkers.YouwillneedtomodifytheAndroidManifest.xmlfileasbeforetouseyourMapsAPIkey.ThesourcecodeforMyMapFragment.javahasbeenmodifiedasshowninListing19-5.ThescreenwillappearsimilartoFigure19-4.

Listing19-5.CodefortheMapFragmentShowingMarkers

publicclassMyMapFragmentextendsSupportMapFragmentimplementsOnMapReadyCallback{

publicstaticMyMapFragmentnewInstance(){MyMapFragmentmyMF=newMyMapFragment();returnmyMF;}

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);getMapAsync(this);}

@OverridepublicvoidonActivityCreated(BundlesavedInstanceState){super.onActivityCreated(savedInstanceState);setRetainInstance(true);}

@OverridepublicvoidonMapReady(GoogleMapmyMap){LatLngdisneyMagicKingdom=newLatLng(28.418971,-81.581436);LatLngdisneySevenLagoon=newLatLng(28.410067,-81.583699);

//AddamarkerMarkerOptionsmarkerOpt=newMarkerOptions().draggable(false)

Page 475: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

.flat(false).position(disneyMagicKingdom).title("MagicKingdom").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));myMap.addMarker(markerOpt);

markerOpt.position(disneySevenLagoon).title("SevenSeasLagoon");myMap.addMarker(markerOpt);

//DeriveaboundingboxaroundthemarkersLatLngBoundslatLngBox=LatLngBounds.builder().include(disneyMagicKingdom).include(disneySevenLagoon).build();

//MovethecameratozoominonourlocationsmyMap.moveCamera(CameraUpdateFactory.newLatLngBounds(latLngBox,200,200,0));}}

Page 476: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure19-4.Markersonamap

Onceagain,everythingstartsfromacquiringtheGoogleMapobjectfromtheMapFragment.Oncethemapisavailable,youcancreatemarkerswhichinthiscasearebasedonacoupleoffixedLatLngobjects.You’llnoticethoughthatyoudon’tdirectlyinstantiateaMarkerobject.Instead,youuseaMarkerOptionsobjecttospecifyhowthemarkershouldbecreated.ItiswithintheMarkerOptionsobjectthatyoudecidetheposition,title,markershape,color,etc.WhileyoucouldinstantiateaMarkerobjectandthencalleachsetterthatyouwant,MarkerOptionsmakesthingsmucheasier,especiallyifyouneedtocreatemultiplemarkersthatwillsharecommonfeatures.ThissampleonlyusessomeoftheMarkerOptionsfeatures;pleaseseethereferencedocumentationtolearnalloftheoptionsavailable.

Thenextthingyoulikelywanttodoisshowthemaptotheusersuchthatallthemarkersarevisibleatthesametime.Thisrequirestwothings:centeringthemapinthemiddleofthemarkers,andsettingthezoomlevelashighaspossiblewithoutbeingsoclosethatyoucan’tfitallthemarkersintotheview.Fortunately,ahelperclassisavailableforthispurpose.TheLatLngBoundsobjectiscreatedbypassingitalloftheLatLngpointsthatshouldbewithintheview,anditcalculatesthesmallestboxthatcontainsthemall.Inthissample,bothpointsarepassedinatonce.Youcouldalsousealooptopassinallthe

Page 477: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

pointsandtheninvokethebuild()methodtoreturntheboundingbox.

Onceyouhaveaboundingbox,youneedtoadjustthemap’scamera.IntheoldversionofGoogleMaps,therewasonlyastraight-downviewofamap,asifyouwereabovethemaplookingstraightdown.WithMapsAPIversion2,thereistheconceptofacamerathatcanlookstraightdown,butcanalsolookatanangle.Ifyouusetwofingersatthesametimeandswipethescreenfromtoptobottom,youwillseetheviewinganglechange.Youhaveineffectpivotedthecamerasoyouarenolongerlookingstraightdown.Thecameracanalsolooktotheeast,southoranyotherdirectionwhenitisangled.Youcantwisttwofingerstorotatethemaptoo.

Allthesecameraangles,zoomlevelsandsoonarecontrolledusingthemap’sanimateCamera()ormoveCamera()methods.ThesemethodstakeaCameraUpdateobjectasinstructions,andtheCameraUpdateFactoryclassgeneratesthose.Inthesample,theboundingboxispassedtotheCameraUpdateFactoryanditreturnsanappropriateCameraUpdatesothatthecamerawillbepositionedinthebestplacetoseeallthemarkers.ThereareseveralothermethodstoCameraUpdateFactorytoaccommodateotherwaysofpositioningthecamera.YoudocansimplezoomIn()andzoomOut()forexample.YoucanalsocreateaCameraPositionobjectandusethat.

Allinall,you’llagreethatplacingmarkersonamapcouldn’tbeeasier.Orcouldit?Wedon’thaveadatabaseoflatitude/longitudepairs,butwe’reguessingthatwe’llneedtosomehowcreateoneormoreLatLngobjectsusingarealaddress.That’swhenyoucanusetheGeocoderclass,whichispartofthelocationpackagethatwe’lldiscussnext.

UnderstandingtheLocationPackageTheandroid.locationpackageprovidesfacilitiesforlocation-basedservices.Inthissection,wearegoingtodiscusstwoimportantpiecesofthispackage:theGeocoderclassandtheLocationManagerservice.We’llstartwithGeocoder.

GeocodingwithAndroidIfyouaregoingtodoanythingpracticalwithmaps,you’lllikelyhavetoconvertanaddress(orlocation)toalatitude/longitudepair.Thisconceptisknownasgeocoding,andtheandroid.location.Geocoderclassprovidesthisfacility.Infact,theGeocoderclassprovidesbothforwardandbackwardconversion—itcantakeanaddressandreturnalatitude/longitudepair,anditcantranslatealatitude/longitudepairintoalistofaddresses.Theclassprovidesthefollowingmethods:

List<Address>getFromLocation(doublelatitude,doublelongitude,intmaxResults)

List<Address>getFromLocationName(StringlocationName,intmaxResults,double

Page 478: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

lowerLeftLatitude,doublelowerLeftLongitude,doubleupperRightLatitude,doubleupperRightLongitude)

List<Address>getFromLocationName(StringlocationName,intmaxResults)

Itturnsoutthatcomputinganaddressisnotanexactsciencebecauseofthevariouswaysalocationcanbedescribed.Forexample,thegetFromLocationName()methodscantakethenameofaplace,thephysicaladdress,anairportcode,orsimplyawell-knownnameforthelocation.Thus,themethodsreturnalistofaddressesandnotasingleaddress.Becausethemethodsreturnalist,whichcouldbequitelong(andtakealongtimetoreturn),youareencouragedtolimittheresultsetbyprovidingavalueformaxResultsthatrangesbetween1and5.Now,let’sconsideranexample.

Listing19-6showstheXMLlayoutandcorrespondingcodefortheactivityandmapfragmentshowninFigure19-5.Toruntheexample,you’llneedtoupdatethemanifestwithyourownMapsAPIkey.

Listing19-6.WorkingwiththeAndroidGeocoderClass

<!--Thisisactivity_main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.androidbook.maps.whereami.MainActivity"tools:ignore="MergeRootFrame">

<EditTextandroid:id="@+id/locationName"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Enterlocationname"android:inputType="text"android:imeOptions="actionGo"/>

<FrameLayoutandroid:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"/>

</LinearLayout>

Page 479: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

/***ThisisfromMainActivity.java**/publicclassMainActivityextendsFragmentActivity{

privatestaticfinalStringMAPFRAGTAG="MAPFRAGTAG";MyMapFragmentmyMapFrag=null;privateGeocodergeocoder;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

if((myMapFrag=(MyMapFragment)getSupportFragmentManager().findFragmentByTag(MAPFRAGTAG))==null){myMapFrag=MyMapFragment.newInstance();getSupportFragmentManager().beginTransaction().add(R.id.container,myMapFrag,MAPFRAGTAG).commit();}if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.GINGERBREAD&&!Geocoder.isPresent()){Toast.makeText(this,"Geocoderisnotavailableonthisdevice",Toast.LENGTH_LONG).show();finish();}geocoder=newGeocoder(this);EditTextloc=(EditText)findViewById(R.id.locationName);loc.setOnEditorActionListener(newOnEditorActionListener(){@OverridepublicbooleanonEditorAction(TextViewv,intactionId,KeyEventevent){if(actionId==EditorInfo.IME_ACTION_GO){StringlocationName=v.getText().toString();

try{List<Address>addressList=

geocoder.getFromLocationName(locationName,5);

Page 480: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

if(addressList!=null&&addressList.size()>0){//Log.v(TAG,"Address:"+addressList.get(0).toString());myMapFrag.gotoLocation(newLatLng(addressList.get(0).getLatitude(),addressList.get(0).getLongitude()),locationName);}}catch(IOExceptione){e.printStackTrace();}}returnfalse;}});}}

publicclassMyMapFragmentextendsSupportMapFragmentimplementsOnMapReadyCallback{privateGoogleMapmMap=null;

publicstaticMyMapFragmentnewInstance(){MyMapFragmentmyMF=newMyMapFragment();returnmyMF;}

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);getMapAsync(this);}

@OverridepublicvoidonActivityCreated(BundlesavedInstanceState){super.onActivityCreated(savedInstanceState);setRetainInstance(true);}

publicvoidgotoLocation(LatLnglatlng,StringlocString){if(mMap==null)return;//Addamarkerforthegivenlocation

Page 481: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MarkerOptionsmarkerOpt=newMarkerOptions().draggable(false).flat(false).position(latlng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)).title("Youchose:").snippet(locString);//SeetheonMarkerClickedcallbackforwhywedothismMap.addMarker(markerOpt);

//MovethecameratozoominonourlocationmMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng,15));}

@OverridepublicvoidonMapReady(GoogleMaparg0){mMap=arg0;}}

Page 482: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure19-5.Geocodingtoapointgiventhelocationname

TodemonstratetheusesofgeocodinginAndroid,typethenameoraddressofalocationintheEditTextfieldandthentaptheGobuttononthekeyboard.Tofindtheaddressofalocation,wecallthegetFromLocationName()methodofGeocoder.Thelocationcanbeanaddressorawell-knownnamesuchas“WhiteHouse.”Geocodingcanbeaprolongedoperation,sowerecommendthatyoulimittheresultstofive,astheAndroiddocumentationsuggests.

ThecalltogetFromLocationName()returnsalistofaddresses.Thesampleapplicationtakesthelistofaddressesandprocessesthefirstoneifanywerefound.Everyaddresshasalatitudeandlongitude,whichyouusetocreateaLatLng.YouthencallourgotoLocation()methodtonavigatetothepoint.Thisnewmethodinthemapfragmentcreatesanewmarker,addsittothemap,andmovesthecameratothemarkerwithazoomlevelof15.Thezoomlevelcanbesettoafloatbetween1and21,inclusive.Asyoumovefrom1toward21by1’s,thezoomlevelincreasesbyafactorof2.Wecouldhavepresentedadialogtodisplaymultiplefoundlocationsifwewantedto,butfornow,we’lljustdisplaythefirstlocationreturnedtous.

Inourexampleapplication,weonlyreadthelatitudeandlongitudeofourreturned

Page 483: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Address.Infact,therecanbeatonofdataaboutAddressesreturnedtous,includingthelocation’scommonname,street,city,state,postal/ZIPcode,country,andevenphonenumberandwebsiteURL.Youshouldunderstandafewpointswithrespecttogeocoding:

WhiletheGeocoderclassmayexist,theservicemaynotbeimplemented.IfthedeviceisGingerbreadorhigher,youshouldcheckwithGeocoder.isPresent()beforeattemptingtogeocodeinyourapplication.

Areturnedaddressisnotalwaysanexactaddress.Obviously,becausethereturnedlistofaddressesdependsontheaccuracyoftheinput,youneedtomakeeveryefforttoprovideanaccuratelocationnametotheGeocoder.

Wheneverpossible,setthemaxResultsparametertoavaluebetween1and5.

YoushouldseriouslyconsiderdoingthegeocodingoperationinadifferentthreadfromtheUIthread.Therearetworeasonsforthis.Thefirstisobvious:theoperationistime-consuming,andyoudon’twanttheUItohangwhileyoudothegeocoding,causingAndroidtokillyouractivity.Thesecondreasonisthat,withamobiledevice,youalwaysneedtoassumethatthenetworkconnectioncanbelostandthattheconnectionisweak.Therefore,youneedtohandleinput/output(I/O)exceptionsandtimeoutsappropriately.Onceyouhavecomputedtheaddresses,youcanposttheresultstotheUIthread.SeetheincludedsampleapplicationcalledWhereAmIGeocoder2forhowtodothis.

UnderstandingLocationServicesLocationServicesprovidetwomainfunctions:amechanismforyoutoobtainthedevice’sgeographicallocationandafacilityforyoutobenotified(viaanintent)whenthedeviceentersorexitsaspecifiedgeographicallocation.Thislatteroperationisknownasgeofencing.

Inthissection,youaregoingtolearnhowtofindthedevice’scurrentlocation.Tousetheservice,youmustfirstobtainareferencetoit.Listing19-7showsasimpleusageoftheFusedLocationProviderApiservice.ThesampleprojectforthisiscalledWhereAmILocationAPI.

Listing19-7.UsingtheLocationProviderAPI

publicclassMyMapFragmentextendsSupportMapFragmentimplementsGoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,OnMapReadyCallback{

Page 484: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

privateContextmContext=null;privateGoogleMapmMap=null;privateGoogleApiClientmClient=null;privateLatLngmLatLng=null;

publicstaticMyMapFragmentnewInstance(){MyMapFragmentmyMF=newMyMapFragment();returnmyMF;}

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);getMapAsync(this);}

@OverridepublicvoidonActivityCreated(BundlesavedInstanceState){super.onActivityCreated(savedInstanceState);if(mClient==null){//firsttimein,setupthisfragmentsetRetainInstance(true);

mContext=getActivity().getApplication();mClient=newGoogleApiClient.Builder(mContext,this,this).addApi(LocationServices.API).build();mClient.connect();}}

@OverridepublicvoidonConnectionFailed(ConnectionResultarg0){Toast.makeText(mContext,"Connectionfailed",Toast.LENGTH_LONG).show();}

@OverridepublicvoidonConnected(Bundlearg0){//Figureoutwhereweare(lat,long)asbestaswecan//basedontheuser'sselectionsforLocationSettingsFusedLocationProviderApilocator=LocationServices.FusedLocationApi;

Page 485: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

LocationmyLocation=locator.getLastLocation(mClient);//iftheservicesarenotavailable,couldgetanulllocationif(myLocation==null)return;doublelat=myLocation.getLatitude();doublelng=myLocation.getLongitude();mLatLng=newLatLng(lat,lng);doWhenEverythingIsReady();}

@OverridepublicvoidonConnectionSuspended(intarg0){Toast.makeText(mContext,"Connectionsuspended",Toast.LENGTH_LONG).show();}

@OverridepublicvoidonMapReady(GoogleMaparg0){mMap=arg0;doWhenEverythingIsReady();}

privatevoiddoWhenEverythingIsReady(){if(mMap==null||mLatLng==null)return;//AddamarkerMarkerOptionsmarkerOpt=newMarkerOptions().draggable(false).flat(true).position(mLatLng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));mMap.addMarker(markerOpt);

//MovethecameratozoominonourlocationmMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mLatLng,15));}}

Toacquirealocationservice,youfirstneedtocreateaGoogleAPIclientobject,whichmakesavailabletoyoutheservicesfromGooglePlayServices.Thisisrelativelyeasytodo,andonceyouhavetheclientobject,youneedtocallitsconnect()method.ThiswilllaterinvoketheonConnected()callbackasynchronouslytoletyourapplicationknowthattheclienthasbeenconnectedandisnowavailableforuse.OryourapplicationmaygettheonConnectionFailed()callback,inwhichcaseyoushouldtake

Page 486: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

appropriateaction.ForthesamplewesimplyshowaToastmessagewhentheconnectionattempthasfailed.Lateronyou’llseehowtodealmorerobustlywithafailedconnection.

WhentheonConnected()callbackisinvoked,nowyoucanworkwiththelocationproviderAPI.Recallthatatthebeginningofthischapteryousetpermissionsinthemanifestfiletoaccesslocationinformation.FinelocationsuseGPSwhilecoarselocationsusecelltowersandWiFihotspots.UsingafusedlocationproviderAPImeansthatyourapplicationisn’tworryingaboutwhatisenabledorwhatpermissionsareset.TheAPIcallsarethesame.Youjustaskforlocationsandyouwillgetthebestlocationinformationthatisavailableatthetime.

Forthissample,wecallthegetLastLocation()method.Withluck,thelocationthatisreturnedisverycurrent;however,beawarethatthelastlocationmightbefromminutesorhoursago.TheLocationobjectcantellyou,viathegetTime()method,whenthislocationfixwasobtained.Youcouldchecktoseeifitisnewenoughforyourpurposesbeforedecidingtouseit.ItistechnicallypossiblethatgetLastLocation()willreturnnullsoyoushouldbepreparedforthatcaseaswell.ThiscanhappenifLocationServiceshavebeendisabledinSettings.

You’llseesoonhowtogetupdatestolocations.Fornow,thesampletakeswhateverthelastlocationwasandcreatesamapmarkeroutofitfordisplaytotheuser.Youshouldrecognizethecodetocreateamarkerfromtheprevioussectionofthischapter.

HowtoEnableLocationServicesYoumightthinkthere’sasimpleAPItoenableLocationServicesiftheyarenotturnedonwhenyourapplicationruns.Unfortunately,thisisnotthecase.TogetLocationServicesturnedon,theusermustdothatfromwithintheSettingsscreensoftheirdevice.YourapplicationcanmakethisalotsimplerfortheuserbylaunchingthatparticularSettingsscreen.Thelocationsettingssourcescreenisreallyjustanactivity,andthisactivityissetuptorespondtoanintent.

Inthesampleapplicationjustcovered,youwillseethecodefromListing19-8intheactivity’sonCreate()callback.

Listing19-8.CheckingtoSeeIfLocationServicesAreOn

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

if((myMapFrag=(MyMapFragment)getSupportFragmentManager().findFragmentByTag(MAPFRAGTAG))==null){myMapFrag=MyMapFragment.newInstance();getSupportFragmentManager().beginTransaction().add(R.id.container,myMapFrag,MAPFRAGTAG).commit();

Page 487: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

if(!isLocationEnabled(this)){//nolocationserviceprovidersareenabledToast.makeText(context,"LocationServicesappeartobeturnedoff."+"Thisappcan'tworkwithoutthem.Pleaseturnthemon.",Toast.LENGTH_LONG).show();startActivityForResult(newIntent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS),0);}}

@SuppressWarnings("deprecation")publicbooleanisLocationEnabled(Contextcontext){intlocationMode=Settings.Secure.LOCATION_MODE_OFF;StringlocationProviders;

if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){try{locationMode=Settings.Secure.getInt(context.getContentResolver(),Settings.Secure.LOCATION_MODE);}catch(SettingNotFoundExceptione){e.printStackTrace();}returnlocationMode!=Settings.Secure.LOCATION_MODE_OFF;}else{locationProviders=Settings.Secure.getString(context.getContentResolver(),Settings.Secure.LOCATION_PROVIDERS_ALLOWED);return!TextUtils.isEmpty(locationProviders);}}

AchangeoccurredinAndroid19(KitKat)wherenewsettingsvalueswereaddedtothestaticSettings.Secureclass.ThismadeiteasiertotellifLocationServiceswereturnedonornot,andwhichones,buttheuserstillneedstodotheworktoenabletheservices.Therearetwowaysinthiscodetocheckforservices:useoneofthenewvalues,ordoagetontheavailablelocationproviders.ThefirstpartofListing19-8checkstoseeiftheversionofAndroidisKitKatorhigher,andifsoitlooksforthevalueofthenewSettingforlocationmode.Thesecondpartofthecode(iftheversionofAndroidisolderthanKitKat)doesagetontheallowedlocationproviders.Iflocationmodeisnotoff,orifthereisatleastonelocationprovideravailable,thenLocationServicesarerunning.Ifnot,

Page 488: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thiscodelaunchesanintenttotheLocationSettingsscreen.Atthatpoint,thisactivitywouldbepausedwhiletheSettingsactivityruns.WhentheSettingsactivityisdone,ouractivitywillresume.

IfyouwanttohandlearesponsefromtheSettingsactivity(i.e.,benotifiedwhenthatactivityisdoneandpresumablyasettingchangehasbeenmade),youmustimplementtheonActivityResult()callbackinyouractivity.Andalsokeepinmindthatalthoughyouhopetheuserturnsonlocationservices,theymaynot.Youwillneedtocheckagaintoseeiftheuserhasenabledlocationservicesandtakeappropriateactionbasedontheresult.We’llshowyouhowtodoallofthisinalatersection.

LocationProvidersYou’veseentheFusedLocationApi,butyoushouldalsobeawareoftheolder,alternatelocationproviders.Thehardwareisrightthereonthedeviceforgettinglocationinformation,andthelocationproviderswillgiveittoyourapplication.You’llsoonseehowtheFusedLocationApihandlesyourlocationneedsatahigherlevelthantheseproviders.Butifyouneedtodigintothedetails,forexampletocheckthestatusoftheavailableGPSsatellites,you’llbehappytoknowtheseprovidersexist.GooglerecommendsthateveryoneswitchovertotheFusedLocationApi;butsinceitreliesonGooglePlayServices,thatmeansapplicationsthatuseFusedLocationApiwillnotrunonanon-GoogleAndroiddevice.

TheLocationManagerserviceisasystem-levelservice.System-levelservicesareservicesthatyouobtainfromthecontextusingtheservicename;youdon’tinstantiatethemdirectly.Theandroid.app.ActivityclassprovidesautilitymethodcalledgetSystemService()thatyoucanusetoobtainasystem-levelservice.YoucallgetSystemService()andpassinthenameoftheserviceyouwant,inthiscase,Context.LOCATION_SERVICE.You’llseethisshortlyinListing19-9.

TheLocationManagerserviceprovidesgeographicallocationdetailsbyusinglocationproviders.Currently,therearethreetypesoflocationproviders:

GPSprovidersuseaGlobalPositioningSystemtoobtainlocationinformation.

Networkprovidersusecell-phonetowersorWiFinetworkstoobtainlocationinformation.

Thepassiveproviderislikealocationupdatesniffer,anditpassestoyourapplicationlocationupdatesthatarerequestedbyotherapplications,withoutyourapplicationhavingtospecificallyrequestanylocationupdates.Ofcourse,ifnooneelseisrequestinglocationupdates,youwon’tgetanyeither.

SimilartotheFusedLocationApi,theLocationManagerclasscanprovidethedevice’slastknownlocation,thistimeviathegetLastKnownLocation()method.Locationinformationisobtainedfromaprovider,sothemethodtakesasaparameterthenameoftheprovideryouwanttouse.Validvaluesforprovidernamesare

Page 489: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

LocationManager.GPS_PROVIDER,LocationManager.NETWORK_PROVIDER,andLocationManager.PASSIVE_PROVIDER.Notethatthereisnooptionforafusedprovider,sincethatisaseparatelocation-findingcapability.

Inorderforyourapplicationtosuccessfullygetlocationinformation,itmusthavetheappropriatepermissionsintheAndroidManifest.xmlfile.android.permission.ACCESS_FINE_LOCATIONisrequiredforGPSandforpassiveproviders,whereasandroid.permission.ACCESS_COARSE_LOCATIONorandroid.permission.ACCESS_FINE_LOCATIONcanbeusedfornetworkproviders,dependingonwhatyouneed.Forinstance,assumeyourapplicationwilluseGPSornetworkdataforlocationupdates.BecauseyouneedACCESS_FINE_LOCATIONforGPS,you’vealsosatisfiedpermissionsfornetworkaccess,soyoudonotneedtoalsospecifyACCESS_COARSE_LOCATION.Ifyou’reonlygoingtousethenetworkprovider,youcouldgetbywithonlyACCESS_COARSE_LOCATIONinthemanifestfile.

CallinggetLastKnownLocation()returnsanandroid.location.Locationinstance,ornullifnolocationisavailable.TheLocationclassprovidesthelocation’slatitudeandlongitude,thetimethelocationwascomputed,andpossiblythedevice’saltitude,speed,andbearing.ALocationobjectcanalsotellyouwhichprovideritcamefromusinggetProvider(),whichwillbeeitherGPS_PROVIDERorNETWORK_PROVIDER.Ifyou’regettinglocationupdatesviathePASSIVE_PROVIDER,rememberthatyou’reonlyreallysniffinglocationupdates,soallupdatesareultimatelyfromeitherGPSorthenetwork.

BecausetheLocationManageroperatesonproviders,theclassprovidesAPIstoobtainproviders.Forexample,youcangetalloftheknownprovidersbycallinggetAllProviders().YoucanobtainaspecificproviderbycallinggetProvider(),passingthenameoftheproviderasanargument(suchasLocationManager.GPS_PROVIDER).OnethingtowatchoutforisthatgetAllProviders()willreturnprovidersthatyoumaynothaveaccesstoorthatarecurrentlydisabled.Fortunately,youareabletodeterminethestatusofprovidersusingothermethods,suchasisProviderEnabled(StringproviderName)orgetProviders(booleanenabledOnly),whichyoucouldcallwithavalueoftruetogetonlyprovidersyouareabletouseimmediately.

There’sanotherwaytogetasuitableprovider,andthatistousethegetProviders(Criteriacriteria,booleanenabledOnly)methodofLocationManager.Byspecifyingcriteriaforlocationupdates,andbysettingenabledOnlytotruesoyougetprovidersthatareenabledandreadytogo,youcangetalistofprovidernamesreturnedtoyouwithouthavingtoknowthespecificsofwhichprovideryougot.Thiscouldbemoreportable,becauseadevicemayhaveacustomLocationProviderthatmeetsyourneedswithoutyouhavingtoknowaboutitinadvance.TheCriteriaobjectcanbesetwithparametersthatincludeaccuracylevelandtheneedforinformationaboutspeed,bearing,altitude,cost,andpowerrequirements.

Page 490: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Ifnoprovidersmeetyourcriteria,anulllistwillbereturned,allowingyoutoeitherbailoutorrelaxthecriteriaandtryagain.

SendingLocationUpdatestoYourApplicationWhendoingdevelopmenttesting,yourapplicationneedslocationinformation,andtheemulatordoesn’thaveaccesstoGPSorcelltowers.Inorderforyoutotestyourapplicationintheemulator,youcanmanuallysendlocationupdatesfromEclipse.Listing19-9showsasimpleexampletoillustratehowtodothis.We’regoingtostickwiththeLocationManagerapproachhere,andthenshowtheFusedLocationApiapproachlater.

Listing19-9.RegisteringforLocationUpdates

publicclassLocationUpdateDemoActivityextendsActivity{LocationManagerlocMgr=null;LocationListenerlocListener=null;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

locMgr=(LocationManager)getSystemService(Context.LOCATION_SERVICE);

locListener=newLocationListener(){publicvoidonLocationChanged(Locationlocation){if(location!=null){Toast.makeText(getBaseContext(),"Newlocationlatitude["+location.getLatitude()+"]longitude["+location.getLongitude()+"]",Toast.LENGTH_SHORT).show();}}

publicvoidonProviderDisabled(Stringprovider){}

publicvoidonProviderEnabled(Stringprovider){}

Page 491: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonStatusChanged(Stringprovider,intstatus,Bundleextras){}};}

@OverridepublicvoidonResume(){super.onResume();

locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,//minTimeinms0,//minDistanceinmeterslocListener);}

@OverridepublicvoidonPause(){super.onPause();locMgr.removeUpdates(locListener);}}

We’renotdisplayingauserinterfaceforthisexample,sothestandardinitiallayoutXMLfilewilldo,aswellasaregularactivity.

OneoftheprimaryusesoftheLocationManagerserviceistoreceivenotificationsofthedevice’slocation.Listing19-9demonstrateshowyoucanregisteralistenertoreceivelocation-updateevents.Toregisteralistener,youcalltherequestLocationUpdates()method,passingtheprovidertypeasoneoftheparameters.Whenthelocationchanges,theLocationManagercallstheonLocationChanged()methodofthelistenerwiththenewLocation.Itisveryimportantthatyouremoveanyregistrationsforlocationupdatesattheappropriatetime.Inourexample,wedoregistrationinonResume(),andweremovethatregistrationinonPause().Ifwearen’tgoingtobearoundtodoanythingwithlocationupdates,weshouldtelltheprovidernottosendthem.There’salsothepossibilitythatouractivitycouldbedestroyed(forexample,iftheuserrotatestheirdeviceandouractivityisrestarted),inwhichcaseouroldactivitycouldstillexist,bereceivingupdates,displayingthemwithToast,andtakingupmemory.

Inourexample,wesettheminTimeandminDistancetozero.ThistellstheLocationManagertosendusupdatesasoftenaspossible.Thesearenotdesiredsettingsforyourproductionapplication,oronrealdevices,butweusethemheretomakethedemonstrationsrunbetterintheemulators.(Inreallife,youwouldnotwantthehardwaretryingtofigureoutourcurrentpositionsooften,asthisdrainsthebattery.)Setthesevaluesappropriatelyforthesituation,tryingtominimizehowoftenyoutrulyneedto

Page 492: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

benotifiedofachangeinposition.Googletypicallyrecommendsvaluesnosmallerthan20seconds.

TestingLocationApplicationswiththeEmulatorLet’stestthisintheemulator,usingtheDalvikDebugMonitorService(DDMS)perspectivethatshipswiththeADTplug-inforEclipse.TheDDMSUIprovidesascreenforyoutosendtheemulatoranewlocation(seeFigure19-6).

Figure19-6.UsingtheDDMSUIinEclipsetosendlocationdatatotheemulator

TogettotheDDMSinEclipse,useWindow OpenPerspective DDMS.TheEmulatorControlviewshouldalreadybethereforyou,butifnot,useWindow ShowViewOther Android EmulatorControltomakeitvisibleinthisperspective.Youmayneedtoscrolldownintheemulatorcontroltofindthelocationcontrols.AsshowninFigure19-6,theManualtabintheDDMSuserinterfaceallowsyoutosendanewGPSlocation(latitude/longitudepair)totheemulator.SendinganewlocationwillfiretheonLocationChanged()methodonthelistener,whichwillresultinamessagetotheuserconveyingthenewlocation.

Youcansendlocationdatatotheemulatorusingseveralothertechniques,asshownintheDDMSuserinterface(seeFigure19-6).Forexample,theDDMSinterfaceallowsyoutosubmitaGPSExchangeFormat(GPX)fileoraKeyholeMarkupLanguage(KML)file.

Page 493: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

YoucanobtainsampleGPXfilesfromthesesites:

www.topografix.com/gpx_resources.asp

http://tramper.co.nz/?view=gpxFiles

www.gpsxchange.com/

Similarly,youcanusethefollowingKMLresourcestoobtainorcreateKMLfiles:

http://bbs.keyhole.com/

http://code.google.com/apis/kml/documentation/kml_tut.html

NoteSomesitesprovideKMZfiles.ThesearezippedKMLfiles,sosimplyunzipthemtogettotheKMLfile.SomeKMLfilesneedtohavetheirXMLnamespacevaluesalteredinordertoplayproperlyinDDMS.IfyouhavetroublewithaparticularKMLfile,makesureithasthis:

<kmlxmlns=”http://earth.google.com/kml/2.x“>.

YoucanuploadaGPXorKMLfiletotheemulatorandsetthespeedatwhichtheemulatorwillplaybackthefile(seeFigure19-7).Theemulatorwillthensendlocationupdatestoyourapplicationbasedontheconfiguredspeed.AsFigure19-7shows,aGPXfilecontainspoints,showninthetoppart,andpaths,showninthebottompart.Youcan’tplayapoint,butwhenyouclickapoint,itwillbesenttotheemulator.Youclickapath,andthenthePlaybuttonwillbeenabledsoyoucanplaythepoints.

Page 494: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure19-7.UploadingGPXandKMLfilestotheemulatorforplayback

NoteTherehavebeenreportsthatnotallGPXfilesareunderstandablebytheemulatorcontrol.IfyouattempttoloadaGPXfileandnothinghappens,tryadifferentfilefromadifferentsource.

Listing19-9includessomeadditionalmethodsforLocationListenerwehaven’tmentionedyet.TheyarethecallbacksonProviderDisabled(),onProviderEnabled(),andonStatusChanged().Foroursample,wedidnotdoanythingwiththese,butinyourapplication,youcouldbenotifiedwhenalocationprovider,suchasgps,isdisabledorenabledbytheuser,orwhenastatuschangeswithoneofthelocationproviders.StatusesincludeOUT_OF_SERVICE,TEMPORARILY_UNAVAILABLE,andAVAILABLE.Evenifaproviderisenabled,itdoesnotmeanthatitwillbesendinganylocationupdates,andyoucantellthatusingstatuses.NotethatonProviderDisabled()willbeinvokedimmediatelyifarequestLocationUpdates()iscalledforadisabledprovider.

SendingLocationUpdatesfromtheEmulatorConsoleEclipsehassomeeasy-touse-toolsforsendinglocationupdatestoyourapplication,butthere’sanotherwaytodoit.Youcouldlaunchtheemulatorconsole,usingthefollowing

Page 495: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

commandfromatoolswindow:

telnetlocalhostemulator_port_number

whereemulator_port_numberisthenumberassociatedtotheinstanceoftheAVDthat’salreadyrunning,displayedinthetitlebaroftheemulatorwindow.Youmayneedtoinstalltelnetforyourworkstationifit’snotalreadyavailable.Onceyou’reconnected,youcanusethegeofixcommandtosendinlocationupdates.Tosendinlatitude/longitudecoordinateswithaltitude(altitudeisoptional),usethisformofthecommand:

geofixlonlat[altitude]

Forexample,thefollowingcommandwillsendthelocationofJacksonville,Floridatoyourapplicationwithanaltitudeof120meters.

geofix-81.562530.334954120

Pleasepaycarefulattentiontotheorderoftheargumentstothegeofixcommand.Longitudeisthefirstargument,andlatitudeisthesecond.

WhatCanYouDowithaLocation?Asmentionedbefore,Locationscantellyouthelatitudeandlongitude,whentheLocationwascomputed,theproviderthatcomputedthisLocation,andoptionallythealtitude,speed,bearing,andaccuracylevel.DependingontheproviderwheretheLocationcamefrom,therecouldbeextrainformationaswell.Forexample,iftheLocationcamefromaGPSprovider,thereisanextrasBundlethatwilltellyouhowmanysatelliteswereusedtocomputetheLocation.Theoptionalvaluesmayormaynotbepresent,dependingontheprovider.ToknowifaLocationhasoneofthesevalues,theLocationclassprovidesasetofhas…()methodsthatreturnabooleanvalue,forexamplehasAccuracy().BeforerelyingonthereturnvalueofgetAccuracy(),itwouldbewisetocallhasAccuracy()first.

TheLocationclasshassomeotherusefulmethods,includingastaticmethoddistanceBetween(),whichwillreturntheshortestdistancebetweentwoLocations.Anotherdistance-relatedmethodisdistanceTo(),whichwillreturntheshortestdistancebetweenthecurrentLocationobjectandtheLocationobjectpassedtothemethod.NotethatdistancesareinmetersandthatthedistancecalculationstakeintoaccountthecurvatureoftheEarth.Butalsobeawarethatthedistancesarenotprovidedintermsofthedistanceyouwouldhavetogobycar,forexample.

Ifyouwanttogetdrivingdirectionsordrivingdistances,youwillneedtohaveyourbeginningandendingLocations,buttodothecalculations,youwilllikelyneedtousetheGoogleDirectionsAPI.TheDirectionsAPIwouldallowyourapplicationtoshowhowtogetfromyourbeginningtoyourendinglocation.ThisisanotheroftheGoogleAPIclientAPIsthatyoucanenableforyourapplication.

SettingUpforGooglePlayServicesLocationUpdates

Page 496: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

You’veseenhowtogetlocationupdateswithaLocationManager,butlet’sreturntotheFusedLocationProviderApitoseehowtogetlocationupdatesfromit.ThesampleprojectforthissectionisFusedLocationApiUpdates.ThisoneisabittrickierbecausewearedealingwithGooglePlayServices,anindependentservicerunningonthedevice.Therefore,youcan’talwaysbesurethatyouhaveavalidclientconnection,andyouneedtobecarefulwhenrequestinglocationupdates.Forthisreason,yourapplicationwillneedtoworryaboutstate.

Intheearliersampleprogram(WhereAmILocationAPI),youcheckedtoseeifLocationServiceswereturnedon,butthecodeassumedthatGooglePlayServiceswereavailableandready.Nowyou’regoingtoseehowtocheckfortheexistenceofGooglePlayServicesandhowtheGooglePlayServicesUtilclasscanhelpyou.Thebasicflowistocheckeachdependencyforlocationupdatestooccurand,ifthereisawaytocorrectaproblem,helptheuserfixit.Iftheuserdoesnot,orcannot,fixaproblem,theapplicationquits.Iftheuserkeepsfixingproblemsuntileverythingisworking,thenlocationupdatesgetrequested,andtheapplicationdisplayslocationupdatesviaToastmessages.

Listing19-10showsourmainmethodfortryingtoconnect.YouwillseeinsidethismethodthesameLocationServicescheckfromtheearlierWhereAmILocationAPIsampleapplication.ThetryToConnect()methodwillbecalledfromtheactivity’sonResume()callback,sothateverytimethisactivityisresumed,anewclientconnectionwillbeestablishedtoGooglePlayServices.Wedonotwanttoassumethatanoldclientisstillvalidandactive.

Listing19-10.CheckingfortheAbilitytoDoLocationUpdates

privatevoidtryToConnect(){//CheckthatGooglePlayservicesisavailableintresultCode=GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);//IfGooglePlayservicesisavailable,thenwe'regoodif(resultCode==ConnectionResult.SUCCESS){Log.d(TAG,"GooglePlayservicesisavailable.");if(!isLocationEnabled(this)){if(lastFix==FIX.LOCATION_SETTINGS){//Sincewe'recomingthroughagain,itmeans//recoverydidn'thappen.Timetobailout.Log.e(TAG,"Locationsettingsdidn'twork");finish();}else{//nolocationserviceprovidersareenabledToast.makeText(this,"LocationServicesareoff."+"Can'tworkwithoutthem.Pleaseturnthemon.",Toast.LENGTH_LONG).show();Log.i(TAG,"LocationServicesneedtobeon."

Page 497: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

+"LaunchingtheSettingsscreen");startActivityForResult(newIntent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS),LOCATION_SETTINGS_REQUEST);lastFix=FIX.LOCATION_SETTINGS;}}else{client.connect();Log.v(TAG,"ConnectingtoGoogleApiClient…");}}//GooglePlayserviceswasnotavailableforsomereason//Seeiftheusercandosomethingaboutitelseif(GooglePlayServicesUtil.isUserRecoverableError(resultCode)){if(lastFix==FIX.PLAY_SERVICES){//Sincewe'recomingthroughagain,itmeans//recoverydidn'thappen.Timetobailout.Log.e(TAG,"Recoverydoesn'tseemtowork");finish();}else{Log.d(TAG,"GooglePlayservicesmaybeavailable."+"Askinguserforhelp");//Thisformofthedialogcallwillresultineithera//callbacktoonActivityResult,oradialogonCancel.GooglePlayServicesUtil.showErrorDialogFragment(resultCode,this,PLAY_SERVICES_RECOVERY_REQUEST,this);lastFix=FIX.PLAY_SERVICES;}}else{//Nohopeleft.Log.e(TAG,"GooglePlayServicesis/arenotavailable."+"Nopointincontinuing");finish();}}

TheGooglePlayServicesUtilclasshasseveralstaticmethodstohelpgeteverythingsetup

Page 498: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

forlocationupdates.ThefirstmethodisisGooglePlayServicesAvailable(),whichrequiresacontext.TheresultisanintegervaluewhichiseitherSUCCESSoroneofseveralothervalueswhichcouldindicateforexamplethattheservicesaremissing,ortheversionisnotappropriate.Formostpurposes,youdon’treallyneedtocareabouttheothervaluesthatarereturned,asyou’llsee.

IfGooglePlayServicesareavailable,youwillcheckforLocationServices(asbefore)andiftheyareokay,youcaninvoketheconnect()methodontheGoogleApiClientclient.Theconnect()callisasynchronousandaseparatecallbackwillhandletheresultsoftheconnectcall.Asbefore,ifLocationServicesarenotturnedon,youwouldlaunchthelocationsettingsactivitysotheusercouldturnthemon.Inthissample,wejustuseaToastmessagetotelltheuserwhytheyarebeingredirectedtotheSettingsscreen.Inaproductionapplication,youwouldprobablywanttoshowanalertdialogwithanOKandCancelbuttonbeforeredirectingtotheSettingsscreen.

IfGooglePlayServicesarenotavailable,thenextcheckistoseeiftheusercouldresolvetheissue,usingtheisUserRecoverableError()method.Hereyoupassintheresultcodefromtheearliercheck,whichshouldbesomethingotherthanSUCCESS.Thisiswhyyoudon’tneedtocarewhatothervaluewasreturned.Thismethoddecidesforyouiftheusercandosomethingaboutitornot.Iftheusercan’tcorrectthesituation(i.e.,isUserRecoverableError()returnsfalse),thentherereallyisn’tanythingelseyoucandoandyouwillprobablywanttobailout.Inthissampleapplicationalogmessageiswrittenandtheactivityends.Youmightwanttobemoregracefulinyourexit.

IftheusercandosomethingabouttheproblemwithGooglePlayServices,theGooglePlayServicesUtilclasshasyetanotherstaticmethodyoucanuse:showErrorDialogFragment().Thiswillshowadialogtotheuserindicatingwhattheproblemisandwhattheycandoaboutit.Thereareafewvariationsonthiscall,andthesampleisusingtheonewhichpopsadialogfragmentwhilelisteningforadialogcancel.Thedialogfragmentcouldlaunchanotheractivity,whichwouldresultinouronActivityResult()beingcalled.Forthisreason,youwanttopassinarequestvalue(i.e.,PLAY_SERVICES_RECOVERY_REQUEST),whichwillbepassedtoonActivityResult()later.Thismethodisalsoasynchronous,andyourapplicationwillseeeitheronActivityResult()invokedlater,ortheonCancel()forthedialog.ThesecondargumenttoshowErrorDialogFragment()isthecontext,andthelastargumentisthelistenerforthedialog.Becausewepassed'this'asthelastargument,torepresentthisactivity,thesampleactivitymustimplementDialogInterface.OnCancelListenerandhaveanonCancel()callback.

You’llsoonseethecodeforonActivityResult(),butyoushouldknowthatwhenaresultispassedbacktoyouractivity,you’regoingtohavedothesechecksagain,bycallingtryToConnect().ThatiswhythismethodsetsalastFixvalue,tokeeptrackofwhichproblemisbeingworkedon.Ifthesameproblemexistsaftertheuserhashadachancetofixit,wecouldassumethattheuserisn’tinterestedinfixingtheproblem,orthesystemisunabletofixtheproblem.Wedonotwantsomesortofinfiniteloopthattheusercannotbreakoutof.Forthissampleactivity,iftryToConnect()hitsthesameproblemtwiceinarow,itbailsoutandtheactivityisfinished.Yourapplicationmight

Page 499: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

wanttotakealternativeaction,givingtheusermoreoptionstocontinuetousetheapp.

TorecapwhathashappenedintryToConnect(),youcheckedfortheexistenceandreadinessofGooglePlayServices,aswellasLocationServices.Ifeverythinglookedgood,aconnectcallwasmadeontheGoogleClientApiclient.Iftheuserwasabletocorrectanything,asuitableintentwasfiredtolaunchanactivitytotakecareofit.Andifthesituationwashopeless,theactivityended.Nowlet’slookatthevariouscallbacksthatcouldresultfromtheseactions.

Iftheconnectionrequestwassuccessful,theonConnected()callbackwillfire.Listing19-11showswhatthislookslike.

Listing19-11.ClientIsConnectedSoRequestLocationUpdates

@OverridepublicvoidonConnected(Bundlearg0){//SetuplocationupdatesLog.v(TAG,"Connected!");lastFix=FIX.NO_FAIL;locator.requestLocationUpdates(client,locReq,this);Log.v(TAG,"Requestinglocationupdates(onConnected)...");}

Thisoneisprettystraightforward.IfwegotagoodconnectiontoGooglePlayServices,startaskingtheFusedLocationProviderApi(locator)forlocationupdates.You’llseemoreaboutlocReqlater,butfornowjustknowthatitisaLocationRequestobjectwithparametersthatdefinewhatkindsoflocationupdatesyourapplicationwants.Thismethodalsoresetsastatevariable(lastFix)whichwillmakemoresensesoon.

Iftheconnectionrequestwasnotsuccessful,theonConnectionFailed()callbackwillfire.Listing19-12showsthiscallback.

Listing19-12.HandlingaFailedConnectionAttempt

@OverridepublicvoidonConnectionFailed(ConnectionResultconnectionResult){/**GooglePlayservicescanresolvesomeerrorsitdetects.*Iftheerrorhasaresolution,trysendinganIntentto*startaGooglePlayservicesactivitythatcanresolve*theerror.*/if(connectionResult.hasResolution()){Log.i(TAG,"Connectionfailed,tryingtoresolveit…");

Page 500: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

if(lastFix==FIX.CONNECTION){//Sincewe'recomingthroughagain,itmeans//recoverydidn'thappen.Timetobailout.Log.e(TAG,"Connectionretrydidn'twork");finish();}try{//StartanactivitythattriestoresolvetheerrorlastFix=FIX.CONNECTION;connectionResult.startResolutionForResult(this,CONNECTION_FAILURE_RESOLUTION_REQUEST);}catch(IntentSender.SendIntentExceptione){//LogtheerrorLog.e(TAG,"Couldnotresolveconnectionfailure");e.printStackTrace();finish();}}else{/**Ifnoresolutionisavailable,displayerrortothe*user.*/Log.e(TAG,"Connectionfailed,noresolutionsavailable,"+GooglePlayServicesUtil.getErrorString(connectionResult.getErrorCode()));Toast.makeText(this,"Connectionfailed.Cannotcontinue",Toast.LENGTH_LONG).show();finish();}}

Iftheconnectionrequesthasfailed,itisstillpossiblethatthesituationcanbecorrected.Onceagainthereisamethodthatcantellifthereisawaytoresolvetheproblem.TheConnectionResultobjectcontainsbothanindicatorifthereisaresolution,aswellastheintenttofiretotrytoresolvethesituation.Inthiscase,theapplicationcallsstartResolutionForResult().Similartobefore,anintentwillbefired,someactivitywillbelaunched,andyourapplicationwillgetaresultbackinonActivityResult().NoticethatheretherequesttagisCONNECTION_FAILURE_RESOLUTION_REQUEST.Ifnothingcanbedone,displayanerrorandbailout.

Therecouldhavebeenseveralintentslaunched,eachofwhichshouldcauseyour

Page 501: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

onActivityResult()callbacktofire.Listing19-13showswhatthiscallbacklookslike.Rememberthattherecouldhavebeenthreeseparateintentsfiredtohandleproblems,sothiscallbackmustexpectanyofthethree.Alsokeepinmindthattheintentscausedanactivitytorun,meaningyouractivitygotpaused,anditwillresumerightaftertheonActivityResult()hasfired.ThisisamajorreasonwhythetryToConnect()method(showninListing19-10)isonlycalledfromtheactivity’sonResume()callback.Wheneverthisactivityisbeingresumed,ittriestomakeanewconnectiontoGooglePlayServicesandtosetuplocationupdates.Whenthisactivitypauses,itdisconnectsfromGooglePlayServices.Itiseasytoreconnectratherthantryingtohangontoaconnectionwhileitisnotneeded.

Listing19-13.GettingNewsBackfromtheLaunchedIntents

@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){/*Decidewhattodobasedontheoriginalrequestcode.*Notethatouractivitygotpausedtolaunchtheother*activity,soafterthiscallbackruns,ouractivity's*onResume()willrun.*/switch(requestCode){casePLAY_SERVICES_RECOVERY_REQUEST:Log.v(TAG,"GotaresultforPlayServicesRecovery");break;caseLOCATION_SETTINGS_REQUEST:Log.v(TAG,"GotaresultforLocationSettings");break;caseCONNECTION_FAILURE_RESOLUTION_REQUEST:Log.v(TAG,"Gotaresultforconnectionfailure");break;}Log.v(TAG,"resultCodewas"+resultCode);Log.v(TAG,"EndofonActivityResult");}

SinceonActivityResult()couldbecalledbecauseofanumberofintents,theswitchstatementisusedtofigureoutwhichoneisbeingrespondedto.TheGooglePlayServicescorrectiveactionmightsayitwassuccessfulbysettingtheresultCodetoActivity.RESULT_OK.Thisdoesn’tnecessarilymeanthattheuserfixedtheproblem,butittellsyouthatnothingfailed.IftheresponsetotheGooglePlayServicescorrectiveactionisActivity.RESULT_CANCELED,itcouldmeantherewassomesortoffailure.Regardlessiftheuserfixedtheproblemornot,you’regoingtoreturnfromthiscallback,andthenonResume()willrun,inwhichtryToConnect()willbecalledagain.Soitreallydoesn’tmatterwhatresultCodeis.Inpractice,evenwhenasettinghasbeenproperlysetforlocationupdatestooccur,youcouldseeresultCodesetto

Page 502: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RESULT_CANCELED.Similarly,ifthere’saresponsetotheotherfixes,logitandcontinuesinceonResume()willrunnextanyway.

Finally,referbacktotheonConnected()callbackinListing19-11,whichcallslocator.requestLocationUpdates(client,locReq,this).ThisiswheretheFusedLocationProviderApiwillbeaskedtosendlocationupdatesbacktothisactivity.GooglePlayServicesisupandrunning,andLocationServicesaresetappropriately.

Oncelocationupdateshavebeenrequested,anynewlocationupdateswillgetsenttotheonLocationChanged()callback.Inthissampleapplication,allthathappensisthatthelocationinformationisdisplayedinaToastmessage.Thenextsectiongoesintomoredetailonhowtorequestlocationupdates.

Thereareafewothermethodsintheactivitythatsofarwerenotdescribed.TheonPause()callbackdisconnectstheclientafterstoppingthelocationupdates.Youshouldnoticethattheclientischeckedforconnectednessbeforecallingmethods.TheGoogleApiClientclasshasamethodcalledisConnected(),whichyouwillusetobesureyourequestorremovelocationupdatesonlywhenthere’saconnectedclient.Otherwise,youwillgetanIllegalStateException.Thetwomethodsforsettingupthemenuarebasicmenucallbacks.Themenuisusedtoallowtheusertoswitchbetweenthevariouspriorityvalues.Whentheuserselectsamenuitem,thelocationrequestobjectisupdatedandpassedbackintoalterthelocationupdateprocess.TheonCancel()callbackcanbecalledfromthepop-uperrordialogthatisshownintryToConnect(seeListing19-10).Iftheusersimplyclosestheerrorfragmentdialogbox,weinferthattheuserdoesn’twanttogetupdatesandtheapplicationexits.

LocationUpdateswithFusedLocationProviderApiWiththeLocationManager,youhadtodealwiththespecificlocationproviders(i.e.,GPSorcell/WiFi).WiththeFusedLocationProviderApi,yousubmitaLocationRequestandtheAPIwillmakechoicesforyouofwhichproviderwouldbethebest,notonlyinitiallybutovertimeaswell.Ingeneral,thetrade-offwhengettinglocationupdatesisbetweenpowerconsumptionandaccuracy.GPSisusuallymoreaccuratebutusesthemostpower.Ontheotherhand,whenindoors,GPSmaybelessaccuratethancell/WiFi,andyou’dwanttoautomaticallyswitchtobemoreaccuratewhileconsumingtheleastamountofpower.TheFusedLocationProviderApicouldalsotakeadvantageofon-boardsensorssuchasagyroscopeorcompass.ThisAPIhidesthecomplexitiesoflocationfixingfromyou.

Youshouldwriteyourcodesoyou’rerequestinglocationupdatesonlywhenitmakessensetodoso.Ifyouaredisplayingthecurrentlocationonamap,andthemapisnotvisible,youdonotneedtorequestupdates.Therearecaseswhenyoumightwanttokeepgettingupdatesevenwhennotdisplayingthecurrentposition,andwe’llcoverthatinthenextsection.Thepointisthatlocationupdatescanbeabigdrainonthebattery,soaskforthemonlywhenyoureallyneedthem.Youshouldnotassumethattheuserisgoingto“berightback”andthereforekeepgettingupdates.Iftheysettheirdevicedownandwon’tbe

Page 503: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

lookingatitagainforsometime,you’dbetternotbedrainingthebatterydown.

Listing19-14showshowthesampleapplicationsetstheLocationRequestobjecttomakealocationupdatesrequestoftheFusedLocationProviderApi.ThisisdoneintheonCreate()callbackoftheactivity.

Listing19-14.SettingUpaLocationRequestObject

locReq=LocationRequest.create().setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY).setInterval(10000).setFastestInterval(5000);

Usethestaticcreate()method,thencalltheappropriatesetterstofillouttherequestobject.ThisobjectwillbepassedtotherequestLocationUpdates()methodoftheFusedLocationProviderApi.Abigdifferencefromdealingwiththeolderlocationprovidersisthatthisrequestobjectdoesnotmakeanyreferencetoaspecificlocationprovider.SimilartotheCriteriamethodoffindingaprovider,thisrequestobjectultimatelyselectsthefrequencyofupdatesandtheconsumptionofpower.

YoucanspecifythedesiredfrequencyoflocationupdatesusingsetInterval()andsetFastestInterval();bothtakealongargumentrepresentingthenumberofmilliseconds.Theformerissayingthatyouwanttogetalocationupdateonaregularbasis,everysomanymillisecondsapart.Thesystemwilltrytohonorthisifitisableto,buttherearenoguarantees.Youcouldgetupdatesmorefrequentlythandesired,evenmuchmorefrequently.Thatiswherethesecondmethodcomesin.Youcanspecifythefastestintervalforreceivinglocationupdates.Moreonthisinabit.

ThepowerportionoftherequestishandledbythesetPriority()setter.Therearecurrentlyfouroptionsfortheargument:

PRIORITY_NO_POWER

PRIORITY_LOW_POWER

PRIORITY_BALANCED_POWER_ACCURACY

PRIORITY_HIGH_ACCURACY

TheNO_POWERoptionisprettymuchsayingthatyourapplicationwillbeusingthepassiveproviderdescribedearlier.Theonlywaytonotconsumeanypoweristopiggybackoffofthelocationupdatesforanotherapplication.Therefore,theaccuracyofthelocationsmaynotbeveryaccurateorfrequent;italldependsonwhatotherapplicationsarerequesting.YoujustlearnedthatyoucanrequestafrequencyofupdatesusingsetInterval()andsetFastestInterval().Ifyouarepiggybackingoffofanotherapplication,andthatapplicationisreceivinglocationupdatesevery5seconds,butyoudon’twantupdatesfasterthanevery20seconds,youshouldusesetFastestInterval(20000)soyourapplicationisnotoverwhelmedwith

Page 504: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

updates.AtthesametimeyoucouldusesetInterval(60000)torequestadesiredintervalofoneupdateeveryminute.Iftherearefewotherlocationupdateshappeningonthedevice,youwon’thavetoworryaboutreducingthefrequencyfrom5secondsto20secondsapart,butatthesametimeyouprobablywon’tgetupdateseveryminuteeither.Youneedtousebothofthesesetterstoindicatewhatyourapplicationwants,butthatdoesn’tmeanyouareguaranteedtogetwhatyouwant.

TheLOW_POWERpriorityingeneralmeansthatlocationupdateswillbederivedonlyviacelltowertriangulationandWiFihotspotlocationinformation.Thesearelow-powerwaysofdeterminingposition,withacorrespondingreductioninaccuracy.Youcouldeasilyfindthelocationstobeaccurateonlytowithin1,500metersorworse,butthenyoucouldgetalocationthat’saccurateto10meters.Alloftheprioritieswilltakeadvantageofthepassiveprovider,soifanaccuratelocationupdatehappenstoberequestedbysomeotherapplication,yourapplicationcouldpickitupevenwhenyourpriorityissettolowpower.

TheBALANCEDprioritywilltrytodoadecentjoboftradingoffaccuracyforlesspower.Itwillconsiderusingalloftheavailablemethodsofdetermininglocation,exceptforGPS.

TheHIGH_ACCURACYprioritywillpotentiallyuseallavailablesourcesoflocationinformation,includingGPS.BecauseoftheGPSradio,thisprioritycouldconsumealotofbattery.

Locationupdatesalsodependonthelocationmodeofthedevice.Asyousawearlier,theLocationSettingschangedinKitKattoallowtheusertospecifyamodeoflocationupdatesfortheirdevice.ReferringnowtotheSettings.Secureclass,thelocationmodesettingvaluesareasfollows:

LOCATION_MODE_OFF

LOCATION_MODE_BATTERY_SAVING

LOCATION_MODE_HIGH_ACCURACY

LOCATION_MODE_SENSORS_ONLY

andthecurrentvaluecanberetrievedusingthecodefromListing19-8.Themodeissetbytheuserfortheentiredevice,notbyapplication.However,yourapplicationhasanopportunitytorequestaprioritytocomplementthemodechoicemadebytheuser.IfthedevicehasamodeofHIGH_ACCURACYandyourapplicationchoosesapriorityofLOW_POWER,yourapplicationwillnotbetheonedrainingthebatterybutcouldstillgetdecentlocationupdates.

Themodecanworkagainstyouhowever.IftheuserchoosesamodeofSENSORS_ONLY,andthepriorityissettoNO_POWER,LOW_POWERorevenBALANCED,locationupdateswillberare,regardlessofwhatyousetinthelocationrequestwithsetInterval().ThepreferredmodeformostusefullocationupdatesisHIGH_ACCURACY,becausethismodewillcombineallpossiblesourcesoflocationinformationandprovidethemostaccurateresults.Yourapplicationwillbeabletogethighaccuracywhenneeded(hopefullythisisarareneed)andgoodaccuracytherestof

Page 505: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thetime.YourapplicationcanaltertheprioritytoHIGH_ACCURACYwhenneeded,butBALANCEDorLOW_POWERtheothertimes.

SomeotherinterestingoptionswithaLocationRequestincludesettingaspecificnumberoflocationupdatestoreceive,ortospecifyatimelimitwhenthelocationupdatesshouldstop.Youcanalsosetaminimumdistance(inmeters)withinwhichyourapplicationdoesnotwantupdates.Thisisageofenceofsorts,whereyoutellthelocationservicethatyouonlywantalocationupdateifthedevicemovesacertaindistancefromitscurrentlocation.Thatisineffectsettingupageofencecirclearoundthecurrentlocation.Moreongeofenceslater.

AlternateWaysofGettingLocationUpdatesYou’veseenhowtogetlocationupdatessenttoyouractivityusingtherequestLocationUpdates()methodoftheLocationManagerandtheFusedLocationProviderApi.Thereareactuallyseveraldifferentsignaturesofthismethod,includingonesthatuseaPendingIntent.Thisgivesyoutheabilitytodirectlocationupdatestoservicesorbroadcastreceivers.YoucanalsodirectlocationupdatestootherLooperthreadsinsteadofthemainthread,givingyoulotsofflexibilityforyourapplication,althoughsomeofthesemethodshavebeenavailableonlysinceAndroid2.3.

UsingProximityAlertsandGeofencingGeofencingisapopularrequirementforamobileapplication.Itmeansthatyourapplicationshouldalteritsbehaviordependingonwhereitislocated.Atypicalusecaseistopreventthedevicefromworkingwhenitisoutsideofaparticularlocation.Forexample,ahospitalapplicationcouldrestrictaccesstopatientdatawhenitisnotatthehospital.Oryourapplicationmightwanttosilencenotificationswhenthedeviceisattheworkplace.LocationManagerhasamechanismcalledproximityalerts,andthereisasimilarrecentAPIcalledGeofencingApiforthenewerLocationServices.We’llbrieflydiscussthefirst,thenaddressthesecondindetail.

WementionedearlierthattheLocationManagercannotifyyouwhenthedeviceentersaspecifiedgeographicallocation.ThemethodtosetthisupisaddProximityAlert()fromtheLocationManagerclass.Basically,youtelltheLocationManagerthatyouwantanIntenttobefiredwhenthelocationofthedevicegoesinto,orleaves,acircleofacertainradiuswithacenteratalatitude/longitudeposition.TheIntentcantriggeraBroadcastReceiveroraServicetobecalled,oranActivitytobestarted.Thereisalsoanoptionaltimelimitplacedonthealert,soitcouldtimeoutbeforetheIntentfires.

Internally,thecodeforthismethodregisterslistenersforboththeGPSandnetworkprovidersandsetsuplocationupdatesforoncepersecondandaminDistanceof1meter.Youdon’thaveanywaytooverridethisbehaviororsetparameters.Therefore,ifyouleavethisrunningforalongtime,youcouldendupdrainingthebatteryveryquickly.Ifthescreengoestosleep,proximityalertswillonlybecheckedonceeveryfourminutes,butagain,youhavenocontroloverthetimedurationhere.Forthesereasons,wehave

Page 506: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

includedademonstrationapplicationcalledProximityAlertDemowiththesampleapplications,butwewillnotdiveintothedetails.Instead,wewillturnourattentiontotheLocationServicesapproach,withanothersampleapplicationcalledGeofencingApi.NotethattheGeofencingApisampleapplicationwilllooksimilartotheFusedLocationProviderApisampleapplicationsincebothsharetheGoogleClientApimechanismforactivation.

TheGeofencingApiAPIAtthetimeofthiswriting,ageofenceisacircularregionwithalatitude/longitudecenter,plussometimeparameters.Atsomepointinthefuture,theregionmightnotbecircularbutfornowitis.Onceageofencehasbeenbuilt,itcanbepassedtotheGeofenceApiformonitoring.Yourapplicationcanevengoawayandyourgeofencecanbeactive.Alongwithageofence,orsetofgeofences,yourapplicationwillpassaPendingIntentwithanIntenttobefiredwhensomethinginterestinghappensaroundageofence.Thethreecurrenteventsareenter,exitanddwell.Enterandexitaresimpletounderstand;theIntentwillbefiredifthedevicegoesinto,orleaves,thecircularregion.ThedwelleventfirestheIntentafterthedeviceremainsinsideofthecircularregionforaperiodoftime.Thisloiteringdelayisspecifiedinmilliseconds.Andthat’sallthereistoit.

SeethesampleapplicationcalledGeofencingApiDemo.Itsetsuptwogeofencescalledhomeandwork,connectstoLocationServices,andregistersaserviceintenttobefiredwhenthedeviceenters,exitsordwellsineitherofthesegeofences.Whentriggered,theservicegeneratesanotificationpereventtomakeiteasierforyoutoseetheresults.Geofencesareoftenusedinthebackground,soaservicemakesalotofsensehere.Thatis,anapplicationshouldn’tneedtobeintheforegroundtohavegeofences.Infact,thebasicideaofageofenceisthatyouwantyourapplicationtobewakenedupifthedeviceentersorleavesaspecificgeographicregion.

ThesetupcodeusedearliertomakesurethatGooglePlayServicesandLocationServicesareavailableandreadyhasbeenleftoutofthissampleapplicationtomakeiteasiertofollowalong,butyouwouldwanttoincludethatcodeinaproductionapplication.Listing19-15showstheonCreate()methodofthemainactivity,inwhichthegeofencesandthePendingIntentarecreated.

Listing19-15.SettingUpGeofences

privateGoogleApiClientmClient=null;privateList<Geofence>mGeofences=newArrayList<Geofence>();privatePendingIntentpIntent=null;

@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

finalfloatradius=0.5f*1609.0f;//halfmiletimes1609meterspermile

Page 507: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Geofence.Buildergb=newGeofence.Builder();//MakeahalfmilegeofencearoundyourhomeGeofencehome=gb.setCircularRegion(28.993818,-81.383816,radius).setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER|Geofence.GEOFENCE_TRANSITION_EXIT|Geofence.GEOFENCE_TRANSITION_DWELL).setExpirationDuration(12*60*60*1000)//12hours.setLoiteringDelay(300000)//5minutes.setRequestId("home").setNotificationResponsiveness(5000)//5secs.build();mGeofences.add(home);

//MakeanothergeofencearoundyourworkGeofencework=gb.setCircularRegion(28.36631,-81.52120,radius).setRequestId("work").build();mGeofences.add(work);Intentintent=newIntent(this,ReceiveTransitionsIntentService.class);

pIntent=PendingIntent.getService(getApplicationContext(),0,intent,PendingIntent.FLAG_UPDATE_CURRENT);

mClient=newGoogleApiClient.Builder(this,this,this).addApi(LocationServices.API).build();

Log.v(TAG,"Activity,clientarecreated");}

Seehowthegeofenceiscreatedasacirclearoundalat/lon,withtheeventsofinterest(inthiscaseallofthem)andsometimeparameters.Inthissample,thegeofenceswillbeactivefor12hours,oruntiltheyareremoved(seeonDestroy()).It’salsopossibletosetgeofencestoneverexpire.Theloiteringdelayof5minutesmeansthatthedwelleventwillfireifthedevicestaysinsidethegeofenceforatleast5minutes.TherequestIDwillbepassedbacktoyourapplicationwiththeIntentsoyoucanidentifywhichgeofencetheIntentisfor.Thenotificationresponsivenessof5secondsmeansthattheGeofencingApiwilltrytosendtheIntentwithin5secondsofwhentheeventhappens.However,therearenoguaranteesthattheIntentwillbethatquick.Thelargerthisvalue,thebetteritison

Page 508: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

batterylife,sincetheAPIcouldsleepmoreandcheckthingslessoften.Ontheotherhand,ifthisvalueisverylong,forexampleseveralminutes,itispossibleyoumightevenmissaneventifthedevicepassesthroughyourgeofencequickly.Thechoiceofnotificationresponsivenesswilldependonhowbigyourgeofencesareandhowyouwantyourapplicationtobehave.

Similartotheprevioussampleapplication,aconnectionisattemptedfromonResume(),andListing19-16showswhatrunswhentheconnectionissuccessful.

Listing19-16.RegisteringGeofenceswiththeAPI

@OverridepublicvoidonConnected(Bundlearg0){//SetupgeofencesLog.v(TAG,"Settingupgeofences(onConnected)...");PendingResult<Status>pResult=mFencer.addGeofences(mClient,mGeofences,pIntent);pResult.setResultCallback(this);//ResultCallback<Status>interface}

@OverridepublicvoidonResult(Statusstatus){Log.v(TAG,"GotaresultfromaddGeofences("+status.getStatusCode()+"):"+status.getStatus().getStatusMessage());}

TheGeofencingApigetspassedtheAPIclienthandle,thelistofgeofences,andthePendingIntent.ThereturnisaPendingResult.Ifyouwanttofindoutiftheresultisultimatelysuccessfulornot,youneedtosetacallbackreceiverusingsetResultCallback().ThisactivityhasimplementedtheResultCallback<Status>interface,sotheonResult()callbackwillbeinvokedwiththeresultsoftheaddGeofences()methodcall.Forthissample,theresultissimplylogged,butofcourseyouwouldwanttotakestepsiftheresultwasnotsuccessful.That’sallthattheactivitydoes.NextupistheservicethatreceivesanIntentwhenaninterestingeventoccurs.

Listing19-17showstheinterestingcallbacksandmethodsoftheReceiveTransitionsIntentService,anIntentServiceforthisapplication.Itbasicallyreportsouttheinformationreceived,whetherthatisanerrororageofenceevent.Eventsaredisplayedusingnotifications.Thisisforyoursafetysincetheexpectationisthatyouwillstartthisapplicationathomeanddrivetowork.Wedonotwantyouhavingtowatchthedevice’sscreenduringthetrip.Instead,youwillbeabletoreviewallofthenotificationsfromeacheventwhenyouaresafelystopped.

Listing19-17.ReceivingIntentsfromtheGeofencingApi

Page 509: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonCreate(){super.onCreate();notificationMgr=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);}

@OverrideprotectedvoidonHandleIntent(Intentintent){GeofencingEventgfEvent=GeofencingEvent.fromIntent(intent);//Firstcheckforerrorsif(gfEvent.hasError()){//GettheerrorcodewithastaticmethodinterrorCode=gfEvent.getErrorCode();//LogtheerrorLog.e(TAG,"LocationServiceserror:"+Integer.toString(errorCode));/**Ifthere'snoerror,getthetransitiontypeandtheIDs*ofthegeofenceorgeofencesthattriggeredthetransition*/}else{//Getthetypeoftransition(entryorexit)inttransitionType=gfEvent.getGeofenceTransition();StringtranTypeStr="UNKNOWN("+transitionType+")";switch(transitionType){caseGeofence.GEOFENCE_TRANSITION_ENTER:tranTypeStr="ENTER";break;caseGeofence.GEOFENCE_TRANSITION_EXIT:tranTypeStr="EXIT";break;caseGeofence.GEOFENCE_TRANSITION_DWELL:tranTypeStr="DWELL";break;}Log.v(TAG,"transitionTypereported:"+tranTypeStr);LocationtriggerLoc=gfEvent.getTriggeringLocation();Log.v(TAG,"triggeringlocationis"+triggerLoc);

List<Geofence>triggerList=gfEvent.getTriggeringGeofences();

Page 510: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

String[]triggerIds=newString[triggerList.size()];

for(inti=0;i<triggerIds.length;i++){//GrabtheIdofeachgeofencetriggerIds[i]=triggerList.get(i).getRequestId();Stringmsg=tranTypeStr+":"+triggerLoc.getLatitude()+","+triggerLoc.getLongitude();Stringtitle=triggerIds[i];displayNotificationMessage(title,msg);}}}

privatevoiddisplayNotificationMessage(Stringtitle,Stringmessage){intnotif_id=(int)(System.currentTimeMillis()&0xFFL);

Notificationnotification=newNotificationCompat.Builder(this).setContentTitle(title).setContentText(message).setSmallIcon(android.R.drawable.ic_menu_compass).setOngoing(false).build();

notificationMgr.notify(notif_id,notification);}

Whenyoureplacethelatitudeandlongitudeofhomeandworkinthisapplication,yourunitonarealdevice,andyouthenmovethedevice,youwillseenotificationssuchasthoseinFigure19-8.

Page 511: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure19-8.NotificationsfromGeofencingApievents

Thefirsteventoccurredat6:40pmandhappenedbecausethedevicewasalreadyinsidethehomeregionwhentheappwasstarted.Thesecondeventat6:45pmisadwelleventbecausethedeviceisstillwithinthehomeregionaftertheloiteringdelayof5minutes.Hadthedeviceleftthehomeregionbeforethescreenshotwascaptured,therewouldhavebeenanexiteventfromhome.Notethatthelatitudeandlongitudeinthenotificationaretheactuallocationofthedeviceandnotnecessarilythecenteroftheregion.

ReferencesHerearehelpfulreferencesyoumaywishtoexplorefurther.

www.androidbook.com/proandroid5/projects.Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforazipfilecalledProAndroid5_Ch19_Maps.zip.Thiszipfilecontainsallprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoanIDEfromoneofthesezipfiles.Therearesomeextrasampleapplicationsinhere,includingWhereAmI4,whichcontainscustominfowindowsformarkers.

https://developer.android.com/guide/topics/location/index.htmlTheAndroiddeveloper’sguideforLocationandMaps.

https://developer.android.com/google/play-services/index.html.TheGooglePlayServicesdocumentationwhichincludestheFusedLocationProviderApi,GeofencingApiandGoogleMap.

https://developer.android.com/google/play-services/setup.html.InstructionsforincludingtheGoogle

Page 512: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PlayServiceslibraryintoyourapplication.Notethedrop-downmenutoallowchoosingbetweenAndroidStudioandEclipsewithADT.https://developers.google.com/maps/documentation/android/TheMapsAPIdocumentationwhichisseparatefromtherestoftheonlineAndroiddocumentation.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedaboutmapssofar:

HowtogetyourownMapsAPIkeyfromGoogle.

MapFragment,themaincomponentforallmaps.

ThemodificationsyouneedtomaketoyourAndroidManifest.xmlfiletogetamapsapplicationtowork.

Definingalayouttocontainamap,andhowtoinstantiateamap.

Zoominginandout,panningandshowingthecurrentlocation.

Includingdifferentmodessuchassatelliteandtraffic.

Howmaptilesareusedtorendermaps.

Addingmarkerstoyourmaps.

Mapcamerasandmethodstosetazoomlevelthataccommodatesaspecificsetofmarkers.

TheGeocoder,andhowitconvertsfromaddresstolatitude/longitude,orfromlatitude/longitudetoaddressesandplacesofinterest.

PuttingtheGeocoderintoabackgroundthreadtoavoidnastyApplicationNotResponding(ANR)pop-ups.

TheLocationServicesservice,whichusesGPSand/ornetworktowerstopinpointthelocationofthedevice.

Selectingalocationprovider,andwhattodoifthedesiredlocationserviceorproviderisnotenabled.

Usingtheemulator’sfeaturestosendlocationeventstoyourapplicationfortesting.Thisincludesusingspecialfilesthatrecordentireseriesoflocationevents.

UsingmethodsoftheLocationclassto,forexample,calculatedistancesbetweenpoints.

HowtodoallofthechecksandcorrectiveactionstosetupGoogle

Page 513: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

PlayServicesforLocationUpdates.

Alertingonproximity—thatis,settingupaproximityandbeingalertedwhenthedeviceentersorleavesthatproximity.

Settingupgeofencestoactonenter,exit,anddwelleventsforoneormoreregionswhileconservingbatterylife.

Page 514: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter20

UnderstandingtheMediaFrameworksNowwearegoingtoexploreaveryinterestingpartoftheAndroidSDK:themediaframeworks.Wewillshowyouhowtoplayaudioandvideofromavarietyofsources.We’llalsocoverintheonlinecompanionsectionhowtotakephotoswiththecameraandrecordaudioandvideo.

UsingtheMediaAPIsAndroidsupportsplayingaudioandvideocontentundertheandroid.mediapackage.Inthischapter,wearegoingtoexplorethemediaAPIsfromthispackage.

Attheheartoftheandroid.mediapackageistheandroid.media.MediaPlayerclass.TheMediaPlayerclassisresponsibleforplayingbothaudioandvideocontent.Thecontentforthisclasscancomefromthefollowingsources:

Web:YoucanplaycontentfromtheWebviaaURL.

.apkfile:Youcanplaycontentthatispackagedaspartofyour

.apkfile.Youcanpackagethemediacontentasaresourceorasanasset(withintheassetsfolder).

TheStorageAccessFramework,newtoAndroidKitKat4.4,whichprovidesaccesstomediafilesstoredacrossarangeofprovidersandinternetservices.

SDcard:Youcanplaycontentthatresidesonthedevice’sSDcardoremulatedlocalstorage.

TheMediaPlayeriscapableofdecodingquiteafewdifferentcontentformats,including3rdGenerationPartnershipProject(3GPP,.3gp),MP3(.mp3),MIDI(.midandothers),OggVorbis(.ogg),PCM/WAVE(.wav),andMPEG-4(.mp4).RTSP,HTTP/HTTPSlivestreaming,andM3Uplaylistsarealsosupported,althoughplayliststhatincludeURLsarenot,atleastasofthiswriting.Foracompletelistofsupportedmediaformats,gotohttp://developer.android.com/guide/appendix/media-formats.html.

WhitherSDCards?Beforewediveintotheheartofthemediaframeworks,weshouldquicklyaddressthetopicofremovablestorage,andSDCardsinparticular.RecenttrendsinAndroiddevices

Page 515: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

haveseensomemanufacturersdropthemfromdevices,whileotherscontinuetoincludethem.Googleitselfhasblurredthelinesofwhatisandisn’tremovalstoragebyobfuscatingthelow-levelfilesystemsinAndroid.

Regardlessofyourpersonalpreferenceasadeveloper,someofyouruserswilllikelystillhavedevicesthatsupportSDCardsandwanttousethem.Manyoftheexampleswe’llcoverhereareequallyapplicabletosourcingmediafilesfromSDCards.However,tosavespace,andspareyouunneededrepetition,we’veplacedsomeextraexamplesthatgointoSDCarddetailsandsupportingmaterialonthebook’swebsite.Besuretocheckitoutatwww.androidbook.com.

PlayingMediaTogetstarted,we’llshowyouhowtobuildasimpleapplicationthatplaysanMP3filelocatedontheWeb(seeFigure20-1).Afterthat,wewilltalkaboutusingthesetDataSource()methodoftheMediaPlayerclasstoplaycontentfromthe.apkfile.MediaPlayerisn’ttheonlywaytoplayaudio,though,sowe’llalsocovertheSoundPoolclass,aswellasJetPlayer,AsyncPlayer,and,forthelowestlevelofworkingwithaudio,theAudioTrackclass.Afterthat,wewilldiscusssomeoftheshortfallsoftheMediaPlayerclass.Finally,we’llseehowtoplayvideocontent.

PlayingAudioContentFigure20-1showstheuserinterfaceforourfirstexample.ThisapplicationwilldemonstratesomeofthefundamentalusesoftheMediaPlayerclass,suchasstarting,pausing,restarting,andstoppingthemediafile.Lookatthelayoutfortheapplication’suserinterface.

Figure20-1.Theuserinterfaceforthemediaapplication

Page 516: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheuserinterfaceconsistsofaRelativeLayoutwithfourbuttons:onetostarttheplayer,onetopausetheplayer,onetorestarttheplayer,andonetostoptheplayer.WecouldhavemadethiseasyandjustcoupledourexamplewithaMediaControllerwidgetthatdoesthesamething,butwewanttoshowyoutheinnerworkingsofcontrollingthingsyourself.ThecodeandlayoutfilefortheapplicationareshowninListing20-1.We’regoingtoassumeyou’rebuildingagainstAndroid2.2orlaterforthisexample,becausewe’reusingthegetExternalStoragePublicDirectory()methodoftheEnvironmentclass.IfyouwanttobuildthisagainstanolderversionofAndroid,simplyusegetExternalStorageDirectory()insteadandadjustwhereyouputthemediafilessoyourapplicationwillfindthem.

NoteSeethe“References”sectionattheendofthischapterfortheURLfromwhichyoucanimporttheseprojectsintoEclipsedirectly,insteadofcopyingandpastingcode.

Listing20-1.TheLayoutandCodefortheMediaApplication

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical">

<Buttonandroid:id="@+id/startPlayerBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="StartPlayingAudio"

android:onClick="doClick"/>

<Buttonandroid:id="@+id/pausePlayerBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="PausePlayer"

android:layout_below="@+id/startPlayerBtn"android:onClick="doClick"/>

<Buttonandroid:id="@+id/restartPlayerBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="RestartPlayer"

android:layout_below="@+id/pausePlayerBtn"android:onClick="doClick"/>

<Buttonandroid:id="@+id/stopPlayerBtn"android:layout_width="match_parent"

Page 517: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:layout_height="wrap_content"android:text="StopPlayer"

android:layout_below="@+id/restartPlayerBtn"android:onClick="doClick"/>

</RelativeLayout>

//ThisfileisMainActivity.javaimportandroid.app.Activity;importandroid.content.res.AssetFileDescriptor;importandroid.media.AudioManager;importandroid.media.MediaPlayer;importandroid.media.MediaPlayer.OnPreparedListener;importandroid.os.Bundle;importandroid.os.Environment;importandroid.util.Log;importandroid.view.View;

publicclassMainActivityextendsActivityimplementsOnPreparedListener{staticfinalStringAUDIO_PATH=

"http://www.androidbook.com/akc/filestorage/android/documentfiles/3389/play.mp3

privateMediaPlayermediaPlayer;privateintplaybackPosition=0;

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}

publicvoiddoClick(Viewview){switch(view.getId()){caseR.id.startPlayerBtn:try{//OnlyhaveoneoftheseplaymethodsuncommentedplayAudio(AUDIO_PATH);//playLocalAudio();//playLocalAudio_UsingDescriptor();}catch(Exceptione){e.printStackTrace();}break;

Page 518: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

caseR.id.pausePlayerBtn:if(mediaPlayer!=null&&mediaPlayer.isPlaying()){playbackPosition=mediaPlayer.getCurrentPosition();mediaPlayer.pause();}break;caseR.id.restartPlayerBtn:if(mediaPlayer!=null&&!mediaPlayer.isPlaying()){mediaPlayer.seekTo(playbackPosition);mediaPlayer.start();}break;caseR.id.stopPlayerBtn:if(mediaPlayer!=null){mediaPlayer.stop();playbackPosition=0;}break;}}

privatevoidplayAudio(Stringurl)throwsException{killMediaPlayer();

mediaPlayer=newMediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(url);mediaPlayer.setOnPreparedListener(this);mediaPlayer.prepareAsync();}

privatevoidplayLocalAudio()throwsException{mediaPlayer=MediaPlayer.create(this,R.raw.music_file);mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);//callingprepare()isnotrequiredinthiscasemediaPlayer.start();}

privatevoidplayLocalAudio_UsingDescriptor()throwsException{

Page 519: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AssetFileDescriptorfileDesc=getResources().openRawResourceFd(R.raw.music_file);if(fileDesc!=null){

mediaPlayer=newMediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(fileDesc.getFileDescriptor(),fileDesc.getStartOffset(),fileDesc.getLength());

fileDesc.close();

mediaPlayer.prepare();mediaPlayer.start();}}

//ThisiscalledwhentheMediaPlayerisreadytostartpublicvoidonPrepared(MediaPlayermp){mp.start();}

@OverrideprotectedvoidonDestroy(){super.onDestroy();killMediaPlayer();}

privatevoidkillMediaPlayer(){if(mediaPlayer!=null){try{mediaPlayer.release();}catch(Exceptione){e.printStackTrace();}}}}

Inthisfirstscenario,youareplayinganMP3filefromawebaddress.Therefore,youwillneedtoaddandroid.permission.INTERNETtoyourmanifestfile.Listing20-1showsthattheMainActivityclasscontainsthreemembers:afinalstringthatpointstotheURLoftheMP3file,aMediaPlayerinstance,andanintegermembercalledplaybackPosition.OuronCreate()methodjustsetsuptheuserinterfacefromourlayoutXMLfile.Inthebutton-clickhandler,whentheStartPlayingAudiobuttonis

Page 520: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

pressed,theplayAudio()methodiscalled.IntheplayAudio()method,anewinstanceoftheMediaPlayeriscreated,andthedatasourceoftheplayerissettotheURLoftheMP3file.

TheprepareAsync()methodoftheplayeristhencalledtopreparetheMediaPlayerforplayback.We’reinthemainUIthreadofouractivity,sowedon’twanttotaketoolongtopreparetheMediaPlayer.Thereisaprepare()methodonMediaPlayer,butitblocksuntiltheprepareiscomplete.Ifthistakesalongtime,oriftheservertakesawhiletorespond,theusercouldthinktheapplicationisstuckor,worse,getanerrormessage.Thingslikeprogressdialogscanhelpyouruserunderstandwhatishappening.TheprepareAsync()methodreturnsimmediatelybutsetsupabackgroundthreadtohandletheprepare()methodoftheMediaPlayer.Whenthepreparationiscomplete,ouractivity’sonPrepared()callbackiscalled.ThisiswhereweultimatelystarttheMediaPlayerplaying.WehavetotelltheMediaPlayerwhothelistenerisfortheonPrepared()callback,whichiswhywecallsetOnPreparedListener()justbeforethecalltoprepareAsync().Youdon’thavetousethecurrentactivityasthelistener;wedoherebecauseit’ssimplerforthisdemonstration.

NowlookatthecodeforthePausePlayerandRestartPlayerbuttons.YoucanseethatwhenthePausePlayerbuttonisselected,yougetthecurrentpositionoftheplayerbycallinggetCurrentPosition().Youthenpausetheplayerbycallingpause().Whentheplayerhastoberestarted,youcallseekTo(),passinginthepositionobtainedearlierfromgetCurrentPosition(),andthencallstart().

TheMediaPlayerclassalsocontainsastop()method.Notethatifyoustoptheplayerbycallingstop(),youneedtopreparetheMediaPlayeragainbeforecallingstart()again.Conversely,ifyoucallpause(),youcancallstart()againwithouthavingtopreparetheplayer.Also,besuretocalltherelease()methodofthemediaplayeronceyouaredoneusingit.Inthisexample,youdothisaspartofthekillMediaPlayer()method.

ThereisasecondURLinthesampleapplicationsourcecodeforanaudiosource,butitisnotanMP3file,it’sastreamingaudiofeed(Radio-Mozart).ThisalsoworkswiththeMediaPlayerandshowsagainwhyyouneedtocallprepareAsync()insteadofprepare().Preparinganaudiostreamforplaybackcantakeawhile,dependingontheserver,networktraffic,andsoon.

Listing20-1showsyouhowtoplayanaudiofilelocatedontheWeb.TheMediaPlayerclassalsosupportsplayingmedialocaltoyour.apkfile.Listing20-2showshowtoreferenceandplaybackafilefromthe/res/rawfolderofyour.apkfile.Goaheadandaddtherawfolderunder/resifit’snotalreadythereintheEclipseproject.Then,copytheMP3fileofyourchoiceinto/res/rawwiththefilenamemusic_file.mp3.NotealsothecommentintheoriginalcodetouncommentthedesiredcalltoplayLocalAudio(),andcommentingoutplayAudio().

Listing20-2.UsingtheMediaPlayertoPlayBackaFileLocaltotheApplication

privatevoidplayLocalAudio()throwsException

Page 521: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

{mediaPlayer=MediaPlayer.create(this,R.raw.music_file);mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);//callingprepare()isnotrequiredinthiscasemediaPlayer.start();}

Ifyouneedtoincludeanaudioorvideofilewithyourapplication,youshouldplacethefileinthe/res/rawfolder.YoucanthengetaMediaPlayerinstancefortheresourcebypassingintheresourceIDofthemediafile.Youdothisbycallingthestaticcreate()method,asshowninListing20-2.NotethattheMediaPlayerclassprovidesafewotherstaticcreate()methodsthatyoucanusetogetaMediaPlayerratherthaninstantiatingoneyourself.InListing20-2,thecreate()methodisequivalenttocallingtheconstructorMediaPlayer(Contextcontext,intresourceId)followedbyacalltoprepare().Youshouldusethecreate()methodonlywhenthemediasourceislocaltothedevice,becauseitalwaysusesprepare()andnotprepareAsync().

UnderstandingthesetDataSourceMethodInListing20-2,wecalledthecreate()methodtoloadtheaudiofilefromarawresource.Withthisapproach,youdon’tneedtocallsetDataSource().Alternatively,ifyouinstantiatetheMediaPlayeryourselfusingthedefaultconstructor,orifyourmediacontentisnotaccessiblethrougharesourceIDoraURI,you’llneedtocallsetDataSource().

ThesetDataSource()methodhasoverloadedversionsthatyoucanusetocustomizethedatasourceforyourspecificneeds.Forexample,Listing20-3showshowyoucanloadanaudiofilefromarawresourceusingaFileDescriptor.

Listing20-3.SettingtheMediaPlayer’sDataSourceusingaFileDescriptor

privatevoidplayLocalAudio_UsingDescriptor()throwsException{AssetFileDescriptorfileDesc=getResources().openRawResourceFd(R.raw.music_file);if(fileDesc!=null){

mediaPlayer=newMediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(fileDesc.getFileDescriptor(),fileDesc.getStartOffset(),fileDesc.getLength());

fileDesc.close();

Page 522: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

mediaPlayer.prepare();mediaPlayer.start();}}

Listing20-3assumesthatit’swithinthecontextofanactivity.Asshown,youcallthegetResources()methodtogettheapplication’sresourcesandthenusetheopenRawResourceFd()methodtogetafiledescriptorforanaudiofilewithinthe/res/rawfolder.YouthencallthesetDataSource()methodusingtheAssetFileDescriptor,thestartingpositiontobeginplayback,andtheendingposition.YoucanalsousethisversionofsetDataSource()ifyouwanttoplaybackaspecificportionofanaudiofile.Ifyoualwayswanttoplaytheentirefile,youcancallthesimplerversionofsetDataSource(FileDescriptordesc),whichdoesnotrequiretheinitialoffsetandlength.

Inthiscase,wechosetouseprepare()followedbystart(),onlytoshowyouwhatitmightlooklike.Weshouldbeabletogetawaywithitbecausetheaudioresourceislocal,butitwon’thurttouseprepareAsync()asbefore.

Wehaveonemoresourceforaudiocontenttotalkabout:theSDcard.RefertotheonlinecompanionchapterforthebasicsondealingwiththeSDcardanditsfilesystemcontents.Inourexample,weusedsetDataSource()toaccesscontentontheInternetbypassinginaURLforanMP3file.Ifyou’vegotanaudiofileonyourSDcard,youcanusethesamesetDataSource()methodbutinsteadpassitthepathtoyouraudiofileontheSDcard.Forexample,afilecalledmusic_file.mp3intheMusicdirectorycanbeplayedwiththeAUDIO_PATHvariablesetlikeso:

staticfinalStringAUDIO_PATH=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+"/music_file.mp3";

YoumayhavenoticedthatwedidnotimplementonResume()andonPause()inourexample.Thismeansthatwhenouractivitygoesintothebackground,itcontinuestoplayaudio—atleast,untiltheactivityiskilled,oruntilaccesstotheaudiosourceisturnedoff.Forexample,ifwedonotholdawakelock,theCPUcouldbeshutdown,thusendingtheplayingofmusic.Manypeoplechoosetomanagemediaplaybackinaservicetoaidinworkingaroundtheseissues.Inourcurrentexample,additionalissuesincludeifMediaPlayerisplayinganaudiostreamoverWi-Fi,andifouractivitydoesnotobtainalockonWi-Fi,Wi-Ficouldbeturnedoff,andwe’llloseourconnectiontothestream.MediaPlayerhasamethodcalledsetWakeMode()thatallowsustosetaPARTIAL_WAKE_LOCKtokeeptheCPUalivewhileplaying.However,inordertolockWi-Fi,weneedtodothatseparatelythroughWifiManagerandWifiManager.WifiLock.

Theotheraspectofcontinuingtoplayaudiointhebackgroundisthatweneedtoknowwhennottodoso,perhapsbecausethere’sanincomingphonecall,orbecauseanalarmis

Page 523: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

goingoff.AndroidhasanAudioManagertohelpwiththis.ThemethodstocallincluderequestAudioFocus()andabandonAudioFocus(),andthere’sacallbackmethodcalledonAudioFocusChange()intheinterfaceAudioManager.OnAudioFocusChangeListener.Formoreinformation,seetheMediapageintheAndroidDeveloper’sGuide.

UsingSoundPoolforSimultaneousTrackPlayingTheMediaPlayerisanessentialtoolinourmediatoolbox,butitonlyhandlesoneaudioorvideofileatatime.Whatifwewanttoplaymorethanoneaudiotracksimultaneously?OnewayistocreatemultipleMediaPlayersandworkwiththematthesametime.Ifyouonlyhaveasmallamountofaudiotoplay,andyouwantsnappyperformance,AndroidhastheSoundPoolclasstohelpyou.Behindthescenes,SoundPoolusesMediaPlayer,butwedon’tgetaccesstotheMediaPlayerAPI,justtheSoundPoolAPI.

OneoftheotherdifferencesbetweenMediaPlayerandSoundPoolisthatSoundPoolisdesignedtoworkwithlocalmediafilesonly.Thatis,youcanloadaudiofromresourcefiles,fileselsewhereusingfiledescriptors,orfilesusingapathname.ThereareseveralothernicefeaturesthatSoundPoolprovides,suchastheabilitytoloopanaudiotrack,pauseandresumeindividualaudiotracks,orpauseandresumeallaudiotracks.

TherearesomedownsidestoSoundPool,though.ThereisanoverallaudiobuffersizeinmemoryforallthetracksthatSoundPoolwillmanageofonly1MB.ThismightseemlargewhenyoulookatMP3filesthatareonlyafewkilobytesinsize.ButSoundPoolexpandstheaudioinmemorytomaketheplaybackfastandeasy.Thesizeofanaudiofileinmemorydependsonthebitrate,numberofchannels(stereoversusmono),samplerate,andlengthoftheaudio.IfyouhavetroublegettingyoursoundsloadedintoSoundPool,youcouldtryplayingwiththeseparametersofyoursourceaudiofiletomaketheaudiosmallerinmemory.

Ourexampleapplicationwillloadandplayanimalsounds.Oneofthesoundsisofcricketsanditplaysconstantlyinthebackground.Theothersoundsplayatdifferentintervalsoftime.Sometimesallyouheararecrickets;othertimesyouwillhearseveralanimalsallatthesametime.We’llalsoputabuttonintheuserinterfacetoallowforpausingandresuming.Listing20-4showsourlayoutXMLfileandtheJavacodeofouractivity.Yourbestbetistodownloadthisfromourwebsite,inordertogetthesoundfilesaswellasthecode.Seethe“References”sectionattheendofthischapterforinformationonhowtolocatethedownloadablesourcecode.

Listing20-4.PlayingAudiowithSoundPool

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"

Page 524: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

><ToggleButtonandroid:id="@+id/button"android:textOn="Pause"android:textOff="Resume"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="doClick"android:checked="true"/></LinearLayout>

//ThisfileisMainActivity.javaimportjava.io.IOException;importandroid.app.Activity;importandroid.content.Context;importandroid.content.res.AssetFileDescriptor;importandroid.media.AudioManager;importandroid.media.SoundPool;importandroid.os.Bundle;importandroid.os.Handler;importandroid.util.Log;importandroid.view.View;importandroid.widget.ToggleButton;

publicclassMainActivityextendsActivityimplementsSoundPool.OnLoadCompleteListener{privatestaticfinalintSRC_QUALITY=0;privatestaticfinalintPRIORITY=1;privateSoundPoolsoundPool=null;privateAudioManageraMgr;

privateintsid_background;privateintsid_roar;privateintsid_bark;privateintsid_chimp;privateintsid_rooster;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}

@OverrideprotectedvoidonResume(){soundPool=newSoundPool(5,AudioManager.STREAM_MUSIC,SRC_QUALITY);soundPool.setOnLoadCompleteListener(this);

aMgr=

Page 525: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

(AudioManager)this.getSystemService(Context.AUDIO_SERVICE);

sid_background=soundPool.load(this,R.raw.crickets,PRIORITY);

sid_chimp=soundPool.load(this,R.raw.chimp,PRIORITY);sid_rooster=soundPool.load(this,R.raw.rooster,PRIORITY);sid_roar=soundPool.load(this,R.raw.roar,PRIORITY);

try{AssetFileDescriptorafd=this.getAssets().openFd("dogbark.mp3");sid_bark=soundPool.load(afd.getFileDescriptor(),0,afd.getLength(),PRIORITY);afd.close();}catch(IOExceptione){e.printStackTrace();}//sid_bark=soundPool.load("/mnt/sdcard/dogbark.mp3",PRIORITY);

super.onResume();}

publicvoiddoClick(Viewview){switch(view.getId()){caseR.id.button:if(((ToggleButton)view).isChecked()){soundPool.autoResume();}else{soundPool.autoPause();}break;}}

@OverrideprotectedvoidonPause(){soundPool.release();soundPool=null;super.onPause();}

@Override

Page 526: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonLoadComplete(SoundPoolsPool,intsid,intstatus){Log.v("soundPool","sid"+sid+"loadedwithstatus"+status);

finalfloatcurrentVolume=((float)aMgr.getStreamVolume(AudioManager.STREAM_MUSIC))/((float)aMgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC));

if(status!=0)return;if(sid==sid_background){if(sPool.play(sid,currentVolume,currentVolume,PRIORITY,-1,1.0f)==0)Log.v("soundPool","Failedtostartsound");}elseif(sid==sid_chimp){queueSound(sid,5000,currentVolume);}elseif(sid==sid_rooster){queueSound(sid,6000,currentVolume);}elseif(sid==sid_roar){queueSound(sid,12000,currentVolume);}elseif(sid==sid_bark){queueSound(sid,7000,currentVolume);}}

privatevoidqueueSound(finalintsid,finallongdelay,finalfloatvolume){newHandler().postDelayed(newRunnable(){@Overridepublicvoidrun(){if(soundPool==null)return;if(soundPool.play(sid,volume,volume,PRIORITY,0,1.0f)==0)Log.v("soundPool","Failedtostartsound("+sid+")");queueSound(sid,delay,volume);}},delay);}}

Thestructureofthisexampleisfairlystraightforward.WehaveauserinterfacewithasingleToggleButtononit.We’llusethistopauseandresumetheactiveaudio

Page 527: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

streams.Whenourappstarts,wecreateourSoundPoolandloaditupwithaudiosamples.Whenthesamplesareproperlyloaded,westartplayingthem.Thecricketssoundplaysinaneverendingloop;theothersamplesplayafteradelayandthensetthemselvesuptoplayagainafterthesamedelay.Bychoosingdifferentdelays,wegetasomewhatrandomeffectofsoundsontopofsounds.

CreatingaSoundPoolrequiresthreeparameters:

ThefirstisthemaximumnumberofsamplesthattheSoundPoolwillplaysimultaneously.ThisisnothowmanysamplestheSoundPoolcanhold.

Thesecondparameteriswhichaudiostreamthesampleswillplayon.ThetypicalvalueisAudioManager.STREAM_MUSIC,butSoundPoolcanbeusedforalarmsorringtones.SeetheAudioManagerreferencepageforthecompletelistofaudiostreams.

TheSRC_QUALITYvalueshouldjustbesetto0whencreatingtheSoundPool.

Thecodedemonstratesseveraldifferentload()methodsofSoundPool.Themostbasicistoloadanaudiofilefrom/res/rawasaresource.Weusethismethodforthefirstfouraudiofiles.Thenweshowhowyoucouldloadanaudiofilefromthe/assetsdirectoryoftheapplication.Thisload()methodalsotakesparametersthatspecifytheoffsetandthelengthoftheaudiotoload.Thiswouldallowustouseasinglefilewithmultipleaudiosamplesinit,pullingoutjustwhatwewanttouse.Finally,weshowincommentshowyoumightaccessanaudiofilefromtheSDcard.UpthroughAndroid4.0,thePRIORITYparametershouldjustbe1.

Forourexample,wechosetousesomeofthefeaturesintroducedinAndroid2.2,specificallytheonLoadCompleteListenerinterfaceforouractivity,andtheautoPause()andautoResume()methodsinourbuttoncallback.

WhenloadingsoundsamplesintoaSoundPool,wemustwaituntiltheyareproperlyloadedbeforewecanstartplayingthem.WithinouronLoadComplete()callback,wecheckthestatusoftheload,and,dependingonwhichsounditis,wethensetituptoplay.Ifthesoundisthecrickets,weplaywithloopingturnedon(avalueof-1forthefifthparameter).Fortheothers,wequeuethesounduptoplayafterashortperiodoftime.Thetimevaluesareinmilliseconds.Notethesettingofthevolume.AndroidprovidestheAudioManagertoletusknowthecurrentvolumesetting.WealsogetthemaximumvolumesettingfromAudioManagersowecancalculateavolumevalueforplay()thatisbetween0and1(asafloat).Theplay()methodactuallytakesaseparatevolumevaluefortheleftandrightchannels,butwejustsetbothtothecurrentvolume.Again,PRIORITYshouldjustbesetto1.Thelastparameterontheplay()methodisforsettingtheplaybackrate.Thisvalueshouldbebetween0.5and2.0,with1.0beingnormal.

Page 528: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

OurqueueSound()methodusesaHandlertobasicallysetupaneventintothefuture.OurRunnablewillrunafterthedelayperiodhaselapsed.WechecktobesurewestillhaveaSoundPooltoplayfrom,thenweplaythesoundonceandschedulethesamesoundtoplayagainafterthesameintervalasbefore.BecausewecallqueueSound()withdifferentsoundIDsanddifferentdelays,theeffectisasomewhatrandomplayingofanimalsounds.

Whenyourunthisexample,you’llhearcrickets,achimp,arooster,adog,andaroar(abear,wethink).Thecricketsareconstantlychirpingwhiletheotheranimalscomeandgo.OnenicethingaboutSoundPoolisthatitletsusplaymultiplesoundsatthesametimewithnorealworkonourpart.Also,we’renottaxingthedevicetoobadly,becausethesoundsweredecodedatloadtime,andwesimplyneedtofeedthesoundbitstothehardware.

Ifyouclickthebutton,thecricketswillstop,aswillanyotheranimalsoundcurrentlybeingplayed.However,theautoPause()methoddoesnotpreventnewsoundsfrombeingplayed.You’llheartheanimalsoundsagainwithinseconds(exceptforthecrickets).Becausewe’vebeenqueuingupsoundsintothefuture,wewillstillhearthosesounds.Infact,SoundPooldoesnothaveawaytostopallsoundsnowandinthefuture.You’llneedtohandlestoppingonyourown.Thecricketswillonlycomebackifweclickthebuttonagaintoresumethesounds.Buteventhen,wemighthavelostthecricketsbecauseSoundPoolwillthrowouttheoldestsoundtomakeroomfornewersoundsifthemaximumnumberofsimultaneouslyplayingsamplesisreached.

PlayingSoundswithJetPlayerSoundPoolisnottoobadaplayer,butthememorylimitationscanmakeitdifficulttogetthejobdone.AnalternativewhenyouneedtoplaysimultaneoussoundsisJetPlayer.Tailoredforgames,JetPlayerisaveryflexibletoolforplayinglotsofsoundsandforcoordinatingthosesoundswithuseractions.ThesoundsaredefinedusingMusicalInstrumentDigitalInterface(MIDI).

JetPlayersoundsarecreatedusingaspecialJETCreatortool.ThistoolisprovidedundertheAndroidSDKtoolsdirectory,althoughyou’llalsoneedtoinstallPythoninordertouseit,anditislimitedtotheMacOSXandWindowsSDKpackages.TheresultingJETfilecanbereadintoyourapplication,andthesoundssetupforplayback.Thewholeprocessissomewhatinvolvedandbeyondthescopeofthisbook,sowe’lljustpointyoutomoreinformationinthe“References”sectionattheendofthischapter.

PlayingBackgroundSoundswithAsyncPlayerIfallyouwantissomeaudioplayed,andyoudon’twanttotieupthecurrentthread,theAsyncPlayermaybewhatyou’relookingfor.TheaudiosourceispassedasaURItothisclass,sotheaudiofilecouldbelocalorremoteoverthenetwork.Thisclassautomaticallycreatesabackgroundthreadtohandlegettingtheaudioandstartingtheplayback.Becauseitisasynchronous,youwon’tknowexactlywhentheaudiowillstart.Norwillyouknowwhenitends,orevenifit’sstillplaying.Youcan,however,call

Page 529: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

stop()togettheaudiotostopplaying.Ifyoucallplay()againbeforethepreviousaudiohasfinishedplaying,thepreviousaudiowillimmediatelystopandthenewaudiowillbeginatsometimeinthefuturewheneverythinghasbeensetupandfetched.Thisisaverysimpleclassthatprovidesanautomaticbackgroundthread.Listing20-5showshowyourcodeshouldlooktoimplementthis.

Listing20-5.PlayingAudiowithAsyncPlayer

privatestaticfinalStringTAG="AsyncPlayerDemo";privateAsyncPlayermAsync=null;

[...]

mAsync=newAsyncPlayer(TAG);mAsync.play(this,Uri.parse("file://”+“/perry_ringtone.mp3"),false,AudioManager.STREAM_MUSIC);

[...]

@OverrideprotectedvoidonPause(){mAsync.stop();super.onPause();}

Low-LevelAudioPlaybackUsingAudioTrackSofar,we’vebeendealingwithaudiofromfiles,betheylocalfilesorremotefiles.Ifyouwanttogetdowntoalowerlevel,perhapsplayingaudiofromastream,youneedtoinvestigatetheAudioTrackclass.Besidestheusualmethodslikeplay()andpause(),AudioTrackprovidesmethodsforwritingbytestotheaudiohardware.Thisclassgivesyouthemostcontroloveraudioplayback,butitismuchmorecomplicatedthantheaudioclassesdiscussedsofarinthischapter.OneofouronlinecompanionsampleapplicationsusestheAudioRecordclass.TheAudioRecordclassisverymuchliketheAudioTrackclass,sotogetabetterunderstandingoftheAudioTrackclass,refertotheAudioRecordsamplelateron.

MoreAboutMediaPlayerIngeneral,theMediaPlayerisverysystematic,soyouneedtocalloperationsinaspecificordertoinitializeaMediaPlayerproperlyandprepareitforplayback.ThefollowinglistsummarizessomeoftheotherdetailsyoushouldknowforusingthemediaAPIs:

OnceyousetthedatasourceofaMediaPlayer,youcannoteasilychangeittoanotherone—you’llhavetocreateanewMediaPlayerorcallthereset()methodtoreinitializethestateoftheplayer.

Page 530: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Afteryoucallprepare(),youcancallgetCurrentPosition(),getDuration(),andisPlaying()togetthecurrentstateoftheplayer.YoucanalsocallthesetLooping()andsetVolume()methodsafterthecalltoprepare().IfyouusedprepareAsync(),youshouldwaituntilonPrepared()iscalledbeforeusinganyoftheseothermethods.

Afteryoucallstart(),youcancallpause(),stop(),andseekTo().

EveryMediaPlayeryoucreateusesalotofresources,sobesuretocalltherelease()methodwhenyouaredonewiththemediaplayer.TheVideoViewtakescareofthisinthecaseofvideoplayback,butyou’llhavetodoitmanuallyifyoudecidetouseMediaPlayerinsteadofVideoView.MoreaboutVideoViewinthenextsections.

MediaPlayerworkswithseverallistenersyoucanuseforadditionalcontrolovertheuserexperience,includingOnCompletionListener,OnErrorListener,andOnInfoListener.Forexample,ifyou’remanagingaplaylistofaudio,OnCompletionListenerwillbecalledwhenapieceisfinishedsoyoucanqueueupthenextpiece.

Thisconcludesourdiscussionaboutplayingaudiocontent.Nowwe’llturnourattentiontoplayingvideo.Asyouwillsee,referencingvideocontentissimilartoreferencingaudiocontent.

PlayingVideoContentInthissection,wearegoingtodiscussvideoplaybackusingtheAndroidSDK.Specifically,wewilldiscussplayingavideofromawebserverandplayingonefromanSDcard.Asyoucanimagine,videoplaybackisabitmoreinvolvedthanaudioplayback.Fortunately,theAndroidSDKprovidessomeadditionalabstractionsthatdomostoftheheavylifting.

NotePlayingbackvideointheemulatorisnotveryreliable.Ifitworks,great.Butifitdoesn’t,tryrunningonadeviceinstead.Becausetheemulatormustuseonlysoftwaretorunvideo,itcanhaveaveryhardtimekeepingupwithvideo,andyouwilllikelygetunexpectedresults.

Playingvideorequiresmoreeffortthanplayingaudio,becausethere’savisualcomponenttotakecareofinadditiontotheaudio.Totakesomeofthepainaway,Androidprovidesaspecializedviewcontrolcalledandroid.widget.VideoViewthatencapsulatescreatingandinitializingtheMediaPlayer.Toplayvideo,youcreateaVideoView

Page 531: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

widgetinyouruserinterface.YouthensetthepathorURIofthevideoandfirethestart()method.Listing20-6demonstratesvideoplaybackinAndroid.

Listing20-6.PlayingVideoUsingtheMediaAPIs

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"xmlns:android="http://schemas.android.com/apk/res/android">

<VideoViewandroid:id="@+id/videoView"android:layout_width="200px"android:layout_height="200px"/>

</LinearLayout>

//ThisfileisMainActivity.javaimportandroid.app.Activity;importandroid.net.Uri;importandroid.os.Bundle;importandroid.widget.MediaController;importandroid.widget.VideoView;

publicclassMainActivityextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);this.setContentView(R.layout.main);

VideoViewvideoView=(VideoView)this.findViewById(R.id.videoView);MediaControllermc=newMediaController(this);videoView.setMediaController(mc);videoView.setVideoURI(Uri.parse("http://www.androidbook.com/akc/filestorage/android/+"documentfiles/3389/movie.mp4"));/*videoView.setVideoPath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)+"/movie.mp4");*/videoView.requestFocus();videoView.start();}

Page 532: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

Listing20-6demonstratesvideoplaybackofafilelocatedontheWebatwww.androidbook.com/akc/filestorage/android/documentfiles/3389/movie.mp4whichmeanstheapplicationrunningthecodewillneedtorequesttheandroid.permission.INTERNETpermission.AlloftheplaybackfunctionalityishiddenbehindtheVideoViewclass.Infact,allyouhavetodoisfeedthevideocontenttothevideoplayer.TheuserinterfaceoftheapplicationisshowninFigure20-2.

Figure20-2.ThevideoplaybackUIwithmediacontrolsenabled

Whenthisapplicationruns,youwillseethebuttoncontrolsalongthebottomofthescreenforaboutthreeseconds,andthentheydisappear.Yougetthembackbyclickinganywherewithinthevideoframe.Whenweweredoingplaybackofaudiocontent,weneededtodisplaythebuttoncontrolsonlytostart,pause,andrestarttheaudio.Wedidnotneedaviewcomponentfortheaudioitself.Withvideo,ofcourse,weneedbuttoncontrolsaswellassomethingtoviewthevideoin.Forthisexample,we’reusingaVideoViewcomponenttodisplaythevideocontent.Butinsteadofcreatingourownbuttoncontrols(whichwecouldstilldoifwechoseto),wecreateaMediaControllerthatprovidesthebuttonsforus.AsshowninFigure20-2andListing20-6,yousettheVideoView’smediacontrollerbycallingsetMediaController()toenabletheplay,pause,andseek-tocontrols.Ifyouwanttomanipulatethevideoprogrammaticallywithyourownbuttons,youcancallthestart(),pause(),stopPlayback(),andseekTo()methods.

Page 533: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Keepinmindthatwe’restillusingaMediaPlayerinthisexample—wejustdon’tseeit.Youcaninfact“play”videosdirectlyinMediaPlayer.IfyougobacktotheexamplefromListing20-1,putamoviefileonyourSDcard,andpluginthemovie’sfilepathinAUDIO_PATH,youwillfindthatitplaystheaudioquitenicelyeventhoughyoucan’tseethevideo.

WhereasMediaPlayerhasasetDataSource()method,VideoViewdoesnot.VideoViewinsteadusesthesetVideoPath()orsetVideoURI()methods.AssumingyouputamoviefileontoyourSDcard,youchangethecodefromListing20-6tocommentoutthesetVideoURI()callanduncommentthesetVideoPath()call,adjustingthepathtothemoviefileasnecessary.Whenyouruntheapplicationagain,youwillnowhearandseethevideointheVideoView.Technically,wecouldhavecalledsetVideoURI()withthefollowingtogetthesameeffectassetVideoPath():

videoView.setVideoURI(Uri.parse("file://"+Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)+"/movie.mp4"));

YoumighthavenoticedthatVideoViewdoesnothaveamethodtoreaddatafromafiledescriptorasMediaPlayerdid.YoumayalsohavenoticedthatMediaPlayerhasacoupleofmethodsforaddingaSurfaceHoldertoaMediaPlayer(aSurfaceHolderislikeaviewportforimagesorvideo).OneoftheMediaPlayermethodsiscreate(Contextcontext,Uriuri,SurfaceHolderholder),andtheotherissetDisplay(SurfaceHolderholder).

BonusOnlineChapteronRecordingandAdvancedMediaNowthatyouhavemasteredmanyoftheaspectsofmediaplayback,includingthevarietyofmethodstobuildyourownaudioandvideocapabilitiesintoyourapplication,thereareafewmoreareastoexploreonthetopicthatarealmostabook’sworthofcontentintheirownright.Sowehaveputthemtogetherintoanotherbonusonlinechapterthatexploresthefollowing:

AudiorecordingwithMediaRecorder,AudioRecord,andothertechniques

Videorecordingfromthegroundup

Cameraandcamcorderprofilesforvideorecording

UsingintentsandtheMediaStoreclasstohaveotherapplicationsdoallyourrecordingforyou!

TakealookattheonlinematerialfortheAudioandVideoRecordingbonuschapter.

Page 534: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Fortheprojectsinthischapter,lookforazipfilecalledProAndroid5_Ch20_Media.zip.Thiszipfilecontainsalltheprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoEclipsefromoneofthesezipfiles.

http://developer.android.com/guide/topics/media/jet/jetcreator_manual.htmlTheusermanualfortheJETCreatortool.YoucanusethistocreateaJETsoundfiletobeplayedusingtheJetPlayer.JETCreatorisonlyavailableforWindowsandMacOS.ToseeJetPlayerinaction,loadtheJetBoysampleprojectfromtheAndroidSDKintoEclipse,buildit,andrunit.NotethattheFirebuttonisthecenterdirectionalpadkey.

SummaryHereisasummarythetopicscoveredinthismediachapteronaudioandvideo:

PlayingaudiothroughaMediaPlayer

SeveralwaystosourceaudioforMediaPlayer,fromlocalapplicationresources,tofiles,tostreamingoverthenetwork

StepstotakewithaMediaPlayertogettheaudiotocomeoutproperly

SoundPoolanditsabilitytoplayseveralsoundssimultaneously

SoundPool’slimitationsintermsoftheamountofaudioitcanhandle

AsyncPlayer,whichisusefulbecausesoundsgenerallyneedtobemanagedinthebackground

AudioTrack,whichprovideslow-levelaccesstoaudioPlayingvideousingVideoView

Page 535: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter21

HomeScreenWidgetsHomescreenwidgetsinAndroidpresentfrequentlychanginginformationonthehomescreenofAndroid.Homescreenwidgetsaredisconnectedviewsdisplayedonthehomescreen.Datacontentoftheseviewsisupdatedatregularintervalsbybackgroundprocessesorjustkeptasastaticview.

Forexample,ane-mailhomescreenwidgetmightalertyoutothenumberofoutstandinge-mailstoberead.Thewidgetmayjustshowyouthenumberofe-mailsandnotthemessagesthemselves.Clickingthee-mailcountmaythentakeyoutotheactivitythatdisplaysactuale-mails.Thesecouldevenbeexternale-mailsourcessuchasYahoo,Gmail,andHotmail,aslongasthedevicehasawaytoaccessthecountsthroughHTTPorotherconnectivitymechanisms.

IntheAndroidSDKawidgetisdeclarativelydefined.Awidgetdefinitioncontainsthefollowing:

Aviewlayouttobedisplayedonthehomescreen,alongwithhowbigitshouldbetofitonahomepage.

Atimerthatspecifiesthefrequencyofupdates.

AbroadcastreceiverJavaclasscalledawidgetproviderthatcanrespondtotimerupdatesinordertoaltertheviewinsomefashionbypopulatingwithdata.

Anactivityclassthatisresponsibleforcollectingtheinputnecessarytofurtherconfigurethewidgettobedisplayed.

Thetimer,thereceiver,andtheconfigurationactivityareoptional.OnceawidgetisdefinedandtheJavaclassesareprovided,thewidgetwillbeavailablefortheusertodragontoahomepage.TheviewandthecorrespondingJavaclassesarearchitectedinsuchawaythattheyaredisconnectedfromeachother.Forexample,anyAndroidserviceoractivitycanretrievetheviewusingitslayoutID,populatethatviewwithdata(justlikepopulatingatemplate),andsendittothehomescreen.Oncetheviewissenttothehomescreen,itisdislodgedfromtheunderlyingJavacode.

Beforeweshowyouhowtoimplementawidget,we’llfirstgiveyouanoverviewofhowawidgetisusedbyanenduser.

UserExperiencewithHomeScreenWidgetsHomescreenwidgetfunctionalityinAndroidallowsyoutochooseapreprogrammed

Page 536: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

widgettobeplacedonthehomescreen.Whenplaced,thewidgetwillallowyoutoconfigureitusinganactivity(definedaspartofthewidgetpackage),ifnecessary.Itisimportanttounderstandthisinteractionbeforeactuallygoingintothedetailsofhowawidgetisimplemented.

WearegoingtowalkyouthroughawidgetcalledBirthdayWidgetthatwehavecreatedforthischapter.Wewillpresentthesourcecodeforitlaterinthechapter.First,wearegoingtousethiswidgetasanexampleforourwalkthrough.Asaconsequenceofsourcecodecominglater,weneedyourconsiderationtoreadalongandfollowthepicturesandnotlookforthiswidgetonyourscreen.Ifyoufollowtheprovidedfiguresandexplanation,youwillknowthenatureandbehavioroftheBirthdayWidget,whichwillmakethingsclearwhenwecodeitsubsequently.

Let’sstartthistourbylocatingthewidgetwewantandcreatinganinstanceofitonthehomescreen.ThewayyouaccesstheavailablewidgetlistisdifferentdependingontheAndroidrelease.Usuallythough,thelistofwidgetsiskeptalongsidethelistofapplicationsavailableonyourdevice.HereisanexamplefromAPI16(orJellybeanversionofAndroid)inFigure21-1.

Figure21-1.Homescreenwidgetpicklist

InthelistofwidgetsinFigure21-1,theBirthdayWidgetisdesignedforthischapter.Ifyouchoosethiswidget,Androidallowsyoutodragittooneofpagesofyourhome

Page 537: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

screen.AndroidwillcreateacorrespondingwidgetinstanceonthehomescreenthatlooksliketheexampleBirthdayWidgetshowninFigure21-2.

Figure21-2.AnexampleBirthdayWidget

BirthdayWidgetinFigure21-2willindicateinitsheaderthenameoftheperson,howmanydaysawaythisperson’sbirthdayis,whenthedateofbirthfallsthisyear,andalinktobuygifts.Youmaybewonderinghowthenameofthepersonanddateofbirthwereconfigured.Whatifyouwanttwoinstancesofthiswidget,eachwiththenameanddateofbirthforadifferentperson?Thisiswherethewidgetconfigurationactivitycomesintoplayandisthetopicwearecoveringnext.

UnderstandingWidgetConfigurationActivityAwidgetdefinitionoptionallyincludesaspecificationofanactivitycalledawidgetconfigurationactivity.Whenyouchooseawidgetfromthehomepagewidgetpicklisttocreatethewidgetinstance,Androidinvokesthecorrespondingwidgetconfigurationactivityifoneisdefinedforit.Thisactivityissomethingyouneedtocode.

IncaseofourBirthdayWidget,thisconfigurationactivitywillpromptyouforthenameofthepersonandtheupcomingbirthdate,asshowninFigure21-3.Itistheresponsibilityoftheconfigurationactivitytosavethisinformationinapersistentplaceso

Page 538: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thatwhenanupdateiscalledonthewidgetprovider,thewidgetproviderwillbeabletolocatethisinformationandupdatethenumberofdaysuntilthebirthday.

Figure21-3.BirthdayWidgetconfigurationactivity

NoteWhenauserchoosestocreatetwoBirthdayWidgetinstancesonthehomescreen,theconfigurationactivitywillbecalledtwice(onceforeachwidgetinstance).

Internally,AndroidkeepstrackofthewidgetinstancesbyallocatingthemuniqueIDs.ThisuniquewidgetinstanceIDispassedtotheJavacallbacksandtotheconfiguratorJavaclasssothatinitialconfigurationandupdatescanbedirectedtotherightinstanceofthewidgetonthehomepage.InFigure21-2,inthelaterpartofthestringsatya:3,the3isthewidgetinstanceID.

UnderstandingtheLifeCycleofaWidgetThelifecycleofawidgethasthefollowingphases:

1. Widgetdefinition

2. Widgetinstancecreation

3. onUpdate()(whenthetimeintervalexpires)

Page 539: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

4. Responsestoclicks(onthewidgetviewonthehomescreen)

5. Widgetdeletion(fromthehomescreen)

6. Uninstallation

Wewillgothroughthesephasesindetailnow.

UnderstandingWidgetDefinitionPhaseWidgetdefinitionstartswiththedefinitionofthewidgetproviderclassintheAndroidmanifestfile.Listing21-1showsthedefinitionfortheAppWidgetProviderthatwehavedesignedforthischaptercalledBDayWidgetProviderinthemanifestfile.

Listing21-1.WidgetDefinitioninAndroidManifestFile

<!--filename:AndroidManifest.xml,project:ProAndroid5_ch21_TestWidgets.zip--><manifest..><application>....<receiverandroid:name=".BDayWidgetProvider">

<meta-dataandroid:name="android.appwidget.provider"

android:resource="@xml/bday_appwidget_provider"/>

<intent-filter>

<actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"

/>

</intent-filter></receiver>...<activity>.....</activity></application></manifest>

ThisdefinitionindicatesthatthereisabroadcastreceiverJavaclasscalledBDayWidgetProviderwhichreceivesapplicationwidgetbroadcastupdatemessages.ThewidgetclassdefinitioninListing21-1alsopointstoanXMLfile@xml/bday_appwidget_providerwhichis/res/xml/bday_appwidget_provider.xml.ThisXMLfileisinListing21-2.Thiswidgetdefinitionfilehasanumberofthingsaboutthiswidgetsuchasitslayoutresourcefile,updatefrequency,etc.

Listing21-2.WidgetViewDefinitioninWidgetProviderInformationXMLFile

<!--/res/xml/bday_appwidget_provider.xml(ProAndroid5_ch21_TestWidgets.zip)--><appwidget-provider

Page 540: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

xmlns:android="http://schemas.android.com/apk/res/android"

android:minWidth="150dp"android:minHeight="120dp"android:updatePeriodMillis="43200000"android:initialLayout="@layout/bday_widget"android:configure="com.androidbook.BDayWidget.ConfigureBDayWidgetActivity"android:resizeMode="horizontal|vertical"android:previewImage="@drawable/some_preview_image_icon"></appwidget-provider>

ThisXMLfileiscalledtheAppwidgetproviderinformationfile.Internally,thisgetstranslatedtotheAppWidgetProviderInfoJavaclass.Thisfileidentifiesthewidthandheightofthelayouttobe150dpand120dp,respectively.Thisdefinitionfilealsoindicatestheupdatefrequencytobe12hourstranslatedtomilliseconds.ThewidgetdefinitionalsopointstoalayoutfilethroughtheinitialLayoutattribute.Thislayoutfile(seefutureListing21-6)producesthewidgetlookthatisshowninFigure21-2.

UnderstandingresizeModeAttributeStartingwithSDK3.1,usershavetheabilitytoresizeawidgetthatisplacedononeoftheirimages.Theuserseesresizehandleswhentheylong-clickthewidgetandcanthenusethesehandlestoresize.Thisresizecanbehorizontal,vertical,ornone.Youcancombinehorizontalandverticaltoresizethewidgetinbothdimensions,asshowninListing21-2.However,totakeadvantageofthis,yourwidgetcontrolsshouldbelaidoutinsuchawaythattheycanexpandandcontractusingtheirlayoutparameters.Thereisnocallbacktotellyouwhatsizeyourwidgetis.

UnderstandingpreviewImageAttributeThepreviewimageattributeinListing21-2indicateswhatimageoriconisusedtoshowyourwidgetinthelistofavailablewidgets.Ifyouomitit,thedefaultbehavioristoshowthemainiconforyourapplicationpackage,whichisindicatedinthemanifestfile.

UnderstandingWidgetLayout:initialLayoutAttributeThelayoutforwidgetviewsisrestrictedtocontainonlycertaintypesofviewelements.TheviewsallowedinawidgetlayoutareexposedthroughaninterfacecalledRemoteViews,andonlycertainviewscanbecomposedintothislayout.SomeoftheallowedviewelementsareshowninListing21-3.Notethattheirsubclassesarenotsupported—onlythosethatareincludedinListing21-3.

Listing21-3.AllowedViewControlsinRemoteViews

FrameLayoutLinearLayoutRelativeLayoutGridLayout

Page 541: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AnalogClockButtonChronometerImageButtonImageViewProgressBarTextViewViewFlipperListViewGridViewStackViewAdapterViewFlipper

Thislistmaygrowwitheachrelease.Theprimaryreasonforrestrictingwhatisallowedinaremoteviewisthattheseviewsaredisconnectedfromtheprocessesthatactuallycontrolthem.ThesewidgetviewsarehostedbyanapplicationliketheHomeapplication.Thecontrollersfortheseviewsarebackgroundprocessesthatgetinvokedbytimers.Forthisreason,theseviewsarecalledremoteviews.ThereisacorrespondingJavaclasscalledRemoteViewsthatallowsaccesstotheseviews.Inotherwords,programmersdonothavedirectaccesstotheseviewstocallmethodsonthem.YouhaveaccesstotheseviewsonlythroughtheRemoteViews(likeagatekeeper).

WewillcovertherelevantmethodsofaRemoteViewsclasswhenweexploretheexampleinthenextmainsection.Fornow,rememberthatonlyalimitedsetofviewsinListing21-3areallowedinthewidgetlayoutfile.

UnderstandingconfigureAttributeThewidgetdefinition(Listing21-2)usestheconfigureattributetospecifytheconfigurationactivitythatneedstobeinvokedwhentheusercreatesawidgetinstance.ThisconfigurationactivityspecifiedinListing21-2istheConfigureBDayWidgetActivity.Thisactivity(Figure21-3)islikeanyotherAndroidactivity.Formfieldsonthisactivityareusedtocollecttheinformationneededbyawidgetinstance.

UnderstandingWidgetInstanceCreationPhaseWhenauserchoosesawidgettocreateawidgetinstance,Androidinvokestheconfigurationactivity(Figure21-3)ifitisdefinedintheconfigurationXMLfileforthewidget.Ifthisconfigurationactivityisnotdefinedthenthisphaseskippedandthewidgetispresenteddirectlyonthehomepage.Wheninvokedthisconfigurationactivitydoesthefollowing:

1. ReceivethewidgetinstanceIDfromtheinvokingintentthatstartedtheconfigurationactivity.

2. Prompttheuserthroughformfieldstocollectthewidget-instance–specificinformation.

Page 542: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

3. PersistthewidgetinstanceinformationsothatsubsequentcallstoAppWidgetProvider’sonUpdatemethodhaveaccesstothisinformation.

4. PreparetodisplaythewidgetviewforthefirsttimebyretrievingthewidgetviewlayoutandcreateaRemoteViewsobjectwithit.

5. CallmethodsontheRemoteViewsobjecttosetvaluesonindividualviewobjects,suchastextandimages.

6. AlsousetheRemoteViewsobjecttoregisteranyonClickeventsonanyofthesubviewsofthewidget.

7. TelltheAppWidgetManagertopainttheRemoteViewsonthehomescreenusingtheinstanceIDofthatwidget.

8. ReturnthewidgetID,andclose.

NoticethatthefirstpopulationofthewidgetinthiscaseisdonebytheconfigurationactivityandnotAppWidgetProvider’sonUpdate()method.

NoteTheconfigurationactivityisoptional.Iftheconfigurationactivityisnotspecified,thecallgoesdirectlytotheonUpdate()methodoftheAppWidgetProvider.ItisuptoonUpdate()toupdatetheview.

Androidwillundertakethisprocessforeachwidgetinstancethattheusercreates.Besidesinvokingtheconfigurationactivity,AndroidalsoinvokestheonEnabledcallbackoftheAppWidgetProvider.Let’sbrieflyconsiderthecallbacksonanAppWidgetProviderclassbytakingalookattheshellofourBDayWidgetProvider(seeListing21-4).WewillexaminethecompletelistingofthisfilelaterinListing21-10.

Listing21-4.AWidgetProviderShell

//filename:BDayWidgetProvider.java(ProAndroid5_ch21_TestWidgets.zip)publicclassBDayWidgetProviderextendsAppWidgetProvider{

publicvoidonUpdate(Contextcontext,AppWidgetManagerappWidgetManager,int[]appWidgetIds){}publicvoidonDeleted(Contextcontext,int[]appWidgetIds){}publicvoidonEnabled(Contextcontext){}publicvoidonDisabled(Contextcontext){}}

TheonEnabled()callbackmethodindicatesthatthereisatleastoneinstanceofthewidgetupandrunningonthehomescreen.Thismeansausermusthavedroppedthewidgetonthehomepageatleastonce.Inthiscall,youwillneedtoenablereceivingmessagesforthisbroadcastreceivercomponent(youwillseethisinListing21-10).The

Page 543: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SDKbaseclassAppWidgetProviderhasthefunctionalitytoenableordisablereceivingbroadcastmessages.

TheonDeleted()callbackmethodiscalledwhenauserdragsthewidgetinstanceviewtothetrashcan.Thisiswhereyouwillneedtodeleteanypersistentvaluesyouareholdingforthatwidgetinstance.

TheonDisabled()callbackmethodiscalledafterthelastwidgetinstanceisremovedfromthehomescreen.Thishappenswhenauserdragsthelastinstanceofawidgettothetrash.Youshouldusethismethodtounregisteryourinterestinreceivinganybroadcastmessagesintendedforthiscomponent(youwillseethisinListing21-9).

TheonUpdate()callbackmethodiscalledeverytimethetimerspecifiedinListing21-2expires.Thismethodisalsocalledtheveryfirsttimethewidgetinstanceiscreatedifthereisnoconfigurationactivity.Ifthereisaconfigurationactivity,thismethodisnotcalledatthecreationofawidgetinstance.Thismethodwillsubsequentlybecalledwhenthetimerexpiresatthefrequencyindicated.

UnderstandingonUpdatePhaseOncethewidgetinstanceisonthehomescreen,thenextsignificanteventistheexpirationofthetimer.AndroidwillcallonUpdate()inresponsetothattimer.BecauseonUpdate()iscalledisthroughabroadcastreceiver,thecorrespondingJavaprocesswillbeloadedandwillremainliveuntiltheendofthatcall.Oncethecallreturns,theprocesswillbereadytobetakendown.

OnceyouhavethenecessarydataavailabletoupdatethewidgetintheonUpdate()method,youcaninvoketheAppWidgetManagertopainttheremoteview.ThisgoestoshowthattheAppWidgetProviderclassisstatelessandmayevenbeincapableofmaintainingstaticvariablesbetweeninvocations.ThisisbecausetheJavaprocesscontainingthisbroadcastreceiverclasscouldbetakendownandreconstructedbetweentwoinvocations,resultinginre-initializationofstaticvariables.

Asaresult,youwillneedtocomeupwithaschemetorememberstateifthatisrequired.Youcansavethestateofthewidgetinstanceinapersistentstoresuchasafile,sharedpreferences,oraSQLitedatabase.Intheexamplesinthischapter,weusedsharedpreferencesasthepersistenceAPI.

CautionTosavepower,Googlerecommendsthatthedurationoftheupdatesbemorethananhour,sothedevicewon’twakeuptoooften.Startingwiththe2.0API,thereisarestrictionof30minutesormorefortheupdatetimeout.

Fordurationsthatareshorter,suchasonlyseconds,youneedtocallthisonUpdate()methodyourselfbyusingthefacilitiesintheAlarmManagerclass.WhenyouuseAlarmManager,youalsohavetheoptionnottocallonUpdate()but,instead,dotheworkofonUpdate()inalarmcallbacks.RefertoChapter17forworkingwiththealarmmanager.

ThisiswhatyoutypicallyneedtodoinanonUpdate()method:

Page 544: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

1. Makesuretheconfiguratorhasfinisheditswork;otherwise,justreturn.Thisshouldnotbeprobleminreleases2.0andabove,wherethedurationisexpectedtobelonger.Otherwise,basedontheupdateinterval(whenitistoosmall)itispossiblethatonUpdate()willbecalledbeforetheuserhasfinishedconfiguringthewidgetintheconfigurator.

2. Retrievethepersisteddataforthatwidgetinstance.

3. Retrievethewidgetviewlayout,andcreateaRemoteViewsobjectwithit.

4. CallmethodsontheRemoteViewstosetvaluesonindividualviewobjectssuchastextandimages.

5. RegisteranyonClickeventsonanyoftheviewsbyusingpendingintents.

6. TelltheAppWidgetManagertopainttheupdatedRemoteViewsusingtheinstanceID.

Asyoucansee,thereisalotofoverlapbetweenwhataconfiguratordoesinitiallyandwhattheonUpdate()methoddoes.Youmaywanttoreusethisfunctionalitybetweenthetwoplaces.

UnderstandingWidgetViewMouseClickEventCallbacksAsstated,theonUpdate()methodkeepsthewidgetviewsuptodate.Thewidgetviewandsubelementsinthatviewcouldhavecallbacksregisteredforamouseclick.Typically,theonUpdate()methodusesapendingintenttoregisteranactionforaneventlikeamouseclick.Thisactioncouldthenstartaserviceorstartanactivitysuchasopeningupabrowser.

Thisinvokedserviceoractivitycanthencommunicatebackwiththeview,ifneeded,usingthewidgetinstanceIDandtheAppWidgetManager.Hence,itisimportantthatthependingintentcarrieswithitthewidgetinstanceID.

DeletingaWidgetInstanceAnotherdistincteventthatcanhappentoawidgetinstanceisthatitcangetdeleted.Todothis,auserhastolong-pressthewidgetonthehomescreen.Thiswillenablethetrashcantoshowonthehomescreen.Theusercanthendragthewidgetinstancetothetrashcantodeletethewidgetinstancefromthescreen.

DoingsocallstheonDelete()methodofthewidgetprovider.Ifyouhavesavedanystateinformationforthiswidgetinstance,youwillneedtodeletethatdatainthisonDeletemethod.

AndroidalsocallsonDisable()ifthewidgetinstancethathasjustbeendeletedisthelastofthewidgetinstancesofthistype.Youwillusethiscallbacktocleanupanypersistenceattributesthatarestoredforallwidgetinstancesandalsounregisterfor

Page 545: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

callbacksfromthewidgetonUpdate()broadcasts.

UninstallingWidgetPackagesThereisaneedtocleanupthewidgetsifyouareplanningtouninstallandinstallanewreleaseofyour.apkfilecontainingthesewidgets.

Itisrecommendedthatyouremoveordeleteallwidgetinstancesbeforetryingtouninstallthepackage.Followthedirectionsinthe“DeletingaWidgetInstance”sectiontodeleteeachwidgetinstanceuntilnoneremain.

Then,youcanuninstallandinstallthenewrelease.ThisisespeciallyimportantifyouareusingtheEclipseADTtodevelopyourwidgets,becauseduringthedevelopmenttime,ADTtriestodothiseverytimeyouruntheapplication.So,betweenruns,makesureyouremovethewidgetinstances.

ImplementingASampleWidgetApplicationSofar,wehavecoveredthetheoryandapproachbehindwidgets.Let’screatethesamplewidgetwhosebehaviorhasbeenusedastheexampletoexplainwidgetarchitecture.Wewilldevelop,test,anddeploythisBirthdayWidget.

EachBirthdayWidgetinstancewillshowaname,thedateofthenextbirthday,andhowmanydaysfromtodayuntilthebirthday.ItwillalsocreateanonClickareawhereyoucanclicktobuygifts.Thisclickwillopenabrowserandtakeyoutowww.google.com.

ThelayoutofthefinishedwidgetshouldlooklikeFigure21-4.

Figure21-4.BirthdayWidgetlookandfeel

Theimplementationofthiswidgetconsistsofthefollowingwidget-relatedfiles.TheentireprojectisalsoavailablefordownloadattheURLmentionedinthe“References”sectionofthischapter.

Thebasicfilesare

AndroidManifest.xml:WheretheAppWidgetProviderisdefined(seeListing21-5)

res/xml/bday_appwidget_provider.xml:Widget

Page 546: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

dimensionsandlayout(seeListing21-2)

res/layout/bday_widget.xml:Thewidgetlayout(seeListing21-6)

res/drawable/box1.xml:Providesboxesforsectionsofthewidgetlayout(seeListing21-7)

src/…/BdayWidgetProvider.java:ImplementationoftheAppWidgetProviderclass(seeListing21-10)

Thesefilesimplementthewidgetconfigurationactivity:

src/…/ConfigureBDayWidgetActivity.java:Configurationactivity(seeListing21-8)

layout/edit_bday_widget.xml:Layoutfortakingthenameandbirthday(seeListing21-9)

Thesefilesstore/retrievethestateofawidgetinstanceusingpreferences:

src/…/IWidgetModelSaveContract.java:Contractforsavingandretrievingawidget’sdata(Seeindownloadableproject)

src/…/APrefWidgetModel.java:Abstractpreference-basedwidgetmodelthatsaveswidgetdatainpreferences(seeindownloadableproject)

src/…/BDayWidgetModel.java:Widgetmodelholdingthedataforawidgetview(seeindownloadableproject)

src/…/Utils.java:Afewutilityclasses(seeindownloadableproject)

Wewillwalkthroughsomeofthekeyfilesandexplainanyadditionalconceptsthatbearfurtherconsideration.Youcangettherestofthefilesfromthedownloadableprojectforthischapter.

DefiningtheWidgetProviderFortheBirthdayWidgetprojectthemanifestfileisinListing21-5.IthasthedeclarationsforthewidgetproviderBDayAppWidgetProviderasabroadcastreceiverandalsothedefinitionfortheconfigurationactivityConfigureBDayWidgetActivity.NoticehowthewidgetproviderdefinitionalsopointstothewidgetdefinitionXMLfile@xml/bday_appwidget_provider.

Listing21-5.AndroidManifestFileforBDayWidgetSampleApplication

<?xmlversion="1.0"encoding="utf-8"?><!--file:

Page 547: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AndroidManifest.xml(ProAndroid5_ch21_TestWidgets.zip)--><manifestxmlns:android="http://schemas.android.com/apk/res/android"

package="com.androidbook.BDayWidget"android:versionCode="1"android:versionName="1.0.0"><applicationandroid:icon="@drawable/icon"android:label="BirthdayWidget"><!--***********************************************************************BirthdayWidgetProviderReceiver**********************************************************************--><receiverandroid:name=".BDayWidgetProvider"><meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/bday_appwidget_provider"/><intent-filter><actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/></intent-filter></receiver><!--***********************************************************************BirthdayProviderConfigurationactivity**********************************************************************--><activityandroid:name=".ConfigureBDayWidgetActivity"android:label="ConfigureBirthdayWidget"><intent-filter><actionandroid:name="android.appwidget.action.APPWIDGET_CONFIGURE"/></intent-filter></activity>

</application><uses-sdkandroid:minSdkVersion="3"/></manifest>

Theapplicationlabelidentifiedby“BirthdayWidget”inthefollowingline

<applicationandroid:icon="@drawable/icon"android:label="BirthdayWidget">

iswhatshowsupinthewidgetpicklist(seeFigure21-2)ofthehomepage.YoucanalsoindicateinthewidgetdefinitionXMLfile(Listing21-2)analternateicontobeshownwhenthewidgetislisted(alsocalledapreview).Theconfigurationactivitydefinitionislikeanyothernormalactivity,exceptthatitneedstodeclareitselfascapableofrespondingtoandroid.appwidget.action.APPWIDGET_CONFIGUREactions.

Page 548: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Refertothewidgetdefinitionfile@xml/bday_appwidget_providerinListing21-2toseehowthewidgetsizeandapathtothelayoutfilearespecified.ThislayoutfileisjustlikeanyotherlayoutfileforaviewinAndroid.Listing21-6showsthelayoutfileweusedtoproducethewidgetlayoutshowninFigure21-4.

Listing21-6.WidgetViewLayoutDefinitionforBDayWidget

<?xmlversion="1.0"encoding="utf-8"?><!--res/layout/bday_widget.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@drawable/box1"><TextViewandroid:id="@+id/bdw_w_name"android:layout_width="fill_parent"android:layout_height="40sp"android:text="Anonymous"android:background="@drawable/box1"android:gravity="center"android:layout_weight="0"/><LinearLayoutandroid:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_weight="1"><TextViewandroid:id="@+id/bdw_w_days"android:layout_width="wrap_content"android:layout_height="fill_parent"android:gravity="center"android:layout_weight="50"android:text="0"android:textSize="30sp"/><TextViewandroid:id="@+id/bdw_w_button_buy"

android:layout_width="wrap_content"android:layout_height="fill_parent"

android:layout_weight="50"android:gravity="center"android:textSize="20sp"android:text="Buy"android:background="#FF6633"/></LinearLayout><TextViewandroid:id="@+id/bdw_w_date"android:layout_width="fill_parent"android:layout_height="40sp"android:gravity="center"android:layout_weight="0"android:text="1/1/2000"android:background="@drawable/box1"/></LinearLayout>

Someofthecontrolsalsouseashapedefinitionfilecalledbox1.xmltodefinethe

Page 549: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

borders.ThecodefortheshapedefinitionfileisshowninListing21-7.

Listing21-7.ABoundaryBoxShapeDefinition

<!--res/drawable/box1.xml--><shapexmlns:android="http://schemas.android.com/apk/res/android"><strokeandroid:width="4dp"android:color="#888888"/><paddingandroid:left="2dp"android:top="2dp"android:right="2dp"android:bottom="2dp"/><cornersandroid:radius="4dp"/></shape>

ImplementingWidgetConfigurationActivityFortheBirthdayWidgetexample,theconfigurationofthewidgetresponsibilitiesareimplementedinConfigureBDayWidgetActivity.SourcecodeforthisclassisinListing21-8.

Listing21-8.ImplementingaConfigurationActivity

//file:ConfigureBDayWidgetActivity.java(ProAndroid5_ch21_TestWidgets.zip)publicclassConfigureBDayWidgetActivityextendsActivity{privatestaticStringtag="ConfigureBDayWidgetActivity";privateintmAppWidgetId=AppWidgetManager.INVALID_APPWIDGET_ID;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.edit_bday_widget);setupButton();//setupthesavebutton

//Getthewidgetinstanceidfromtheintentextra

Intentintent=getIntent();Bundleextras=intent.getExtras();if(extras!=null){mAppWidgetId=extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);}}privatevoidsetupButton(){Buttonb=(Button)this.findViewById(R.id.bdw_button_update_bday_widget);b.setOnClickListener(

Page 550: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

newButton.OnClickListener(){publicvoidonClick(Viewv){saveConfiguration(v);}});}//Readnameanddate.

//CallupdateAppWidgetLocaltosavethevaluesforthisinstance//inthatmethodalsosendtheviewtothehomepage.//ReturntheresultoftheconfigurationactivitytotheSDK//finishtheactivity.privatevoidsaveConfiguration(Viewv){

Stringname=this.getName();Stringdate=this.getDate();if(Utils.validateDate(date)==false){this.setDate("wrongdate:"+date);return;}if(this.mAppWidgetId==AppWidgetManager.INVALID_APPWIDGET_ID){return;}updateAppWidgetLocal(name,date);IntentresultValue=newIntent();resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,

mAppWidgetId);

setResult(RESULT_OK,resultValue);

finish();}privateStringgetName(){EditTextnameEdit=(EditText)this.findViewById(R.id.bdw_bday_name_id);Stringname=nameEdit.getText().toString();returnname;}privateStringgetDate(){EditTextdateEdit=(EditText)this.findViewById(R.id.bdw_bday_date_id);StringdateString=dateEdit.getText().toString();returndateString;}privatevoidsetDate(StringerrorDate){EditTextdateEdit=(EditText)this.findViewById(R.id.bdw_bday_date_id);dateEdit.setText("error");

Page 551: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

dateEdit.requestFocus();}privatevoidupdateAppWidgetLocal(Stringname,Stringdob){

//Createanobjecttoholdthedata:widgetid,name,anddob

BDayWidgetModelm=newBDayWidgetModel(mAppWidgetId,name,dob);//Createtheviewandsendittothehomescreen

updateAppWidget(this,AppWidgetManager.getInstance(this),m);//Usethedatamodelobjecttosavetheid,name,anddobinprefs

m.savePreferences(this);}//AkeymethodwherealotofmagichappenspublicstaticvoidupdateAppWidget(Contextcontext,AppWidgetManagerappWidgetManager,BDayWidgetModelwidgetModel){//ConstructaRemoteViewsObjectfromthewidgetlayoutfileRemoteViewsviews=newRemoteViews(context.getPackageName(),R.layout.bday_widget);

//Usethecontrolidsinthelayouttosetvaluesonthem.

//Noticethatthesemethodsarelimitedandavailableonthe

//ontheRemoteViewsobject.Inotherwordswearenotusingthe

//TextViewdirectlytosetthesevalues.

views.setTextViewText(R.id.bdw_w_name,widgetModel.getName()+":"+widgetModel.iid);

views.setTextViewText(R.id.bdw_w_date,widgetModel.getBday());

//updatethenameviews.setTextViewText(R.id.bdw_w_days,

Long.toString(widgetModel.howManyDays()));

//Setintentstoinvokeotheractivitieswhenwidgetisclickedon

IntentdefineIntent=newIntent(Intent.ACTION_VIEW,Uri.parse("http://www.google.com"));PendingIntentpendingIntent=PendingIntent.getActivity(context,0/*norequestCode*/,defineIntent,0/*noflags*/);views.setOnClickPendingIntent(R.id.bdw_w_button_buy,pendingIntent);

Page 552: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Tellthewidgetmanagertopainttheremoteview

appWidgetManager.updateAppWidget(widgetModel.iid,views);}}

Beforewecoverwhatthiscodedoes,thelayoutusedbythiswidgetconfigurationactivityisinListing21-9.Thislayoutisstraightforward.YoucanalsoseethisvisuallyinFigure21-3.

Listing21-9.LayoutDefinitionforConfigurationActivity

<?xmlversion="1.0"encoding="utf-8"?><!--res/layout/edit_bday_widget.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/root_layout_id"android:orientation="vertical"

android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:id="@+id/bdw_text1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Name:"/><EditTextandroid:id="@+id/bdw_bday_name_id"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Anonymous"/><TextViewandroid:id="@+id/bdw_text2"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Birthday(9/1/2001):"/><EditTextandroid:id="@+id/bdw_bday_date_id"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="ex:10/1/2009"/><Buttonandroid:id="@+id/bdw_button_update_bday_widget"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="update"/></LinearLayout>

GoingbacktotheconfigurationactivitycodeinListing21-8,itaccomplishesthefollowingtasks:

Page 553: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReadingthewidgetinstanceIDfrominvokingintent

Collectingthenameanddateofbirthusingformfields

ObtainingRemoteViewsbyloadingwidgetlayoutfile

SettingtextvaluesontheRemoteViews

RegisteringapendingintentthroughRemoteViews

InvokingtheAppWidgetManagertosendtheRemoteViewstothewidget

SavingthenameanddateofbirthinpreferencesagainstthiswidgetinstanceID.ThisisdonethroughtheclassBDayWidgetModel.Wewilltalkaboutthisshortly.

Returningattheendwitharesult.

NoteThestaticfunctionudpateAppWidgetcanbecalledfromanywhereaslongasyouknowthewidgetID.Thissuggeststhatyoucanupdateawidgetfromanywhereonyourdeviceandfromanyprocess,bothvisualandnonvisual.

NoticehowwearepassingthewidgetIDbacktotheinvokerofthisconfigurationactivity.ThisishowAppWidgetManagerknowsthattheconfigurationactivityiscompletedforthatwidgetinstance.

Let’stalkaboutsavingandretrievalofthewidgetinstancestatethroughBDayWidgetModelobjectinListing21-8.TheroleofBDayWidgetModelobjectistostoreandretrievethreevalues:ThewidgetinstanceID(primarykey),name,anddateofbirth.ThisclassusesthepreferencesAPItopersistandreadbackthesevalues.Alternatively,youcanuseanypersistencemechanismforthisneed.Wearenotincludingthesourcecodeforthisclassasitisquiteasimpleneedtoimplement.Inthedownloadableprojectforthischapterwehaveanimplementationforthisclassthatisabitmoreextensive,wherewecodedareusableframeworktostorevaluesforanyjavaobjectinthepreferences.Wehaveamplydocumentedthesourcecodesothatyoucanuseitasisforotherneedsortweakitfurtherandusereflectiontosimplifyfurther.Intheendyouwillhaveamodelframeworkthatisquiteextensible.Asthisisnottheprimarygoalofthischapterwehavenotgottenintothosedetailshere.Whatmattersforthischapteristhatthesethreevalues,theinstanceID,name,anddobbesavedandretrieved.YoucanfollowthenamesontheBDayWidgetModelasaguide.

ImplementingaWidgetProviderLet’sseenowhowwewillrespondtothelifecycleeventsofwidgetsbyexaminingthewidgetproviderclass.Listing21-10implementsthewidgetproviderclass.

Listing21-10.SourcecodeforSampleWidgetProvider:BDayWidgetProvider

//file:

Page 554: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

BDayWidgetProvider.java(ProAndroid5_ch21_TestWidgets.zip)publicclassBDayWidgetProviderextendsAppWidgetProvider{

privatestaticfinalStringtag="BDayWidgetProvider";publicvoidonUpdate(Contextcontext,AppWidgetManager

appWidgetManager,

int[]appWidgetIds){finalintN=appWidgetIds.length;for(inti=0;i<N;i++){intappWidgetId=appWidgetIds[i];updateAppWidget(context,appWidgetManager,appWidgetId);}}publicvoidonDeleted(Contextcontext,int[]appWidgetIds){

finalintN=appWidgetIds.length;for(inti=0;i<N;i++){BDayWidgetModelbwm=BDayWidgetModel.retrieveModel(context,appWidgetIds[i]);bwm.removePrefs(context);}}publicvoidonEnabled(Contextcontext){

BDayWidgetModel.clearAllPreferences(context);PackageManagerpm=context.getPackageManager();pm.setComponentEnabledSetting(newComponentName("com.androidbook.BDayWidget",".BDayWidgetProvider"),PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);}

publicvoidonDisabled(Contextcontext){

BDayWidgetModel.clearAllPreferences(context);PackageManagerpm=context.getPackageManager();pm.setComponentEnabledSetting(newComponentName("com.androidbook.BDayWidget",".BDayWidgetProvider"),PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);}privatevoidupdateAppWidget(Contextcontext,AppWidgetManager

appWidgetManager,

intappWidgetId){BDayWidgetModelbwm=BDayWidgetModel.retrieveModel(context,appWidgetId);if(bwm==null){return;}ConfigureBDayWidgetActivity.updateAppWidget(context,appWidgetManager,bwm);

Page 555: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}}

Inthe“LifeCycleofaWidget”sectionwediscussedtheresponsibilitiesofthesemethods.FortheBirthdayWidget,allthesemethodsmakeuseoftheBDayWidgetModeltoretrievethedataassociatedwithawidgetinstanceforwhichthecallbacksarecalled.SomeofthesemethodsontheBDayWidgetModelareremovePrefs(),retrievePrefs(),andclearAllPreferences().

Theupdatecallbackmethodiscalledforallthewidgetinstancesofthiswidgettype.Thismethodmustupdateallthewidgetinstances.ThewidgetinstancesarepassedinasanarrayofIDs.Foreachid,theonUpdate()methodwilllocatethecorrespondingwidgetinstancemodelandcallthesamemethodthatisusedbytheconfigurationactivity(seeListing21-8)todisplaytheretrievedwidgetmodel.

IntheonDeleted()method,wehaveinstantiatedaBDayWidgetModelandthenaskedittoremoveitselffromthepreferencespersistencestore.

IntheonEnabled()method,becauseitiscalledonlyoncewhenthefirstinstancecomesintoplay,wehaveclearedallpersistenceofthewidgetmodelssothatwestartwithacleanslate.WedothesameintheonDisabled()methodsothatnomemoryofwidgetinstancesexists.

IntheonEnabled()method,weenablethewidgetprovidercomponentsothatitcanreceivebroadcastmessages.IntheonDisabled()method,wedisablethecomponentsothatitwon’tlookforanybroadcastmessages.

Collection-BasedWidgetsStartingwithSDK3.0,Androidhasexpandedthewidgetstoincludewidgetsbasedoncollections.Wedon’thaveroomintheprintcopyofthisbook.Wewillincludethechapterfromthepreviouseditiononcollectionwidgetsatouronlinesitefordownload.

ResourcesHerearehelpfulreferencestothetopicsthatarecoveredinthischapter:

http://developer.android.com/guide/topics/appwidgets/index.htmlOfficialAndroidSDKdocumentationonappwidgets.

http://developer.android.com/reference/android/content/SharedPreferences.htmlSharedPreferencesAPIformanagingstate.

http://developer.android.com/reference/android/content/SharedPreferences.Editor.htmlTheSharedPreferences.EditorAPI,whichisrelatedtosharedpreferences.

http://developer.android.com/guide/practices/ui_guidelines/widget_design.html

Page 556: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Designpleasingwidgetlayouts.

http://developer.android.com/reference/android/widget/RemoteViews.htmlRemoteViewsAPI,usedtopaintandmanipulatewidgetviews.

http://developer.android.com/reference/android/appwidget/AppWidgetManager.htmlWidgetsthemselvesaremanagedbyawidgetmanagerclass.

http://www.androidbook.com/item/3938:Researchnotesusedwhilewritingthischapter,includingasummary,researchlogs,codesnippets,andusefulURLs.

http://www.androidbook.com/free-android-chapters:YoucanusethisURLtodownloadadetailedchapteronlistwidgets.

http://www.androidbook.com/proandroid5/projects:Downloadabletestprojectsforthischapter.ThenameoftheZIPfileforthischapterisProAndroid5_ch21_TestWidgets.zip.

SummaryWidgetsareoftenusedalongsideyourapplicationsinAndroid.Thischapterhascoveredtheessentialsyouneedtocreateandconfigurewidgets.Asupplementalchapteronlistwidgetsisprovidedonline.

Page 557: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter22

TouchScreensManyAndroiddevicesincorporatetouchscreens.Whenadevicedoesnothaveaphysicalkeyboard,muchoftheuserinputmustcomethroughthetouchscreen.Thereforeyourapplicationswilloftenneedtobeabletodealwithtouchinputfromtheuser.You’vemostlikelyalreadyseenthevirtualkeyboardthatdisplaysonthescreenwhentextinputisrequiredfromtheuser.WeusedtouchwithmappingapplicationsinChapter19.Theimplementationsofthetouchscreeninterfacehavebeenhiddenfromyousofar,butnowwe’llshowyouhowtotakeadvantageofthetouchscreen.

Thischapterismadeupofthreemajorparts.ThefirstsectionwilldealwithMotionEventobjects,whichishowAndroidtellsanapplicationthattheuseristouchingatouchscreen.We’llalsocovertheVelocityTracker.Thesecondsectionwilldealwithmultitouch,whereausercanhavemorethanonefingeratatimeonthetouchscreen.Finally,wewillincludeasectionongestures,aspecializedtypeofcapabilityinwhichtouchsequencescanbeinterpretedascommands.

UnderstandingMotionEventsInthissection,we’regoingtocoverhowAndroidtellsapplicationsabouttoucheventsfromtheuser.Fornow,wewillonlybeconcernedwithtouchingthescreenonefingeratatime(we’llcovermultitouchinalatersection).

Atthehardwarelevel,atouchscreenismadeupofspecialmaterialsthatcanpickuppressureandconvertthattoscreencoordinates.Theinformationaboutthetouchisturnedintodata,andthatdataispassedtothesoftwaretodealwithit.

TheMotionEventObjectWhenausertouchesthetouchscreenofanAndroiddevice,aMotionEventobjectiscreated.TheMotionEventcontainsinformationaboutwhereandwhenthetouchtookplace,aswellasotherdetailsofthetouchevent.TheMotionEventobjectgetspassedtoanappropriatemethodinyourapplication.ThiscouldbetheonTouchEvent()methodofaViewobject.RememberthattheViewclassistheparentofquiteafewclassesinAndroid,includingLayouts,Buttons,Lists,Clocks,andmore.ThismeanswecaninteractwithallofthesedifferenttypesofViewobjectsusingtouchevents.Whenthemethodiscalled,itcaninspecttheMotionEventobjecttodecidewhattodo.Forexample,aGoogleMapcouldusetoucheventstomovethemapsidewaystoallowtheusertopanthemaptootherpointsofinterest.Avirtualkeyboardobjectcouldreceivetoucheventstoactivatethevirtualkeystoprovidetextinputtosomeotherpartoftheuserinterface(UI).

Page 558: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReceivingMotionEventObjectsAMotionEventobjectisoneofasequenceofeventsrelatedtoatouchbytheuser.Thesequencestartswhentheuserfirsttouchesthetouchscreen,continuesthroughanymovementsofthefingeracrossthesurfaceofthetouchscreen,andendswhenthefingerisliftedfromthetouchscreen.Theinitialtouch(anACTION_DOWNaction),themovementssideways(ACTION_MOVEactions),andtheupevent(anACTION_UPaction)ofthefingerallcreateMotionEventobjects.YoucouldreceivequiteafewACTION_MOVEeventsasthefingermovesacrossthesurfacebeforeyoureceivethefinalACTION_UPevent.EachMotionEventobjectcontainsinformationaboutwhatactionisbeingperformed,wherethetouchistakingplace,howmuchpressurewasapplied,howbigthetouchwas,whentheactionoccurred,andwhentheinitialACTION_DOWNoccurred.Thereisafourthpossibleaction,whichisACTION_CANCEL.Thisactionisusedtoindicatethatatouchsequenceisendingwithoutactuallydoinganything.Finally,thereisACTION_OUTSIDE,whichissetinaspecialcasewhereatouchoccursoutsideofourwindowbutwestillgettofindoutaboutit.

Thereisanotherwaytoreceivetouchevents,andthatistoregisteracallbackhandlerfortoucheventsonaViewobject.TheclasstoreceivetheeventsmustimplementtheView.OnTouchListenerinterface,andtheViewobject’ssetOnTouchListener()methodmustbecalledtosetupthehandlerforthatView.TheimplementingclassoftheView.OnTouchListenermustimplementtheonTouch()method.WhereastheonTouchEvent()methodtakesjustaMotionEventobjectasaparameter,onTouch()takesbothaViewandaMotionEventobjectasparameters.ThisisbecausetheOnTouchListenercouldreceiveMotionEventobjectsformultipleviews.Thiswillbecomeclearerwithournextexampleapplication.

IfaMotionEventhandler(eitherthroughtheonTouchEvent()oronTouch()method)consumestheeventandnooneelseneedstoknowaboutit,themethodshouldreturntrue.ThistellsAndroidthattheeventdoesnotneedtobepassedtoanyotherviews.IftheViewobjectisnotinterestedinthiseventoranyfutureeventsrelatedtothistouchsequence,itreturnsfalse.TheonTouchEvent()methodofthebaseclassViewdoesn’tdoanythingandreturnsfalse.SubclassesofViewmayormaynotdothesame.Forexample,aButtonobjectwillconsumeatouchevent,becauseatouchisequivalenttoaclick,andthereforereturnstruefromtheonTouchEvent()method.UponreceivinganACTION_DOWNevent,theButtonwillchangeitscolortoindicatethatitisintheprocessofbeingclicked.TheButtonalsowantstoreceivetheACTION_UPeventtoknowwhentheuserhasletgo,soitcaninitiatethelogicofclickingthebutton.IfaButtonobjectreturnedfalsefromonTouchEvent(),itwouldnotreceiveanymoreMotionEventobjectstotellitwhentheuserliftedafingerfromthetouchscreen.

WhenwewanttoucheventstodosomethingnewwithaparticularViewobject,wecanextendtheclass,overridetheonTouchEvent()method,andputourlogicthere.We

Page 559: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

canalsoimplementtheView.OnTouchListenerinterfaceandsetupacallbackhandlerontheViewobject.BysettingupacallbackhandlerwithonTouch(),MotionEventswillbedeliveredtherefirstbeforetheygototheView’sonTouchEvent()method.OnlyiftheonTouch()methodreturnedfalsewouldourView’sonTouchEvent()methodgetcalled.Let’sgettoourexampleapplicationwherethisshouldbeeasiertosee.

NoteWewillgiveyouaURLattheendofthechapterwhichyoucanusetodownloadprojectsofthischapter.ThiswillallowyoutoimporttheseprojectsintoyourIDEdirectly.

SettingUpanExampleApplicationListing22-1showstheXMLofalayoutfile.CreateanewAndroidprojectstartingwiththislayout.

Listing22-1.XMLLayoutFileforTouchDemo1

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/main.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">

<RelativeLayoutandroid:id="@+id/layout1"android:tag="trueLayoutTop"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1">

<com.androidbook.touch.demo1.TrueButtonandroid:text="ReturnsTrue"android:id="@+id/trueBtn1"android:tag="trueBtnTop"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<com.androidbook.touch.demo1.FalseButtonandroid:text="ReturnsFalse"android:id="@+id/falseBtn1"android:tag="falseBtnTop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/trueBtn1"/>

</RelativeLayout><RelativeLayoutandroid:id="@+id/layout2"

Page 560: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:tag="falseLayoutBottom"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:background="#FF00FF">

<com.androidbook.touch.demo1.TrueButtonandroid:text="ReturnsTrue"android:id="@+id/trueBtn2"android:tag="trueBtnBottom"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

<com.androidbook.touch.demo1.FalseButtonandroid:text="ReturnsFalse"android:id="@+id/falseBtn2"android:tag="falseBtnBottom"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/trueBtn2"/>

</RelativeLayout></LinearLayout>

Thereareacoupleofthingstopointoutaboutthislayout.We’veincorporatedtagsonourUIobjects,andwe’llbeabletorefertothesetagsinourcodeaseventsoccuronthem.We’veusedcustomobjects(TrueButtonandFalseButton).You’llseeintheJavacodethattheseareclassesextendedfromtheButtonclass.BecausetheseareButtons,wecanuseallofthesameXMLattributeswewoulduseonotherbuttons.Figure22-1showswhatthislayoutlookslike,andListing22-2showsourbuttonJavacode.

Page 561: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure22-1.TheUIofourTouchDemo1application

Listing22-2.JavaCodefortheButtonClassesforTouchDemo1

//ThisfileisBooleanButton.javapublicabstractclassBooleanButtonextendsButton{protectedbooleanmyValue(){returnfalse;}

publicBooleanButton(Contextcontext,AttributeSetattrs){super(context,attrs);}

@OverridepublicbooleanonTouchEvent(MotionEventevent){StringmyTag=this.getTag().toString();Log.v(myTag,"-----------------------------------");Log.v(myTag,MainActivity.describeEvent(this,event));Log.v(myTag,"superonTouchEvent()returns"+

Page 562: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

super.onTouchEvent(event));Log.v(myTag,"andI'mreturning"+myValue());return(myValue());}}

//ThisfileisTrueButton.javapublicclassTrueButtonextendsBooleanButton{protectedbooleanmyValue(){returntrue;}

publicTrueButton(Contextcontext,AttributeSetattrs){super(context,attrs);}}

//ThisfileisFalseButton.javapublicclassFalseButtonextendsBooleanButton{

publicFalseButton(Contextcontext,AttributeSetattrs){super(context,attrs);}}

TheBooleanButtonclasswasbuiltsowecanreusetheonTouchEvent()method,whichwe’vecustomizedbyaddingthelogging.Then,wecreatedTrueButtonandFalseButton,whichwillresponddifferentlytotheMotionEventspassedtothem.Thiswillbemadeclearerwhenyoulookatthemainactivitycode,whichisshowninListing22-3.

Listing22-3.JavaCodeforOurMainActivity

//ThisfileisMainActivity.javaimportandroid.view.MotionEvent;importandroid.view.View.OnTouchListener;publicclassMainActivityextendsActivityimplementsOnTouchListener{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

RelativeLayoutlayout1=(RelativeLayout)findViewById(R.id.layout1);layout1.setOnTouchListener(this);ButtontrueBtn1=(Button)findViewById(R.id.trueBtn1);

Page 563: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

trueBtn1.setOnTouchListener(this);ButtonfalseBtn1=(Button)findViewById(R.id.falseBtn1);falseBtn1.setOnTouchListener(this);

RelativeLayoutlayout2=(RelativeLayout)findViewById(R.id.layout2);layout2.setOnTouchListener(this);ButtontrueBtn2=(Button)findViewById(R.id.trueBtn2);trueBtn2.setOnTouchListener(this);ButtonfalseBtn2=(Button)findViewById(R.id.falseBtn2);falseBtn2.setOnTouchListener(this);}

@OverridepublicbooleanonTouch(Viewv,MotionEventevent){StringmyTag=v.getTag().toString();Log.v(myTag,"-----------------------------");Log.v(myTag,"Gotview"+myTag+"inonTouch");Log.v(myTag,describeEvent(v,event));if("true".equals(myTag.substring(0,4))){/*Log.v(myTag,"***callingmyonTouchEvent()method***");v.onTouchEvent(event);Log.v(myTag,"***backfromonTouchEvent()method***");*/Log.v(myTag,"andI'mreturningtrue");returntrue;}else{Log.v(myTag,"andI'mreturningfalse");returnfalse;}}

protectedstaticStringdescribeEvent(Viewview,MotionEventevent){StringBuilderresult=newStringBuilder(300);result.append("Action:").append(event.getAction()).append("\n");result.append("Location:").append(event.getX()).append("x").append(event.getY()).append("\n");if(event.getX()<0||event.getX()>view.getWidth()||event.getY()<0||event.getY()>

Page 564: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

view.getHeight()){result.append(">>>Touchhaslefttheview<<<\n");}result.append("Edgeflags:").append(event.getEdgeFlags());result.append("\n");result.append("Pressure:").append(event.getPressure());result.append("").append("Size:").append(event.getSize());result.append("\n").append("Downtime:");result.append(event.getDownTime()).append("ms\n");result.append("Eventtime:").append(event.getEventTime());result.append("ms").append("Elapsed:");result.append(event.getEventTime()-event.getDownTime());result.append("ms\n");returnresult.toString();}}

Ourmainactivitycodesetsupcallbacksonourbuttonsandthelayoutssowecanprocessthetouchevents(theMotionEventobjects)foreverythinginourUI.We’veaddedlotsoflogging,soyou’llbeabletotellexactlywhat’sgoingonastoucheventsoccur.OneothergoodideaistoaddthefollowingtagtoyourmanifestfilesoGooglePlayStorewillknowyourapplicationrequiresatouchscreentowork:<uses-configurationandroid:reqTouchScreen=“finger”/>.Forexample,GoogleTVsdon’thavetouchscreens,soitwouldn’tmakesensetotrytorunthisappthere.Whenyoucompileandrunthisapplication,youshouldseeascreenthatlookslikeFigure22-1.

RunningtheExampleApplicationTogetthemostoutofthisapplication,youneedtoopenLogCatinyourIDE(EclipseorAndroidStudio)towatchthemessagesflybyasyoutouchthetouchscreen.Thisworksintheemulatoraswellasonarealdevice.WealsoadviseyoutomaximizetheLogCatwindow,soyoucanmoreeasilyscrollupanddowntoseeallofthegeneratedeventsfromthisapplication.Tomaximizethewindow,justdouble-clicktheLogCattab.Now,gototheapplicationUI,andtouchandreleaseonthetopmostbuttonmarkedReturnsTrue(ifyou’reusingtheemulator,useyourmousetoclickandreleasethebutton).YoushouldseeatleasttwoeventsloggedinLogCat.ThemessagesaretaggedascomingfromtrueBtnTopandwereloggedfromtheonTouch()methodinMainActivity.SeeMainActivity.javafortheonTouch()method’scode.AsyouviewtheLogCatoutput,seewhichmethodcallsareproducingthevalues.Forexample,thevaluedisplayedafterActioncomesfromthegetAction()method.Listing22-4showsasampleof

Page 565: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

whatyoumightseeinLogCatfromthesampleapplication.

Listing22-4.SampleLogCatMessagesfromTouchDemo1

trueBtnTop-----------------------------trueBtnTopGotviewtrueBtnTopinonTouchtrueBtnTopAction:0trueBtnTopLocation:42.8374x25.293747trueBtnTopEdgeflags:0trueBtnTopPressure:0.05490196Size:0.2trueBtnTopDowntime:24959412mstrueBtnTopEventtime:24959412msElapsed:0mstrueBtnTopandI'mreturningtruetrueBtnTop-----------------------------trueBtnTopGotviewtrueBtnTopinonTouchtrueBtnTopAction:2trueBtnTopLocation:42.8374x25.293747trueBtnTopEdgeflags:0trueBtnTopPressure:0.05490196Size:0.2trueBtnTopDowntime:24959412mstrueBtnTopEventtime:24959530msElapsed:118mstrueBtnTopandI'mreturningtruetrueBtnTop-----------------------------trueBtnTopGotviewtrueBtnTopinonTouchtrueBtnTopAction:1trueBtnTopLocation:42.8374x25.293747trueBtnTopEdgeflags:0trueBtnTopPressure:0.05490196Size:0.2trueBtnTopDowntime:24959412mstrueBtnTopEventtime:24959567msElapsed:155mstrueBtnTopandI'mreturningtrue

UnderstandingMotionEventContentsThefirsteventhasanactionof0,whichisACTION_DOWN.Thelasteventhasanactionof1,whichisACTION_UP.Ifyouusedarealdevice,youmightseemorethantwoevents.AnyeventsinbetweenACTION_DOWNandACTION_UPwillmostlikelyhaveanactionof2,whichisACTION_MOVE.Theotherpossibilitiesareanactionof3,whichisACTION_CANCEL,or4,whichisACTION_OUTSIDE.Whenusingrealfingersonarealtouchscreen,youcan’talwaystouchandreleasewithoutaslightmovementonthesurface,soexpectsomeACTION_MOVEevents.

NoticetheLocationvalues.ThelocationforaMotionEventhasanxandycomponent,wherexrepresentsthedistancefromtheleft-handsideoftheViewobjecttothepointtouchedandyrepresentsthedistancefromthetopoftheViewobjecttothepointtouched.

Intheemulator,pressureislikely1.0andsizeislikely0.0.Forarealdevice,thepressure

Page 566: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

representshowhardthefingerpresseddown,andsizerepresentshowlargethetouchis.Ifyoutouchlightlywiththetipofyourpinkyfinger,thevaluesforpressureandsizewillbesmall.Ifyoupresshardwithyourthumb,bothpressureandsizewillbelarger.Pressinglightlywithyourthumbshouldresultinasmallvalueforpressurebutalargevalueforsize.Thedocumentationsaysthatthevaluesofpressureandsizewillbebetween0and1.However,duetodifferencesinhardware,itmaybeverydifficulttouseanyabsolutenumbersinyourapplicationformakingdecisionsaboutpressureandsize.ItwouldbefinetocomparepressureandsizebetweenMotionEventsastheyoccurinyourapplication,butyoumayrunintotroubleifyoudecidethatpressuremustexceedavaluesuchas0.8tobeconsideredahardpress.Onthatparticulardevice,youmightnevergetavalueabove0.8.Youmightnotevengetavalueabove0.2.

Thedowntimeandeventtimevaluesoperateinthesamewaybetweentheemulatorandarealdevice,theonlydifferencebeingthattherealdevicehasmuchlargervalues.Theelapsedtimesworkthesame.

Theedgeflagsarefordetectingwhenatouchhasreachedtheedgeofthephysicalscreen.TheAndroidSDKdocumentationsaysthattheflagsaresettoindicatethatatouchhasintersectedwithanedgeofthedisplay(top,bottom,left,orright).However,thegetEdgeFlags()methodmayalwaysreturnzero,dependingonwhatdeviceoremulatoritisusedon.Withsomehardware,itistoodifficulttoactuallydetectatouchattheedgeofthedisplay,soAndroidissupposedtopinthelocationtotheedgeandsettheappropriateedgeflagforyou.Thisdoesn’talwayshappen,soyoushouldnotrelyontheedgeflagsbeingsetproperly.TheMotionEventclassprovidesasetEdgeFlags()methodsoyoucansettheflagsyourselfifyouwantto.

ThelastthingtonoticeisthatouronTouch()methodreturnstrue,becauseourTrueButtoniscodedtoreturntrue.ReturningtruetellsAndroidthattheMotionEventobjecthasbeenconsumedandthereisnoreasontogiveittosomeoneelse.ItalsotellsAndroidtokeepsendingtoucheventsfromthistouchsequencetothismethod.That’swhywegottheACTION_UPevent,aswellastheACTION_MOVEeventinthecaseoftherealdevice.

NowtouchtheReturnsFalsebuttonnearthetopofthescreen.Listing22-5showsasampleLogCatoutputforyourReturnsFalsetouch.

Listing22-5.SampleLogCatfromTouchingtheTopReturnsFalseButton

falseBtnTop-----------------------------falseBtnTopGotviewfalseBtnTopinonTouchfalseBtnTopAction:0falseBtnTopLocation:61.309372x44.281494falseBtnTopEdgeflags:0falseBtnTopPressure:0.0627451Size:0.26666668falseBtnTopDowntime:28612178msfalseBtnTopEventtime:28612178msElapsed:0msfalseBtnTopandI'mreturningfalsefalseBtnTop-----------------------------------falseBtnTopAction:0

Page 567: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

falseBtnTopLocation:61.309372x44.281494falseBtnTopEdgeflags:0falseBtnTopPressure:0.0627451Size:0.26666668falseBtnTopDowntime:28612178msfalseBtnTopEventtime:28612178msElapsed:0msfalseBtnTopsuperonTouchEvent()returnstruefalseBtnTopandI'mreturningfalsetrueLayoutTop-----------------------------trueLayoutTopGotviewtrueLayoutTopinonTouchtrueLayoutTopAction:0trueLayoutTopLocation:61.309372x116.281494trueLayoutTopEdgeflags:0trueLayoutTopPressure:0.0627451Size:0.26666668trueLayoutTopDowntime:28612178mstrueLayoutTopEventtime:28612178msElapsed:0mstrueLayoutTopandI'mreturningtruetrueLayoutTop-----------------------------trueLayoutTopGotviewtrueLayoutTopinonTouchtrueLayoutTopAction:2trueLayoutTopLocation:61.309372x111.90039trueLayoutTopEdgeflags:0trueLayoutTopPressure:0.0627451Size:0.26666668trueLayoutTopDowntime:28612178mstrueLayoutTopEventtime:28612217msElapsed:39mstrueLayoutTopandI'mreturningtruetrueLayoutTop-----------------------------trueLayoutTopGotviewtrueLayoutTopinonTouchtrueLayoutTopAction:1trueLayoutTopLocation:55.08958x115.30792trueLayoutTopEdgeflags:0trueLayoutTopPressure:0.0627451Size:0.26666668trueLayoutTopDowntime:28612178mstrueLayoutTopEventtime:28612361msElapsed:183mstrueLayoutTopandI'mreturningtrue

Nowyou’reseeingverydifferentbehavior,sowe’llexplainwhathappened.AndroidreceivestheACTION_DOWNeventinaMotionEventobjectandpassesittoouronTouch()methodintheMainActivityclass.OuronTouch()methodrecordstheinformationinLogCatandreturnsfalse.ThistellsAndroidthatouronTouch()methoddidnotconsumetheevent,soAndroidlookstothenextmethodtocall,whichinourcaseistheoverriddenonTouchEvent()methodofourFalseButtonclass.BecauseFalseButtonisanextensionoftheBooleanButtonclass,refertotheonTouchEvent()methodinBooleanButton.javatoseethecode.IntheonTouchEvent()method,weagainwriteinformationtoLogCat,wecalltheparentclass’sonTouchEvent()method,andthenwealsoreturnfalse.NoticethatthelocationinformationinLogCatisexactlythesameasbefore.Thisshouldbeexpected

Page 568: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

becausewe’restillinthesameViewobject,theFalseButton.WeseethatourparentclasswantstoreturntruefromonTouchEvent(),andwecanseewhy.IfyoulookatthebuttonintheUI,itshouldbeadifferentcolorfromtheReturnsTruebutton.OurReturnsFalsebuttonnowlookslikeit’spartwaythroughbeingpressed.Thatis,itlookslikeabuttonlookswhenithasbeenpressedbuthasnotbeenreleased.Ourcustommethodreturnedfalseinsteadoftrue.BecauseweagaintoldAndroidthatwedidnotconsumethisevent,byreturningfalse,AndroidneversendstheACTION_UPeventtoourbutton,soourbuttondoesn’tknowthatthefingereverliftedfromthetouchscreen.Therefore,ourbuttonisstillinthepressedstate.Ifwehadreturnedtruelikeourparentwantedto,wewouldeventuallyhavereceivedtheACTION_UPevent,sowecouldchangethecolorbacktothenormalbuttoncolor.Torecap,everytimewereturnfalsefromaUIobjectforareceivedMotionEventobject,AndroidstopssendingMotionEventobjectstothatUIobject,andAndroidkeepslookingforanotherUIobjecttoconsumeourMotionEventobject.

YoumighthaverealizedthatwhenwetouchedourReturnsTruebutton,wedidn’tgetacolorchangeinthebutton.Whyisthat?Well,ouronTouch()methodwascalledbeforeanyactualbuttonmethodsgotcalled,andonTouch()returnedtrue,soAndroidneverbotheredtocalltheReturnsTruebutton’sonTouchEvent()method.Ifyouaddav.onTouchEvent(event);linetotheonTouch()methodjustbeforereturningtrue,youwillseethebuttonchangecolor.YouwillalsoseemoreloglinesinLogCat,becauseouronTouchEvent()methodisalsowritinginformationtoLogCat.

Let’skeepgoingthroughtheLogCatoutput.NowthatAndroidhastriedtwicetofindaconsumerfortheACTION_DOWNeventandfailed,itgoestothenextViewintheapplicationthatcouldpossiblyreceivetheevent,whichinourcaseisthelayoutunderneaththebutton.WecalledourtoplayouttrueLayoutTop,andwecanseethatitreceivedtheACTION_DOWNevent.

NoticethatouronTouch()methodgotcalledagain,althoughnowwiththelayoutviewandnotthebuttonview.EverythingabouttheMotionEventobjectpassedtoonTouch()fortrueLayoutTopisthesameasbefore,includingthetimes,exceptfortheycoordinateofthelocation.Theycoordinatechangedfrom44.281494forthebuttonto116.281494forthelayout.ThismakessensebecausetheReturnsFalsebuttonisnotintheupper-leftcornerofthelayout,it’sbelowtheReturnsTruebutton.Thereforetheycoordinateofthetouchrelativetothelayoutislargerthantheycoordinateofthesametouchrelativetothebutton;thetouchisfurtherawayfromthetopedgeofthelayoutthanitisfromthetopedgeofthebutton.BecauseonTouch()forthetrueLayoutTopreturnstrue,Androidsendstherestofthetoucheventstothelayout,andweseethelogrecordscorrespondingtotheACTION_MOVEandtheACTION_UPevents.GoaheadandtouchthetopReturnsFalsebuttonagain,andnoticethatthesamesetoflogrecordsoccurs.Thatis,onTouch()iscalledforfalseBtnTop,onTouchEvent()iscalledforfalseBtnTop,andthenonTouch()iscalledfortrueLayoutTopfortherestoftheevents.Androidonlystopssendingtheeventstothebuttonforonetouchsequenceatatime.Foranewsequenceoftouchevents,Androidwillsendtothebuttonunlessitgets

Page 569: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

anotherreturnoffalsefromthecalledmethod,whichitstilldoesinoursampleapplication.

Nowtouchyourfingeronthetoplayoutbutnotoneitherbutton,andthendragyourfingeraroundabitandliftitoffthetouchscreen(ifyou’reusingtheemulator,justuseyourmousetomakeasimilarmotion).NoticeastreamoflogmessagesinLogCat,wherethefirstrecordhasanactionofACTION_DOWN,andthenmanyACTION_MOVEeventsarefollowedbyanACTION_UPevent.

Now,touchthetopReturnsTruebutton,andbeforeliftingyourfingerfromthebutton,dragyourfingeraroundthescreenandthenliftitoff.Listing22-6showssomenewinformationinLogCat.

Listing22-6.LogCatRecordsShowingaTouchOutsideofOurView

[...logmessagesofanACTION_DOWNeventfollowedbysomeACTION_MOVEevents…]

trueBtnTopGotviewtrueBtnTopinonTouchtrueBtnTopAction:2trueBtnTopLocation:150.41768x22.628128trueBtnTop>>>Touchhaslefttheview<<<trueBtnTopEdgeflags:0trueBtnTopPressure:0.047058824Size:0.13333334trueBtnTopDowntime:31690859mstrueBtnTopEventtime:31691344msElapsed:485mstrueBtnTopandI'mreturningtrue

[...moreACTION_MOVEeventslogged…]

trueBtnTopGotviewtrueBtnTopinonTouchtrueBtnTopAction:1trueBtnTopLocation:291.5864x223.43854trueBtnTop>>>Touchhaslefttheview<<<trueBtnTopEdgeflags:0trueBtnTopPressure:0.047058824Size:0.13333334trueBtnTopDowntime:31690859mstrueBtnTopEventtime:31692493msElapsed:1634mstrueBtnTopandI'mreturningtrue

Evenafteryourfingerdragsitselfoffofthebutton,wecontinuetogetnotifiedoftoucheventsrelatedtothebutton.ThefirstrecordinListing22-6showsaneventrecordwherewe’renolongeronthebutton.Inthiscase,thexcoordinateofthetoucheventistotherightoftheedgeofourbuttonobject.However,wekeepgettingcalledwithMotionEventobjectsuntilwegetanACTION_UPevent,becausewecontinuetoreturntruefromtheonTouch()method.Evenwhenyoufinallyliftyourfingeroffofthetouchscreen,andevenifyourfingerisn’tonthebutton,ouronTouch()methodstillgetscalledtogiveustheACTION_UPeventbecausewekeepreturningtrue.Thisis

Page 570: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

somethingtokeepinmindwhendealingwithMotionEvents.Whenthefingerhasmovedoffoftheview,wecoulddecidetocancelwhateveroperationmighthavebeenperformedandreturnfalsefromtheonTouch()method,sowedon’tgetnotifiedoffurtherevents.Orwecouldchoosetocontinuetoreceiveevents(byreturningtruefromtheonTouch()method)andonlyperformthelogicifthefingerreturnstoourviewbeforeliftingoff.

ThetouchsequenceofeventsgotassociatedtoourtopReturnsTruebuttonwhenwereturnedtruefromonTouch().ThistoldAndroidthatitcouldstoplookingforanobjecttoreceivetheMotionEventobjectsandjustsendallfutureMotionEventobjectsforthistouchsequencetous.Evenifweencounteranotherviewwhendraggingourfinger,we’restilltiedtotheoriginalviewforthissequence.

ExercisingtheBottomHalfoftheExampleApplicationLet’sseewhathappenswiththelowerhalfofourapplication.GoaheadandtouchtheReturnsTruebuttoninthebottomhalf.WeseethesamethingashappenedwiththetopReturnsTruebutton.BecauseonTouch()returnstrue,Androidsendsustherestoftheeventsinthetouchsequenceuntilthefingerisliftedfromthetouchscreen.Now,touchthebottomReturnsFalsebutton.Onceagain,theonTouch()methodandonTouchEvent()methodsreturnfalse(bothassociatedwiththefalseBtnBottomviewobject).Butthistime,thenextviewtoreceivetheMotionEventobjectisthefalseLayoutBottomobject,anditalsoreturnsfalse.Now,we’refinished.

BecausetheonTouchEvent()methodcalledthesuper’sonTouchEvent()method,thebuttonhaschangedcolortoindicateit’shalfwaythroughbeingpressed.Again,thebuttonwillstaythisway,becausewenevergettheACTION_UPeventinthistouchsequence,becauseourmethodsreturnfalseallthetime.Unlikebefore,eventhelayoutisnotinterestedinthisevent.IfyouweretotouchthebottomReturnsFalsebuttonandholditdownandthendragyourfingeraroundthedisplay,youwouldnotseeanyextrarecordsinLogCat,becausenomoreMotionEventobjectsaresenttous.Wereturnedfalse,soAndroidwon’tbotheruswithanymoreeventsforthistouchsequence.Again,ifwestartanewtouchsequence,wecanseenewLogCatrecordsshowingup.Ifyouinitiateatouchsequenceinthebottomlayoutandnotonabutton,youwillseeasingleeventinLogCatforfalseLayoutBottomthatreturnsfalseandthennothingafterthat(untilyoustartanewtouchsequence).

Sofar,we’veusedbuttonstoshowyoutheeffectsofMotionEventeventsfromtouchscreens.It’sworthpointingoutthat,normally,youwouldimplementlogiconbuttonsusingtheonClick()method.Weusedbuttonsforthissampleapplication,becausethey’reeasytocreateandtheyaresubclassesofViewthatcanthereforereceivetoucheventsjustlikeanyotherview.RememberthatthesetechniquesapplytoanyViewobjectinyourapplication,beitastandardorcustomizedviewclass.

RecyclingMotionEvents

Page 571: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Youmayhavenoticedtherecycle()methodoftheMotionEventclassintheAndroidreferencedocumentation.ItistemptingtowanttorecycletheMotionEventsthatyoureceiveinonTouch()oronTouchEvent(),butdon’tdoit.IfyourcallbackmethodisnotconsumingtheMotionEventobjectandyou’rereturningfalse,theMotionEventobjectislikelytobehandedtosomeothermethodorvieworouractivity,soyoudon’twantAndroidrecyclingityet.Evenifyouconsumedtheeventandreturnedtrue,theeventobjectdoesn’tbelongtoyou,soyoushouldnotrecycleit.

IfyoulookatMotionEventdocumentation,youwillseeafewvariationsofamethodcalledobtain().ThisiseithercreatingacopyofaMotionEventorabrandnewMotionEvent.Yourcopy,oryourbrand-neweventobject,istheeventobjectthatyoushouldrecyclewhenyouaredonewithit.Forexample,ifyouwanttohangontoaneventobjectthatispassedtoyouviaacallback,youshoulduseobtain()tomakeacopy,becauseonceyoureturnfromthecallback,thateventobjectwillberecycledbyAndroid,andyoumaygetstrangeresultsifyoucontinuetouseit.Whenyouarefinishedusingyourcopy,youinvokerecycle()onit.

UsingVelocityTrackerAndroidprovidesaclasstohelphandletouchscreensequences,andthatclassisVelocityTracker.Whenafingerisinmotiononatouchscreen,itmightbenicetoknowhowfastitismovingacrossthesurface.Forexample,iftheuserisdragginganobjectacrossthescreenandletsgo,yourapplicationprobablywantstoshowthatobjectflyingacrossthescreenaccordingly.AndroidprovidesVelocityTrackertohelpwiththemathinvolved.

TouseVelocityTracker,youfirstgetaninstanceofaVelocityTrackerbycallingthestaticmethodVelocityTracker.obtain().YoucanthenaddMotionEventobjectstoitwiththeaddMovement(MotionEventev)method.YouwouldcallthismethodinyourhandlerthatreceivesMotionEventobjects,fromahandlermethodsuchasonTouch(),orfromaview’sonTouchEvent().TheVelocityTrackerusestheMotionEventobjectstofigureoutwhatisgoingonwiththeuser’stouchsequence.OnceVelocityTrackerhasatleasttwoMotionEventobjectsinit,wecanusetheothermethodstofindoutwhat’shappening.

ThetwoVelocityTrackermethods—getXVelocity()andgetYVelocity()—returnthecorrespondingvelocityofthefingerinthexandydirections,respectively.Thevaluereturnedfromthesetwomethodswillrepresentpixelspertimeperiod.Thiscouldbepixelspermillisecondorpersecondorreallyanythingyouwant.TotelltheVelocityTrackerwhattimeperiodtouse,andbeforeyoucancallthesetwogettermethods,youneedtoinvoketheVelocityTracker’scomputeCurrentVelocity(intunits)method.Thevalueofunitsrepresentshowmanymillisecondsareinthetimeperiodformeasuringthevelocity.Ifyouwantpixelspermillisecond,useaunitsvalueof1;ifyouwantpixelspersecond,useaunitsvalueof1000.ThevaluereturnedbythegetXVelocity()and

Page 572: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

getYVelocity()methodswillbepositiveifthevelocityistowardtheright(forx)ordown(fory).Thevaluereturnedwillbenegativeifthevelocityistowardtheleft(forx)orup(fory).

WhenyouarefinishedwiththeVelocityTrackerobjectyougotwiththeobtain()method,calltheVelocityTrackerobject’srecycle()method.Listing22-7showsasampleonTouchEvent()handlerforanactivity.ItturnsoutthatanactivityhasanonTouchEvent()callback,whichiscalledwhenevernoviewshavehandledthetouchevent.Becausewe’reusingastock,emptylayout,wehavenoviewsconsumingourtouchevents.

Listing22-7.SampleActivityThatUsesVelocityTracker

importandroid.view.MotionEvent;importandroid.view.VelocityTracker;

publicclassMainActivityextendsActivity{privatestaticfinalStringTAG="VelocityTracker";

/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}

privateVelocityTrackervTracker=null;

publicbooleanonTouchEvent(MotionEventevent){intaction=event.getAction();switch(action){caseMotionEvent.ACTION_DOWN:if(vTracker==null){vTracker=VelocityTracker.obtain();}else{vTracker.clear();}vTracker.addMovement(event);break;caseMotionEvent.ACTION_MOVE:vTracker.addMovement(event);vTracker.computeCurrentVelocity(1000);Log.v(TAG,"Xvelocityis"+vTracker.getXVelocity()+"pixelspersecond");Log.v(TAG,"Yvelocityis"+vTracker.getYVelocity()+

Page 573: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

"pixelspersecond");break;caseMotionEvent.ACTION_UP:caseMotionEvent.ACTION_CANCEL:Log.v(TAG,"FinalXvelocityis"+vTracker.getXVelocity()+"pixelspersecond");Log.v(TAG,"FinalYvelocityis"+vTracker.getYVelocity()+"pixelspersecond");vTracker.recycle();vTracker=null;break;}returntrue;}}

Obviously,whenyou’veonlyaddedoneMotionEventtoaVelocityTracker(theACTION_DOWNevent),thevelocitiescannotbecomputedasanythingotherthanzero.ButweneedtoaddthestartingpointsothatthesubsequentACTION_MOVEeventscancalculatevelocitiesthen.

VelocityTrackerissomewhatcostlyintermsofperformance,souseitsparingly.Also,makesurethatyourecycleitassoonasyouaredonewithit.TherecanbemorethanoneVelocityTrackerinuseinAndroid,buttheycantakeupalotofmemory,sogiveyoursbackifyou’renotgoingtocontinuetouseit.InListing22-7,wealsousetheclear()methodifwe’restartinganewtouchsequence(thatis,ifwegetanACTION_DOWNeventandourVelocityTrackerobjectalreadyexists)insteadofrecyclingthisoneandobtaininganewone.

MultitouchNowthatyou’veseensingletouchesinaction,let’smoveontomultitouch.MultitouchhasgainedalotofinteresteversincetheTEDconferencein2006atwhichJeffHandemonstratedamultitouchsurfaceforacomputeruserinterface.Usingmultiplefingersonascreenopensupalotofpossibilitiesformanipulatingwhat’sonthescreen.Forexample,puttingtwofingersonanimageandmovingthemapartcouldzoominontheimage.Byplacingmultiplefingersonanimageandturningclockwise,youcouldrotatetheimageonthescreen.ThesearestandardtouchoperationsinGoogleMaps,forinstance.

Ifyouthinkaboutit,though,thereisnomagictothis.Ifthescreenhardwarecandetectmultipletouchesastheyinitiateonthescreen,notifyyourapplicationasthosetouchesmoveintimeacrossthesurfaceofthescreen,andnotifyyouwhenthosetouchesliftoffofthescreen,yourapplicationcanfigureoutwhattheuseristryingtodowiththosetouches.Althoughit’snotmagic,itisn’teasyeither.We’regoingtohelpyouunderstand

Page 574: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

multitouchinthissection.

TheBasicsofMultitouchThebasicsofmultitouchareexactlythesameasforsingletouches.MotionEventobjectsgetcreatedfortouches,andtheseMotionEventobjectsarepassedtoyourmethodsjustlikebefore.Yourcodecanreadthedataaboutthetouchesanddecidewhattodo.Atabasiclevel,themethodsofMotionEventarethesame;thatis,wecallgetAction(),getDownTime(),getX(),andsoon.However,whenmorethanonefingeristouchingthescreen,theMotionEventobjectmustincludeinformationfromallfingers,withsomecaveats.TheactionvaluefromgetAction()isforonefinger,notall.Thedowntimevalueisfortheveryfirstfingerdownandmeasuresthetimeaslongasatleastonefingerisdown.ThelocationvaluesgetX()andgetY(),aswellasgetPressure()andgetSize(),cantakeanargumentforthefinger;therefore,youneedtouseapointerindexvaluetorequesttheinformationforthefingeryou’reinterestedin.Therearemethodcallsthatweusedpreviouslythatdidnottakeanyargumenttospecifyafinger(forexample,getX(),getY()),sowhichfingerwouldthevaluesbeforifweusedthosemethods?Youcanfigureitout,butittakessomework.Therefore,ifyoudon’ttakeintoaccountmultiplefingersallofthetime,youmightendupwithsomestrangeresults.Let’sdigintothistofigureoutwhattodo.

ThefirstmethodofMotionEventyouneedtoknowaboutformultitouchisgetPointerCount().ThistellsyouhowmanyfingersarerepresentedintheMotionEventobjectbutdoesn’tnecessarilytellyouhowmanyfingersareactuallytouchingthescreen;thatdependsonthehardwareandontheimplementationofAndroidonthathardware.Youmayfindthat,oncertaindevices,getPointerCount()doesnotreportallfingersthataretouching,justsome.Butlet’spresson.Assoonasyou’vegotmorethanonefingerbeingreportedinMotionEventobjects,youneedtostartdealingwiththepointerindexesandthepointerIDs.

TheMotionEventobjectcontainsinformationforpointersstartingatindex0andgoinguptothenumberoffingersbeingreportedinthatobject.Thepointerindexalwaysstartsat0;ifthreefingersarebeingreported,pointerindexeswillbe0,1,and2.CallstomethodssuchasgetX()mustincludethepointerindexforthefingeryouwantinformationabout.PointerIDsareintegervaluesrepresentingwhichfingerisbeingtracked.PointerIDsstartat0forthefirstfingerdownbutdon’talwaysstartat0oncefingersarecomingandgoingonthescreen.ThinkofapointerIDasthenameofthatfingerwhileitisbeingtrackedbyAndroid.Forexample,imagineapairoftouchsequencesfortwofingers,startingwithfinger1down,andfollowedbyfinger2down,finger1up,andfinger2up.ThefirstfingerdownwillgetpointerID0.ThesecondfingerdownwillgetpointerID1.Oncethefirstfingergoesup,thesecondfingerwillstillbepointerID1.Atthatpoint,thepointerindexforthesecondfingerbecomes0,becausethepointerindexalwaysstartsat0.Inthisexample,thesecondfinger(pointerID1)startsaspointerindex1whenitfirsttouchesdownandthenshiftstopointerindex0oncethefirstfingerleavesthescreen.Evenwhenthesecondfingeristheonlyfingeronthescreen,itremainsaspointerID1.YourapplicationswillusepointerIDstolinktogethertheevents

Page 575: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

associatedtoaparticularfingerevenasotherfingersareinvolved.Let’slookatanexample.

Listing22-8showsournewXMLlayoutplusourJavacodeforamultitouchapplication.ThisistheapplicationcalledMultiTouchDemo1.Figure22-2showswhatitshouldlooklike.

Listing22-8.XMLLayoutandJavaforaMultitouchDemonstration

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileis/res/layout/main.xml--><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/androidandroid:id="@+id/layout1"android:tag="trueLayout"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1">

<TextViewandroid:text="TouchfingersonthescreenandlookatLogCat"android:id="@+id/message"android:tag="trueText"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"/>

</RelativeLayout>

//ThisfileisMainActivity.javaimportandroid.view.MotionEvent;importandroid.view.View.OnTouchListener;

publicclassMainActivityextendsActivityimplementsOnTouchListener{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

RelativeLayoutlayout1=(RelativeLayout)findViewById(R.id.layout1);layout1.setOnTouchListener(this);}

publicbooleanonTouch(Viewv,MotionEventevent){StringmyTag=v.getTag().toString();Log.v(myTag,"-----------------------------");

Page 576: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.v(myTag,"Gotview"+myTag+"inonTouch");Log.v(myTag,describeEvent(event));logAction(event);if("true".equals(myTag.substring(0,4))){returntrue;}else{returnfalse;}}

protectedstaticStringdescribeEvent(MotionEventevent){StringBuilderresult=newStringBuilder(500);result.append("Action:").append(event.getAction()).append("\n");intnumPointers=event.getPointerCount();result.append("Numberofpointers:");result.append(numPointers).append("\n");intptrIdx=0;while(ptrIdx<numPointers){intptrId=event.getPointerId(ptrIdx);result.append("PointerIndex:").append(ptrIdx);result.append(",PointerId:").append(ptrId).append("\n");result.append("Location:").append(event.getX(ptrIdx));result.append("x").append(event.getY(ptrIdx)).append("\n");result.append("Pressure:");result.append(event.getPressure(ptrIdx));result.append("Size:").append(event.getSize(ptrIdx));result.append("\n");

ptrIdx++;}result.append("Downtime:").append(event.getDownTime());result.append("ms\n").append("Eventtime:");result.append(event.getEventTime()).append("ms");result.append("Elapsed:");result.append(event.getEventTime()-event.getDownTime());result.append("ms\n");returnresult.toString();

Page 577: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

privatevoidlogAction(MotionEventevent){intaction=event.getActionMasked();intptrIndex=event.getActionIndex();intptrId=event.getPointerId(ptrIndex);

if(action==5||action==6)action=action-5;

Log.v("Action","Pointerindex:"+ptrIndex);Log.v("Action","PointerId:"+ptrId);Log.v("Action","Trueactionvalue:"+action);}}

Figure22-2.Ourmultitouchdemonstrationapplication

Ifyouonlyhavetheemulator,thisapplicationwillstillwork,butyouwon’tbeabletogetmultiplefingerssimultaneouslyonthescreen.You’llseeoutputsimilartowhatwesawin

Page 578: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thepreviousapplication.Listing22-9showssampleLogCatmessagesforatouchsequencelikewedescribedearlier.Thatis,thefirstfingerpressesonthescreen,andthenthesecondfingerpresses,thefirstfingerleavesthescreen,andthesecondfingerleavesthescreen.Listing22-9.SampleLogCatOutputforaMultitouchApplication

trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:0trueLayoutNumberofpointers:1trueLayoutPointerIndex:0,PointerId:0trueLayoutLocation:114.88211x499.77502trueLayoutPressure:0.047058824Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33733650msElapsed:0msActionPointerindex:0ActionPointerId:0ActionTrueActionvalue:0trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:2trueLayoutNumberofpointers:1trueLayoutPointerIndex:0,PointerId:0trueLayoutLocation:114.88211x499.77502trueLayoutPressure:0.05882353Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33733740msElapsed:90msActionPointerindex:0ActionPointerId:0ActionTrueActionvalue:2trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:261trueLayoutNumberofpointers:2trueLayoutPointerIndex:0,PointerId:0trueLayoutLocation:114.88211x499.77502trueLayoutPressure:0.05882353Size:0.13333334trueLayoutPointerIndex:1,PointerId:1trueLayoutLocation:320.30692x189.67395trueLayoutPressure:0.050980393Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33733962msElapsed:312msActionPointerindex:1ActionPointerId:1ActionTrueActionvalue:0trueLayout-----------------------------

Page 579: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:2trueLayoutNumberofpointers:2trueLayoutPointerIndex:0,PointerId:0trueLayoutLocation:111.474594x499.77502trueLayoutPressure:0.05882353Size:0.13333334trueLayoutPointerIndex:1,PointerId:1trueLayoutLocation:320.30692x189.67395trueLayoutPressure:0.050980393Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33734189msElapsed:539msActionPointerindex:0ActionPointerId:0ActionTrueActionvalue:2trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:6trueLayoutNumberofpointers:2trueLayoutPointerIndex:0,PointerId:0trueLayoutLocation:111.474594x499.77502trueLayoutPressure:0.05882353Size:0.13333334trueLayoutPointerIndex:1,PointerId:1trueLayoutLocation:320.30692x189.67395trueLayoutPressure:0.050980393Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33734228msElapsed:578msActionPointerindex:0ActionPointerId:0ActionTrueActionvalue:1trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:2trueLayoutNumberofpointers:1trueLayoutPointerIndex:0,PointerId:1trueLayoutLocation:318.84656x191.45105trueLayoutPressure:0.050980393Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33734240msElapsed:590msActionPointerindex:0ActionPointerId:1ActionTrueActionvalue:2trueLayout-----------------------------trueLayoutGotviewtrueLayoutinonTouchtrueLayoutAction:1trueLayoutNumberofpointers:1trueLayoutPointerIndex:0,PointerId:1

Page 580: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

trueLayoutLocation:314.95224x190.5625trueLayoutPressure:0.050980393Size:0.13333334trueLayoutDowntime:33733650mstrueLayoutEventtime:33734549msElapsed:899msActionPointerindex:0ActionPointerId:1ActionTrueActionvalue:1

UnderstandingMultitouchContentsWe’llnowdiscusswhatisgoingonwiththisapplication.ThefirsteventweseeistheACTION_DOWN(actionvalueof0)ofthefirstfinger.WelearnaboutthisusingthegetAction()method.PleaserefertothedescribeEvent()methodinMainActivity.javatofollowalongwithwhichmethodsproducewhichoutput.Wegetonepointerwithindex0andpointerID0.Afterthat,you’llprobablyseeseveralACTION_MOVEevents(actionvalueof2)forthisfirstfinger,eventhoughwe’reonlyshowingoneoftheseinListing22-9.WestillonlyhaveonepointerandtheindexandIDarestillboth0.

Alittlelaterwegetthesecondfingertouchingthescreen.Theactionisnowadecimalvalueof261.Whatdoesthismean?Theactionvalueisactuallymadeupoftwoparts:anindicatorofwhichpointertheactionisforandwhatactionthatpointerisdoing.Convertingdecimal261tohexadecimal,weget0x00000105.Theactionisthesmallestbyte(5inthiscase),andthepointerindexisthenextbyteover(1inthiscase).NotethatthistellsusthepointerindexbutnotthepointerID.Ifyoupressedathirdfingerontothescreen,theactionwouldbe0x00000205(ordecimal517).Afourthfingerwouldbe0x00000305(ordecimal773)andsoon.Youhaven’tseenanactionvalueof5yet,butit’sknownasACTION_POINTER_DOWN.It’sjustlikeACTION_DOWNexceptthatit’susedinmultitouchsituations.

Now,lookatthenextpairofrecordsfromLogCatinListing22-9.ThefirstrecordisforanACTION_MOVEevent(actionvalueof2).Rememberthatitisdifficulttokeepfingersfrommovingonarealscreen.We’reonlyshowingoneACTION_MOVEevent,butyoumightseeseveralwhenyoutrythisforyourself.Whenthefirstfingerisliftedoffofthescreen,wegetanactionvalueof0x00000006(ordecimal6).Likebefore,wehavepointerindex0andanactionvaluethatisACTION_POINTER_UP(similartoACTION_UPbutformultitouchsituations).Ifthesecondfingerwasliftedinamultitouchsituation,wewouldgetanactionvalueof0x00000106(ordecimal262).NoticehowwestillhaveinformationfortwofingerswhenwegettheACTION_UPforoneofthem.

ThelastpairofrecordsinListing22-9showsonemoreACTION_MOVEeventforthesecondfinger,followedbyanACTION_UPforthesecondfinger.Thistime,weseeanactionvalueof1(ACTION_UP).Wedidn’tgetanactionvalueof262,butwe’llexplainthatnext.Also,noticethatoncethefirstfingerleftthescreen,thepointerindexforthesecondfingerhaschangedfrom1to0,butthepointerIDhasremainedas1.

ACTION_MOVEeventsdonottellyouwhichfingermoved.Youwillalwaysgetanaction

Page 581: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

valueof2foramoveregardlessofhowmanyfingersaredownorwhichfingerisdoingthemoving.AlldownfingerpositionsareavailablewithintheMotionEventobject,soyouneedtoreadthepositionsandthenfigurethingsout.Ifthere’sonlyonefingerleftonthescreen,thepointerIDwilltellyouwhichfingeritisthat’sstillmovingbecauseit’stheonlyfingerleft.InListing22-9,whenthesecondfingerwastheonlyoneleftonthescreen,theACTION_MOVEeventhadapointerindexof0andapointerIDof1,soweknewitwasthesecondfingerthatwasmoving.

NotonlycanaMotionEventobjectcontainmoveeventsformorethanonefinger,butitcanalsocontainmultiplemoveeventsperfinger.Itdoesthisusinghistoricalvaluescontainedwithintheobject.AndroidshouldreportallhistorysincethelastMotionEventobject.SeegetHistoricalSize()andtheothergetHistorical…()methods.

GoingbacktothebeginningofListing22-9,thefirstfingerdownispointerindex0andpointerID0,sowhydon’tweget0x00000005(ordecimal5)fortheactionvaluewhenthefirstfingerispressedtothescreenbeforeanyotherfingers?Unfortunately,thisquestiondoesn’thaveahappyanswer.Wecangetanactionvalueof5inthefollowingscenario:pressthefirstfingertothescreenandthenthesecondfinger,resultinginactionvaluesof0and261(ignoringtheACTION_MOVEeventsforthemoment).Now,liftthefirstfinger(actionvalueof6),andpressitbackdownonthescreen.ThepointerIDofthesecondfingerremainedas1.Forthemomentwhenthefirstfingerwasintheair,ourapplicationknewaboutpointerID1only.Oncethefirstfingertouchedthescreenagain,AndroidreassignedpointerID0tothefirstfingerandgaveitpointerindex0aswell.Becausenowweknowtherearemultiplefingersinvolved,wegetanactionvalueof5(pointerindexof0andtheactionvalueof5).Theanswertothequestion,therefore,isbackwardcompatibility,butitisnotahappyanswer.Theactionvaluesof0and1arepre-multitouch.

Whenonlyonefingerremainsonthescreen,Androidtreatsitlikeasingle-touchcase.SowegettheoldACTION_UPvalueof1insteadofamultitouchACTION_UPvalueof6.Ourcodewillneedtoconsiderthesecasescarefully.Apointerindexof0couldresultinanACTION_DOWNvalueof0or5,dependingonwhichpointersareinplay.ThelastfingerupwillgetanACTION_UPvalueof1nomatterwhichpointerIDithas.

Thereisanotheractionwehaven’tmentionedsofar:ACTION_SCROLL(valueof8),introducedinAndroid3.1.Thiscomesfromaninputdevicelikeamouse,notatouchscreen.Infact,asyoucanseefromthemethodsinMotionEvent,theseobjectscanbeusedforlotsofthingsotherthantouchscreentouches.Wewon’tbecoveringtheseotherinputdevicesinthisbook.

GesturesGesturesareaspecialtypeofatouchscreenevent.ThetermgestureisusedforavarietyofthingsinAndroid,fromasimpletouchsequencelikeaflingorapinchtotheformalGestureclass.Flings,pinches,longpresses,andscrollshaveexpectedbehaviorswith

Page 582: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

expectedtriggers.Thatis,itisprettycleartomostpeoplethataflingisagesturewhereafingertouchesthescreen,dragssomewhatquicklyoffinasingledirection,andthenliftsup.Forexample,whensomeoneusesaflingintheGalleryapplication(theonethatshowsimagesinaleft-to-rightchain),theimageswillmovesidewaystoshownewimagestotheuser.

Inthefollowingsections,youwilllearnhowtoimplementapinchgesture,fromwhichyoucaneasilyimplementtheothercommongestures.TheformalGestureclassreferstogesturesdrawnbyauseronatouchscreen,sothatanapplicationcanreacttothosegestures.Thetypicalexampleincludesdrawinglettersofthealphabetwhichtheapplicationcanunderstandasletters.TheformalGestureclassisnotcoveredinthisbook.Let'slearntopinch!

ThePinchGestureOneofthecoolapplicationsofmultitouchisthepinchgesture,whichisusedforzooming.Theideaisthatifyouplacetwofingersonthescreenandspreadthemapart,theapplicationshouldrespondbyzoomingin.Ifyourfingerscometogether,theapplicationshouldzoomout.Theapplicationisusuallyshowingimages,whichcouldbemaps.

Beforewegettothepinchgesture’snativesupport,wefirstneedtocoveraclassthat’sbeenaroundfromthebeginning—GestureDetector.

GestureDetectorandOnGestureListenersThefirstclasstohelpuswithgesturesisGestureDetector,whichhasbeenaroundfromtheverybeginningofAndroid.ItspurposeinlifeistoreceiveMotionEventobjectsandtelluswhenasequenceofeventslookslikeacommongesture.WepassallofoureventobjectstotheGestureDetectorfromourcallback,anditcallsothercallbackswhenitrecognizesagesture,suchasaflingorlongpress.WeneedtoregisteralistenerforthecallbacksfromtheGestureDetector,andthisiswhereweputourlogicthatsayswhattodoiftheuserhasperformedoneofthesecommongestures.Unfortunately,thisclassdoesnottellusifapinchgestureistakingplace;forthat,weneedtouseanewclass,whichwe’llgettoshortly.

Thereareafewwaystobuildthelistenerside.Yourfirstoptionistowriteanewclassthatimplementstheappropriategesturelistenerinterface:forexample,theGestureDetector.OnGestureListenerinterface.Thereareseveralabstractmethodsthatmustbeimplementedforeachofthepossiblecallbacks.

Yoursecondoptionistopickoneofthesimpleimplementationsofalistenerandoverridetheappropriatecallbackmethodsthatyoucareabout.Forexample,theGestureDetector.SimpleOnGestureListenerclasshasimplementedalloftheabstractmethodstodonothingandreturnfalse.Allyouhavetodoisextendthatclassandoverridethefewmethodsyouneedtoactonthosefewgesturesyoucareabout.Theothermethodshavetheirdefaultimplementations.It’smorefuture-prooftochoosethesecondoptionevenifyoudecidetooverrideallofthecallbackmethods,becauseifa

Page 583: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

futureversionofAndroidaddsanotherabstractcallbackmethodtotheinterface,thesimpleimplementationwillprovideadefaultcallbackmethod,soyou’recovered.

We’regoingtoexploreScaleGestureDetector,plusthecorrespondinglistenerclass,toseehowtousethepinchgesturetoresizeanimage.Inthisexample,weextendthesimpleimplementation(ScaleGestureDetector.SimpleOnScaleGestureListener)forourlistener.Listing22-10hastheXMLlayoutandtheJavacodeforourMainActivity.

Listing22-10.LayoutandJavaCodeforthePinchGestureUsingScaleGestureDetector

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/layout"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent">

<TextViewandroid:text="Usethepinchgesturetochangetheimagesize"android:layout_width="match_parent"android:layout_height="wrap_content"/>

<ImageViewandroid:id="@+id/image"android:src="@drawable/icon"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="matrix"/>

</LinearLayout>

//ThisfileisMainActivity.javapublicclassMainActivityextendsActivity{privatestaticfinalStringTAG="ScaleDetector";privateImageViewimage;privateScaleGestureDetectormScaleDetector;privatefloatmScaleFactor=1f;privateMatrixmMatrix=newMatrix();@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

image=(ImageView)findViewById(R.id.image);mScaleDetector=newScaleGestureDetector(this,newScaleListener());}

Page 584: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

@OverridepublicbooleanonTouchEvent(MotionEventev){Log.v(TAG,"inonTouchEvent");//GivealleventstoScaleGestureDetectormScaleDetector.onTouchEvent(ev);

returntrue;}

privateclassScaleListenerextendsScaleGestureDetector.SimpleOnScaleGestureListener{@OverridepublicbooleanonScale(ScaleGestureDetectordetector){mScaleFactor*=detector.getScaleFactor();

//Makesurewedon'tgettoosmallortoobigmScaleFactor=Math.max(0.1f,Math.min(mScaleFactor,5.0f));

Log.v(TAG,"inonScale,scalefactor="+mScaleFactor);mMatrix.setScale(mScaleFactor,mScaleFactor);

image.setImageMatrix(mMatrix);image.invalidate();returntrue;}}}

Ourlayoutisstraightforward.WehaveasimpleTextViewwithourmessagetousethepinchgesture,andwehaveourImageViewwiththestandardAndroidicon.We’regoingtoresizethisiconimageusingapinchgesture.Ofcourse,feelfreetosubstituteyourownimagefileinsteadoftheicon.Justcopyyourimagefileintoadrawablefolder,andbesuretochangetheandroid:srcattributeinthelayoutfile.Noticetheandroid:scaleTypeattributeintheXMLlayoutforourimage.ThistellsAndroidthatwe’llbeusingagraphicsmatrixtodoscalingoperationsontheimage.Althoughagraphicsmatrixcanalsodomovementofourimagewithinthelayout,we’reonlygoingtofocusonscalingfornow.AlsonoticethatwesettheImageViewsizetoasbigaspossible.Aswescaletheimage,wedon’twantitclippedbytheboundariesoftheImageView.

Thecodeisalsostraightforward.WithinonCreate(),wegetareferencetoourimageandcreateourScaleGestureDetector.WithinouronTouchEvent()callback,

Page 585: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

allwedoispasseveryeventobjectwegettotheScaleGestureDetector’sonTouchEvent()methodandreturntruesowekeepgettingnewevents.ThisallowstheScaleGestureDetectortoseealleventsanddecidewhentonotifyusofgestures.

TheScaleListeneriswherethezoominghappens.Thereareactuallythreecallbackswithinthelistenerclass:onScaleBegin(),onScale(),andonScaleEnd().Wedon’tneedtodoanythingspecialwiththebeginandendmethods,sowedidn’timplementthemhere.

WithinonScale(),thedetectorpassedincanbeusedtofindoutlotsofinformationaboutthescalingoperation.Thescalefactorisavaluethathoversaround1.Thatis,asthefingerspinchclosertogether,thisvalueisslightlybelow1;asthefingersmoveapart,thisvalueisslightlylargerthan1.OurmScaleFactormemberstartsat1,soitgetsprogressivelysmallerorlargerthan1asthefingersmovetogetherorapart.IfmScaleFactorequals1,ourimagewillbenormalsize.Otherwise,ourimagewillbesmallerorlargerthannormalasmScaleFactormovesbeloworabove1.WesetsomeboundsonmScaleFactorwiththeelegantmin/maxfunctioncombination.Thispreventsourimagefromgettingtoosmallortoolarge.WethenusemScaleFactortoscalethegraphicsmatrix,andweapplythenewlyscaledmatrixtoourimage.Theinvalidate()callforcesaredrawoftheimageonthescreen.

ToworkwiththeOnGestureListenerinterface,you’ddosomethingverysimilartowhatwe’vedoneherewithourScaleListener,exceptthatthecallbackswillbefordifferentcommongesturessuchassingletap,doubletap,longpress,andfling.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther.

www.androidbook.com/proandroid5/projects:Downloadableprojectsrelatedtothisbook.Forthischapter,lookforazipfilecalledProAndroid5_Ch22_Touchscreens.zip.Thiszipfilecontainsallprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoyourIDEfromoneofthesezipfiles.

www.ted.com/talks/jeff_han_demos_his_breakthrough_touchscreen.htmlJeffHandemonstrateshismultitouchcomputeruserinterfaceatTEDin2006—verycool.

http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html:AnAndroidblogpostaboutmultitouchoffersyetanotherwaytoimplementaGestureDetectorinside

Page 586: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

anextensionofaview.

SummaryLet’sconcludethischapterbyquicklyenumeratingwhatyouhavelearnedabouttouchscreenssofar:

MotionEventasthefoundationonwhichtouchhandlingisdone

DifferentcallbacksthathandletoucheventsonaViewobjectandthroughanOnTouchListener

Differenttypesofeventsthatoccurduringatouchsequence

Howtoucheventstravelthroughanentireviewhierarchy,unlesshandledalongtheway

InformationthataMotionEventobjectcontainsabouttouches,includingformultiplefingers

WhentorecycleaMotionEventobjectandwhennotto

Determiningthespeedatwhichafingerdragsacrossascreen

Thewonderfulworldofmultitouch,andtheinternaldetailsofhowitworks

Implementingthepinchgesture,aswellasothercommongestures

Page 587: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter23

ImplementingDragandDropInthelastchapter,wecoveredtouchscreens,theMotionEventclass,andgestures.Youlearnedhowtousetouchtomakethingshappeninyourapplication.Oneareathatwedidn’tcoverwasdraganddrop.Onthesurface,draganddropseemslikeitshouldbefairlysimple:touchanobjectonthescreen,dragitacrossthescreen(usuallyoversomeotherobject),andletgo,andtheapplicationshouldtaketheappropriateaction.Inmanycomputeroperatingsystems,thisisacommonwaytodeleteafilefromthedesktop;youjustdragthefile’sicontothetrash-binicon,andthefilegetsdeleted.InAndroid,youmayhaveseenhowtorearrangeiconsonthehomescreenbydraggingthemtonewlocationsortothetrash.

Thischapterisgoingtogoindepthintodraganddrop.PriortoAndroid3.0,developerswereontheirownwhenitcametodraganddrop.ButbecausetherearestillquiteafewphonesoutthererunningAndroid2.3,we’llshowyouhowtododraganddroponthem.We’llshowyoutheoldwayinthefirstsectionofthischapter,andthenwe'llshowyouthenewwayinthesecondpart.

ExploringDragandDropInthisnextexampleapplication,we’regoingtotakeawhitedotanddragittoanewlocationinouruserinterface.We’realsogoingtoplacethreecountersinouruserinterface,andiftheuserdragsthewhitedottooneofthecounters,thatcounterwillincrementandthedotwillreturnbacktoitsstartingplace.Ifthedotisdraggedsomewhereelseonthescreen,we’lljustleaveitthere.

NoteSeethe“References”sectionattheendofthischapterfortheURLfromwhichyoucanimporttheseprojectsintoyourIDEdirectly.We’llonlyshowcodeinthetexttoexplainconcepts.You'llneedtodownloadthecodetocreateaworkingexampleapplication.

ThefirstsampleapplicationforthischapteriscalledTouchDragDemo.Therearetwokeyfileswewanttotalkaboutinthissection:

/res/layout/main.xml

/src/com/androidbook/touch/dragdemo/Dot.java

Themain.xmlfilecontainsourlayoutforthedrag-and-dropdemo.ItisshowninListing23-1.SomeofthekeyconceptswewantyoutonoticearetheuseofaFrameLayoutasthetop-levellayout,insideofwhichisaLinearLayoutcontainingTextViewsandacustomViewclasscalledDot.BecausetheLinearLayoutand

Page 588: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

DotcoexistwithintheFrameLayout,theirpositionsandsizesdon’treallyimpacteachother,buttheywillbesharingthescreenrealestate,oneontopoftheother.TheUIforthisapplicationisshowninFigure23-1.

Listing23-1.ExampleLayoutXMLforOurDragExample

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/main.xml--><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#0000ff">

<LinearLayoutandroid:id="@+id/counters"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent">

<TextViewandroid:id="@+id/top"android:text="0"android:background="#111111"android:layout_height="wrap_content"android:layout_width="60dp"android:layout_gravity="right"android:layout_marginTop="30dp"android:layout_marginBottom="30dp"android:padding="10dp"/>

<TextViewandroid:id="@+id/middle"android:text="0"android:background="#111111"android:layout_height="wrap_content"android:layout_width="60dp"android:layout_gravity="right"android:layout_marginBottom="30dp"android:padding="10dp"/>

<TextViewandroid:id="@+id/bottom"android:text="0"android:background="#111111"android:layout_height="wrap_content"android:layout_width="60dp"android:layout_gravity="right"android:padding="10dp"/></LinearLayout>

<com.androidbook.touch.dragdemo.Dotandroid:id="@+id/dot"android:layout_width="match_parent"android:layout_height="match_parent"/>

Page 589: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

</FrameLayout>

Figure23-1.UserinterfaceforTouchDragDemo

NotethatthepackagenameinthelayoutXMLfilefortheDotelementmustmatchthepackagenameyouuseforyourapplication.Asmentioned,thelayoutofDotisseparatedfromtheLinearLayout.Thisisbecausewewantthefreedomtomovethedotaroundthescreen,whichiswhywechosethelayout_widthandlayout_heightof“match_parent”.Whenwedrawthedotonthescreen,wewantittobevisible,andifweconstrictthesizeofourdot’sviewtothediameterofthedot,wewon’tbeabletoseeitwhenwedragitawayfromourstartingplace.

NoteTechnically,wecouldsetandroid:clipChildrentotrueintheFrameLayouttagandsetthelayoutwidthandheightofthedottowrap_content,butthatdoesn’tfeelasclean.

Foreachofthecounters,wesimplylaythemoutwithabackground,padding,margins,andgravitytogetthemtoshowupalongtheright-handsideofthescreen.Westartthemoffatzero,butasyou’llsoonsee,we'llbeincrementingthosevaluesasdotsaredraggedovertothem.AlthoughwechosetouseTextViewsinthisexample,youcouldusejustaboutanyViewobjectasadroptarget.NowwewilllookattheJavacodeforourDotclassinListing23-2.

Listing23-2.JavaCodeforOurDotClass

publicclassDotextendsView{privatestaticfinalStringTAG="TouchDrag";privatefloatleft=0;privatefloattop=0;privatefloatradius=20;privatefloatoffsetX;privatefloatoffsetY;

Page 590: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

privatePaintmyPaint;privateContextmyContext;

publicDot(Contextcontext,AttributeSetattrs){super(context,attrs);

//Savethecontext(theactivity)myContext=context;

myPaint=newPaint();myPaint.setColor(Color.WHITE);myPaint.setAntiAlias(true);}

publicbooleanonTouchEvent(MotionEventevent){intaction=event.getAction();floateventX=event.getX();floateventY=event.getY();switch(action){caseMotionEvent.ACTION_DOWN://Firstmakesurethetouchisonourdot,//sincethesizeofthedot'sviewis//technicallythewholelayout.Ifthe//touchis*not*within,thenreturnfalse//indicatingwedon'twantanymoreevents.if(!(left-20<eventX&&eventX<left+radius*2+20&&top-20<eventY&&eventY<top+radius*2+20))returnfalse;

//Remembertheoffsetofthetouchascompared//toourleftandtopedges.offsetX=eventX-left;offsetY=eventY-top;break;caseMotionEvent.ACTION_MOVE:caseMotionEvent.ACTION_UP:caseMotionEvent.ACTION_CANCEL:left=eventX-offsetX;top=eventY-offsetY;if(action==MotionEvent.ACTION_UP){checkDrop(eventX,eventY);}break;}invalidate();returntrue;

Page 591: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

privatevoidcheckDrop(floatx,floaty){//Seeifthex,yofourdroplocationisnearto//oneofourcounters.Ifso,incrementit,and//resetthedotbacktoitsstartingpositionLog.v(TAG,"checkingdroptargetfor"+x+","+y);

intviewCount=((MainActivity)myContext).counterLayout.getChildCount();

for(inti=0;i<viewCount;i++){Viewview=((MainActivity)myContext).counterLayout.getChildAt(i);if(view.getClass()==TextView.class){Log.v(TAG,"Isthedroptotherightof"+(view.getLeft()-20));Log.v(TAG,"andverticallybetween"+(view.getTop()-20)+"and"+(view.getBottom()+20)+"?");if(x>view.getLeft()-20&&view.getTop()-20<y&&y<view.getBottom()+20){Log.v(TAG,"Yes.Yesitis.");

//IncreasethecountvalueintheTextViewbyoneintcount=Integer.parseInt(((TextView)view).getText().toString());((TextView)view).setText(String.valueOf(++count));

//Resetthedotbacktostartingpositionleft=top=0;break;}}}}

publicvoiddraw(Canvascanvas){canvas.drawCircle(left+radius,top+radius,radius,myPaint);

Page 592: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}}

Whenyourunthisapplication,youwillseeawhitedotonabluebackground.Youcantouchthedotanddragitaroundthescreen.Whenyouliftyourfinger,thedotstayswhereitisuntilyoutouchitagainanddragitsomewhereelse.Thedraw()methodputsthedotatitscurrentlocationofleftandtop,adjustedbythedot’sradius.ByreceivingMotionEventobjectsintheonTouchEvent()method,wecanmodifytheleftandtopvaluesbythemovementofourtouch.

Becausetheuserwon’talwaystouchtheexactcenteroftheobject,thetouchcoordinateswillnotbethesameasthelocationcoordinatesoftheobject.Thatisthepurposeoftheoffsetvalues:togetusbacktotheleftandtopedgesofourdotfromthepositionofthetouch.Butevenbeforewestartadragoperation,wewanttobesurethattheuser’stouchisconsideredcloseenoughtothedottobevalid.Iftheusertouchesthescreenfarawayfromthedot,whichistechnicallywithintheviewlayoutofthedot,wedon’twantthattostartadragsequence.Thatiswhywelooktoseeifthetouchiswithinthewhitedotitself;ifitisnot,wesimplyreturnfalse,whichpreventsreceivinganymoretoucheventsinthattouchsequence.

Whenyourfingerstartsmovingacrossthescreen,weadjustthelocationoftheobjectbythedeltasinxandybasedontheMotionEventsthatweget.Whenyoustopmoving(ACTION_UP),wefinalizeourlocationusingthelastcoordinatesofyourtouch.Wedon’thavetoworryaboutscrollbarsinthisexample,whichcouldcomplicatethecalculationoftheobject’spositionofourobjectonthescreen.Butthebasicprincipleisstillthesame.ByknowingthestartinglocationoftheobjecttobemovedandkeepingtrackofthedeltavaluesofatouchfromACTION_DOWNthroughtoACTION_UP,wecanadjustthelocationoftheobjectonthescreen.

Droppinganobjectontoanotherobjectonthescreenhasmuchlesstodowithtouchthanitdoeswithknowingwherethingsareonthescreen.Aswedraganobjectaroundthescreen,weareawareofitspositionrelativetooneormorereferencepoints.Wecanalsointerrogateobjectsonthescreenfortheirlocationsandsizes.Wecanthendetermineifourdraggedobjectis“over”anotherobject.Thetypicalprocessoffiguringoutadroptargetforadraggedobjectistoiteratethroughtheavailableobjectsthatcanbedroppedonanddetermineifourcurrentpositionoverlapswiththatobject.Eachobject’ssizeandposition(andsometimesshape)canbeusedtomakethisdetermination.IfwegetanACTION_UPevent,meaningthattheuserhasletgoofourdraggedobject,andtheobjectisoversomethingwecandroponto,wecanfirethelogictoprocessthedropaction.

Weusedthisapproachinoursampleapplication.WhentheACTION_UPactionisdetected,wethenlookthroughthechildviewsoftheLinearLayout,andforeachTextViewthatisfound,wecomparethelocationofthetouchtotheedgesoftheTextView(plusalittlebitextra).IfthetouchiswithinthatTextView,wegrabthecurrentnumericvalueoftheTextView,incrementitbyone,andwriteitback.Ifthishappens,thepositionofthedotisresetbacktoitsstartingplace(left=0,top=0)forthenextdrag.

Page 593: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

OurexampleshowsyouthebasicsofawaytododraganddropinAndroidpriorto3.0.Withthisyoucouldimplementdrag-and-dropfeaturesinyourapplication.Thismightbetheactionofdraggingsomethingtothetrashcan,wheretheobjectbeingdraggedshouldbedeleted,oritcouldbedraggingafiletoafolderforthepurposesofmovingorcopyingit.Toembellishyourapplication,youcouldpre-identifywhichviewsarepotentialdroptargetsandcausethemtovisuallychangeasadragstarts.Ifyouwantedthedraggedobjecttodisappearfromthescreenwhenitisdropped,youcouldalwaysprogrammaticallyremoveitfromthelayout(seethevariousremoveViewmethodsinViewGroup).

Nowthatyou’veseenthehardwaytododraganddrop,we’dliketoshowyouthedrag-and-dropsupportthatwasaddedinAndroid3.0.

BasicsofDragandDropin3.0+PriortoAndroid3.0,therewasnodirectsupportfordraganddrop.YoulearnedinthefirstsectionofthischapterhowtodragaViewaroundthescreen;youalsolearnedthatitwaspossibletousethecurrentlocationofthedraggedobjecttodetermineiftherewasadroptargetunderneath.WhentheMotionEventforthefinger-upeventwasreceived,yourcodecouldfigureoutifthatmeantadrophadoccurred.Althoughthiswasdoable,itcertainlywasn’taseasyashavingdirectsupportinAndroidforthedrag-and-dropoperation.Younowhavethatdirectsupport.

Atitsmostbasic,thedrag-and-dropoperationstartswithaviewdeclaringthatadraghasstarted;thenallinterestedpartieswatchthedragtakeplaceuntilthedropeventisfired.Ifaviewcatchesthedropeventandwantstoreceiveit,thenadraganddrophasjustoccurred.Ifthereisnoviewtoreceivethedrop,oriftheviewthatreceivesitdoesn’twantit,thennodroptakesplace.DraggingiscommunicatedthroughtheuseofaDragEventobject,whichispassedtoallofthedraglistenersavailable.

WithintheDragEventobjectaredescriptorsforlotsofinformation,dependingontheinitiatorofthedragsequence.Forexample,theDragEventcancontainobjectreferencestotheinitiatoritself,stateinformation,textualdata,URIs,orprettymuchwhateveryouwanttopassthroughthedragsequence.

Informationcouldbepassedthatresultsinview-to-viewdynamiccommunication;however,theoriginatordatainaDragEventobjectissetwhentheDragEventiscreated,anditstaysthesamethereafter.Inadditiontothisdata,theDragEventhasanactionvalueindicatingwhatisgoingonwiththedragsequence,andlocationinformationindicatingwherethedragisonthescreen.

ADragEventhassixpossibleactions:

ACTION_DRAG_STARTEDindicatesthatanewdragsequencehasbegun.

ACTION_DRAG_ENTEREDindicatesthatthedraggedobjecthasbeendraggedintotheboundariesofaspecificview.

Page 594: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ACTION_DRAG_LOCATIONindicatesthatthedraggedobjecthasbeendraggedonthescreentoanewlocation.

ACTION_DRAG_EXITEDindicatesthatthedraggedobjecthasbeendraggedoutsidetheboundariesofaspecificview.

ACTION_DROPindicatesthattheuserhasletgoofthedraggedobject.Itisuptothereceiverofthiseventtodeterminewhetherthistrulymeansadrophasoccurred.

ACTION_DRAG_ENDEDtellsalldraglistenersthatthepreviousdragsequencehasended.TheDragEvent.getResult()methodindicatesasuccessfuldroporfailure.

Youmightthinkthatyouneedtosetupadraglisteneroneachviewinthesystemthatcouldparticipateinadragsequence;but,infact,youcandefineadraglisteneronjustaboutanythinginyourapplication,anditwillreceiveallofthedrageventsforallviewsinthesystem.Thiscanmakethingsalittleconfusingbecausethedraglistenerdoesnotneedtobeassociatedwitheithertheobjectbeingdraggedorthedroptarget.Thelistenercanmanageallofthecoordinationofthedraganddrop.

Infact,ifyouinspectthedrag-and-dropexampleprojectthatcomeswiththeAndroidSDK,youwillseethatitsetsupalisteneronaTextViewthathasnothingtodowiththeactualdragginganddropping.Theupcomingexampleprojectusesdraglistenersthataretiedtospecificviews.ThesedraglistenerseachreceiveaDragEventobjectforthedrageventsthatoccurinthedragsequence.ThismeansaviewcouldreceiveaDragEventobjectthatcanbeignoredbecauseitisreallyaboutadifferentview.ThisalsomeansthedraglistenermustmakethatdeterminationincodeandthattheremustbeenoughinformationwithintheDragEventobjectforthedraglistenertofigureoutwhattodo.

IfadraglistenergotaDragEventobjectthatmerelysaidthere’sanunknownobjectbeingdraggedandit’satcoordinates(15,57),thereisn’tmuchthedraglistenercandowithit.ItismuchmorehelpfultogetaDragEventobjectthatsaysaparticularobjectisbeingdragged,it’satcoordinates(15,57),it’sacopyoperation,andthedataisaspecificURI.Whenthatdrops,there’senoughinformationtobeabletoinitiateacopyoperation.

We’reactuallyseeingtwodifferentkindsofdragginggoingon.Inourfirstexampleapplication,wedraggedaviewacrossaframelayout,andwecouldletgoandthatviewwouldstaywhereitwas.Weonlygotdrag-and-dropbehaviorwhenwedroppedourviewontopofsomethingelse.Thesupportedformofdraganddropworksdifferentlythanthis.Now,whenyoudragaviewaspartofadrag-and-dropsequence,thedraggedviewdoesn’tmoveatall.Wegetashadowimageofthedraggedviewwhichdoestravelacrossthescreen,butifweletgoofit,thatshadowviewgoesaway.WhatthismeansisthatyoumightstillhaveoccasiontousethetechniquefromthebeginningofthischapterinanAndroid3.0+application,tomoveimagesaroundonthescreenperhaps,withoutnecessarilydoingdraganddrop.

Page 595: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Drag-and-DropExampleApplicationForyournextexampleapplication,you’regoingtoemployastapleof3.0,thefragment.This,amongotherthings,willprovethatdragscancrossfragmentboundaries.You’llcreateapaletteofdotsontheleftandasquaretargetontheright.Whenadotisgrabbedusingalongclick,you’llchangethecolorofthatdotinthepaletteandAndroidwillshowashadowofthedotasyoudrag.Whenthedraggeddotreachesthesquaretarget,thetargetwillbegintoglow.Ifyoudropthedotonthesquaretarget,amessagewillindicatethatyou’vejustaddedonemoredroptothedropcount,theglowingwillstop,andtheoriginaldotwillgobacktoitsoriginalcolor.

ListofFilesThisapplicationbuildsuponconceptswe’vecoveredthroughoutthisbook.We’reonlygoingtoincludetheinterestingfilesinthetext.Fortheothers,justlookattheminyourIDEatyourleisure.Herearetheonesthatwe’veincludedinthetext:

palette.xmlisthefragmentlayoutforthedotsontheleftside(seeListing23-3).

dropzone.xmlisthefragmentlayoutforthesquaretargetontherightside,plusthedrop-countmessage(seeListing23-4).

DropZone.javainflatesthedropzone.xmlfragmentlayoutfileandthenimplementsthedraglistenerforthedroptarget(seeListing23-5).

Dot.javaisyourcustomviewclassfortheobjectsyou’regoingtodrag.Ithandlesbeginningthedragsequence,watchingdragevents,anddrawingthedots(seeListing23-6).

LayingOuttheExampleDrag-and-DropApplicationBeforewegetintothecode,Figure23-2showswhattheapplicationwilllooklike.

Page 596: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure23-2.DragDropFragsexampleapplicationuserinterface

Themainlayoutfilehasasimplehorizontallinearlayoutandtwofragmentspecifications.Thefirstfragmentwillbeforthepaletteofdotsandthesecondwillbeforthedropzone.

Thepalettefragmentlayoutfile(Listing23-3)getsabitmoreinteresting.Althoughthislayoutrepresentsafragment,youdon’tneedtoincludeafragmenttagwithinthislayout.Thislayoutwillbeinflatedtobecometheviewhierarchyforyourpalettefragment.Thedotsarespecifiedascustomdots,andtherearetwoofthemarrangedvertically.NoticethatthereareacoupleofcustomXMLattributesinthedefinitionofyourdots(dot:coloranddot:radius).Asyoucansee,theseattributesspecifythecolorandtheradiusofyourdots.Youmightalsohavenoticedthatthelayoutwidthandheightarewrap_content,notmatch_parentasintheearlierexampleapplicationinthischapter.Thenewdrag-and-dropsupportmakesthingsmucheasier.

Listing23-3.Thepalette.xmlLayoutFilefortheDots

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/palette.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:dot="http://schemas.android.com/apk/res/com.androidbook.drag.drop.demoandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">

Page 597: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<com.androidbook.drag.drop.demo.Dotandroid:id="@+id/dot1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="30dp"android:tag="Bluedot"dot:color="#ff1111ff"dot:radius="20dp"/>

<com.androidbook.drag.drop.demo.Dotandroid:id="@+id/dot2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:tag="Whitedot"dot:color="#ffffffff"dot:radius="40dp"/>

</LinearLayout>

ThedropzonefragmentlayoutfileinListing23-4isalsoeasytounderstand.There’sagreensquareandatextmessagearrangedhorizontally.Thiswillbethedropzoneforthedotsyou’llbedragging.Thetextmessagewillbeusedtodisplayarunningcountofthedrops.

Listing23-4.Thedropzone.xmlLayoutFile

<?xmlversion="1.0"encoding="utf-8"?><!--Thisfileisres/layout/dropzone.xml--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal">

<Viewandroid:id="@+id/droptarget"android:layout_width="75dp"android:layout_height="75dp"android:layout_gravity="center_vertical"android:background="#00ff00"/>

<TextViewandroid:id="@+id/dropmessage"android:text="0drops"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:paddingLeft="50dp"android:textSize="17sp"/>

</LinearLayout>

Page 598: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RespondingtoonDragintheDropzoneNowthatyouhavethemainapplicationlayoutset,let’sseehowthedroptargetneedstobeorganizedbyexaminingListing23-5.

Listing23-5.TheDropZone.javaFile

publicclassDropZoneextendsFragment{

privateViewdropTarget;privateTextViewdropMessage;

@OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,Bundleicicle){Viewv=inflater.inflate(R.layout.dropzone,container,false);

dropMessage=(TextView)v.findViewById(R.id.dropmessage);

dropTarget=(View)v.findViewById(R.id.droptarget);dropTarget.setOnDragListener(newView.OnDragListener(){privatestaticfinalStringDROPTAG="DropTarget";privateintdropCount=0;privateObjectAnimatoranim;

publicbooleanonDrag(Viewv,DragEventevent){intaction=event.getAction();booleanresult=true;switch(action){caseDragEvent.ACTION_DRAG_STARTED:Log.v(DROPTAG,"dragstartedindropTarget");break;caseDragEvent.ACTION_DRAG_ENTERED:Log.v(DROPTAG,"dragentereddropTarget");anim=ObjectAnimator.ofFloat((Object)v,"alpha",1f,0.5f);anim.setInterpolator(newCycleInterpolator(40));anim.setDuration(30*1000);//30secondsanim.start();break;

Page 599: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

caseDragEvent.ACTION_DRAG_EXITED:Log.v(DROPTAG,"dragexiteddropTarget");if(anim!=null){anim.end();anim=null;}break;caseDragEvent.ACTION_DRAG_LOCATION:Log.v(DROPTAG,"dragproceedingindropTarget:"+event.getX()+","+event.getY());break;caseDragEvent.ACTION_DROP:Log.v(DROPTAG,"dragdropindropTarget");if(anim!=null){anim.end();anim=null;}

ClipDatadata=event.getClipData();Log.v(DROPTAG,"Itemdatais"+data.getItemAt(0).getText());

dropCount++;Stringmessage=dropCount+"drop";if(dropCount>1)message+="s";dropMessage.setText(message);break;caseDragEvent.ACTION_DRAG_ENDED:Log.v(DROPTAG,"dragendedindropTarget");if(anim!=null){anim.end();anim=null;}break;default:Log.v(DROPTAG,"otheractionindropzone:"+action);result=false;}returnresult;}});returnv;

Page 600: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}}

Nowyou’restartingtogetintointerestingcode.Forthedropzone,youneedtocreatethetargetuponwhichyouwanttodragthedots.Asyousawearlier,thelayoutspecifiesagreensquareonthescreenwithatextmessagenexttoit.Becausethedropzoneisalsoafragment,you’reoverridingtheonCreateView()methodofDropZone.Thefirstthingtodoisinflatethedropzonelayoutandthenextractouttheviewreferenceforthesquaretarget(dropTarget)andforthetextmessage(dropMessage).Thenyouneedtosetupadraglisteneronthetargetsoitwillknowwhenadragisunderway.

Thedrop-targetdraglistenerhasasinglecallbackmethodinit:onDrag().ThiscallbackwillreceiveaviewreferenceaswellasaDragEventobject.TheviewreferencerelatestotheviewthattheDragEventisrelatedto.Asmentioned,thedraglistenerisnotnecessarilyconnectedtotheviewthatwillbeinteractingwiththedragevent,sothiscallbackmustidentifytheviewforwhichthedrageventistakingplace.

OneofthefirstthingsyoulikelywanttodoinanyonDrag()callbackisreadtheactionfromtheDragEventobject.Thiswilltellyouwhat’sgoingon.Forthemostpart,theonlythingyouwanttodointhiscallbackislogthefactthatadrageventistakingplace.Youdon’tneedtoactuallydoanythingforACTION_DRAG_LOCATION,forexample.Butyoudowanttohavesomespeciallogicforwhentheobjectisdraggedwithinyourboundaries(ACTION_DRAG_ENTERED)thatwillbeturnedoffeitherwhentheobjectisdraggedoutsideofyourboundaries(ACTION_DRAG_EXITED)orwhentheobjectisdropped(ACTION_DROP).

You’reusingtheObjectAnimatorclassthatwasintroducedinChapter18,onlyhereyou’reusingitincodetospecifyacyclicinterpolatorthatmodifiesthetarget’salpha.Thiswillhavetheeffectofpulsingthetransparencyofthegreentargetsquare,whichwillbethevisualindicationthatthetargetiswillingtoacceptadropoftheobjectontoit.Becauseyouturnontheanimation,youmustmakesuretoalsoturnitoffwhentheobjectleavesorisdropped,orthedraganddropisended.Intheory,youshouldn’tneedtostoptheanimationonACTION_DRAG_ENDED,butit’swisetodoitanyway.

Forthisparticulardraglistener,you’regoingtogetACTION_DRAG_ENTEREDandACTION_DRAG_EXITEDonlyifthedraggedobjectinteractswiththeviewwithwhichyou’reassociated.Andasyou’llsee,theACTION_DRAG_LOCATIONeventshappenonlyifthedraggedobjectisinsideyourtargetview.

TheonlyotherinterestingconditionistheACTION_DROPitself(noticethatDRAG_isnotpartofthenameofthisaction).Ifadrophasoccurredonyourview,itmeanstheuserhasletgoofthedotoverthegreensquare.Becauseyou’reexpectingthisobjecttobedroppedonthegreensquare,youcanjustgoaheadandreadthedatafromthefirstitemandthenlogittoLogCat.Inaproductionapplication,youmightpaycloserattentiontotheClipDataobjectthatiscontainedinthedrageventitself.Byinspectingitsproperties,youcoulddecideifyouevenwanttoacceptthedropornot.

ThisisagoodtimetopointouttheresultbooleaninthisonDrag()callbackmethod.

Page 601: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Dependingonhowthingsgo,youwanttoletAndroidknoweitherthatyoutookcareofthedragevent(byreturningtrue)orthatyoudidn’t(byreturningfalse).Ifyoudon’tseewhatyouwanttoseeinsideofthedrageventobject,youcouldcertainlyreturnfalsefromthiscallback,whichwouldtellAndroidthatthisdropwasnothandled.

OnceyoulogtheinformationfromthedrageventinLogCat,youincrementthecountofthedropsreceived;thisisupdatedintheuserinterface,andthat’saboutitforDropZone.

Ifyoulookthisclassover,it’sreallyrathersimple.Youdon’tactuallyhaveanycodeinherethatdealswithMotionEvents,nordoyouevenneedtomakeyourowndeterminationofwhetherthereisadraggoingon.Youjustgetappropriatecallbackcallsasadragsequenceunfolds.

SettingUptheDragSourceViewsLet’snowconsiderhowviewscorrespondingtoadragsourceareorganized,startingbylookingatListing23-6.

Listing23-6.TheJavafortheCustomView:Dot

publicclassDotextendsViewimplementsView.OnDragListener{privatestaticfinalintDEFAULT_RADIUS=20;privatestaticfinalintDEFAULT_COLOR=Color.WHITE;privatestaticfinalintSELECTED_COLOR=Color.MAGENTA;protectedstaticfinalStringDOTTAG="DragDot";privatePaintmNormalPaint;privatePaintmDraggingPaint;privateintmColor=DEFAULT_COLOR;privateintmRadius=DEFAULT_RADIUS;privatebooleaninDrag;

publicDot(Contextcontext,AttributeSetattrs){super(context,attrs);

//Applyattributesettingsfromthelayoutfile.//Note:thesecouldchangeonareconfiguration//suchasascreenrotation.TypedArraymyAttrs=context.obtainStyledAttributes(attrs,R.styleable.Dot);

finalintnumAttrs=myAttrs.getIndexCount();for(inti=0;i<numAttrs;i++){intattr=myAttrs.getIndex(i);switch(attr){caseR.styleable.Dot_radius:

Page 602: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

mRadius=myAttrs.getDimensionPixelSize(attr,DEFAULT_RADIUS);break;caseR.styleable.Dot_color:mColor=myAttrs.getColor(attr,DEFAULT_COLOR);break;}}myAttrs.recycle();

//SetuppaintcolorsmNormalPaint=newPaint();mNormalPaint.setColor(mColor);mNormalPaint.setAntiAlias(true);

mDraggingPaint=newPaint();mDraggingPaint.setColor(SELECTED_COLOR);mDraggingPaint.setAntiAlias(true);

//StartadragonalongclickonthedotsetOnLongClickListener(lcListener);setOnDragListener(this);}

privatestaticView.OnLongClickListenerlcListener=newView.OnLongClickListener(){privatebooleanmDragInProgress;

publicbooleanonLongClick(Viewv){ClipDatadata=ClipData.newPlainText("DragData",(String)v.getTag());

mDragInProgress=v.startDrag(data,newView.DragShadowBuilder(v),(Object)v,0);

Log.v((String)v.getTag(),"startingdrag?"+mDragInProgress);

returntrue;}};

@OverrideprotectedvoidonMeasure(intwidthSpec,intheightSpec){intsize=2*mRadius+getPaddingLeft()+getPaddingRight();

Page 603: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

setMeasuredDimension(size,size);}

//ThedraggingfunctionalitypublicbooleanonDrag(Viewv,DragEventevent){StringdotTAG=(String)getTag();//Onlyworryaboutdrageventsifthisisusbeingdraggedif(event.getLocalState()!=this){Log.v(dotTAG,"Thisdrageventisnotforus");returnfalse;}booleanresult=true;

//geteventvaluestoworkwithintaction=event.getAction();floatx=event.getX();floaty=event.getY();

switch(action){caseDragEvent.ACTION_DRAG_STARTED:Log.v(dotTAG,"dragstarted.X:"+x+",Y:"+y);inDrag=true;//usedindraw()belowtochangecolorbreak;caseDragEvent.ACTION_DRAG_LOCATION:Log.v(dotTAG,"dragproceeding…At:"+x+","+y);break;caseDragEvent.ACTION_DRAG_ENTERED:Log.v(dotTAG,"dragentered.At:"+x+","+y);break;caseDragEvent.ACTION_DRAG_EXITED:Log.v(dotTAG,"dragexited.At:"+x+","+y);break;caseDragEvent.ACTION_DROP:Log.v(dotTAG,"dragdropped.At:"+x+","+y);//Returnfalsebecausewedon'tacceptthedropinDot.result=false;break;caseDragEvent.ACTION_DRAG_ENDED:Log.v(dotTAG,"dragended.Success?"+event.getResult());

Page 604: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

inDrag=false;//changecoloroforiginaldotbackbreak;default:Log.v(dotTAG,"someotherdragaction:"+action);result=false;break;}returnresult;}

//Hereiswhereyoudrawourdot,andwhereyouchangethecolorif//you'reintheprocessofbeingdragged.Note:thecolorchange//affectstheoriginaldotonly,nottheshadow.publicvoiddraw(Canvascanvas){floatcx=this.getWidth()/2+getLeftPaddingOffset();floatcy=this.getHeight()/2+getTopPaddingOffset();Paintpaint=mNormalPaint;if(inDrag)paint=mDraggingPaint;canvas.drawCircle(cx,cy,mRadius,paint);invalidate();}}

TheDotcodelookssomewhatsimilartothecodeforDropZone.Thisisinpartbecauseyou’realsoreceivingdrageventsinthisclass.TheconstructorforaDotfiguresouttheattributesinordertosetthecorrectradiusandcolor,andthenitsetsupthetwolisteners:oneforlongclicksandanotherforthedragevents.

Thetwopaintsaregoingtobeusedtodrawyourcircle.Youusethenormalpaintwhenthedotisjustsittingthere.Butwhenthedotisbeingdragged,youwanttoindicatethatbychangingthecoloroftheoriginaltomagenta.

Thelong-clicklisteneriswhereyouinitiateadragsequence.Theonlywayyoulettheuserstartdraggingadotisiftheuserclicksandholdsonadot.Whenthelong-clicklistenerisfiring,youcreateanewClipDataobjectusingastringandthedot’stag.YouhappentoknowthatthetagisthenameofthedotasspecifiedintheXMLlayoutfile.ThereareseveralotherwaystospecifydataintoaClipDataobject,sofeelfreetoreadthereferencedocumentationonotherwaystostoredatainaClipDataobject.

Thenextstatementisthecriticalone:startDrag().ThisiswhereAndroidwilltakeoverandstarttheprocessofdragging.NotethatthefirstargumentistheClipDataobjectfrombefore;thenit’sthedrag-shadowobject,thenalocal-stateobject,andfinallythenumberzero.

Page 605: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thedrag-shadowobjectistheimagethatwillbedisplayedasthedraggingistakingplace.Inyourcase,thisdoesnotreplacetheoriginaldotimageonthescreenbutshowsashadowofadotasthedraggingistakingplace,inadditiontotheoriginaldotonthescreen.ThedefaultDragShadowBuilderbehavioristocreateashadowthatlooksverymuchliketheoriginal,soforyourpurposes,youmerelycallitandpassinyourview.Youcangetfancyhereandcreatewhateversortofshadowviewyouwant,butifyoudooverridethisclass,you’llneedtoimplementafewmethodstomakeitwork.

TheonMeasure()methodisheretosupplydimensioninformationtoAndroidforthecustomviewyou’reusinghere.YouhavetotellAndroidhowbigyourviewissoitknowshowtolayitoutwitheverythingelse.Thisisstandardpracticeforacustomview.

Finally,there’stheonDrag()callback.Asmentioned,eachdraglistenercanreceivedragevents.TheyallgetACTION_DRAG_STARTEDandACTION_DRAG_ENDED,forexample.So,wheneventshappen,youmustbecarefulwhatyoudowiththeinformation.Becausetherearetwodotsinplayinthisexampleapplication,wheneveryoudosomethingwiththedots,youmustbecarefulthatyou’reaffectingthecorrectone.

WhenbothdotsreceivetheACTION_DRAG_STARTEDaction,onlyoneshouldsetthecolorofitselftomagenta.Tofigureoutwhichoneiscorrect,comparethelocalstateobjectpassedinwithyourself.Ifyoulookbackwhereyousetthelocal-stateobject,youpassedthecurrentviewin.Sonow,whenyou’vereceivedthelocal-stateobjectout,youcompareittoyourselftoseeifyou’retheviewthatinitiatedthedragsequence.

Ifyouaren’tthesameview,youwritealogmessagetoLogCatsayingthisisnotforyou,andyoureturnfalsetosayyou’renothandlingthismessage.

Ifyouaretheviewthatshouldbereceivingthisdragevent,youcollectsomevaluesfromthedragevent,thenyoumostlyjustlogtheeventtoLogCat.ThefirstexceptiontothisisACTION_DRAG_STARTED.Ifyougotthisactionandit’sforyou,youthenknowthatyourdothasbegunadragsequence.Therefore,yousettheinDragbooleansothedraw()methodlateronwilldotherightthinganddisplayadifferent-coloreddot.ThisdifferentcoloronlylastsuntilACTION_DRAG_ENDEDisreceived,atwhichtimeyourestoretheoriginalcolorofthedot.

IfadotgetstheACTION_DROPaction,thismeanstheusertriedtodropadotonadot—maybeeventheoriginaldot.Thisshouldn’tdoanything,soyoujustreturnfalsefromthiscallbackinthiscase.

Finally,thedraw()methodofyourcustomviewfiguresoutthelocationofthecenterpointofyourcircle(dot)andthendrawsitwiththeappropriatepaint.Theinvalidate()methodistheretotellAndroidthatyou’vemodifiedtheviewandthatAndroidshouldredrawtheuserinterface.Bycallinginvalidate(),youensurethattheuserinterfacewillbeupdatedveryshortlywithwhateverisnew.

Younowhaveallthefilesandthebackgroundnecessarytocompileanddeploythisexampledrag-and-dropapplication.

Page 606: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TestingtheExampleDrag-and-DropApplicationFollowingissomeexampleoutputfromLogCatwhenweranthisexampleapplication.NoticehowthelogmessageusedBluedottoindicatemessagesfromthebluedot,Whitedotformessagesfromthewhitedot,andDropTargetfortheviewwherethedropsareallowedtogo.

Whitedot:startingdrag?trueBluedot:ThisdrageventisnotforusWhitedot:dragstarted.X:53.0,Y:206.0DropTarget:dragstartedindropTargetDropTarget:dragentereddropTargetDropTarget:dragproceedingindropTarget:29.0,36.0DropTarget:dragproceedingindropTarget:48.0,39.0DropTarget:dragproceedingindropTarget:45.0,39.0DropTarget:dragproceedingindropTarget:41.0,39.0DropTarget:dragproceedingindropTarget:40.0,39.0DropTarget:dragdropindropTargetDropTarget:ItemdataisWhitedotViewRoot:Reportingdropresult:trueWhitedot:dragended.Success?trueBluedot:ThisdrageventisnotforusDropTarget:dragendedindropTarget

Inthisparticularcase,thedragwasstartedwiththewhitedot.Oncethelongclickhastriggeredthebeginningofthedragsequence,wegetthestartingdragmessage.

NoticehowthenextthreelinesallindicatethatanACTION_DRAG_STARTEDactionwasreceivedinthreedifferentviews.Bluedotdeterminedthatthecallbackwasnotforit.ItwasalsonotforDropTarget.

Next,noticehowthedrag-proceedingmessagesshowthedraghappeningthroughDropTarget,beginningwiththeACTION_DRAG_ENTEREDaction.Thismeansthedotwasbeingdraggedontopofthegreensquare.Thexandycoordinatesreportedinthedrageventobjectarethecoordinatesofthedragpointrelativetotheupper-leftcorneroftheview.So,intheexampleapp,thefirstrecordofthedraginthedroptargetisat(x,y)=(29,36),andthedropoccurredat(40,39).Seehowthedroptargetwasabletoextractthetagnameofthewhitedotfromtheevent’sClipDatatowriteittoLogCat.

Alsoseehowonceagain,alldraglistenersreceivedtheACTION_DRAG_ENDEDaction.OnlyWhitedotdeterminedthatit’sokaytodisplaytheresultsusinggetResult().

Feelfreetoexperimentwiththisexampleapplication.Dragadottotheotherdot,oreventoitself.Goaheadandaddanotherdottopalette.xml.Noticehowwhenthedragged

Page 607: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

dotleavesthegreensquare,there’samessagesayingthatthedragexited.Notealsothatifyoudropadotsomewhereotherthanthegreensquare,thedropisconsideredfailed.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforazipfilecalledProAndroid5_Ch23_DragnDrop.zip.Thiszipfilecontainsalltheprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoyourIDEfromoneofthesezipfiles.

http://developer.android.com/guide/topics/ui/drag-drop.html:TheAndroiddeveloper’sguidetodraganddrop.

SummaryLet’ssummarizethetopicscoveredinthischapter:

Drag-and-dropsupportinAndroid3.0,andimplementingitpriorto3.0usingothermethods

Iteratingthroughpossibledroptargetstoseeifadrop(thatis,fingerleavingthescreenafterdragging)occurred

Thedifficultyofdoingthemathtokeeptrackofwhereadraggedobjectisandwhetherit’soveradroptarget

Drag-and-dropsupportinAndroid3.0+,whichismuchnicerbecauseiteliminatesalotofguesswork

Draglisteners,whichcanbeanyobjectsanddonotneedtobedraggablesordrop-targetviews

Thefactthatadragcanoccuracrossfragments

TheDragEventobject,whichcancontainlotsofgreatinformationaboutwhatisbeingdraggedandwhy

HowAndroidtakescareofthemathtodeterminewhetheradropisoccurringontopofaview

Page 608: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter24

UsingSensorsAndroiddevicesoftencomewithhardwaresensorsbuiltin,andAndroidprovidesaframeworkforworkingwiththosesensors.Sensorscanbefun.Measuringtheoutsideworldandusingthatinsoftwareinadeviceisprettycool.Itisthekindofprogrammingexperienceyoujustdon’tgetonaregularcomputerthatsitsonadeskorinaserverroom.Thepossibilitiesfornewapplicationsthatusesensorsarehuge,andwehopeyouareinspiredtorealizethem.

Inthischapter,we’llexploretheAndroidsensorframework.We’llexplainwhatsensorsareandhowwegetsensordata,andthendiscusssomespecificsofthekindsofdatawecangetfromsensorsandwhatwecandowithit.WhileAndroidhasdefinedseveralsensortypesalready,therearenodoubtmoresensorsinAndroid’sfuture,andweexpectthatfuturesensorswillgetincorporatedintothesensorframework.

WhatIsaSensor?InAndroid,asensorisasourceofdataeventsfromthephysicalworld.Thisistypicallyapieceofhardwarethathasbeenwiredintothedevice,butAndroidalsoprovidessomelogicalsensorsthatcombinedatafrommultiplephysicalsensors.Applicationsinturnusethesensordatatoinformtheuseraboutthephysicalworld,tocontrolgameplay,todoaugmentedreality,ortoprovideusefultoolsforworkingintherealworld.Sensorsoperateinonedirectiononly;they’reread-only.Thatmakesusingthemfairlystraightforward.Yousetupalistenertoreceivesensordata,andthenyouprocessthedataasitcomesin.GPShardwareislikethesensorswecoverinthischapter.InChapter19,wesetuplistenersforGPSlocationupdates,andweprocessedthoselocationupdatesastheycamein.ButalthoughGPSissimilartoasensor,itisnotpartofthesensorframeworkthatisprovidedbyAndroid.

SomeofthesensortypesthatcanappearinanAndroiddeviceinclude

Lightsensor

Proximitysensor

Temperaturesensor

Pressuresensor

Gyroscopesensor

Accelerometer

Magneticfieldsensor

Gravitysensor

Page 609: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Linearaccelerationsensor

Rotationvectorsensor

Relativehumiditysensor

DetectingSensorsPleasedon’tassume,however,thatallAndroiddeviceshaveallofthesesensors.Infact,manydeviceshavejustsomeofthesesensors.TheAndroidemulator,forexample,hasonlyanaccelerometer.Sohowdoyouknowwhichsensorsareavailableonadevice?Therearetwoways,onedirectandoneindirect.

ThefirstwayisthatyouasktheSensorManagerforalistoftheavailablesensors.Itwillrespondwithalistofsensorobjectsthatyoucanthensetuplistenersforandgetdatafrom.We’llshowyouhowabitlaterinthischapter.Thismethodassumesthattheuserhasalreadyinstalledyourapplicationontoadevice,butwhatifthedevicedoesn’thaveasensorthatyourapplicationneeds?

That’swherethesecondmethodcomesin.WithintheAndroidManifest.xmlfile,youcanspecifythefeaturesadevicemusthaveinordertoproperlysupportyourapplication.Ifyourapplicationneedsaproximitysensor,youspecifythatinyourmanifestfilewithalinesuchasthefollowing:

<uses-featureandroid:name="android.hardware.sensor.proximity"/>

TheGooglePlayStorewillonlyinstallyourapponadevicethathasaproximitysensor,soyouknowit’stherewhenyourapplicationruns.ThesamecannotbesaidforallotherAndroidappstores.Thatis,someAndroidappstoresdonotperformthatkindofchecktomakesureyourappcanonlybeinstalledontoadevicethatsupportsthesensorsyouspecify.

WhatCanWeKnowAboutaSensor?Whileusingtheuses-featuretagsinthemanifestfileletsyouknowthatasensoryourapplicationrequiresexistsonadevice,itdoesn’ttellyoueverythingyoumaywanttoknowabouttheactualsensor.Let’sbuildasimpleapplicationthatqueriesthedeviceforsensorinformation.Listing24-1showstheJavacodeofourMainActivity.

Note

Youcandownloadthischapter’sprojects.WewillgiveyoutheURLattheendofthechapter.ThiswillallowyoutoimporttheseprojectsintoyourIDEdirectly.

Listing24-1.JavaforaSensorListApp

publicclassMainActivityextendsActivity{@Override

Page 610: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

TextViewtext=(TextView)findViewById(R.id.text);

SensorManagermgr=(SensorManager)this.getSystemService(SENSOR_SERVICE);

List<Sensor>sensors=mgr.getSensorList(Sensor.TYPE_ALL);

StringBuildermessage=newStringBuilder(2048);message.append("Thesensorsonthisdeviceare:\n");

for(Sensorsensor:sensors){message.append(sensor.getName()+"\n");message.append("Type:"+sensorTypes.get(sensor.getType())+"\n");message.append("Vendor:"+sensor.getVendor()+"\n");message.append("Version:"+sensor.getVersion()+"\n");try{message.append("MinDelay:"+sensor.getMinDelay()+"\n");}catch(NoSuchMethodErrore){}//ignoreifnotfoundtry{message.append("FIFOMaxEventCount:"+sensor.getFifoMaxEventCount()+"\n");}catch(NoSuchMethodErrore){}//ignoreifnotfoundmessage.append("Resolution:"+sensor.getResolution()+"\n");message.append("MaxRange:"+sensor.getMaximumRange()+"\n");message.append("Power:"+sensor.getPower()+"mA\n");}text.setText(message);}

privateHashMap<Integer,String>sensorTypes=newHashMap<Integer,String>();

Page 611: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

{sensorTypes.put(Sensor.TYPE_ACCELEROMETER,"TYPE_ACCELEROMETER");sensorTypes.put(Sensor.TYPE_AMBIENT_TEMPERATURE,"TYPE_AMBIENT_TEMPERATURE");/*...therestisomittedtosavespace…*/}}

WithinouronCreate()method,westartbygettingareferencetotheSensorManager.Therecanbeonlyoneofthese,soweretrieveitasasystemservice.WethencallitsgetSensorList()methodtogetalistofsensors.Foreachsensor,wewriteoutinformationaboutit.TheoutputwilllooksomethinglikeFigure24-1.

Figure24-1.Outputfromoursensorlistapp

Thereareafewthingstoknowaboutthissensorinformation.Thetypevaluetellsyouthebasictypeofthesensorwithoutgettingspecific.Alightsensorisalightsensor,butyoucouldgetvariationsinlightsensorsfromonedevicetoanother.Forexample,theresolutionofalightsensorononedevicecouldbedifferentfromthatonanotherdevice.

Page 612: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Whenyouspecifythatyourappneedsalightsensorina<uses-feature>tag,youdon’tknowinadvanceexactlywhattypeoflightsensoryou’regoingtoget.Ifitmatterstoyourapplication,you’llneedtoquerythedevicetofindoutandadjustyourcodeaccordingly.Thevaluesyougetforresolutionandmaximumrangewillbeintheappropriateunitsforthatsensor.Thepowermeasurementisinmilliamperes(mA)andrepresentstheelectricalcurrentthatthesensordrawsfromthedevice’sbattery;smallerisbetter.

Nowthatweknowwhatsensorswehaveavailabletous,howdowegoaboutgettingdatafromthem?Asweexplainedearlier,wesetupalistenerinordertogetsensordatasenttous.Let’sexplorethatnow.

GettingSensorEventsSensorsprovidedatatoourapplicationonceweregisteralistenertoreceivethedata.Whenourlistenerisnotlistening,thesensorcanbeturnedoff,conservingbatterylife,somakesureyouonlylistenwhenyoureallyneedto.Settingupasensorlisteneriseasytodo.Let’ssaythatwewanttomeasurethelightlevelsfromthelightsensor.Listing24-2showstheJavacodeforasampleappthatdoesthis.

Listing24-2.JavaCodeforaLightSensorMonitorApp

publicclassMainActivityextendsActivityimplementsSensorEventListener{privateSensorManagermgr;privateSensorlight;privateTextViewtext;privateStringBuildermsg=newStringBuilder(2048);

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

mgr=(SensorManager)this.getSystemService(SENSOR_SERVICE);light=mgr.getDefaultSensor(Sensor.TYPE_LIGHT);text=(TextView)findViewById(R.id.text);}

@OverrideprotectedvoidonResume(){mgr.registerListener(this,light,SensorManager.SENSOR_DELAY_NORMAL);super.onResume();}

Page 613: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

@OverrideprotectedvoidonPause(){mgr.unregisterListener(this,light);super.onPause();}

publicvoidonAccuracyChanged(Sensorsensor,intaccuracy){msg.insert(0,sensor.getName()+"accuracychanged:"+accuracy+(accuracy==1?"(LOW)":(accuracy==2?"(MED)":"(HIGH)"))+"\n");text.setText(msg);text.invalidate();}

publicvoidonSensorChanged(SensorEventevent){msg.insert(0,"Gotasensorevent:"+event.values[0]+"SIluxunits\n");text.setText(msg);text.invalidate();}}

Inthissampleapp,weagaingetareferencetotheSensorManager,butinsteadofgettingalistofsensors,wequeryspecificallyforthelightsensor.WethensetupalistenerintheonResume()methodofouractivity,andweunregisterthelistenerintheonPause()method.Wedon’twanttobeworryingaboutthelightlevelswhenourapplicationisnotintheforeground.

FortheregisterListener()method,wepassinavaluerepresentinghowoftenwewanttobenotifiedofsensorvaluechanges.Thisparametercouldbe

SENSOR_DELAY_NORMAL(represents200,000microseconddelay)

SENSOR_DELAY_UI(represents60,000microseconddelay)

SENSOR_DELAY_GAME(represents20,000microseconddelay)

SENSOR_DELAY_FASTEST(representsasfastaspossible)

YoucanalsospecifyaspecificmicroseconddelayusingoneoftheotherregisterListener

Page 614: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

methods,aslongasit’slargerthan3microseconds;howeveranythinglessthan20,000isnotlikelytobehonored.Itisimportanttoselectanappropriatevalueforthisparameter.Somesensorsareverysensitiveandwillgeneratealotofeventsinashortamountoftime.IfyouchooseSENSOR_DELAY_FASTEST,youmightevenoverrunyourapplication’sabilitytokeepup.Dependingonwhatyourapplicationdoeswitheachsensorevent,itispossiblethatyouwillbecreatinganddestroyingsomanyobjectsinmemorythatgarbagecollectionwillcausenoticeableslowdownsandhiccupsonthedevice.Ontheotherhand,certainsensorsprettymuchdemandtobereadasoftenaspossible;thisistrueoftherotationvectorsensorinparticular.Also,don’trelyonthisparametertogenerateeventswithprecisetiming.Theeventscouldcomealittlefasterorslower.

BecauseouractivityimplementstheSensorEventListenerinterface,wehavetwocallbacksforsensorevents:onAccuracyChanged()andonSensorChanged().Thefirstmethodwillletusknowiftheaccuracychangesonoursensor(orsensors,sinceitcouldbecalledformorethanone).ThevalueoftheaccuracyparameterwillbeSENSOR_STATUS_UNRELIABLE,SENSOR_STATUS_ACCURACY_LOW,SENSOR_STATUS_ACCURACY_MEDIUM,orSENSOR_STATUS_ACCURACY_HIGH.Unreliableaccuracydoesnotmeanthatthedeviceisbroken;itnormallymeansthatthesensorneedstobecalibrated.Thesecondcallbackmethodtellsuswhenthelightlevelhaschanged,andwegetaSensorEventobjecttotellusthedetailsofthenewvalueorvaluesfromthesensor.

ASensorEventobjecthasseveralmembers,oneofthembeinganarrayoffloatvalues.Foralightsensorevent,onlythefirstfloatvaluehasmeaning,whichistheSIluxvalueofthelightthatwasdetectedbythesensor.Foroursampleapp,webuildupamessagestringbyinsertingthenewmessagesontopoftheoldermessages,andthenwedisplaythebatchofmessagesinaTextView.Ournewestsensorvalueswillalwaysbedisplayedatthetopofthescreen.

Whenyourunthisapplication(onarealdevice,ofcourse,sincetheemulatordoesnothavealightsensor),youmaynoticethatnothingisdisplayedatfirst.Justchangethelightthatisshiningontheupper-leftcornerofyourdevice.Thisismostlikelywhereyourlightsensoris.Ifyoulookverycarefully,youmightseethedotbehindthescreenthatisthelightsensor.Ifyoucoverthisdotwithyourfinger,thelightlevelwillprobablychangetoaverysmallvalue(althoughitmaynotreachzero).Themessagesshoulddisplayonthescreen,tellingyouaboutthechanginglightlevels.

Note

Youmightalsonoticethatwhenthelightsensoriscovered,yourbuttonslightup(ifyouhaveadevicewithlightedbuttons).ThisisbecauseAndroidhasdetectedthedarknessandlightsupthebuttonstomakethedeviceeasiertouse“inthedark.”

IssueswithGettingSensorDataTheAndroidsensorframeworkhasproblemsthatyouneedtobeawareof.Thisisthepartthat’snotfun.Insomecases,wehavewaysofworkingaroundtheproblem;inotherswe

Page 615: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

don’t,orit’sverydifficult.

NoDirectAccesstoSensorValuesYoumayhavenoticedthatthereisnodirectwaytoquerythesensor’scurrentvalue.Theonlywaytogetdatafromasensoristhroughalistener.Therearetwokindsofsensors:thosethatarestreamingandthosethatarenot.Streamingsensorswillsendvaluesonaregularbasis,suchastheaccelerometer.ThemethodcallgetMinDelay()willreturnanonzerovalueforstreamingsensors,totellyoutheminimumnumberofmicrosecondsthatasensorwillusetosensetheenvironment.Fornon-streamingsensorsthereturnvalueiszero,soevenonceyou’vesetupthelistener,therearenoguaranteesthatyou’llgetanewdatumwithinasetperiodoftime.Atleastthecallbackisasynchronoussoyouwon’tblocktheUIthreadwaitingforapieceofdatafromasensor.However,yourapplicationhastoaccommodatethefactthatsensordatamaynotbeavailableattheexactmomentthatyouwantit.RevisitingFigure24-1,you’llnoticethatthelightsensorisnon-streaming.Therefore,yourappwillgetaneventonlyifthelightlevelchanges.Fortheothersensorsshown,thedelaybetweeneventswillbeaminimumof20milliseconds,butcouldbemore.

ItispossibletodirectlyaccesssensorsusingnativecodeandtheJNIfeatureofAndroid.You’llneedtoknowthelow-levelnativeAPIcallsforthesensordriveryou’reinterestedin,plusbeabletosetuptheinterfacebacktoAndroid.Soitcanbedone,butit’snoteasy.

SensorValuesNotSentFastEnoughEvenatSENSOR_DELAY_FASTEST,youprobablywon’tgetnewvaluesmoreoftenthanevery20ms(itdependsonthedeviceandthesensor).IfyouneedmorerapidsensordatathanyoucangetwitharatesettingofSENSOR_DELAY_FASTEST,itispossibletousenativecodeandJNItogettothesensordatafaster,butsimilartotheprevioussituation,itisnoteasy.

SensorsTurnOffwiththeScreenTherehavebeenproblemsinAndroid2.xwithsensorupdatesthatgetturnedoffwhenthescreenisturnedoff.Apparentlysomeonethoughtitwasagoodideatonotsendsensorupdatesifthescreenisoff,evenifyourapplication(mostlikelyusingaservice)hasawakelock.Basically,yourlistenergetsunregisteredwhenthescreenturnsoff.

Thereareseveralworkaroundstothisproblem.Formoreinformationonthisissueandpossibleresolutionsandworkarounds,pleaserefertoAndroidIssue11028:

http://code.google.com/p/android/issues/detail?id=11028

Nowthatyouknowhowtogetdatafromsensors,whatcanyoudowiththedata?Aswesaidearlier,dependingonwhichsensoryou’regettingdatafrom,thevaluesreturnedinthevaluesarraymeandifferentthings.Thenextsectionwillexploreeachofthesensortypesandwhattheirvaluesmean.

Page 616: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

InterpretingSensorDataNowthatyouunderstandhowtogetdatafromasensor,you’llwanttodosomethingmeaningfulwiththedata.Thedatayouget,however,willdependonwhichsensoryou’regettingthedatafrom.Somesensorsaresimplerthanothers.Inthesectionsthatfollow,wewilldescribethedatathatyou’llgetfromthesensorswecurrentlyknowabout.Asnewdevicescomeintobeing,newsensorswillundoubtedlybeintroducedaswell.Thesensorframeworkisverylikelytoremainthesame,sothetechniquesweshowhereshouldapplyequallywelltothenewsensors.

LightSensorsThelightsensorisoneofthesimplestsensorsonadevice,andoneyou’veusedinthefirstsampleapplicationsofthischapter.Thesensorgivesareadingofthelightleveldetectedbythelightsensorofthedevice.Asthelightlevelchanges,thesensorreadingschange.TheunitsofthedataareinSIluxunits.Tolearnmoreaboutwhatthismeans,pleaseseethe“References”sectionattheendofthischapterforlinkstomoreinformation.

ForthevaluesarrayintheSensorEventobject,alightsensorusesjustthefirstelement,values[0].Thisvalueisafloatandrangestechnicallyfrom0tothemaximumvaluefortheparticularsensor.Wesaytechnicallybecausethesensormayonlysendverysmallvalueswhenthere’snolight,andneveractuallysendavalueof0.

Rememberalsothatthesensorcantellusthemaximumvaluethatitcanreturnandthatdifferentsensorscanhavedifferentmaximums.Forthisreason,itmaynotbeusefultoconsiderthelight-relatedconstantsintheSensorManagerclass.Forexample,SensorManagerhasaconstantcalledLIGHT_SUNLIGHT_MAX,whichisafloatvalueof120,000;however,whenwequeriedourdeviceearlier,themaximumvaluereturnedwas10,240,clearlymuchlessthanthisconstantvalue.There’sanotheronecalledLIGHT_SHADEat20,000,whichisalsoabovethemaximumofthedevicewetested.Sokeepthisinmindwhenwritingcodethatuseslightsensordata.

ProximitySensorsTheproximitysensoreithermeasuresthedistancethatsomeobjectisfromthedevice(incentimeters)orrepresentsaflagtosaywhetheranobjectiscloseorfar.Someproximitysensorswillgiveavaluerangingfrom0.0tothemaximuminincrements,whileothersreturneither0.0orthemaximumvalueonly.Ifthemaximumrangeoftheproximitysensorisequaltothesensor’sresolution,thenyouknowit’soneofthosethatonlyreturns0.0,orthemaximum.Therearedeviceswithamaximumof1.0andotherswhereit’s6.0.Unfortunately,there’snowaytotellbeforetheapplicationisinstalledandrunwhichproximitysensoryou’regoingtoget.Evenifyouputa<uses-feature>taginyourAndroidManifest.xmlfilefortheproximitysensor,youcouldgeteitherkind.Unlessyouabsolutelyneedtohavethemoregranularproximitysensor,yourapplicationshouldaccommodatebothtypesgracefully.

Page 617: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Here’saninterestingfactaboutproximitysensors:theproximitysensorissometimesthesamehardwareasthelightsensor.Androidstilltreatsthemaslogicallyseparatesensors,though,soifyouneeddatafrombothyouwillneedtosetupalistenerforeachone.Here’sanotherinterestingfact:theproximitysensorisoftenusedinthephoneapplicationtodetectthepresenceofaperson’sheadnexttothedevice.Iftheheadisthatclosetothetouchscreen,thetouchscreenisdisabledsonokeyswillbeaccidentlypressedbytheearorcheekwhilethepersonistalkingonthephone.

Thesourcecodeprojectsforthischapterincludeasimpleproximitysensormonitorapplication,whichisbasicallythelightsensormonitorapplicationmodifiedtousetheproximitysensorinsteadofthelightsensor.Wewon’tincludethecodeinthischapter,butfeelfreetoexperimentwithitonyourown.

TemperatureSensorsTheolddeprecatedtemperaturesensor(TYPE_TEMPERATURE)providedatemperaturereadingandalsoreturnedjustasinglevalueinvalues[0].Thissensorusuallyreadaninternaltemperature,suchasatthebattery.ThereisanewtemperaturesensorcalledTYPE_AMBIENT_TEMPERATURE.ThenewvaluerepresentsthetemperatureoutsidethedeviceindegreesCelsius.

Theplacementofthetemperaturesensorisdevice-dependent,anditispossiblethatthetemperaturereadingscouldbeimpactedbytheheatgeneratedbythedeviceitself.TheprojectsforthischapterincludeoneforthetemperaturesensorcalledTemperatureSensor.IttakescareofcallingthecorrecttemperaturesensorbasedonwhichversionofAndroidisrunning.

PressureSensorsThissensormeasuresbarometricpressure,whichcoulddetectaltitudeforexampleorbeusedforweatherpredictions.ThissensorshouldnotbeconfusedwiththeabilityofatouchscreentogenerateaMotionEventwithapressurevalue(thepressureofthetouch).WecoveredthistouchtypeofpressuresensinginChapter22.Touchscreenpressuresensingdoesn’tusetheAndroidsensorframework.

TheunitofmeasurementforapressuresensorisatmosphericpressureinhPa(millibar),andthismeasurementisdeliveredinvalues[0].

GyroscopeSensorsGyroscopesareverycoolcomponentsthatcanmeasurethetwistofadeviceaboutareferenceframe.Saidanotherway,gyroscopesmeasuretherateofrotationaboutanaxis.Whenthedeviceisnotrotating,thesensorvalueswillbezeros.Whenthereisrotationinanydirection,you’llgetnonzerovaluesfromthegyroscope.Gyroscopesareoftenusedfornavigation.Butbyitself,agyroscopecan’ttellyoueverythingyouneedtoknowtonavigate.Andunfortunately,errorscreepinovertime.Butcoupledwithaccelerometers,youcandeterminethepathofmovementofthedevice.

Page 618: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Kalmanfilterscanbeusedtolinkdatafromthetwosensorstogether.Accelerometersarenotterriblyaccurateintheshortterm,andgyroscopesarenotveryaccurateinthelongterm,socombinedtheycanbereasonablyaccurateallthetime.WhileKalmanfiltersareverycomplex,thereisanalternativecalledcomplementaryfiltersthatareeasiertoimplementincodeandproduceresultsthatareprettygood.Theseconceptsarebeyondthescopeofthisbook.

Thegyroscopesensorreturnsthreevaluesinthevaluesarrayforthex,y,andzaxes.Theunitsareradianspersecond,andthevaluesrepresenttherateofrotationaroundeachofthoseaxes.Onewaytoworkwiththesevaluesistointegratethemovertimetocalculateananglechange.Thisisasimilarcalculationtointegratinglinearspeedovertimetocalculatedistance.

AccelerometersAccelerometersareprobablythemostutilizedofthesensorsonadevice.Usingthesesensors,yourapplicationcandeterminethephysicalorientationofthedeviceinspacerelativetogravity’spullstraightdown,plusbeawareofforcesactingonthedevice.Providingthisinformationallowsanapplicationtodoallsortsofinterestingthings,fromgameplaytoaugmentedreality.Andofcourse,theaccelerometerstellAndroidwhentoswitchtheorientationoftheuserinterfacefromportraittolandscapeandbackagain.

Theaccelerometercoordinatesystemworkslikethis:theaccelerometer’sxaxisoriginatesinthebottom-leftcornerofthedeviceandgoesacrossthebottomtotheright.Theyaxisalsooriginatesinthebottom-leftcornerandgoesupalongtheleftofthedisplay.Thezaxisoriginatesinthebottom-leftcornerandgoesupinspaceawayfromthedevice.Figure24-2showswhatthismeans.

Figure24-2.Accelerometercoordinatesystem

Thiscoordinatesystemisdifferentthantheoneusedinlayoutsand2Dgraphics.Inthatcoordinatesystem,theorigin(0,0)isatthetop-leftcorner,andyispositiveinthedirectiondownthescreenfromthere.Itiseasytogetconfusedwhendealingwithcoordinatesystemsindifferentframesofreference,sobecareful.

Page 619: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Wehaven’tyetsaidwhattheaccelerometervaluesmean,sowhatdotheymean?Accelerationismeasuredinmeterspersecondsquared(m/s2).NormalEarthgravityis9.81m/s2,pullingdowntowardthecenteroftheEarth.Fromtheaccelerometer’spointofview,themeasurementofgravityis–9.81.Ifyourdeviceiscompletelyatrest(notmoving)andisonaperfectlyflatsurface,thexandyreadingswillbe0andthezreadingwillbe+9.81.Actually,thevalueswon’tbeexactlythesebecauseofthesensitivityandaccuracyoftheaccelerometer,buttheywillbeclose.Gravityistheonlyforceactingonthedevicewhenthedeviceisatrest,andbecausegravitypullsstraightdown,ifourdeviceisperfectlyflat,itseffectonthexandyaxesiszero.Onthezaxis,theaccelerometerismeasuringtheforceonthedeviceminusgravity.Therefore,0minus–9.81is+9.81,andthat’swhatthezvaluewillbe(a.k.a.values[2]intheSensorEventobject).

Thevaluessenttoyourapplicationbytheaccelerometeralwaysrepresentthesumoftheforcesonthedeviceminusgravity.Ifyouweretotakeyourperfectlyflatdeviceandliftitstraightup,thezvaluewouldincreaseatfirst,becauseyouincreasedtheforceintheup(z)direction.Assoonasyourliftingforcestopped,theoverallforcewouldreturntobeingjustgravity.Ifthedeviceweretobedropped(hypothetically—pleasedon’tdothis),itwouldbeacceleratingtowardtheground,whichwouldzerooutgravitysotheaccelerometerwouldread0force.

Let’stakethedevicefromFigure24-2androtateitupsoitisinportraitmodeandvertical.Thexaxisisthesame,pointinglefttoright.Ouryaxisisnowstraightupanddown,andthezaxisispointingoutofthescreenstraightatus.Theyvaluewillbe+9.81,andbothxandzwillbe0.

Whathappenswhenyourotatethedevicetolandscapemodeandcontinuetoholditvertically,sothescreenisrightinfrontofyourface?Ifyouguessedthatyandzarenow0andxis+9.81,you’dbecorrect.Figure24-3showswhatitmightlooklike.

Figure24-3.Accelerometervaluesinlandscapevertical

Whenthedeviceisnotmoving,orismovingwithaconstantvelocity,theaccelerometersareonlymeasuringgravity.Andineachaxis,thevaluefromtheaccelerometerisgravity’scomponentinthataxis.Therefore,usingsometrigonometry,youcouldfigureouttheanglesandknowhowthedeviceisorientedrelativetogravity’spull.Thatis,youcouldtellifthedevicewereinportraitmodeorinlandscapemodeorinsometiltedmode.Infact,thisisexactlywhatAndroiddoestofigureoutwhichdisplaymodetouse(portraitorlandscape).Note,however,thattheaccelerometersdonotsayhowthedeviceisoriented

Page 620: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

withrespecttomagneticnorth.Sowhileyoucouldknowthatthedeviceisbeingheldinlandscapemodevertically,youwouldn’tknowifyouwerefacingeastorwestoranywhereinbetween.That’swherethemagneticfieldsensorwillcomein,whichwewillcoverinalatersection.

AccelerometersandDisplayOrientationAccelerometersinadevicearehardware,andthey’refirmlyattached,andassuchhaveaspecificorientationrelativetothedevicethatdoesnotchangeasthedeviceisturnedthiswayorthat.ThevaluesthattheaccelerometerssendintoAndroidwillchangeofcourseasadeviceismoved,butthecoordinatesystemoftheaccelerometerswillstaythesamerelativetothephysicaldevice.Thecoordinatesystemofthedisplay,however,changesastheusergoesfromportraittolandscapeandbackagain.Infactdependingonwhichwaythescreenisturned,portraitcouldberight-sideup,or180degreesupside-down.Similarly,landscapecouldbeinoneoftwodifferentrotations180degreesapart.

Whenyourapplicationisreadingaccelerometerdataandwantingtoaffecttheuserinterfacecorrectly,yourapplicationmustknowhowmuchrotationofthedisplayhasoccurredtoproperlycompensate.Asyourscreenisreorientedfromportraittolandscape,thescreen’scoordinatesystemhasrotatedwithrespecttothecoordinatesystemoftheaccelerometers.Tohandlethis,yourapplicationmustusethemethodDisplay.getRotation().Thereturnvalueisasimpleintegerbutnottheactualnumberofdegreesofrotation.ThevaluewillbeoneofSurface.ROTATION_0,Surface.ROTATION_90,Surface.ROTATION_180,orSurface.ROTATION_270.Theseareconstantswithvaluesof0,1,2,and3,respectively.Thisreturnvaluetellsyouhowmuchthedisplayhasrotatedfromthe“normal”orientationofthedevice.BecausenotallAndroiddevicesarenormallyinportraitmode,youcannotassumethatportraitisatROTATION_0.

AccelerometersandGravitySofar,we’veonlybrieflytouchedonwhathappenstotheaccelerometervalueswhenthedeviceismoved.Let’sexplorethatfurther.Allforcesactingonthedevicewillbedetectedbytheaccelerometers.Ifyouliftthedevice,theinitialliftingforceispositiveinthezdirection,andyougetazvaluegreaterthan+9.81.Ifyoupushthedeviceonitsleftside,you’llgetaninitialnegativereadinginthexdirection.

Whatyou’dliketobeabletodoisseparateouttheforceofgravityfromtheotherforcesactingonthedevice.There’safairlyeasywaytodothis,andit’scalledalow-passfilter.Forcesotherthangravityactingonthedevicewilldosoinawaythatistypicallynotgradual.Inotherwords,iftheuserisshakingthedevice,theshakingforcesarereflectedintheaccelerometervaluesquickly.Alow-passfilterwillineffectstripouttheshakingforcesandleaveonlythesteadyforce,whichisgravity.Let’suseasampleapplicationtoillustratethisconcept.It’scalledGravityDemo.Listing24-3showstheJavacode.

Listing24-3.MeasuringGravityfromtheAccelerometers

//ThisfileisMainActivity.java

Page 621: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicclassMainActivityextendsActivityimplementsSensorEventListener{privateSensorManagermgr;privateSensoraccelerometer;privateTextViewtext;privatefloat[]gravity=newfloat[3];privatefloat[]motion=newfloat[3];privatedoubleratio;privatedoublemAngle;privateintcounter=0;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);

mgr=(SensorManager)this.getSystemService(SENSOR_SERVICE);accelerometer=mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);text=(TextView)findViewById(R.id.text);}

@OverrideprotectedvoidonResume(){mgr.registerListener(this,accelerometer,SensorManager.SENSOR_DELAY_UI);super.onResume();}

@OverrideprotectedvoidonPause(){mgr.unregisterListener(this,accelerometer);super.onPause();}

publicvoidonAccuracyChanged(Sensorsensor,intaccuracy){//ignore}

publicvoidonSensorChanged(SensorEventevent){//Usealow-passfiltertogetgravity.//Motioniswhat'sleftoverfor(inti=0;i<3;i++){gravity[i]=(float)(0.1*event.values[i]+0.9*gravity[i]);

Page 622: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

motion[i]=event.values[i]-gravity[i];}

//ratioisgravityontheYaxiscomparedtofullgravity//shouldbenomorethan1,nolessthan-1ratio=gravity[1]/SensorManager.GRAVITY_EARTH;if(ratio>1.0)ratio=1.0;if(ratio<-1.0)ratio=-1.0;

//convertradianstodegrees,makenegativeiffacingupmAngle=Math.toDegrees(Math.acos(ratio));if(gravity[2]<0){mAngle=-mAngle;}

//Displayevery10thvalueif(counter++%10==0){Stringmsg=String.format("Rawvalues\nX:%8.4f\nY:%8.4f\nZ:%8.4f\n"+"Gravity\nX:%8.4f\nY:%8.4f\nZ:%8.4f\n"+"Motion\nX:%8.4f\nY:%8.4f\nZ:%8.4f\nAngle:%8.1f",event.values[0],event.values[1],event.values[2],gravity[0],gravity[1],gravity[2],motion[0],motion[1],motion[2],mAngle);text.setText(msg);text.invalidate();counter=1;}}}

TheresultofrunningthisapplicationisadisplaythatlookslikeFigure24-4.Thisscreenshotwastakenasthedevicelayflatonatable.

Page 623: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure24-4.Gravity,motion,andanglevalues

MostofthissampleapplicationisthesameastheAccelSensorapplicationfrombefore.ThedifferencesareintheonSensorChanged()method.Insteadofsimplydisplayingthevaluesfromtheeventarray,weattempttokeeptrackofgravityandmotion.Yougetgravitybyusingonlyasmallportionofthenewvaluefromtheeventarray,andalargeportionofthepreviousvalueofthegravityarray.Thetwoportionsusedmustaddupto1.0.Weused0.9and0.1.Youcouldtryothervalues,too,suchas0.8and0.2.Ourgravityarraycannotpossiblychangeasfastastheactualsensorvaluesarechanging.Butthisisclosertoreality.Andthisiswhatalow-passfilterdoes.Theeventarrayvalueswouldonlybechangingifforceswerecausingthedevicetomove,andyoudon’twanttomeasurethoseforcesaspartofgravity.Youonlywanttorecordintoyourgravityarraytheforceofgravityitself.Themathheredoesnotmeanyou’remagicallyrecordingonlygravity,butthevaluesyou’recalculatingaregoingtobealotcloserthantherawvaluesfromtheeventarray.

Noticealsothemotionarrayinthecode.Bytrackingthedifferencebetweentheraweventarrayvaluesandthecalculatedgravityvalues,youarebasicallymeasuringtheactive,non-gravity,forcesonthedeviceinthemotionarray.Ifthevaluesinthemotionarrayarezeroorveryclosetozero,itmeansthedeviceisprobablynotmoving.Thisisusefulinformation.Technically,adevicemovinginaconstantspeedwouldalsohavevaluesinthemotionarrayclosetozero,buttherealityisthatifauserismovingthedevice,themotionvalueswillbesomewhatlargerthanzero.Userscan’tpossiblymoveadeviceataperfectconstantspeed.

Lastly,pleasenoticethatthisexampledoesnotproducenewobjectsthatneedtobegarbagecollected.Itisveryimportantwhendealingwithsensoreventstonotcreatenew

Page 624: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

objects;otherwiseyourapplicationwillspendtoomuchtimepausedforgarbagecollectioncycles.

UsingAccelerometerstoMeasuretheDevice’sAngleWewantedtoshowyouonemorethingabouttheaccelerometersbeforewemoveon.Ifwegobacktoourtrigonometrylessons,werememberthatthecosineofanangleistheratioofthenearsideandthehypotenuse.Ifweconsidertheanglebetweentheyaxisandgravityitself,wecouldmeasuretheforceofgravityontheyaxisandtakethearccosinetodeterminetheangle.We’vedonethatinthiscodeaswell,althoughherewehavetodealyetagainwithsomeofthemessinessofsensorsinAndroid.ThereareconstantsinSensorManagerfordifferentgravityconstants,includingEarth’s.Butyouractualmeasuredvaluescouldpossiblyexceedthedefinedconstants.Wewillexplainwhatwemeanbythisnext.

Intheory,yourdeviceatrestwouldmeasureavalueforgravityequaltotheconstantvalue,butthisisrarelythecase.Atrest,theaccelerometersensorisverylikelytogiveusavalueforgravitythatislargerorsmallerthantheconstant.Therefore,ourratiocouldendupgreaterthanone,orlessthannegativeone.Thiswouldmaketheacos()methodcomplain,sowefixtheratiovaluetobenomorethan1andnolessthan–1.Thecorrespondinganglesindegreesrangefrom0to180.That’sfineexceptthatwedon’tgetnegativeanglesfrom0to–180thisway.Togetthenegativeangles,weuseanothervaluefromourgravityarray,whichisthezvalue.Ifthezvalueofgravityisnegative,itmeansthedevice’sfaceisorienteddownward.Forallthosevalueswherethedevicefaceispointeddown,wemakeouranglenegativeaswell,withtheresultbeingthatouranglegoesfrom–180to+180,justaswewouldexpect.

Goaheadandexperimentwiththissampleapplication.Noticethatthevalueoftheangleis90whenthedeviceislaidflat,andit’szero(orclosetoit)whenthedeviceisheldstraightupanddowninfrontofus.Ifwekeeprotatingdownpastflat,wewillseethevalueoftheangleexceed90.Ifwetiltthedeviceupmorefromthe0position,thevalueofanglegoesnegativeuntilwe’reholdingthedeviceaboveourheadsandthevalueoftheangleis–90.Finally,youmayhavenoticedourcounterthatcontrolshowoftenthedisplayisupdated.Becausethesensoreventscancomeratherfrequently,wedecidedtoonlydisplayeverytenthtimewegetvalues.

MagneticFieldSensorsThemagneticfieldsensormeasurestheambientmagneticfieldinthex,y,andzaxes.Thiscoordinatesystemisalignedjustliketheaccelerometers,sox,y,andzareasshowninFigure24-2.Theunitsofthemagneticfieldsensoraremicroteslas(uT).ThissensorcandetecttheEarth’smagneticfieldandthereforetelluswherenorthis.Thissensorisalsoreferredtoasthecompass,andinfactthe<uses-feature>tagusesandroid.hardware.sensor.compassasthenameofthissensor.Becausethissensorissotinyandsensitive,itcanbeaffectedbymagneticfieldsgeneratedbythingsnearthedevice,andeventosomeextenttocomponentswithinthedevice.Thereforetheaccuracyofthemagneticfieldsensormayattimesbesuspect.

Page 625: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

We’veincludedasimpleCompassSensorapplicationinthedownloadsectionofthewebsite,sofeelfreetoimportthatandplaywithit.Ifyoubringmetalobjectsclosetothedevicewhilethisapplicationisrunning,youmightnoticethevalueschanginginresponse.Certainlyifyoubringamagnetclosetothedeviceyouwillseethevalueschange.Infact,theGoogleCardboard“device”usesamagnetunderaphysicalbuttonwhichisthendetectedbythephoneasachangeinthemagneticfieldwhenthebuttonispressed.

Youmightbeasking,canIusethecompasssensorasacompasstodetectwherenorthis?Andtheansweris:notbyitself.Whilethecompasssensorcandetectmagneticfieldsaroundthedevice,ifthedeviceisnotbeingheldperfectlyflatinrelationtotheEarth’ssurface,you’dhavenowayofcorrectlyinterpretingthecompasssensorvalues.ButyouhaveaccelerometersthatcantellyoutheorientationofthedevicerelativetotheEarth’ssurface!Therefore,youcancreateacompassfromthecompasssensor,butyou’llneedhelpfromtheaccelerometerstoo.Solet’sseehowtodothat.

UsingAccelerometersandMagneticFieldSensorsTogetherTheSensorManagerprovidessomemethodsthatallowustocombinethecompasssensorandtheaccelerometerstofigureoutorientation.Aswejustdiscussed,youcan’tusejustthecompasssensoralonetodothejob.SoSensorManagerprovidesamethodcalledgetRotationMatrix(),whichtakesthevaluesfromtheaccelerometersandfromthecompassandreturnsamatrixthatcanbeusedtodetermineorientation.

AnotherSensorManagermethod,getOrientation(),takestherotationmatrixfromthepreviousstepandgivesanorientationmatrix.Thevaluesfromtheorientationmatrixtellyouyourdevice’srotationrelativetotheEarth’smagneticnorth,aswellasthedevice’spitchandrollrelativetotheground.

MagneticDeclinationandGeomagneticFieldThere’sanothertopicwewanttocoverwithregardtoorientationanddevices.Thecompasssensorwilltellyouwheremagneticnorthis,butitwon’ttellyouwheretruenorthis(a.k.a.,geographicnorth).Imagineyouarestandingatthemidpointbetweenthemagneticnorthpoleandthegeographicnorthpole.They’dbe180degreesapart.Thefurtherawayyougetfromthetwonorthpoles,thesmallerthisangledifferencebecomes.Theangledifferencebetweenmagneticnorthandtruenorthiscalledmagneticdeclination.Andthevaluecanonlybecomputedrelativetoapointontheplanet’ssurface.Thatis,youhavetoknowwhereyou’restandingtoknowwheregeographicnorthisinrelationtomagneticnorth.Fortunately,Androidhasawaytohelpyouout,andit’stheGeomagneticFieldclass.

InordertoinstantiateanobjectoftheGeomagneticFieldclass,youneedtopassinalatitudeandlongitude.Therefore,inordertogetamagneticdeclinationangle,youneedtoknowwherethepointofreferenceis.Youalsoneedtoknowthetimeatwhichyouwantthevalue.Magneticnorthdriftsovertime.Onceinstantiated,yousimplycallthismethod

Page 626: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

togetthedeclinationangle(indegrees):

floatdeclinationAngle=geoMagField.getDeclination();

ThevalueofdeclinationAnglewillbepositiveifmagneticnorthistotheeastofgeographicnorth.

GravitySensorsThissensorisn’taseparatepieceofhardware.It’savirtualsensorbasedontheaccelerometers.Infact,thissensoruseslogicsimilartowhatwedescribedearlierforaccelerometerstoproducethegravitycomponentoftheforcesactingonadevice.Wecannotaccessthislogic,however,sowhateverfactorsandlogicareusedinsidethegravitysensorclassarewhatwemustaccept.It’spossible,though,thatthevirtualsensorwilltakeadvantageofotherhardwaresuchasagyroscopetohelpitcalculategravitymoreaccurately.Thevaluesarrayforthissensorreportsgravityjustliketheaccelerometersensorreportsitsvalues.

LinearAccelerationSensorsSimilartothegravitysensor,thelinearaccelerationsensorisavirtualsensorthatrepresentstheaccelerometerforcesminusgravity.Again,wedidourowncalculationsearlierontheaccelerometersensorvaluestostripoutgravitytogetjusttheselinearaccelerationforcevalues.Thissensormakesthatmoreconvenientforyou.Anditcouldtakeadvantageofotherhardware,suchasagyroscope,tohelpitcalculatelinearaccelerationmoreaccurately.Thevaluesarrayreportslinearaccelerationjustliketheaccelerometersensorreportsitsvalues.

RotationVectorSensorsTherotationvectorsensorrepresentstheorientationofthedeviceinspace,withanglesrelativetotheframeofreferenceofthehardwareaccelerometer(seeFigure24-2).Thissensorreturnsasetofvaluesthatrepresentsthelastthreecomponentsofaunitquaternion.Quaternionsareasubjectthatcouldfillabook,sowewon’tbegoingintothemhere.

Thankfully,GooglehasprovidedafewmethodswithinSensorManagertohelpwiththissensor.ThegetQuaternionFromVector()methodconvertsarotationvectorsensoroutputtoanormalizedquaternion.ThegetRotationMatrixFromVector()methodconvertsarotationvectorsensoroutputtoarotationmatrix,andthatcanbeusedwithgetOrientation().Whenconvertingrotationvectorsensoroutputtoanorientationvector,though,youneedtorealizethatitgoesfrom–180degreesto+180degrees.

TheZIPfileofsampleappsforthischapterincludesaversionofVirtualJaxthatshowstherotationvectorinuse.

Page 627: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

www.androidbook.com/proandroid5/projects:Alistofdownloadableprojectsrelatedtothisbook.Forthischapter,lookforaZIPfilecalledProAndroid5_Ch24_Sensors.zip.Thisfilecontainsalltheprojectsfromthischapter,listedinseparaterootdirectories.ThereisalsoaREADME.TXTfilethatdescribesexactlyhowtoimportprojectsintoanIDEfromoneoftheseZIPfiles.

http://en.wikipedia.org/wiki/Lux:TheWikipediaentryforlux,theunitoflightmeasurement.

www.ngdc.noaa.gov/geomag/faqgeom.shtml:InformationaboutgeomagnetismfromNOAA.

www.youtube.com/watch?v=C7JQ7Rpwn2k:AGoogleTechTalkfromDavidSachsonaccelerometers,gyroscopes,compasses,andAndroiddevelopment.

http://stackoverflow.com/questions/1586658/combine-gyroscope-and-accelerometer-data:Anicepostingonstackoverflow.comthattalksaboutcombininggyroscopeandaccelerometersensordataforuseinapplications.

http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotationTheWikipediapageonquaternionsandhowtheycanbeusedinrepresentingspatialrotation,suchasanAndroiddevice.

SummaryInthischapter,wecoveredthefollowingtopics:

WhatsensorsareinAndroid.

Findingoutwhatsensorsareonadevice.

SpecifyingthesensorsthatarerequiredforanapplicationbeforeitwillbeloadableontoanAndroiddevice.

Determiningthepropertiesofasensoronadevice.

Howtogetsensorevents.

Thefactthateventscomewheneverthesensorvaluechanges,soitisimportanttounderstandtherecouldbealagbeforeyougetyourfirstvalue.

Thedifferentspeedsofupdatesfromasensorandwhentouseeach

Page 628: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

one.

ThedetailsofaSensorEventandhowthesecanbeusedforthevarioussensortypes.

Virtualsensors,madeupofdatafromothersensors.TheROTATION_VECTORsensorisoneofthese.

Determiningtheangleofthedeviceusingsensors,andtellingwhichdirectionthedeviceisfacing.

Page 629: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter25

ExploringAndroidPersistenceandContentProvidersThereareanumberofwaysofsavingstateintheAndroidSDK.Someoftheseare1)sharedpreferences,2)internalfiles,3)externalfiles,4)SQLite,5)contentproviders,6)O/Rmappingtools,and7)networkstorageinthecloud.Wewillbrieflyintroduceeachofthesestate-savingoptionsfirstandthencoverindetailmanagingapplicationstateusingSQLiteandcontentproviders.

SavingStateUsingSharedPreferencesWehavecoveredsharedpreferencesinChapter11.Sharedpreferencesarekey/value-basedXMLfilesownedbyyourapplication.Androidhasaframeworkontopofthisgeneralpersistencemechanismtodisplay/update/retrievepreferenceswithoutwritingalotofcode.ThislatteraspectisthemaintopicofChapter11.

Chapter11alsotouchedbrieflyonhowanapplicationcanstoreanytypeofdatausingthesharedpreferenceAPIinXMLfiles.Inthisapproachdataisconvertedtoastringrepresentationfirstandthenstoredinthepreferenceskey/valuestore.Thisapproachcanbeusedtostoreanyarbitrarystateofyourapplicationaslongasitissmalltomediuminsize.

ThesharedpreferenceXMLfilesareinternaltotheapplicationonyourdevice.Thisdataisnotdirectlyavailabletootherapplications.EndusercannotdirectlymanipulatethisdatabymountingontoaUSBport.Thisdataisremovedautomaticallywhentheapplicationisremoved.

Fromsimpletomoderateapplicationpersistenceneeds,youcantakeadvantageofsharedpreferencesbystoringvarioustreesofJavaobjectsdirectlyinasharedpreferencefile.InagivenpreferencefileyoucanhaveakeypointtoaserializedJavaobjecttree.YoucanalsousemultiplepreferencefilesformultipleJavaobjecttrees.WehaveusedJSON/GSONlibraryfromgoogletodothisconversionfromJavaobjectstotheirequivalentJSONstringvaluesquiteeffectively.InthisapproachaJavaobjecttreeisstreamedasaJSONstringusingthegoogleGSONlibrary.Thistreeisthenstoredasavalueinakey/valuepairofapreferencefile.KeepinmindthatGSONandJSONconversionofaJavaobjectmayhavesomelimitations.ReadtheGSON/JSONdocumentationtoseehowcomplexaJavaobjectcangettomakethisapproachwork.Wearefairlyconfidentthatformostdata-basedJavaobjectsthiswillwork.

Listing25-1hassomesamplecodeforhowtosaveaJavatreeusingGSON/JSONandsharedpreferences.

Listing25-1.SavingaJavaObjectTreeUsingJSONinSharedPreferencesXMLFiles

Page 630: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//ImplementationofstoreJSONforstoringanyobjectpublicvoidstoreJSON(Contextcontext,ObjectanyObject){

//GetaGSONinstanceGsongson=newGson();

//ConvertJavaobjecttoaJSONstringStringjsonString=gson.toJson(anyObject);

//SeeChapter11formoredetailsonhowtogetasharedpreferencesreferenceStringfilename="somefilename.xml";intmode=Context.MODE_PRIVATE;SharedPreferencessp=context.getSharedPreferences(filename,mode);

//SavetheJSONstringinthesharedpreferencesSharedPreferences.Editorspe=sp.edit();spe.putString("json",jsonString);spe.commit();}//Thiscodecanthenbeusedbyaclientlikethis://Createanydataobjectwithreasonablecomplexity//Ex:MainObjectmo=MainObject.createTestMainObject();//YoucanthencallstoreJSON(some-activity,mo)below

Listing25-2showssomesamplecodeforhowtoretrieveaJavatreeusingGSON/JSONandsharedpreferences.

Listing25-2.ReadingaJavaObjectTreeUsingJSONfromSharedPreferencesXMLFiles

publicObjectretrieveJSON(Contextcontext,Stringfilename,ClassclassRef){intmode=Context.MODE_PRIVATE;SharedPreferencessp=context.getSharedPreferences(filename,mode);StringjsonString=sp.getString("json",null);if(jsonString==null){thrownewRuntimeException("Notabletoreadthepreference");}Gsongson=newGson();returngson.fromJson(jsonString,classRef);}

//YoucanthendothisintheclientcodeMainObjectmo

Page 631: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

=(MainObject)retrieveJSON(context,"somefilename.xml",MainObject.class);StringcompareResult=MainObject.checkTestMainObject(mo);if(compareResult!=null){thrownewRuntimeException("Somethingiswrong.Objectsdon'tmatch");}

ThiscoderequiresthatyouhavetheGSONJavalibraryaddedtoyourproject.ThisGSON-basedapproachiscoveredindetailinourcompanionbook,ExpertAndroidfromApress.Thisisalsobrieflydocumentedonlineathttp://androidbook.com/item/4438.

SavingStateUsingInternalFilesInAndroid,youcanalsouseinternalfilestostorethestateofyourapplication.Theseinternalfilesareinternaltotheapplicationonyourdevice.Thisdataisnotdirectlyavailabletootherapplications.EndusercannotdirectlymanipulatethisdatabymountingontoaUSBport.Thisdataisremovedautomaticallywhentheapplicationisremoved.

Listing25-3showssamplecodeforhowtosaveaJavatreeusingGSON/JSONandinternalfiles.

Listing25-3.Reading/WritingJSONStringsfrom/toanAndroidInternalFile

privateObjectreadFromInternalFile(ContextappContext,Stringfilename,ClassclassRef)throwsException{FileInputStreamfis=null;try{fis=appContext.openFileInput(filename);//ReadthefollowingstringfromthefilestreamfisStringjsonString;

Gsongson=newGson();returngson.fromJson(jsonString,classRef);}finally{//writecodetocloseStreamSilently(fis);}}privatevoidsaveToInternalFile(ContextappContext,Stringfilename,ObjectanyObject){Gsongson=newGson();StringjsonString=gson.toJson(anyObject);

FileOutputStreamfos=null;

Page 632: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

try{fos=appContext.openFileOutput(filename,Context.MODE_PRIVATE);fos.write(jsonString.getBytes());}finally{//closeStreamSilently(fos);}}

ThisapproachbasedoninternalfilesandGSONiscoveredindetailinourcompanionbook,ExpertAndroidfromApress(http://www.apress.com/9781430249504).Thisisalsobrieflydocumentedonlineathttp://androidbook.com/item/4439.

SavingStateUsingExternalFilesInAndroid,externalfilesarestoredeitherontheSDcardoronthedevice.Thesebecomepublicfilesthatotherappsincludingtheusercouldseeandreadoutsidethecontextofyourapplication.Formanyappsthatwanttomanagetheirinternalstatetheseexternalfileswillunnecessarilypollutethepublicspace.

BecausethedatayouwouldrepresentasJSONistypicallyveryspecifictoyourapplication,itdoesn’tmakesensetomakethisavailableasexternalstorage,whichistypicallyusedformusicfiles,videofiles,orfilesthatarecommonlyinaformatthatisunderstandablebyotherapplications.

BecauseexternalstoragesuchasanSDcardcanbeinvariousstates(available,notmounted,full,etc.),itishardertoprogramthisforsimpleappswhenthedataissmallenough.Sowecouldnotmakeagoodcasefornowthattheapplicationstatebemaintainedonexternalstorage.

AhybridapproachmaybemeaningfuliftheapplicationrequiresmusicandphotosandthosecangoontheexternalstoragewhilekeepingthecorestatedatainJSONandinternal.

Theandroid.os.Environmentclassandtheandroid.content.Contextclasshaveanumberofmethodstoreadandwritetoexternalfilesanddirectories.Wehavenotincludedcodeexamplesbecausetheapproachisverysimilartointernalfilesonceyougetaccesstothesefilesthroughtheandorid.content.Context.

SavingStateUsingSQLiteAndroidappscanuseSQLitedatabasestostoretheirstate.SQLiteiswellintegratedintothefabricofAndroid.Ifyouwanttostoretheinternalstateofyourapplicationrobustlythenthisisprobablythebestapproach.However,workingwithanyrelationaldatabaseincludingSQLitehasalotofnuances.WewillcovertheessentialsandnuancesofusingSQLiteonAndroidalittlelaterinthechapter.

Page 633: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SavingStateUsingO/RMappingLibrariesO/RmappingstandsforObject-to-RelationalMapping.AkeydifficultywithstoringstateinarelationaldatabasefromaprogramminglanguagelikeJavaisthemismatchbetweenJavaobjectstructuresandrelationalstructuresofthedatabase.Oneneedstomapbetweenthenames,types,andrelationshipsoffieldsastheyareintheJavaspaceandtheirequivalentsinthedatabasespace.Thismappingiserrorprone.YouwillseethiswhenwecovertheSQLiteindetaillater.

ThereisaneedforsimplifyingthismappingofdatabetweenJavaandSQL.ThisspaceintheindustryiscalledO/Rmapping.AfewtoolsarenowavailabletosolvethisinAndroid.ItisbeyondthescopeofthisbooktocovertheessentialsoftheseO/Rmappingtools.Butwewillnameacoupleofthesetoolsandgivetheironlinereferencesnow.

TwokeytoolsinthisspaceareGreenDAO(http://greendao-orm.com/)andOrmLite(http://ormlite.com/).Therearemoreappearingeveryyear.Socheckoftentoseeifthenewonesarefasteroreasier.GreenDAOusesacodegenerationapproachbasedonschemadefinitions.ItissaidtobethreetofourtimesfasterthanOrmLite.OrmLitefusestheschemadefinitionwithJavaclassesthroughannotations.Thelatterapproachiseasierprogrammatically.AlsoOrmLiteworksthesameonanyJavaplatform.However,possiblyduetoreflectionusedatruntime,itcanbeslower,butIsuspectisfastenoughformostapplications.

WepredictthatusingoneoftheseO/Rmappinglibrariesisakeyneedtogetyourappsfastertothemarket.WerecommendthatyouisolatethepersistenceservicesandstartwithOrmLiteandthenmovetoGreenDAOifyourappgainsenoughtractionorformovingtoproductionfromyourprototype.

SavingStateUsingContentProvidersAndroidprovidesahigher-levelabstractionontopofdatastoresbasedonURIs.UsingthisapproachanyapplicationcanreadorstoredatausingRESTlikeURIs.ThisabstractionalsoallowsapplicationstosharetheirdatathroughAPIsbasedonURIstrings.InthisapproachsubmittingaURIwillgivebackacollectionofrowsandcolumnsinadatabasecursor.AURIcanalsotakeasetofkey/valuepairsandpersisttheminatargetdatabaseifpermissionsaregranted.Thisisageneral-purposemechanismforinteroperabilityofdatabetweenAndroidapplications.Wewillcoverthisingreaterdetaillaterinthechapter.Thisisapreferredmechanismifyourapplicationhasdatathatisvaluabletobeshared,created,ormanipulatedbyotherapplications.Forexamplemanyapplicationsthatdealwithnotes,documents,audio,orvideoimplementtheirdataascontentproviders.ThisisalsothecasewithmostofAndroid’scoredata-relatedservices.

SavingStateUsingNetworkStorageNetworkstoragecomesintoplaywhenthedatacreatedorusedbyanapplicationneedstobesharedviaanetworkbyotherusersoneitherthesameplatformordifferentplatformslikeinacollaborativeapplication.Thisback-endservicefacilityutilizedbymobile

Page 634: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

applicationisbeingcalledMBaaS(MobileBack-endAsAService).Parse.comisanexampleofaMBAASthatprovidesback-endservicessuchasusermanagement,userlogins,security,social,commonnetworkstorage,serversidebusinesslogic,andnotifications.

Androidalsonativelyusesaconceptcalledsyncadapterstotransferdatabetweenthedeviceandnetworkservers.Youcanreadmoreonsyncadaptersathttp://developer.android.com/training/sync-adapters/index.html.Thisisaframeworkthatusesasynchronouscallbackstooptimizetransferofarbitraryamountsofdataefficientlybyschedulingandexecutingitatthemostopportunemoment.Theframeworksweatsthedetailanddevelopersjustprovidethetransfercode.

ThatconcludestheoverviewofvariouswaystosavestateforAndroidmobileapplications.Wewillcovernowtwoofthoseapproachesindetail:SQLiteandcontentproviders.WewillstartwiththeAndroidSQLiteAPI.

StoringDataDirectlyUsingSQLiteInthissectionwewillexploreindetailhowtouseSQLiteeffectivelytomanageAndroidapplicationstate.YouwillunderstandtheextentofSQLitesupportinAndroid.Wewillshowyoutheessentialcodesnippets.WewillshowyoubestpracticesforusingSQLiteonAndroid.WewillshowyouhowbesttoloadDDLstocreateyourdatabase.Wewillshowyouacleanerarchitecturalpatterntoabstractpersistenceservices.Wewillshowhowtoapplytransactionsthroughdynamicproxies.ThissectionisarobusttreatmentofusingSQLiteonAndroid.Wealsohaveasampleprogramthatyoucandownloadtoseethecompleteworkingimplementation.Let’sstartwithaquickoverviewofSQLitepackagesandclassesinAndroid.

SummarizingKeySQLitePackagesandClassesAndroidsupportsSQLitethroughitsJavapackageandroid.database.sqlite.SomeofthekeyclassesyouwillneedtounderstandforeffectivelyusingtheAndroidSQLiteAPIarelistedinListing25-4.Notethatsomeoftheclassesareoutsidetheandroid.database.sqlitepackage.

Listing25-4.KeySQLiteJavaClassesintheAndroidSDK

android.database.sqlite.SQLiteDatabaseandroid.database.sqlite.SQLiteCursorandroid.database.sqlite.SQLiteQueryBuilderandroid.content.ContentValuesandroid.database.Cursorandroid.database.SQLExceptionandroid.database.sqlite.SQLiteOpenHelper

Let’stalkabouteachofthesepackagesandclassesbriefly.

Page 635: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SQLiteDatabase:SQLiteDatabaseisaJavaclassthatrepresentsthedatabaseusuallyreferringtoa“.db”fileonthefilesystem.Usingthisobjectyoucanquery,insert,update,ordeleteforagiventableinthatdatabase.YoucanalsoexecuteasinglearbitrarySQLstatement.Youcanapplytransactions.YoucanalsousethisobjecttodefinetablesthroughDDLs(DataDefinitionLanguage).DDLsarestatementsthatletyoucreatedatabaseentitiessuchastables,views,indexes,etc.Typicallythereisasingleinstanceofthisobjectinyourapplicationrepresentingyourdatabase.

SQLiteCursor:ThisJavaclassrepresentsacollectionofrowsthatarereturnedfromanSQLiteDatabase.Italsoimplementstheandroid.database.Cursorinterface.Thisobjecthasmethodstonavigatetherowsoneatatimelikeaforwarddatabasecursorandretrievingtherowsonlyasneeded.Thisobjectcanalsojumpforwardorbackwardifneededlikearandomcursorbyimplementingwindowingqualities.Thisisalsotheobjectyouwillusetoreadthecolumnvaluesforanycurrentrow.

SQLiteQueryBuilder:ThisisahelperJavaclasstoconstructanSQLitequerystringbyincrementallyspecifyingtablenames,columnnames,whereclause,etc.,asseparatefields.ThisclasshasanumberofsetmethodstograduallybuildupthequeryasopposedtospecifyingtheentireSQLQueryasastring.YoucanalsousethequerymethodsdirectlyontheSQLiteDatabaseclassifyourqueryissimple.

ContentValues:AJavaobjectofthisclassholdsasetofkey/valuepairsthatareusedbyanumberofSQLiteclassestoinsertorupdatearowofdata.

SQLException:MostAndroidSQLitedatabaseAPIsthrowthisexceptionwhenthereareerrors.

SQLiteOpenHelper:ThishelperJavaobjectprovidesaccesstoanSQLiteDatabasebyexaminingafewthings:givenafilenameofthedatabase,thisobjectcheckstoseeifthatdatabaseisalreadyinstalledandavailable.Ifitisavailableitcheckstoseeiftheversionisthesame.IftheversionisalsothesameitprovidesareferencetotheSQLiteDatabaserepresentingthatdatabase.Iftheversionisdifferentitprovidesacallbacktomigratethedatabasepriortoprovidingavalidreferencetothedatabase.Ifthedatabasefiledoesn’texistthenitprovidesacallbacktocreateandpopulatethedatabase.Youwillextendthisbaseclassandprovideimplementationstothesevariouscallbacks.Youwillseethisshortlyintheprovidedcodesnippets.

ThatisaquicksummaryofthekeyclassesyouusetosavestateofyourapplicationinanSQLitedatabase.LetusnowturntokeyconceptsinusingSQLiteformanagingapplicationstate.Let’sstartwithcreatingadatabase.

CreatinganSQLiteDatabaseCreationofadatabaseinAndroidiscontrolledthroughtheSQLiteOpenHelperclass.ForeachdatabaseinyourapplicationyouwillhaveaJavadatabaseobjectthatisaninstanceofthisclass.ThisSQLiteOpenHelperobjecthasapairofgetmethodstogetareferencetotheread-optimized(configuredfor)orwrite-optimized(configuredfor)SQLiteDatabaseobject.CreatingorgettingaccesstoyourSQLitedatabaseobject

Page 636: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

involvesthefollowing:

1. ExtendingSQLiteOpenHelperandsupplyingthedatabasenameandversiontotheconstructorofthisderivedclasssothatthosevaluescanbepassedtothebaseclass

2. OverridingtheonCreate(),onUpgrade(),andonDowngrade()methodsfromSQLiteOpenHelper.YougetacalltoonCreate()ifthisdatabaseisnotthere.YougetacalltoonUpgrade()iftheversionofthedatabaseisnewer,andacalltoonDowngrade()iftheversionofthedatabaseisolderfromtheonethatisonthedevice.YouwilluseexecuteDDLstatementsinthesemethodstocreateoradjustyourdatabase.Ifyourdatabaseisnotneworhasthesameversion,thenneitherofthesecallbackswillbeinvoked.

3. Haveasinglestaticreferencetothisderivedobject.Callgetmethodsonthisobjecttogetareferencetoacopyofreadableorwritabledatabase.UsethesedatabasereferencestoperformCRUDoperationsandtransactions.

Listing25-5isacodesnippetthatdemonstrateshowthesestepsareimplementedincreatingadatabasecalled“booksqlite.db”,adatabasetoholdasingletableofbooksandtheirdetail.

Listing25-5.UsingSQLiteOpenHelper

//Filereferenceinproject:DirectAccessBookDBHelper.Java/***AcompleteexampleofSQLiteOpenHelperdemonstrating*1.Howtocreateadatabases*2.Howtomigrateadatabase*3.Howtoholdastaticreference*4.Howtogiveoutreadandwritedatabasereferences**ThisclassalsocanactasaDatabaseContext.IFactorytoproducereadandwrite*databasereferences.Thisaspectisnotcriticaltounderstandingbutincluded*foradvancedreadersandforsomemateriallaterinthechapter.*/publicclassDirectAccessBookDBHelperextendsSQLiteOpenHelper

implementsDatabaseContext.IFactory{//thereisoneandonlyoneofthesedatabasehelpers//forthisdatabaseforthisentireapplicationpublicstaticDirectAccessBookDBHelperm_self=new

Page 637: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

DirectAccessBookDBHelper(MyApplication.m_appContext);

//NameofthedatabaseonthedeviceprivatestaticfinalStringDATABASE_NAME="bookSQLite.db";

//NameoftheDDLfileyouwanttoloadwhilecreatingadatabaseprivatestaticfinalStringCREATE_DATABASE_FILENAME="create-book-db.sql";

//CurrentversionnumberofthedatabasefortheApptoworkprivatestaticfinalintDATABASE_VERSION=1;

//JustaloggingtagprivatestaticfinalStringTAG="DirectAccessBookDBHelper";

//Passthedatabasenameandversiontothebaseclass//Thisisanonpublicconstructor//Clientscanjustusem_selfandnotconstructthisobjectatalldirectlyDirectAccessBookDBHelper(Contextcontext){

super(context,DATABASE_NAME,null,DATABASE_VERSION);//Initializeanythingelseinyoursystemthatmayneeda//referencetothisobject.//Example:DatabaseContext.initialize(this);}@OverridepublicvoidonCreate(SQLiteDatabasedb){

try{//Nodatabaseexists.LoadDDLfromafileintheassetsdirectoryloadSQLFrom(this.CREATE_DATABASE_FILENAME,db);}catch(Throwablet){//ProblemcreatingdatabasethrownewRuntimeException(t);}}//AfunctiontoloadoneSQLstatementatatimeusingexecSQLmethodprivatevoidloadSQLFrom(StringassetFilename,SQLiteDatabasedb){List<String>statements

Page 638: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

=getDDLStatementsFrom(assetFilename);for(Stringstmt:statements){Log.d(TAG,"ExecutingStatement:"+stmt);db.execSQL(stmt);

}}//Optimizethisfunctionforrobustness.//Fornowitassumestherearenocommentsinthefile//thestatementsareseparatedbyasemicolonprivateList<String>getDDLStatementsFrom(StringassetFilename){ArrayList<String>l=newArrayList<String>();Strings=getStringFromAssetFile(assetFilename);for(Stringstmt:s.split(";")){//Addthestmtifitisavalidstatementif(isValid(stmt)){l.add(stmt);}}returnl;}privatebooleanisValid(Strings){//writelogicheretoseeifitisnull,emptyetc.returntrue;//fornow}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,int

newVersion){

//UseoldandnewversionnumberstorunDDLstatements//toupgradethedatabase}//Usingyourspecificapplicationobjecttoremembertheapplicationcontext//ThenusingthatapplicationcontexttoreadassetsprivateStringgetStringFromAssetFile(Stringfilename){Contextctx=MyApplication.m_appContext;if(ctx==null){thrownewRuntimeException("Sorryyourappcontextisnull");}try{AssetManageram=ctx.getAssets();InputStreamis=am.open(filename);Strings=convertStreamToString(is);is.close();

Page 639: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returns;}catch(IOExceptionx){thrownewRuntimeException("Sorrynotabletoreadfilename:"+filename,x);}}//Optimizelater.ThismaynotbeanefficientreadprivateStringconvertStreamToString(InputStreamis)throwsIOException{ByteArrayOutputStreambaos=newByteArrayOutputStream();inti=is.read();while(i!=-1){baos.write(i);i=is.read();}returnbaos.toString();}//Herearesomeexamplesofhowtogetaccesstoreadableand//writabledatabases.Thesemethodswillmakesenseoncewegetthroughthe//thetransactionsappliedthroughdynamicproxies/*publicReadDatabaseContextcreateReadableDatabase(){returnnewReadDatabaseContext(this.getReadableDatabase());}publicWriteDatabaseContextcreateWritableDatabase(){returnnewWriteDatabaseContext(this.getWritableDatabase());}*/}//eof-classDatabaseHelper//HereisthecodeforMyApplicationtorememberthecontextpublicclassMyApplicationextendsApplication{

publicfinalstaticStringtag="MyApplication";publicstaticvolatileContextm_appContext=null;

@OverridepublicvoidonCreate(){super.onCreate();MyApplication.m_appContext=this.getApplicationContext();}

Page 640: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}//assets/create-book-db.sql

CREATETABLEt_books(idINTEGERPRIMARYKEY,nameTEXT,isbnTEXT,authorTEXT,created_onINTEGER,created_byTEXT,last_updated_onINTEGER,last_updated_byTEXT);

DefiningaDatabaseThroughDDLsInListing25-5,theDirectAccessBookDBHelperisaderivedclassofSQLiteOpenHelperthatallowsustoexamineanexistingdatabaseandseeifitneedstobecreatedorjustmigratedbasedonitsversion.

ThemethodonCreate()iscalledonlyifthisdatabasedoesnotexistonthedevice.WithouttheSQLiteOpenHelperwewouldhavehadtoexaminethephysicallocationofthisfileandseeifitexists.InotherwordsSQLiteOpenHelperisreallyathinwrapperthatissavingusanumberof“if-else”clausestoexaminethedatabaseanddothenecessaryinitialization:beitcreatingitormigratingit.

AnumberofexamplesforcreatinganAndroiddatabaseontheInternetuseembeddedDDLstringsinJavacodetocreatethetablesneeded.AsDDLstatements,stringsinJavacodearedifficulttoreadanderrorprone.Abetterapproachistoputthesedatabasecreationscriptsinatextfileintheassetsdirectory.SamplecodeinListing25-5demonstrateshowtoreadatextfilefromanassetsdirectoryofyourapplicationandusetheexecSQL()functionavailableontheSQLiteDatabasetoinitializethedatabase.

AlimitationofexecSQL()isitcanexecuteonlyoneSQLstatementatatime.ThatiswhythecodeinListing25-5readsthescriptfileandparsesitintoaseriesofstatementsusingasimplesyntax.YoumaywanttoscourtheInternettoseebetterparsingutilitiestoallowabetterscriptfilesupport.Anotheralternative,ifitworksforyourcase,istohaveaschemaclasswhosesolepurposeiscontainstaticpublicstringsforyourDDLasitalleviatestheneedforparsingfiles.WehavelinkstosomeoftheseJava-basedlibrariesintheonlinereferencesprovidedattheendofthischapter.Especially,Java-basedtoolsusingANTLRhavealotofpromiseforcomplexdatabasesetups.

TheonCreate()functionalsowrapsitsexecutioninatransactionsothattheexecuteddatabaseisconsistent.

Ifyouhavealotofscriptsitisalsopossibletocreatethedatabaseentirelyandkeepitintheassetsfolder.Duringdeploymentifthedatabasedoesn’texistyoucanjustcopythefiletoitstargetlocation.

MigratingaDatabaseAsstatedtheSQLiteOpenHelperrecognizesversionnumbersandappropriatelycallstheonUpgrade()methodtoupgradethedatabase.Herealsoyoumaywanttokeepseriesofscriptsintheassetsfolderthatcanalterthedatabaseappropriatelydependingon

Page 641: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thedifferencesintheversionnumbers.Keepinmindthattheversionnumberonthedevicemaybesmallerorlargerthanyourtargetversion.Soyoumayneedasetofscriptsthatareuniquetoeachconversionsequence:GoingfromV1toV3orfromV2toV3orV3toV1.Goingbackwardsmayrequireeitherwarningsordynamicdownloadingofserver-sideconversionstoanolderversion,asthesourcecodeofanolderversionoftheappisunlikelytohavetheneededutilitiestostepdownfromafutureversion.

InsertingRowsAtitscore,insertingarowwithitscolumnvaluesintoSQLiteDatabaseismerelycallingtheinsert-relatedmethodsontheSQLiteDatabaseobject.PseudocodethatexplainsthisisshowninListing25-6.

Listing25-6.BasicsofInsertingaRowUsingSQLiteDatabase

//Getareferencetothedatabaseobject//DependingontheframeworkyouhavetherecouldbemanywaysofdoingthisSQLiteDatatabasedb=DirectAccessBookDBHelper.m_self.getReadableDatabase();Stringtablename;//whichtableyouwanttoinserttherowinto

//populateastructurewiththeneededcolumnsandtheirvaluesContentValuescv=newContentValues();cv.put(columnName1,column1Value);//etc.

//Acolumnthatcouldbenullif'cv'isemptyifanemptyrowisneeded//ProvidenullifthatbehaviorisnotneededStringnullColumnName=null;

//InserttherowlongrowId=db.insertOrThrow(tablename,nullColumnName,cv);

Thiscodeisreallysimple.InsertinganyJavaobjectusingthiscodeismerelyreadingitsattributesandputtingthosevaluesintotheContentValuesdatasetandjustinsert.AsfarasAndroid’sSQLiteinsertcapabilitiesareconcerned,thatisallyouneedtoknow.

HowbesttostructuretogettoyourJavaobjectsandhowtoconvertthosevaluesintothecontentvaluesdependsonyourframework.Thisisatediousprocesstodocorrectly.Butagain,thisdetailisnotessentialforthebasicunderstandingofinsert.Youwillneedthislevelofrigorformostofyourapplications.Youcanskipthisifyouthinkthisiscomplicated,butweareincludingithereaswefeelyouwillneedthislevelofrigorformostofyourapplications.

Sogettingtherightcolumnnamesandvaluesforinsertingrowsrequiressomeworkand

Page 642: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

youtypicallyneedthefollowing(irrespectiveoftheframeworkyouuse):

1. AJavaobjectthattypicallyrepresentstherowinadatabase,forexample,aBookobject

2. Atablenametoholdasetofbooks

3. StringnamesforthecolumnsavailableintheBookstable

4. Finally,callingtheinsertmethodtopersisttheBookobjectasarowintheBookstable

Wewillgivecodesnippets(someinpseudocodefashion)foreachoftheseneeds.Foractualcodeyoucandownloadtheprojectforthischapter.HereareacoupleofclassesinListing25-7thatrepresentaBookobjectinJavacode.

Listing25-7.EnsuringMinimalDependencyBetweenDomainObjectsandPersistence

//Filereferenceinproject:BaseEntity.JavapublicclassBaseEntity{

privateintid;//databaseidentifier

privateStringownedAccount=null;//Multi-tenantifneededprivateStringcreatedBy;privateDatecreatedOn;privateStringlastUpdatedBy;privateDatelastUpdatedOn;

publicBaseEntity(StringownedAccount,StringcreatedBy,DatecreatedOn,StringlastUpdatedBy,DatelastUpdatedOn,intid){super();this.ownedAccount=ownedAccount;this.createdBy=createdBy;this.createdOn=createdOn;this.lastUpdatedBy=lastUpdatedBy;this.lastUpdatedOn=lastUpdatedOn;this.id=id;}//ForpersistencepublicBaseEntity(){}

//Usualgeneratedget/setmethods//eliminatedhereforspace.Seethedownloads}//Filereferenceinproject:Book.JavapublicclassBookextendsBaseEntity

{//Keydatafields

Page 643: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//*************************************privateStringname;privateStringauthor;privateStringisbn;//*************************************

publicBook(StringownedAccount,StringcreatedBy,DatecreatedOn,StringlastUpdatedBy,DatelastUpdatedOn,Stringname,Stringauthor,Stringisbn){super(ownedAccount,createdBy,createdOn,lastUpdatedBy,lastUpdatedOn,-1);this.name=name;this.author=author;this.isbn=isbn;}//TohelpwithpersistencepublicBook(){}//Generatedmethodsgetandsetmethods…//....//Thefollowingmethodisherefortestingpurposes//andalsotoseehowabookobjectistypicallycreatedpublicstaticBookcreateAMockBook(){

StringownedAccount="Account1";StringcreatedBy="satya";DatecreatedOn=Calendar.getInstance().getTime();StringlastUpdatedBy="satya";DatelastUpdatedOn=Calendar.getInstance().getTime();

//SeehowmanybooksIhaveandincrementitbyone//Thefollowingmethodreturnsacollectionofbooksinthedatabase//Thisisnotessentialforyourunderstandinghere//YouwillseethisclarifiedwhenyoureadthesectionoftransactionsList<Book>books=Services.PersistenceServices.bookps.getAllBooks();inti=books.size();Stringname=String.format("Book%s",i);Stringauthor="satya";Stringisbn="isbn-12344-"+i;

returnnewBook(ownedAccount,createdBy,createdOn,lastUpdatedBy,lastUpdatedOn,name,author,isbn);}

Page 644: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}

ThislistinghastwoJavaclasses:aBaseEntityandaBookthatextendstheBaseEntity.ObjectsthatlooklikeaBookinListing25-7arecalleddomainobjects.ThesearepureJavaobjectsthatcanmovearoundintheJavaspaceofyourprogramwithoutbeingburdenedbytheirbehaviorrelatingtopersistence.However,whocreatedtheseobjects,whentheywerecreated,andsuchattributesareencapsulatedintheBaseEntitysothatalldomainobjectshavethisbasicinformation.

BecausetheSQLitedatabasemethodsrequireexplicitcolumnnamesfortheseobjectsthataspectisdefinedinaseparatesetofclassesthatdescribethemetadatafortheseobjects.ThesesupportingclassesaregiveninListing25-8.

Listing25-8.DefiningMetadataforDomainObjects

//Filereferenceinproject:BaseEntitySQLiteSQLiteMetaData.JavapublicclassBaseEntitySQLiteSQLiteMetaData{

staticpublicfinalStringOWNED_ACCOUNT_COLNAME="owned_account";staticpublicfinalStringCREATED_BY_COLNAME="created_by";staticpublicfinalStringCREATED_ON_COLNAME="created_on";staticpublicfinalStringLAST_UPDATED_ON="last_updated_on";staticpublicfinalStringLAST_UPDATED_BY="last_updated_by";staticpublicfinalStringID_COLNAME="id";}//Filereferenceinproject:BookSQLiteSQLiteMetaData.JavapublicclassBookSQLiteSQLiteMetaDataextends

BaseEntitySQLiteSQLiteMetaData{

staticpublicfinalStringTABLE_NAME="t_books";staticpublicfinalStringNAME="name";staticpublicfinalStringAUTHOR="author";staticpublicfinalStringISBN="isbn";}

ThesetwoclassesparalleltheirrespectiveBaseEntityandBookobjectclasses.Youhavetopayattentionthatthecolumnnamesmatchtothoseinthedatabase.Sothisneedisfundamentallyerrorprone.UnlessyouuseanO/Rmappinglibraryandcraftoneofyourown,thisissuewillremainandyouhavetotestwell.ItisdefiningtheseclassesexplicitlybytheprogrammerthatiseliminatedintheO/Rmappingtoolsthatwediscussedearlier.

NowthatwehaveaJavaclasstorepresentabookanditsmetadatadefinition,thattellsusthetablenameandthefieldswecanproceedtowritetheJavacodetosaveabookobjectinthedatabase,asshowninListing25-9(notethatthisisstillpseudocodeandusethedownloadtoseeanymissingdetails).

Page 645: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing25-9.UsingAndroidSQLiteAPIstoInsertaRow

//Filereferenceinproject:BookPSSQLite.JavaprivatelongcreateBook(Bookbook){//Getaccesstoareaddatabase

SQLiteDatabasedb=DirectAccessBookDBHelper.m_self.getWritableDatabase();

//Fillfieldsfromthebookobjectintothecontentvalues

ContentValuesbcv=newContentValues();//....fillotherfieldsexamplebcv.put(BookSQLiteSQLiteMetaData.NAME,book.getName());bcv.put(BookSQLiteSQLiteMetaData.ISBN,book.getIsbn());bcv.put(BookSQLiteSQLiteMetaData.AUTHOR,book.getAuthor());//....fillotherfields

//ifbcvisanemptyset,thenanemptyrowcanpossiblybeinserted.//Itisnotthecaseforourbooktable.Ifitwerethough,theemptybcv//willresultinaninsertstatementwithnocolumnnamesinit.//AtleastonecolumnnameisneededbySQLinsertsyntax.//Itisoneofthesecolumnnamesthatgoesbelow.ForusthisisnotcasesoanullStringnullColumnName=null;

longrowId=db.insertOrThrow(BookSQLiteSQLiteMetaData.TABLE_NAME,

nullColumnName,

bcv);

returnrowId;}

ThelogicinListing25-9isquitesimple.GetareferencetoaBookobjectwewanttosave.CopythefieldvaluesfromthebookintoaContentValueskey/valuepairobject.Usemetadataclassestodefinethefieldnamescorrectly.Usethefilled-inContentValuesobjectandcalltheinsertmethod.Ifwedon’tdoanything,theinsertisencapsulatedinanautocommit.Wewilltalkabouthowtodotransactionsshortly,asthetheoryofitisabitinvolvedalthoughthecodeisquitesimpletowrite.TheinsertmethodreturnsthenewlyinsertedprimarykeyIDforthistable.ThisconventionofreturningtheprimarykeyofthetablecomesfromtheunderlyingSQLiteproductdocumentationandisnotAndroidspecific.

ThenullColumnNameisrelatedtothesyntaxoftheSQLinsertstatement.Iftherowhastencolumnsbutonlytwocolumnsandtheirnon-nullvaluesareindicated,thenanewrowisinsertedwiththosetwocolumns,anditisexpectedthattheremainingeightcolumnswillallownulls.Ifyouwantarowwitheverycolumnasnullitispossibleto

Page 646: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

issueaninsertstatementwithnocolumnnamesatall,matchingtheemptycontentvaluesset.However,aninsertstatementwithnocolumnnamesisnotallowed.SothisparameternullColumnNamecancontainoneofthecolumnnamesthatcouldbenullsothattheinsertstatementsyntaxrequirementissatisfied.Therestofthecolumnswillbemadenullbythedatabaseinternallywhenthisrowisinserted.Usuallythiscolumnnameispassedinasnullbecauseitisrarethatwewanttoinsertarowwhereeverycolumnisemptyornull.

UpdatingRowsListing25-10isasamplepseudocodesnippet(forfullcodeseethedownloadproject)toshowhowtoupdatearowinthedatabase.NoticehowBookobjectandBookSQLiteMetaDataclassesareusedtominimizeerrorsinspecifyingtablenamesandcolumnnames.Theapproachissimilartotheinsertmethod.

Listing25-10.AndroidSQLiteAPItoUpdateaRecord

//Filereferenceinproject:BookPSSQLite.JavapublicvoidupdateBook(Bookbook){

if(book.getId()<0){thrownewSQLException("Bookidislessthan0");}//GetaccesstoareaddatabaseSQLiteDatabasedb=DirectAccessBookDBHelper.m_self.getWritableDatabase();

//FillfieldsfromthebookobjectintothecontentvaluesContentValuesbcv=newContentValues();//....fillotherfieldsbcv.put(BookSQLiteSQLiteMetaData.NAME,book.getName());bcv.put(BookSQLiteSQLiteMetaData.ISBN,book.getIsbn());bcv.put(BookSQLiteSQLiteMetaData.AUTHOR,book.getAuthor());//....fillotherfields

//YoucandothisStringwhereClause=String.format("%s=%s",BookSQLiteSQLiteMetaData.ID_COLNAME,book.getId());StringwhereClauseArgs=null;//Orthenext4lines(thisispreferred)StringwhereClause2=BookSQLiteSQLiteMetaData.ID_COLNAME+"=?";String[]whereClause2Args=newString[1];whereClause2Args[1]=Integer.toString(book.getId());

intcount=db.update(BookSQLiteSQLiteMetaData.TABLE_NAME,bcv,whereClause2,whereClause2Args);if(count==0){

Page 647: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thrownewSQLException(String.format("Failedtoupdatebookforbookid:%s",book.getId()));}}

DeletingRowsListing25-11isanexampleofhowtodeletearowfromthedatabase.

Listing25-11.AndroidSQLiteAPItoDeleteaRecord

//Filereferenceinproject:BookPSSQLite.JavapublicvoiddeleteBook(intbookid){

//GetaccesstoawritabledatabaseSQLiteDatabasedb=DirectAccessBookDBHelper.m_self.getWritableDatabase();

Stringtname=BookSQLiteSQLiteMetaData.TABLE_NAME;StringwhereClause=String.format("%s=%s;",BookSQLiteSQLiteMetaData.ID_COLNAME,bookid);String[]whereClauseargs=null;inti=db.delete(tname,whereClause,whereClauseargs);if(i!=1){thrownewRuntimeException("Thenumberofdeletedbooksisnot1but:"+i);}}

ReadingRowsListing25-12showspseudocodesnippet(forfullcodeseethedownloadproject)toreadfromSQLiteusingtheSQLiteDatabase.query()method.ThismethodreturnsaCursorobject,whichyoucanusetoretrieveeachrow.

Listing25-12.AndroidSQLiteAPItoReadRecords

//Filereferenceinproject:BookPSSQLite.JavapublicList<Book>getAllBooks(){

//GetaccesstoareaddatabaseSQLiteDatabasedb=DirectAccessBookDBHelper.m_self.getReadableDatabase();

Stringtname=BookSQLiteSQLiteMetaData.TABLE_NAME;//Getcolumnnamearrayfromthemetadataclass//(Seethedownloadhowthecolumnnamesaregathered)

Page 648: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//(attheendofthedayitisjustasetofcolumnnamesString[]colnames=BookSQLiteSQLiteMetaData.s_self.getColumnNames();

//SelectionStringselection=null;//allrows.Usuallyawhereclause.excludewherepartString[]selectionArgs=null;//use?sifyouneedit

StringgroupBy=null;//sqlgroupbyclause:excludegroupbypartStringhaving=null;//similarStringorderby=null;StringlimitClause=null;//maxnumberofrows//db.query(tname,colnames)Cursorc=null;

try{c=db.query(tname,colnames,selection,selectionArgs,groupBy,having,orderby,limitClause);//Thismaynotbetheoptimalwaytoreaddatathroughalist//DirectlypassthecursorbackifyourintentistoreadtheseonerowatatimeList<Book>bookList=newArrayList<Book>();for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){Log.d(tag,"Therearebooks");Bookb=newBook();

//..fillbasefieldsthesameway

b.setName(c.getString(c.getColumnIndex(BookSQLiteMetaData.NAME)));

b.setAuthor(c.getString(c.getColumnIndex(BookSQLiteMetaData.AUTHOR)));

b.setIsbn(c.getString(c.getColumnIndex(BookSQLiteMetaData.ISBN)));//..fillotherfields

//OryoucoulddelegatethisworktotheBookSQLiteMetaDataobject//aswehavedoneinthesampledownloadableproject//Ex:BookSQLiteSQLiteMetaData.s_self.fillFields(c,b);

bookList.add(b);}returnbookList;}

Page 649: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

finally{if(c!=null)c.close();}}

HereareafewfactsaboutanAndroidcursorobject:

Acursorisacollectionofrows.

YouneedtousemoveToFirst()beforereadinganydatabecausethecursorstartsoffpositionedbeforethefirstrow.

Youneedtoknowthecolumnnames.

Youneedtoknowthecolumntypes.

Allfield-accessmethodsarebasedoncolumnnumber,soyoumustconvertthecolumnnametoacolumnnumberfirst.Notethatthislookupcanbeoptimized.It’smoreefficienttopopulatethecolumnnamearrayinorderifyouwishtofetchthevaluesandthenuseexplicitconstantindicesonthecursor.

Thecursorisrandom(youcanmoveforwardandbackward,andyoucanjump).

Becausethecursorisrandom,youcanaskitforarowcount.

ApplyingTransactionsSQLitelibrariesonAndroidsupporttransactions.ThetransactionmethodsareavailableontheSQLiteDatabaseclass.Thesemethodsareshowninpseudocodesnippet(forfullcodeseethedownloadproject)inListing25-13.

Listing25-13.SQLiteAPIforTransactions

//Filereferenceinproject:DBServicesProxyHandler.JavapublicvoiddoSomeUpdates(){SQLiteDatabasedb;//Getareferencetothisdatabasethroughhelperdb.beginTransaction();

try{//...callanumberofdatabasemethodsdb.setTransactionSuccessful();

}finally{db.endTransaction();

}}

SummarizingSQLite

Page 650: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IfyouareaJavaprogrammerwithafewyearsofexperience,whatwehavecoveredsofarissufficienttounderstandtheSQLiteAPIinAndroid.Withthematerialcoveredsofar,youknowhowtocheckforadatabase,createadatabasethroughDDL,insertrows,updaterows,deleterows,orreadusingdatabasecursors.WehavealsoshowedyouthebasicAPIfortransactions.However,ifyouarenotanexperiencedhandatJava,databasetransactionsaretrickytoimplementcorrectlyandefficiently.ThenextsectionwilltellyouanAPI-basedpatternusingJavadynamicproxies.

DoingTransactionsThroughDynamicProxiesYoucanvisualizeyourmobileapplicationasacollectionoftwobricks:AnAPIbrickandaUIbrick.TheAPIbrickwillhaveaseriesofstatelessmethodsthatprovidelogicanddatatotheUIbrick.InthiscontextthemethodinListing25-13doSomeUpdates()isconsideredareusableAPIbymanypartsoftheUIorbyotherAPIs.BecauseitisareusableAPItheclientdecideswhethersomethingshouldbecommittedornotcommittedinthattransaction.ThismeanstheAPIshouldnotbedealingwithtransactionsmostofthetime.Itisverymuchlikeastoredprocedureinarelationaldatabase.Astoredprocedurerarelydoestransactionsdirectly.Thecontainerofthestoredproceduredecidestocommitornotcommitexternaltothestoredprocedure.Thelogicisthis:ifthestoredprocedureisinvokedbyitselfthenitsoutputiscommittedatthestoredprocedurelevel.Ifthestoredprocedureiscalledbyanotherstoredprocedurethecommitwaitsuntilthemaininvokingstoredprocedureiscomplete.

ItisbettertousethesamestrategyfortheseAPIsinyourapplicationtoreducethecomplexityinimplementingtheAPIs.ThisisdonebyinterceptingcallstoalltheAPIstomakeadeterminationifthisisadirectcallorbeingcalledbyanotherAPIthatisalreadybeingmonitoredforatransaction.ThereareanumberofwaystointercepttheAPIcallsthatneedtobeintercepted.ThisisalsosometimescalledAspect-OrientedProgrammingorAOP.AOPneedssophisticatedtoolingtodo.Javaprovidesalesssophisticatedbutstraightforwardwaytodothisthroughdynamicproxies.AdynamicproxyisafacilityinJava,basedonJavareflection,thatallowsyoutointerceptcallstoanunderlyingobjectwithouttheobjectbeingawareofit.Whenaclientcallstheobjectthroughthisproxy,theclientthinksitistalkingtotheobjectdirectly.However,theproxycanchoosetoapplyotheraspects(likesecurity,logging,transactions,etc.)beforesendingthecalltotherealobject.Theincludedprojectforthischapterprovidesafullimplementationofadynamicproxythatautomaticallyappliesthetransactionalaspects.

WewillshowyoufirstwhatyourAPIimplementationslooklikeonceadynamicproxyisinplace.Thiswillgiveyouanideaofthesimplicityofthisapproachtotransactionsfirst.Thenyoucanseeifyouwanttotakethisrouteandusedynamicproxies.Aswepresentthecodebelownotethatwewillbeincludingonlysnippetsorsamplesandnottheentirecode.Usethedownloadableprojectforfulldetails.Wehaveannotatedthedownloadprojectwithalotofcommentstohelpyourunderstanding.WiththatcaveatconsidertheAPItoworkwithBook-basedobjects.

Listing25-14.API-BasedInterfacesforWorkingwiththeBookDomainObject

//Filereferenceinproject:IBookPS.Java

Page 651: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicinterfaceIBookPS{publicintsaveBook(Bookbook);publicBookgetBook(intbookid);publicvoidupdateBook(Bookbook);publicvoiddeleteBook(intbookid);publicList<Book>getAllBooks();}

ThisinterfacedefinesoperationsusingJava-basedobjects.Theletters“PS”attheendofIBookPSserviceindicatesthatthisisapersistenceserviceAPIforabook.Listing25-15showsanSQLiteimplementationfortheIBookPS

Listing25-15.ImplementingtheBookAPIsUsingSQLite

//Filereferenceinproject:BookPSSQLite.Java//Themissingclassesinthiscodeareinthedownloadandnotessentialfor//exploringtheidea.//ASQLitePSisaclassthatcontainsreusablecommonmethodslikegettingaccess//tothereadandwritedatabasesusingthesingletondatabasehelper.publicclassBookPSSQLiteextendsASQLitePSimplementsIBookPS{

privatestaticStringtag="BookPSSQLite";@OverridepublicintsaveBook(Bookbook){

//getthedatabase//case:iddoesnotexistinthebookobjectif(book.getId()==-1){//idofthebookdoesn'texistsocreateitreturn(int)createBook(book);}//case:idexistsinbookobjectupdateBook(book);returnbook.getId();}@OverridepublicvoiddeleteBook(intbookid){

SQLiteDatabasedb=getWriteDb();Stringtname=BookSQLiteSQLiteMetaData.TABLE_NAME;StringwhereClause=String.format("%s=%s;",BookSQLiteSQLiteMetaData.ID_COLNAME,bookid);String[]whereClauseargs=null;inti=db.delete(tname,whereClause,whereClauseargs);if(i!=1){thrownewRuntimeException("Thenumberofdeletedbooksisnot1but:"+i);}

Page 652: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}privatelongcreateBook(Bookbook){

//bookdoesn'texist//createitSQLiteDatabasedb=getWriteDb();

ContentValuesbcv=this.getBookAsContentValuesForCreate(book);

//Idon'tneedtoinsertanemptyrow//usuallyanynullablecolumnnamegoeshereifIwanttoinsertanemptyrow.StringnullColumnNameHack=null;//ConstructvaluesfromtheBookobject.SQLExceptionisaruntimeexceptionlongrowId=db.insertOrThrow(BookSQLiteMetaData.TABLE_NAME,nullColumnNameHack,bcv);returnrowId;}@OverridepublicvoidupdateBook(Bookbook){

if(book.getId()<0){thrownewSQLException("Bookidislessthan0");}SQLiteDatabasedb=getWriteDb();ContentValuesbcv=this.getBookAsContentValuesForUpdate(book);StringwhereClause=String.format("%s=%s",BookSQLiteMetaData.ID_COLNAME,book.getId());whereArgs[0]=BookSQLiteMetaData.ID_COLNAME;whereArgs[1]=Integer.toString(book.getId());

intcount=db.update(BookSQLiteMetaData.TABLE_NAME,bcv,whereClause,null);if(count==0){thrownewSQLException(String.format("Failedtoupdatebookforbookid:%s",book.getId()));}}privateContentValuesgetBookAsContentValuesForUpdate(Bookbook){

ContentValuescv=newContentValues();//Followingcodeloadscolumnvaluesfrombookobjecttothecv//SeethedownloadableprojectforthemechanicsofitBookSQLiteMetaData.s_self.fillUpdatableColumnValues(cv,book);

Page 653: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returncv;}privateContentValuesgetBookAsContentValuesForCreate(Bookbook){

ContentValuescv=newContentValues();BookSQLiteMetaData.s_self.fillAllColumnValues(cv,book);returncv;}@OverridepublicList<Book>getAllBooks(){

SQLiteDatabasedb=getReadDb();Stringtname=BookSQLiteMetaData.TABLE_NAME;String[]colnames=BookSQLiteMetaData.s_self.getColumnNames();

//SelectionStringselection=null;//allrows.Usuallyawhereclause.excludewherepartString[]selectionArgs=null;//use?sifyouneedit

StringgroupBy=null;//sqlgroupbyclause:excludegroupbypartStringhaving=null;//similarStringorderby=null;StringlimitClause=null;//maxnumberofrows//db.query(tname,colnames)Cursorc=null;

try{c=db.query(tname,colnames,selection,selectionArgs,groupBy,having,orderby,limitClause);//Thismaynotbetheoptimalwaytoreaddatathroughalist//DirectlypassthecursorbackifyourintentistoreadtheseonerowatatimeList<Book>bookList=newArrayList<Book>();for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){Log.d(tag,"Therearebooks");Bookb=newBook();BookSQLiteMetaData.s_self.fillFields(c,b);bookList.add(b);}returnbookList;}finally{if(c!=null)c.close();}

Page 654: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}@OverridepublicBookgetBook(intbookid){

SQLiteDatabasedb=getReadDb();Stringtname=BookSQLiteMetaData.TABLE_NAME;String[]colnames=BookSQLiteMetaData.s_self.getColumnNames();

//SelectionStringselection=String.format("%s=%s",BookSQLiteMetaData.ID_COLNAME,bookid);//allrows.Usuallyawhereclause.excludewherepartString[]selectionArgs=null;//use?sifyouneedit

StringgroupBy=null;//sqlgroupbyclause:excludegroupbypartStringhaving=null;//similarStringorderby=null;StringlimitClause=null;//maxnumberofrows//db.query(tname,colnames)Cursorc=db.query(tname,colnames,selection,selectionArgs,groupBy,having,orderby,limitClause);try{if(c.isAfterLast()){Log.d(tag,"Norowsforid"+bookid);returnnull;}Bookb=newBook();BookSQLiteMetaData.s_self.fillFields(c,b);returnb;}finally{c.close();}}}//eof-class

NoticehowtheimplementationoftheBookpersistenceAPIdoesnotdirectlydealwiththetransactionalaspectsofthesemethods.Instead,thetransactionsarehandledbyJavadynamicproxy,whichwewillshowshortly.Listing25-16showshowaclientcanseetheseAPIsandinvokethesepersistenceAPIsindirectly(again,pleaserefertothedownloadprojectsforclassesthatarereferencedinthiscodebutnotlistedhereastheyarenotessentialforunderstanding).

Listing25-16.ClientAccesstoAPI-BasedServices

//Filereferenceinproject:SQLitePersistenceTester.Java

Page 655: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//BaseTesterisjustahelperclasstoprovidercommonfunctionality//itimplementssomeloggingandreportbackmethodstotheUIactivitypublicclassSQLitePersistenceTesterextendsBaseTester{

privatestaticStringtag="SQLitePersistenceTester";//Servicesisastaticclassthatprovidesaccesstopersistenceservices//ServicesclassprovidesvisibilitytotheimplementeroftheIBookPS//Itdemonstrateshowaclientgetsaccesstothenamespaceofservices//Youwillshortlyseewhatthisclassis.Understandtheintentfirst.privateIBookPSbookPersistenceService

=Services.PersistenceServices.bookps;

//IReportBackisalogginginterfacetoreportloggableeventsbacktotheUI//UIwillthenchoosetologthoseeventsandalsoshowontheactivityscreen.SQLitePersistenceTester(Contextctx,IReportBacktarget){super(ctx,target,tag);}

//Addabookwhoseidisonelargerthanthebooks//inthedatabasepublicvoidaddBook(){

Bookbook=Book.createAMockBook();intbookid=bookPersistenceService.saveBook(book);

reportString(String.format("Insertedabook%swhosegeneratedidnowis%s",book.getName(),bookid));}//DeletethelastbookpublicvoidremoveBook(){List<Book>bookList=bookPersistenceService.getAllBooks();if(bookList.size()<=0){reportString("Therearenobooksthatcanbedeleted");return;}reportString(String.format("Thereare%sbooks.Firstonewillbedeleted",bookList.size()));

Page 656: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Bookb=bookList.get(0);bookPersistenceService.deleteBook(b.getId());reportString(String.format("Bookwithid:%ssuccessfullydeleted",b.getId()));}

//writethelistofbookssofartothescreenpublicvoidshowBooks(){

List<Book>bookList=bookPersistenceService.getAllBooks();

reportString(String.format("Numberofbooks:%s",bookList.size()));for(Bookb:bookList){reportString(String.format("id:%sname:%sauthor:%sisbn:%s",b.getId(),b.getName(),b.getAuthor(),b.getIsbn()));}}

//CountthenumberofbooksinthedatabaseprivateintgetCount(){

List<Book>bookList=bookPersistenceService.getAllBooks();

returnbookList.size();}}

InListing25-16,noticehowsimpleitistoaccesstheAPIsthroughthestaticclassServices.Ofcoursewehaven’tshownyoutheimplementationofServicesandalsothedynamicproxyheldbythestaticclassServices.Listing25-17showsthesourcecodeforthestaticServicesclassinordertogiveyouanideaofhowthisschemeworks.Thegoalofmany,ifnotall,ofthelistingsinthischapteristoaidyourunderstanding.Forcompletecompilablesourcecodewekindlyrequestthatyourefertothedownloadableprojectsforthischapter.

Listing25-17.ExposingAPIstoClientsThroughaServicesNameSpace

//Filereferenceinproject:Services.Java/***Allowanamespaceforclientstodiscovervariousservices*Usage:Services.persistenceServices.bookps.addBook();etc.

*Dynamicproxywilltakecareoftransactions.*Dynamicproxywilltakecareofmockdata.*DynamicProxywillallowmorethanoneinterface*toapplytheaboveaspects.*/

Page 657: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicclassServices{

publicstaticStringtag="Services";publicstaticclassPersistenceServices{

////sethispointerduringinitializationpublicstaticIBookPSbookps=null;

static{Services.init();}}//Althoughthismethodisempty,callingit//willtriggerallstaticinitializationcodeforthisclasspublicstaticvoidinit(){}privatestaticObjectmainProxy;static{//Autilityclasstocompilealldatabase-relatedinitializationssofar//Getsthedatabasehelpergoing.//SeethedownloadprojecthowitusestheconceptspresentedsofartodothisDatabase.initialize();

//setupbookpsClassLoadercl=IBookPS.class.getClassLoader();//AddmoreinterfacesasavailableClass[]variousServiceInterfaces=newClass[]{IBookPS.class};

//Createabigobjectthatcanproxyalltherelatedinterfaces//forwhichsimilarcommonaspectsareapplied//InthiscasesitisandroidSQLitetransactionsmainProxy=Proxy.newProxyInstance(cl,

variousServiceInterfaces,newDBServicesProxyHandler());

//PresetthenamespaceforeasydiscoveryPersistenceServices.bookps=(IBookPS)mainProxy;}}

NoticehowDBServicesProxyHandlerisaproxyfortheimplementationofIBookPS.Whencalledbyclients,theDBServicesProxyHandlerthencallstheactualimplementationforIBookPS.TheactualimplementationofIBookPSisshowninListing25-15.Let’sturntotheimplementationofthedynamicproxyinListing25-18.SomeofthecodeandclassesreferencedinListing25-18areonlyavailableinthedownloadableprojects.However,thatshouldnothinderthegeneralunderstandingofthearchitectureofthedynamicproxy.

Page 658: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing25-18.JavaDynamicProxytoWraptheSQLiteAPIImplementations

//Filereferenceinproject:DBServicesProxyHandler.Java/***DBServicesProxyHandler:AclasstoexternalizeSQLiteTransactions.*Itisadynamicproxy.SeeServices.Javatoseehowareferencetothisisused.**Thisproxyiscapableofhostingmultiplepersistenceinterfaces.*Eachinterfacemayrepresentpersistenceaspectsofaparticularentityoradomainobject*likeaBook.Ortheinterfacecanbeacompositeinterfacedealingwithmultipleentities.**ItalsousesThreadLocalstopasstheDatabaseContext*DatabaseContextholdsareferencetothedatabasethatisonthisthread*Italsoknowshowtoapplytransactionstothatdatabase*Italsoknowsifthecurrentthreadalsohasarunningtransaction*@SeeDatabaseContext**DatabaseContextprovidestheSQLiteDatabasereferenceto*theimplementationclasses.**Relatedclasses******************Services.Java:Clientaccesstointerfaces*IBookPS:ClientinterfacetodealwithpersistingaBook*BookPSSQLite:SQLiteImplementationofIBookPS**DBServicesProxyHandler:Thisclassthatisadynamicproxy*DatabaseContext:HoldsadbreferenceforBookPSSQLiteimplementation*DirectAccessBookDBHelper:AndroidDBHelpertoconstructthedatabase**/publicclassDBServicesProxyHandlerimplementsInvocationHandler{

privateBookPSSQLitebookServiceImpl=newBookPSSQLite();privatestaticStringtag="DBServicesProxyHandler";DBServicesProxyHandler(){}publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)

Page 659: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

throwsThrowable{logMethodSignature(method);Stringmname=method.getName();if(mname.startsWith("get")){returnthis.invokeForReads(method,args);}else{returnthis.invokeForWrites(method,args);}}privatevoidlogMethodSignature(Methodmethod){

StringinterfaceName=method.getDeclaringClass().getName();Stringmname=method.getName();Log.d(tag,String.format("%s:%s",interfaceName,mname));}privateObjectcallDelegatedMethod(Methodmethod,Object[]args)

throwsThrowable{returnmethod.invoke(bookServiceImpl,args);}privateObjectinvokeForReads(Methodmethod,Object[]args)throws

Throwable{

//SeecommentsaboveaboutDatabaseContextif(DatabaseContext.isItAlreadyInsideATransaction()==true){//ItisalreadyboundreturninvokeForReadsWithoutATransactionalWrap(method,args);}else{//AnewtransactionreturninvokeForReadsWithATransactionalWrap(method,args);}

}privateObjectinvokeForReadsWithATransactionalWrap(Methodmethod,

Object[]args)

throwsThrowable{try{DatabaseContext.setReadableDatabaseContext();returncallDelegatedMethod(method,args);}finally{DatabaseContext.reset();}

Page 660: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}privateObjectinvokeForReadsWithoutATransactionalWrap(Methodmethod,

Object[]args)

throwsThrowable{returncallDelegatedMethod(method,args);}privateObjectinvokeForWrites(Methodmethod,Object[]args)throws

Throwable{

if(DatabaseContext.isItAlreadyInsideATransaction()==true){//ItisalreadyboundreturninvokeForWritesWithoutATransactionalWrap(method,args);}else{//AnewtransactionreturninvokeForWritesWithATransactionalWrap(method,args);}}privateObjectinvokeForWritesWithATransactionalWrap(Methodmethod,

Object[]args)

throwsThrowable{try{DatabaseContext.setWritableDatabaseContext();DatabaseContext.beginTransaction();ObjectrtnObject=callDelegatedMethod(method,args);DatabaseContext.setTransactionSuccessful();returnrtnObject;}finally{try{DatabaseContext.endTransaction();}finally{DatabaseContext.reset();}}}privateObjectinvokeForWritesWithoutATransactionalWrap(Methodmethod,

Object[]args)

throwsThrowable{returncallDelegatedMethod(method,args);}}//eof-class

ThiscodeinListing25-18isthedynamicproxyimplementation.Wehavenotincludedallthedetailsbutsufficientdetailisheretounderstandhowthisdynamicproxyperforms

Page 661: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

transactionsinanautomatedaspect-orientedway.Itexaminesthecalledmethodnamethroughreflectiontoseeifthemethodnamestartswith“get,”andifsothenitassumesthemethoddoesn’tneedatransactionalcontext.Otherwiseitmarksthecurrentthreadasatransactionalcontext.Atthereturnofthemethoditcompletesthetransactionassuccessful.Ifthereareothermethodscalledinbetween,thedynamicproxyknowsfromthethreadthatthereisatransactioninplaceandhenceignoresthatmethodfromatransactionalaspectperspective.

Nowbasedonyourneedyoumaywanttoalterthisprotocolbasedonannotationsorsomeotheraspectofyourinterfaces,butyougettheidea.ThisapproachofseparatingAPIsfromyourUIisgooddesignandyoucanuseanynumberofpersistentstoreswithoutchangingyourclientUIcode.Westronglyrecommendthatyouadaptthisapproachirrespectiveofthepersistencemechanismyouuse,includingtheO/Rmappingtools.

ExploringDatabasesontheEmulatorandAvailableDevicesAsyouuseSQLiteasyourpersistencemechanismeitherdirectlyorthroughcontentproviders(nextsection),youmaywanttoexaminetheresultingdatabasefilesonthedevicefordebuggingpurposes.

ThedatabasefilescreatedbySQLiteAPIarekeptinthefollowingdirectory:

/data/data/<fully-qualified-package-name>/databases

YoucanuseEclipseAndroidfileexplorertolocatethedirectoryandcopythefilestoyourlocaldriveandusenativeSQLitetoolsprovidedbySQLitedirectlytoseeandmanipulatethatdatabase.

YoucanalsousetoolsprovidedbothbyAndroidandbySQLitetoexaminethesedatabases.Manyofthesetoolsresideinthe\<android-sdk-install-directory>\toolssubdirectory;othersarein\<android-sdk-install-directory>\platform-tools.

Someusefulcommandsfromthesedirectoriesare

androidlistavd:ToseealistofAVDsoremulatorsemulator.exe@avdname:Tostartanemulatorwithagivennameadb.exedevices:Toseethedevicesoremulatorsadbshell:Toopenashellontheemulatorordevice

Youcanusethefollowingcommandsfroman“adbshell.”Thesewillworkontheemulatorbutonarealdeviceyouwillneedrootaccess.

ls/system/bin:Toseeavailablecommandsls-l/:Rootleveldirectoriesls/data/data/com.android.providers.contacts/databases:anexample

Page 662: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ls-R/data/data/*/databases:Toseealldatabasesonthedeviceoremulator

IftherewereafindcommandintheincludedAndroidUnixshell,youcouldlookatallthe*.dbfiles.Butthereisnogoodwaytodothiswithlsalone.Thenearestthingyoucandoisthis:

ls-R/data/data/*/databases

Withthiscommand,youwillnoticethattheAndroiddistributionhasthedatabasesshowninListing25-19(dependingonyourrelease,thislistmayvary):

Listing25-19.AFewSampleDatabases

alarms.dbcontacts.dbdownloads.dbinternal.dbsettings.dbmmssms.dbtelephony.db

Youcaninvokesqlite3ononeofthesedatabasesinsidetheadbshellbytypingthis:

sqlite3/data/data/com.android.providers.contacts/databases/contacts.db

Youcanexitsqlite3bytypingthis:

sqlite>.exit

Noticethatthepromptforadbis#andthepromptforsqlite3issqlite>.Thesepromptscouldbedifferentdependingonthedevice.Youcanreadaboutthevarioussqlite3commandsbyvisitingwww.sqlite.org/sqlite.html.However,wewilllistafewimportantcommandsheresoyoudon’thavetomakeatriptotheWeb.Youcanseealistoftablesbytyping

sqlite>.tables

Thiscommandisashortcutforqueryingonthesqlite_mastertableasshowninListing25-20(formatandstructureoftheresultingoutputmayvary).

Listing25-20.UsingSQLitesqlite_masterTable

SELECTnameFROMsqlite_masterWHEREtypeIN('table','view')ANDnameNOTLIKE'sqlite_%'UNIONALLSELECTnameFROMsqlite_temp_masterWHEREtypeIN('table','view')ORDERBY1

Page 663: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Thetablesqlite_masterisamastertablethatkeepstrackoftablesandviewsintheSQLitedatabase.Thefollowingcommandlinedisplaysacreatestatementforatablecalledpeopleincontacts.db(assumingthisdatabaseexistsonyourdevice):

.schemapeople

ThisisonewaytogetatthecolumnnamesofatableinSQLite.Thiswillalsoshowthecolumndatatypes.Whileworkingwithcontentproviders,youshouldnotethesecolumntypesbecauseaccessmethodsdependonthem.Alsonotethatthismaynotbeapracticalwaytoseethesedatabasesasyoumaynothaveaccesstothemonrealdevices.Inthatcaseyouhavetorelyonthedocumentationprovidedbythecontentprovider.

YoucanissuethefollowingcommandfromyourOScommandprompttopulldownthecontacts.dbfiletothelocalfilesystem:

adbpull/data/data/com.android.providers.contacts/databases/contacts.dbÉc:/somelocaldir/contacts.db

ThesampleSQLstatementsinListing25-21couldhelpyounavigatethroughanSQLitedatabasequickly(alternativelyyoucanuseanythird-partySQLitebrowsertool):

Listing25-21.SampleSQLCodeforSQLite

--Setthecolumnheaderstoshowinthetoolsqlite>.headerson

--selectallrowsfromatableselect*fromtable1;

--countthenumberofrowsinatableselectcount(*)fromtable1;

--selectaspecificsetofcolumnsselectcol1,col2fromtable1;

--Selectdistinctvaluesinacolumnselectdistinctcol1fromtable1;

--countingthedistinctvaluesselectcount(col1)from(selectdistinctcol1fromtable1);

--groupbyselectcount(*),col1fromtable1groupbycol1;

--regularinnerjoinselect*fromtable1t1,table2t2wheret1.col1=t2.col1;

Page 664: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

--leftouterjoin--Givemeeverythingint1eventhoughtherearenorowsint2select*fromtablet1leftouterjointable2t2ont1.col1=t2.col1where….

ExploringContentProvidersEarlierinthechapterwetoucheduponcontentproviderstosharedatabetweenapplications.Contentprovidersasstatedarewrappersaroundadatastore.Thedatastorescouldbelocalorremote.ThedatastoresareusuallySQLitedatabasesonthelocaldevice.

Toretrievedatafromacontentproviderorsavedataintoacontentprovider,youwilluseasetofREST-likeURIs.Forexample,ifyouweretoretrieveasetofbooksfromacontentproviderthatisanencapsulationofabookdatabase,youmightneedtouseaURIlikethis:

content://com.android.book.BookProvider/books

Toretrieveaspecificbookfromthebookdatabase(likesaybook23),youmightuseaURIlikethis:

content://com.android.book.BookProvider/books/23

YouwillseeinthischapterhowtheseURIstranslatetounderlyingdatabase-accessmechanisms.AnyapplicationwiththeappropriateaccesspermissionsonthedevicecanmakeuseoftheseURIstoaccessandmanipulatedata.

ExploringAndroid’sBuilt-inProvidersAndroidcomeswithanumberofbuilt-incontentproviders,whicharedocumentedintheSDK’sandroid.providerJavapackage.Youcanviewthelistoftheseprovidershere:

http://developer.android.com/reference/android/provider/package-summary.html

Theprovidersinclude,forexample,ContactsandMediaStore.TheseSQLitedatabasestypicallyhaveanextensionof.dbandareaccessibleonlyfromtheimplementationpackage.Anyaccessoutsidethatpackagemustgothroughthecontent-providerinterface.Youcanusetheprevioussection“ExploringDatabasesontheEmulatorandAvailableDevices”toexplorethedatabasefilescreatedbybuilt-inprovidersontheemulator.Onrealdevicesthisisnotfeasibleunlessofcourseyouhaverootaccessonthedevice.

UnderstandingtheStructureofContentProvider

Page 665: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

URIsEachcontentprovideronadeviceisregisteredintheAndroidmanifestfilelikeawebsitewithastringidentifiercalledanauthority(akintoadomainname).Listing25-22hastwoexamplesofthisregistration:

Listing25-22.ExampleofRegisteringaProvider

<!--Filereferenceinproject:AndroidManifest.xml--><providerandroid:name="SomeProviderJavaClass"android:authorities="com.your-company.SomeProvider"/>

<providerandroid:name="BookProvider"

android:authorities="com.androidbook.provider.BookProvider"/>

TheuniqueauthoritystringformsthebasisofasetofURIsthatthiscontentprovideroffers.AnAndroidcontentURIhasthefollowingstructure:

content://<authority-name>/<path-segment1>/<path-segment2>/etc…

Here’sanexampleURIthatidentifiesabooknumbered23inadatabaseofbooks:

content://com.androidbook.provider.BookProvider/books/23

Aftercontent:,theURIcontainstheauthority,whichisusedtolocatetheproviderintheproviderregistry.Intheprecedingexample,com.androidbook.provider.BookProvideristheauthorityportionoftheURI.

/books/23isthepathsectionoftheURIthatisspecifictoeachprovider.Thebooksand23portionsofthepathsectionarecalledpathsegments.ItistheresponsibilityoftheprovidertodocumentandinterpretthepathsectionandpathsegmentsoftheURIs.HencecontentprovidersprovidetheseREST-likeURLstoretrieveormanipulatedata.Fortheprecedingregistration,theURItoidentifyadirectoryoracollectionofbooksinthebooksdatabaseis

content://com.androidbook.provider.BookProvider/books

TheURItoidentifyaspecificnoteis

content://com.androidbook.provider.BookProvider/books/#

where#istheidofaparticularnote.Listing25-23showsadditionalexamplesofURIsthatsomedataprovidersonAndroidaccept:

Listing25-23.FewSampleAndroidContentURLs

content://media/internal/images

Page 666: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

content://media/external/imagescontent://contacts/people/content://contacts/people/23

Noticehowtheseproviders’media(content://media)andcontacts(content://contacts)don’thaveafullyqualifiedauthorityname.ThisisbecauseprovidersofferedbyAndroidmaynotcarryafullyqualifiedauthorityname.

GiventhesecontentURIs,aproviderisexpectedtoretrieverowsthattheURIsrepresent.TheproviderisalsoexpectedtoaltercontentatthisURIusinganyofthestate-changemethods:insert,update,ordelete.

ImplementingContentProvidersLet’sfullyunderstandcontentprovidersbyimplementingandusingone.Towriteacontentprovider,youhavetoextendandroid.content.ContentProviderandimplementthefollowingkeymethods:query(),insert(),update(),delete(),andgetType().

You’llneedtosetupanumberofthingsforimplementingthesemethods.Implementingacontentproviderneedsthefollowingsteps:

1. Planyourdatabase,URIs,columnnames,andsoon,andcreateametadataclassthatdefinesconstantsforallofthesemetadataelements.

2. ExtendtheabstractclassContentProvider.

3. Implementthesemethods:query,insert,update,delete,andgetType.

4. Registertheproviderinthemanifestfile.

5. Usethecontentprovider.

PlanningaDatabaseToexplorethistopic,we’llcreateadatabasesimilartotheonethatwehaveusedforthebookcollectionthatwasusedtoillustratethestoringofdatainSQLitedirectly.Notethattokeepthedatabasesfromconflictingwitheachothersomeofthenamesmaybedifferent.

Thebookdatabasecontainsonlyonetablecalledbooks,anditscolumnsarename,isbn,andauthor.Thesecolumnnamesfallundermetadata.You’lldefinethissortofrelevantmetadatainaJavaclass.Thismetadata-bearingJavaclassBookProviderMetaDataisshowninListing25-24.

Listing25-24.DefiningMetadataforYourDatabase

//Filereferenceinproject:BookProviderMetaData.Java

Page 667: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicclassBookProviderMetaData{

publicstaticfinalStringAUTHORITY="com.androidbook.provider.BookProvider";

publicstaticfinalStringDATABASE_NAME="book.db";publicstaticfinalintDATABASE_VERSION=1;publicstaticfinalStringBOOKS_TABLE_NAME="books";

privateBookProviderMetaData(){}

//innerclassdescribingBookTablepublicstaticfinalclassBookTableMetaDataimplementsBaseColumns{privateBookTableMetaData(){}publicstaticfinalStringTABLE_NAME="books";

//uriandMIMEtypedefinitionspublicstaticfinalUriCONTENT_URI=Uri.parse("content://"+AUTHORITY+"/books");publicstaticfinalStringCONTENT_TYPE=

"vnd.android.cursor.dir/vnd.androidbook.book";publicstaticfinalStringCONTENT_ITEM_TYPE="vnd.android.cursor.item/vnd.androidbook.book";

publicstaticfinalStringDEFAULT_SORT_ORDER="modifiedDESC";

//AdditionalColumnsstarthere.//stringtypepublicstaticfinalStringBOOK_NAME="name";//stringtypepublicstaticfinalStringBOOK_ISBN="isbn";//stringtypepublicstaticfinalStringBOOK_AUTHOR="author";//IntegerfromSystem.currentTimeMillis()publicstaticfinalStringCREATED_DATE="created";//IntegerfromSystem.currentTimeMillis()publicstaticfinalStringMODIFIED_DATE="modified";}}

ThisBookProviderMetaDataclassstartsbydefiningitsauthoritytobecom.androidbook.provider.BookProvider.

Thisclassthenproceedstodefineitsonetable(books)asaninnerBookTableMetaDataclass.TheBookTableMetaDataclassthendefinesaURIfor

Page 668: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

identifyingacollectionofbooks.Giventheauthorityinthepreviousparagraph,theURIforacollectionofbookswilllooklikethis:

content://com.androidbook.provider.BookProvider/books

ThisURIisindicatedbytheconstant

BookProviderMetaData.BookTableMetaData.CONTENT_URI

TheBookTableMetaDataclassthenproceedstodefinetheMIMEtypesforacollectionofbooksandasinglebook.TheproviderimplementationwillusetheseconstantstoreturntheMIMEtypesfortheincomingURIs.MIMEtypesaresimilartotheMIMEtypesdefinedbyHTTP.AsaguidelinetheprimaryMIMEtypeforacollectionofitemsreturnedthroughanAndroidcursorshouldalwaysbevnd.android.cursor.dir,andtheprimaryMIMEtypeofasingleitemretrievedthroughanAndroidcursorshouldbevnd.android.cursor.item.Youhavemorewiggleroomwhenitcomestothesubtype,asinvnd.androidbook.bookinListing25-24.

BookTableMetaDatathendefinesthesetofcolumnsforthebooktable:name,isbn,author,created(creationdate),andmodified(last-updateddate).

ThemetadataclassBookTableMetaDataalsoinheritsfromtheBaseColumnsclassthatprovidesthestandard_idfield,whichrepresentstherowID.Withthesemetadatadefinitionsinhand,we’rereadytotackletheproviderimplementation.

ExtendingContentProviderImplementingtheBookProviderinvolvesextendingtheContentProviderclassandoverridingonCreate()tocreatethedatabaseandthenimplementthequery,insert,update,delete,andgetTypemethods.

Aquerymethodrequiresthesetofcolumnsitneedstoreturn.Thisissimilartoaselectclausethatrequirescolumnnamesalongwiththeirascounterparts(sometimescalledsynonyms).AsaconventionAndroidSDKusesamapobjectthatitcallsaprojectionmaptorepresentthesecolumnnamesandtheirsynonyms.Wewillneedtosetupthismapsowecanuseitlaterinthequery-methodimplementation.Inthecodefortheproviderimplementation(seeListing25-26),youwillseethisdoneupfrontaspartofprojectionmapsetup.

Mostofthemethodswe’llbeimplementingforthecontentprovidercontracttakeaURIasaninput.Listing25-25showsbookproviderURIexamples:

Listing25-25.ExamplesofBookProviderContentURIs

Uri1:content://com.androidbook.provider.BookProvider/booksUri2:content://com.androidbook.provider.BookProvider/books/12

Page 669: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThebookproviderneedstodistinguisheachoftheseURIs.BookProviderisasimplecase.Ifourbookproviderhadbeenhousingmoreobjectsinadditiontojustbooks,thentherewouldbemoreURIstoidentifythoseadditionalobjects.

TheproviderimplementationneedsamechanismtodistinguishoneURIfromtheother;AndroidusesaclasscalledUriMatcherforthispurpose.SoweneedtosetupthisobjectwithallourURIvariations.YouwillseethiscodeinListing25-26rightafterwedefinetheprojectionmap.We’llfurtherexplaintheUriMatcherclassinthesection“UsingUriMatchertoFigureOuttheURIs.”

ThecodeinListing25-26thenoverridestheonCreate()methodtofacilitatethedatabasecreation.ThedatabasecreationisidenticaltothedatabasecreationwehavecoveredaspartofusingSQLitedirectlyforinternalpersistenceneeds.

ThesourcecodeinListing25-26thenimplementstheinsert(),query(),update(),getType(),anddelete()methods.ThecodeforallofthisispresentedtogetherinListing25-26,butwewillexplaineachaspectinaseparatesubsection.

Listing25-26.ImplementingtheBookProviderContentProvider

//Filereferenceinproject:BookProvider.JavapublicclassBookProviderextendsContentProvider{//Logginghelpertag.Nosignificancetoproviders.privatestaticfinalStringTAG="BookProvider";

//SetupprojectionMap//Projectionmapsaresimilarto"as"(columnalias)construct//inansqlstatementwherebyyoucanrenamethe//columns.privatestaticHashMap<String,String>sBooksProjectionMap;

static{sBooksProjectionMap=newHashMap<String,String>();sBooksProjectionMap.put(BookTableMetaData._ID,BookTableMetaData._ID);

//name,isbn,authorsBooksProjectionMap.put(BookTableMetaData.BOOK_NAME,BookTableMetaData.BOOK_NAME);sBooksProjectionMap.put(BookTableMetaData.BOOK_ISBN,BookTableMetaData.BOOK_ISBN);sBooksProjectionMap.put(BookTableMetaData.BOOK_AUTHOR,BookTableMetaData.BOOK_AUTHOR);

//createddate,modifieddatesBooksProjectionMap.put(BookTableMetaData.CREATED_DATE,BookTableMetaData.CREATED_DATE);

Page 670: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

sBooksProjectionMap.put(BookTableMetaData.MODIFIED_DATE,BookTableMetaData.MODIFIED_DATE);}

//Provideamechanismtoidentifyalltheincominguripatterns.

privatestaticfinalUriMatchersUriMatcher;privatestaticfinalintINCOMING_BOOK_COLLECTION_URI_INDICATOR=1;privatestaticfinalintINCOMING_SINGLE_BOOK_URI_INDICATOR=2;static{sUriMatcher=newUriMatcher(UriMatcher.NO_MATCH);sUriMatcher.addURI(BookProviderMetaData.AUTHORITY,"books",INCOMING_BOOK_COLLECTION_URI_INDICATOR);sUriMatcher.addURI(BookProviderMetaData.AUTHORITY,"books/#",INCOMING_SINGLE_BOOK_URI_INDICATOR);

}//Setup/CreateDatabasetousefortheimplementationprivatestaticclassDatabaseHelperextendsSQLiteOpenHelper{

DatabaseHelper(Contextcontext){super(context,BookProviderMetaData.DATABASE_NAME,null,BookProviderMetaData.DATABASE_VERSION);}@OverridepublicvoidonCreate(SQLiteDatabasedb){Log.d(TAG,"inneroncreatecalled");db.execSQL("CREATETABLE"+BookTableMetaData.TABLE_NAME+"("+BookTableMetaData._ID+"INTEGERPRIMARYKEY,"+BookTableMetaData.BOOK_NAME+"TEXT,"+BookTableMetaData.BOOK_ISBN+"TEXT,"+BookTableMetaData.BOOK_AUTHOR+"TEXT,"+BookTableMetaData.CREATED_DATE+"INTEGER,"+BookTableMetaData.MODIFIED_DATE+"INTEGER"+");");}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){

Page 671: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Log.d(TAG,"inneronupgradecalled");Log.w(TAG,"Upgradingdatabasefromversion"+oldVersion+"to"+newVersion+",whichwilldestroyallolddata");db.execSQL("DROPTABLEIFEXISTS"+BookTableMetaData.TABLE_NAME);onCreate(db);}}//eof-innerDatabaseHelperclass//ThisisinitializedintheonCreate()methodprivateDatabaseHelpermOpenHelper;

//Componentcreationcallback@OverridepublicbooleanonCreate(){

Log.d(TAG,"mainonCreatecalled");mOpenHelper=newDatabaseHelper(getContext());returntrue;}

@OverridepublicCursorquery(Uriuri,String[]projection,Stringselection,

String[]selectionArgs,StringsortOrder){SQLiteQueryBuilderqb=newSQLiteQueryBuilder();

switch(sUriMatcher.match(uri)){caseINCOMING_BOOK_COLLECTION_URI_INDICATOR:qb.setTables(BookTableMetaData.TABLE_NAME);qb.setProjectionMap(sBooksProjectionMap);break;

caseINCOMING_SINGLE_BOOK_URI_INDICATOR:qb.setTables(BookTableMetaData.TABLE_NAME);qb.setProjectionMap(sBooksProjectionMap);qb.appendWhere(BookTableMetaData._ID+"="+uri.getPathSegments().get(1));break;

default:thrownewIllegalArgumentException("UnknownURI"+uri);}

//IfnosortorderisspecifiedusethedefaultStringorderBy;if(TextUtils.isEmpty(sortOrder)){orderBy=BookTableMetaData.DEFAULT_SORT_ORDER;

Page 672: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}else{orderBy=sortOrder;}

//GetthedatabaseandrunthequerySQLiteDatabasedb=mOpenHelper.getReadableDatabase();Cursorc=qb.query(db,projection,selection,selectionArgs,null,null,orderBy);

//exampleofgettingacountinti=c.getCount();

//Tellthecursorwhaturitowatch,//soitknowswhenitssourcedatachangesc.setNotificationUri(getContext().getContentResolver(),uri);returnc;}@OverridepublicStringgetType(Uriuri){

switch(sUriMatcher.match(uri)){caseINCOMING_BOOK_COLLECTION_URI_INDICATOR:returnBookTableMetaData.CONTENT_TYPE;caseINCOMING_SINGLE_BOOK_URI_INDICATOR:returnBookTableMetaData.CONTENT_ITEM_TYPE;default:thrownewIllegalArgumentException("UnknownURI"+uri);}}@OverridepublicUriinsert(Uriuri,ContentValuesinitialValues){

//Validatetherequesteduriif(sUriMatcher.match(uri)!=INCOMING_BOOK_COLLECTION_URI_INDICATOR){thrownewIllegalArgumentException("UnknownURI"+uri);}ContentValuesvalues;if(initialValues!=null){values=newContentValues(initialValues);}else{values=newContentValues();}Longnow=Long.valueOf(System.currentTimeMillis());//Makesurethatthefieldsareallsetif(values.containsKey(BookTableMetaData.CREATED_DATE)

Page 673: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

==false){values.put(BookTableMetaData.CREATED_DATE,now);}if(values.containsKey(BookTableMetaData.MODIFIED_DATE)==false){values.put(BookTableMetaData.MODIFIED_DATE,now);}if(values.containsKey(BookTableMetaData.BOOK_NAME)==false){thrownewSQLException("FailedtoinsertrowbecauseBookNameisneeded"+uri);}if(values.containsKey(BookTableMetaData.BOOK_ISBN)==false){values.put(BookTableMetaData.BOOK_ISBN,"UnknownISBN");}if(values.containsKey(BookTableMetaData.BOOK_AUTHOR)==false){values.put(BookTableMetaData.BOOK_ISBN,"UnknownAuthor");}

SQLiteDatabasedb=mOpenHelper.getWritableDatabase();longrowId=db.insert(BookTableMetaData.TABLE_NAME,BookTableMetaData.BOOK_NAME,values);if(rowId>0){UriinsertedBookUri=ContentUris.withAppendedId(BookTableMetaData.CONTENT_URI,rowId);getContext().getContentResolver().notifyChange(insertedBookUri,null);

returninsertedBookUri;}thrownewSQLException("Failedtoinsertrowinto"+uri);}@Overridepublicintdelete(Uriuri,Stringwhere,String[]whereArgs){

SQLiteDatabasedb=mOpenHelper.getWritableDatabase();intcount;switch(sUriMatcher.match(uri)){caseINCOMING_BOOK_COLLECTION_URI_INDICATOR:

Page 674: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

count=db.delete(BookTableMetaData.TABLE_NAME,where,whereArgs);break;caseINCOMING_SINGLE_BOOK_URI_INDICATOR:StringrowId=uri.getPathSegments().get(1);count=db.delete(BookTableMetaData.TABLE_NAME,BookTableMetaData._ID+"="+rowId+(!TextUtils.isEmpty(where)?"AND("+where+')':""),whereArgs);break;default:thrownewIllegalArgumentException("UnknownURI"+uri);}

getContext().getContentResolver().notifyChange(uri,null);returncount;}@Overridepublicintupdate(Uriuri,ContentValuesvalues,

Stringwhere,String[]whereArgs){SQLiteDatabasedb=mOpenHelper.getWritableDatabase();intcount;switch(sUriMatcher.match(uri)){caseINCOMING_BOOK_COLLECTION_URI_INDICATOR:count=db.update(BookTableMetaData.TABLE_NAME,values,where,whereArgs);break;

caseINCOMING_SINGLE_BOOK_URI_INDICATOR:StringrowId=uri.getPathSegments().get(1);count=db.update(BookTableMetaData.TABLE_NAME,values,BookTableMetaData._ID+"="+rowId+(!TextUtils.isEmpty(where)?"AND("+where+')':""),whereArgs);break;

default:thrownewIllegalArgumentException("UnknownURI"+uri);}

getContext().getContentResolver().notifyChange(uri,null);

Page 675: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returncount;}}

Now,let’sanalyzethiscodesectionbysection.

UsingUriMatchertoFigureOuttheURIsWe’vementionedtheUriMatcherclassseveraltimesnow;let’slookintoit.AlmostallmethodsinacontentproviderareoverloadedwithrespecttotheURI.Forexample,thesamequery()methodiscalledwhetheryouwanttoretrieveasinglebookoralistofbooks.ItisuptothemethodtoknowwhichtypeofURIisbeingrequested.Android’sUriMatcherutilityclasshelpsyouidentifytheURItypes.

Here’showitworks.YoutellaninstanceofUriMatcherwhatkindofURIpatternstoexpectduringitsinitialization.Youwillalsoassociateauniquenumberwitheachpattern.Oncethesepatternsareregistered,youcanthenaskUriMatcheriftheincomingURImatchesacertainpattern.

Aswe’vementioned,ourBookProvidercontentproviderhastwoURIpatterns:oneforacollectionofbooksandoneforasinglebook.ThecodeinListing25-26registersbothofthesepatternsusingUriMatcher.Itallocates1foracollectionofbooksand2forasinglebook(theURIpatternsthemselvesaredefinedinthemetadataforthebookstable).YoucanseethisinthestaticinitializationofthevariablesUriMatcherinListing25-26.YoucanthenseehowUriMatcherplaysapartinthequery()methodimplementationindistinguishingtheURIsusingtheconstantsforeachtypeofURI.

UsingProjectionMapsAcontentprovideractslikeanintermediarybetweenanabstractsetofcolumnsandarealsetofcolumnsinadatabase,yetthesecolumnsetscoulddiffer.Whileconstructingqueries,youmustmapbetweenthewhereclausecolumnsthataclientspecifiesandtherealdatabasecolumns.YousetupthisprojectionmapwiththehelpoftheSQLiteQueryBuilderclass.YoucanseehowthisprojectionmapvariablesBooksProjectionMapissetfortheBookProviderinListing25-26.YoucanalsoseeinthatlistinghowthisvariablesBooksProjectionMapisthenusedbytheSQLiteQueryBuilderobject.

FulfillingMIME-TypeContractsLet’sstartwiththegetType()methodinListing25-26.ThismethodreturnsaMIMEtypeforagivenURI.Thismethod,likemanyothermethodsofacontentprovider,issensitivetotheincomingURI.Asaresult,thefirstresponsibilityofthegetType()methodistodistinguishthetypeoftheURI.Isitacollectionofbooksorasinglebook?ThecodeusedtheUriMatchertodecipherthisURItype.DependingonthisURI,the

Page 676: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

BookTableMetaDataclasshasdefinedtheMIME-typeconstantstoreturnforeachURI.

ImplementingtheQueryMethodLiketheothermethods,thequerymethodusesUriMatchertoidentifytheURItype.IftheURItypeisasingle-itemtype,themethodretrievesthebookIDfromtheincomingURIbylookingatthefirstsegmentreturnedbygetPathSegments().

ThequerymethodthenusestheprojectionsthatwecreatedupfrontinListing25-26toidentifythereturncolumns.Intheend,queryreturnsthecursortothecaller.Throughoutthisprocess,thequerymethodusestheSQLiteQueryBuilderobjecttoformulateandexecutethequery.

WhilereadingthedataonecanconstraintherowsreturnedeitherusingtheURIorthroughexplicitwhereclauseargumentspassedtothequerymethodasinputs.IntheBookProviderimplementationofListing25-26weusedtheapproachofusingtheURIsegmentstoretrievethebookIDtoreturnthevaluesforjustthatbook.

InsteadyoucanusetheselectionparameterandtheselectionArgsparameterofthequery()methodtoexplicitlypassthewhereclausearguments.TheseargumentsworkjustliketheSQLiteDatabase.query()argumentsinListing25-12,where“?”areusedasplaceholdersforthevaluespassedintheselectionArgsarray.

ImplementingtheInsertMethodTheinsertmethodinacontentproviderisresponsibleforinsertingarecordintotheunderlyingdatabaseandthenreturningaURIthatpointtothenewlycreatedrecord.

Liketheothermethods,insertusesUriMatchertoidentifytheURItype.ThecodefirstcheckswhethertheURIindicatesthepropercollection-typeURI.Ifnot,thecodethrowsanexception.

Thecodethenvalidatestheoptionalandmandatorycolumnparameters.Thecodecansubstitutedefaultvaluesforsomecolumnsiftheyaremissing.

Next,thecodeusesanSQLiteDatabaseobjecttoinsertthenewrecordandreturnsthenewlyinsertedID.Intheend,thecodeconstructsthenewURIusingthereturnedIDfromthedatabase.

ImplementingtheUpdateMethodTheupdatemethodinacontentproviderisresponsibleforupdatingarecord(orrecords)basedonthecolumnvaluespassedin,aswellasthewhereclausethatispassedin.Theupdatemethodthenreturnsthenumberofrowsupdatedintheprocess.

Liketheothermethods,updateusesUriMatchertoidentifytheURItype.IftheURItypeisacollection,thewhereclauseispassedthroughsoitcanaffectasmanyrecordsas

Page 677: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

possible.IftheURItypeisasingle-recordtype,thenthebookIDisextractedfromtheURIandspecifiedasanadditionalwhereclause.Intheend,thecodereturnsthenumberofrecordsupdated.AlsonoticehowthisnotifyChangemethodenablesyoutoannouncetotheworldthatthedataatthatURIhaschanged.Potentially,youcandothesameintheinsertmethodbysayingthatthecollectionofbooksdataatURI“…/books”haschangedwhenarecordisinserted.

ImplementingtheDeleteMethodThedeletemethodinacontentproviderisresponsiblefordeletingarecord(orrecords)basedonthewhereclausethatispassedin.Thedeletemethodthenreturnsthenumberofrowsdeletedintheprocess.

Liketheothermethods,deleteusesUriMatchertoidentifytheURItype.IftheURItypeisacollectiontype,thewhereclauseispassedthroughsoyoucandeleteasmanyrecordsaspossible.Ifthewhereclauseisnull,allrecordswillbedeleted.IftheURItypeisasingle-recordtype,thebookIDisextractedfromtheURIandspecifiedasanadditionalwhereclause.Intheend,thecodereturnsthenumberofrecordsdeleted.

RegisteringtheProviderFinally,youmustregisterthecontentproviderintheAndroid.Manifest.xmlfileusingthetagstructureinListing25-27.Aproviderisacomponentandhenceasiblingoftheothercomponentssuchasanactivityandareceiver.SoitisasiblingnodetootheractivitiesintheAndroidmanifestfile.

Listing25-27.RegisteringaProvider

<providerandroid:name=".BookProvider"

android:authorities="com.androidbook.provider.BookProvider"/>

ExercisingtheBookProviderNowthatwehaveabookprovider,wearegoingtoshowyousamplecodetoexercisethatprovider.Thesamplecodeincludesaddingabook,removingabook,gettingacountofthebooks,andfinallydisplayingallthebooks.

Keepinmindthatthesearecodeextractsfromthesampleprojectandwillnotcompile,becausetheyrequireadditionaldependencyfiles.However,wefeelthissamplecodeissufficientindemonstratingtheconceptswehaveexplored.

Attheendofthischapter,wehaveincludedalinktothedownloadablesampleproject,whichyoucanuseinyourEclipseenvironmenttocompileandtest.

AddingaBook

Page 678: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ThecodeinListing25-28insertsanewbookintothebookdatabase.

Listing25-28.ExercisingaProviderInsert

//Filereferenceinproject:ProviderTester.JavapublicvoidaddBook(Contextcontext){Stringtag="ExerciseBookProvider";Log.d(tag,"Addingabook");ContentValuescv=newContentValues();cv.put(BookProviderMetaData.BookTableMetaData.BOOK_NAME,"book1");cv.put(BookProviderMetaData.BookTableMetaData.BOOK_ISBN,"isbn-1");cv.put(BookProviderMetaData.BookTableMetaData.BOOK_AUTHOR,"author-1");

ContentResolvercr=context.getContentResolver();Uriuri=BookProviderMetaData.BookTableMetaData.CONTENT_URI;Log.d(tag,"bookinserturi:"+uri);UriinsertedUri=cr.insert(uri,cv);Log.d(tag,"inserteduri:"+insertedUri);}

RemovingaBookThecodeinListing25-29deletesthelastrecordfromthebookdatabase.

Listing25-29.ExercisingaProviderDelete

//Filereferenceinproject:ProviderTester.JavapublicvoidremoveBook(){intfirstBookId=this.getFirstBookId();if(firstBookId==-1)thrownewSQLException("Bookidislessthan0");ContentResolvercr=this.mContext.getContentResolver();Uriuri=BookProviderMetaData.BookTableMetaData.CONTENT_URI;UridelUri=Uri.withAppendedPath(uri,Integer.toString(firstBookId));reportString("DelUri:"+delUri);cr.delete(delUri,null,null);this.reportString("NumberofBooksafterthedelete:"+getCount());}

privateintgetFirstBookId(){Uriuri

Page 679: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

=BookProviderMetaData.BookTableMetaData.CONTENT_URI;Activitya=(Activity)this.mContext;Cursorc=null;try{c=a.getContentResolver().query(uri,null,//projectionnull,//selectionstringnull,//selectionargsarrayofstringsnull);//sortorderintnumberOfRecords=c.getCount();if(numberOfRecords==0){return-1;}c.moveToFirst();intid=c.getInt(1);//idcolumnreturnid;}finally{if(c!=null)c.close();}}

DisplayingtheListofBooksThecodeinListing25-30retrievesalltherecordsinthebookdatabase.

Listing25-30.DisplayingaListofBooks

//Filereferenceinproject:ProviderTester.JavapublicvoidshowBooks(){Uriuri=BookProviderMetaData.BookTableMetaData.CONTENT_URI;Activitya=(Activity)this.mContext;Cursorc=null;try{c=a.getContentResolver().query(uri,null,//projectionnull,//selectionstringnull,//selectionargsarrayofstringsnull);//sortorderintiid=c.getColumnIndex(BookProviderMetaData.BookTableMetaData._ID);intiname=c.getColumnIndex(BookProviderMetaData.BookTableMetaData.BOOK_NAME);intiisbn=c.getColumnIndex(BookProviderMetaData.BookTableMetaData.BOOK_ISBN);intiauthor

Page 680: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

=c.getColumnIndex(BookProviderMetaData.BookTableMetaData.BOOK_AUTHOR);

//ReportyourindexesLog.d(tag,"name,isbn,author:"+iname+iisbn+iauthor);

//walkthroughtherowsbasedonindexesfor(c.moveToFirst();!c.isAfterLast();c.moveToNext()){//GathervaluesStringid=c.getString(iid);Stringname=c.getString(iname);Stringisbn=c.getString(iisbn);Stringauthor=c.getString(iauthor);

//ReportorlogtherowStringBuffercbuf=newStringBuffer(id);cbuf.append(",").append(name);cbuf.append(",").append(isbn);cbuf.append(",").append(author);Log.d(tag,cbuf.toString());}

//ReporthowmanyrowshavebeenreadintnumberOfRecords=c.getCount();Log.d(tag,"NumofRecords:"+numberOfRecords);}finally{if(c!=null)c.close();}}

NoticethatthemethodofretrievingthebooksfromacontentproviderisverysimilartoretrievingdatafromanSQLitedatabase.InListing25-30wehaveusedthequery()methodfromaContentResolverobject.Afterusingthecursorobjectwehaveclosedthecursor.

InsteadifyouwerepassingthiscursorobjecttoaUIcomponentthatisintheActivitythenthiscursorobjectneedstobemanagedastheactivityfollowsitslifecycle.PriortoHoneycomb,therewasamethodcalledmanagedQuery()ontheActivitytodothisautomatically,whichhassincebeendeprecatedinfavorofCursorLoader.

WhenaqueryisthusmanagedthroughmanagedQuery(),theactivitycancallmethodsonthecursortoplaceitintoproperstate.Forexample,theactivitywillcalldeactivate()onthecursorwhenitisstoppedandlatercallsrequery()whenitisstarted.Thecursorwillbeclosedwhentheactivityisdestroyed.YoucanchoosetocallstopManagingCursor()onthatcursorifyouwanttocontrolthebehaviorofthecursoryourself.Becausetheactivityclosesthecursor,don’tcloseamanagedcursor.Ifyourintentionistoreadalltherowsonetimeandclosethecursor,thenusethequery()

Page 681: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

methodoftheContentResolverasopposedtotheActivity.managedQuery()methodandexplicitlyclosethecursor.

SinceHoneycomb,thecursorreadsarewrappedintoamoregeneralapproachcalled“Loaders,”whichallowyoutoreaddatainanasynchronousthreadthroughcallbacksexposedtofragmentsoractivities.Thisistherecommendedandpreferredmethod.Wewillcoverthisapproachinthenextchapter,Chapter26,onLoaders.

YouhaveseenhowwehaveusedupdateAPIsonacontentproviders.Theseupdateoperationscanbeinefficientifdoneonebyonethroughacontentprovider.InChapter27wewillcoverhowtheseindividualupdateoperationscanbesentasabatchtoacontentproviderforefficiencyreasons.

ResourcesHerearesomeadditionalAndroidresourcesthatcanhelpyouwiththetopicscoveredinthischapter:

http://developer.android.com/guide/topics/data/data-storage.html:VariousdatastorageoptionsfromAndroiddocumentation.

http://www.androidbook.com/item/4437:AsummaryofoptionsforpersistenceonAndroid.

http://www.androidbook.com/item/4876:ExploringtoolsandtechniquesfordirectSQLstorageonAndroid.ThisincludesresearchonO/Rmappingtoolsaswell.

http://www.androidbook.com/item/4877:StoringdatainthecloudthroughParseforAndroid.

http://www.androidbook.com/item/4440:UsingGSON/JSONformobileappstorage.

http://www.androidbook.com/item/4438:Usingsharedpreferencesforapplicationstatemanagement.

http://developer.android.com/guide/topics/providers/content-providers.html:Androiddocumentationoncontentproviders.

http://developer.android.com/reference/android/content/ContentProvider.htmlAPIdescriptionforaContentProvider,whereyoucanlearnaboutContentProvidercontracts.

http://developer.android.com/reference/android/content/UriMatcher.htmlInformationthatisusefulforunderstandingUriMatcher.

http://developer.android.com/reference/android/database/Cursor.htmlInformationthathelpsyoureaddatafromacontentproviderora

Page 682: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

databasedirectly.

http://developer.android.com/guide/components/loaders.htmlDeveloper’sguideforLoaders.

http://developer.android.com/reference/android/app/Activity.html#startManagingCursor(android.database.CursorAPIdocumentationofwhatamanagedcursoris.

http://www.sqlite.org/sqlite.html:HomepageofSQLite,whereyoucanlearnmoreaboutSQLiteanddownloadtoolsthatyoucanusetoworkwithSQLitedatabases.

http://androidbook.com/proandroid5/projects:DownloadabletestprojectforthischapterisaccessiblefromthisURL.ThenameofthezipfileisProAndroid5_Ch25_TestProvider.zip.

SummaryThischapterhascoveredalotofaspectsaboutavitalneedofyourapplications:persistence.WehavegivenyouaplethoraofoptionsavailableinAndroidforpersistenceandhowtochooseanappropriateoption.WehavecoveredhowtouseSQLiteforinternalpersistenceneedsinsignificantdetail.Wehaveshownyouanindustrial-strengthAPIpatternforpersistenceusingSQLitewhichcanbeextendedtoanypersistenceimplementation.Importantly,thispatternshowedyouhowtoexternalizetransactionstokeepyourpersistencecodesimple.Wehavethencoveredwhatcontentprovidersare,thenatureofcontentURIs,MIMEtypes,howtouseSQLitetoconstructprovidersthatrespondtoURIs,howtowriteanewcontentprovider,andhowtoaccessanexistingcontentprovider.

Page 683: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter26

UnderstandingLoadersThischapterlooksatloadingdatafromdatasourcesthroughtherecommendedmechanismofLoaders.TheAPIofLoadersisdesignedtodealwithtwoissueswithloadingdatabyactivitiesandfragments.

Thefirstisthenon-deterministicnatureofactivitieswhereanactivitycanbehiddenpartiallyorfully,restartedduetodevicerotation,orremovedfrommemorywheninbackgroundduetolow-memoryconditions.Theseeventsarecalledactivitylifecycleevents.Anycodethatretrievesdatamustworkinharmonywiththeactivitylifecycleevents.PriortotheintroductionofLoadersin3.0(API11),thiswashandledthroughManagedCursors.ThismechanismisnowdiscontinuedinfavorofLoaders.

Thesecondissuewithloadingdatainactivitiesandfragmentsisthatdataaccesscouldtakelongeronthemainthreadresultinginapplication-not-responding(ANR)messages.Loaderssolvethisbydoingtheworkonaworkerthreadandprovidingcallbackstotheactivitiesandfragmentstorespondtotheasynchronousnatureofdatafetch.

UnderstandingtheArchitectureofLoadersLoadersmakeiteasytoasynchronouslyloaddatainanactivityorafragment.Multipleloaders,eachwithitsownsetofdata,canbeassociatedwithanactivityorafragment.Loadersalsomonitorthesourceoftheirdataanddelivernewresultswhenthedatacontentchanges.Loadersautomaticallyreconnecttothepreviouslyretrieveddatastructure,likeacursor,whenbeingre-createdafteraconfigurationchange.Asthepreviouscursorisnotdestroyed,dataisnotrequeried.

Whenwetalkaboutloadersinthischapterallaspectsofloadersapplytobothactivitiesandfragmentsunlessweindicateotherwisefromnowon.

EveryactivityusesasingleLoaderManagerobjecttomanagetheloadersassociatedwiththatactivity.Oncealoaderisregisteredwithaloadermanager,theLoaderManagerwillfacilitatethenecessarycallbackstoa)createandinitializetheLoader,b)readthedatawhentheLoaderfinishesloadingthedata,andc)closetheresourcewhentheloaderisabouttobedestroyedastheactivityisnolongerneeded.TheLoaderManagerishiddenfromyouandyouworkwithitthroughcallbacksandLoaderManagerpublicAPIs.ThecreationoftheLoaderManageriscontrolledbytheactivity.LoaderManagerisalmostlikeanintegralpartoftheactivityitself.

ItistheresponsibilityoftheregisteredLoadertoworkwithitsdatasourceandalsowiththeLoaderManagertoreadthedataandsendtheresultsbacktothe

Page 684: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

LoaderManager.TheLoaderManagerwilltheninvokethecallbacksontheactivitythatdataisready.TheLoaderisalsoresponsibleforpausingthedataaccessormonitoringdatachangesorworkingwiththeLoaderManagertounderstandandreacttotheactivitylifecycleevents.

WhileyoucanwritealoaderfromscratchforyourspecificdataneedsbyextendingtheloaderAPI,youtypicallyusetheLoadersthatarealreadyimplementedintheSDK.MostloadersextendtheAsyncTaskLoaderwhichprovidesthebasicabilitytodoitsworkonaworkerthreadfreeingthemainthread.Whentheworkerthreadreturnsdata,theLoaderManagerwillinvokethemaincallbackstotheactivitythatthedataisreadyonthemainthread.

ThemostusedoftheseprebuiltloadersistheCursorLoader.WiththeavailabilityofCursorLoader,usingLoadersbecomesreally,reallytrivialwithafewlinesofcode.ThisisbecauseallthedetailsarehiddenbehindtheLoaderManager,Loader,AsyncTaskLoader,andtheCursorLoader.

ListingBasicLoaderAPIClassesListing26-1liststhekeyclassesinvolvedintheLoaderAPI.

Listing26-1.AndroidLoaderAPIKeyParticipatingClasses

LoaderManagerLoaderManager.LoaderCallbacksLoaderAsyncTaskLoaderCursorLoader

TheAPIsthataremostoftenusedaretheLoaderManager.LoaderCallbacksandtheCursorLoader.However,letusbrieflyintroduceeachoftheseclasses.

ThereisoneLoaderManagerobjectperactivity.ThisistheobjectthatdefinestheprotocolofhowLoadersshouldwork.SoLoaderManageristheorchestratorfortheloadersassociatedwithanactivity.LoaderManager'sinteractionwiththeactivityisthroughtheLoaderManager.LoaderCallbacks.TheseloadercallbacksarewhereyouaregiventhedatabytheLoaderviatheLoaderManagerandexpectedtointeractwiththeactivity.

TheLoaderclassdefinestheprotocolthatmustbeadheredtoifonewantstodesigntheirownloader.AsyncTaskLoaderisoneexamplewhereitimplementstheloaderprotocolinanasynchronousmanneronaworkerthread.ItistypicallytheAsyncTaskLoaderthatisthebaseclasstoimplementmostofyourloaders.CursorLoaderisanimplementationofthisAsyncTaskLoaderthatknowshowtoloadcursorsfromcontentproviders.IfoneisimplementingtheirownloaderitisimportanttounderstandthatallinteractionwiththeloaderfromaLoaderManagerhappensonthemainthread.EventheLoaderManagercallbacksthatareimplementedbytheactivity

Page 685: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

takeplaceonthemainthread.

DemonstratingtheLoadersWewillnowshowyouhowtouseLoadersbyimplementingasimpleone-pageapplication(Figure26-1)thatloadscontactsfromthecontactproviderdatabaseonanAndroiddevice.ThisapplicationistypicalofhowonewoulddevelopAndroidactivities.Youcouldevenusethissampleprojectasastarterapplicationtemplate.

Figure26-1.Filteredlistofcontactsloadedthroughloaders

WewanttheactivityinFigure26-1toexhibitthefollowingcharacteristics:1)Itshoulddisplayallthecontactsonthedevice;b)Itshouldretrievedataasynchronously;c)Whiledataisbeingretrieved,theactivityshouldshowaprogressbarviewinplaceofthelistview;d)Onretrievingdatasuccessfully,thecodeshouldreplacetheprogressviewwiththefilled-inlistview;e)Theactivityshouldprovideasearchmechanismtofilterthenecessarycontacts;f)Whenthedeviceisrotated,itshouldshowthecontactsagainwithoutmakingarequerytothecontactscontentprovider;g)Thecodeshouldallowustoseetheorderofcallbacksalongwiththeactivitylifecyclecallbacks.

Wewillfirstpresentthesourcecodefortheactivityandthenexplaineachsection.BytheendofthechapteryouwillhaveaclearunderstandingofhowLoadersworkandhowto

Page 686: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

usetheminyourcode.Withthat,Listing26-2showsthecodefortheactivityofFigure26-1.PleasenotethatthecodeinListing26-2reliesonanumberofresourcesthatarepresentedhere.SomeofthesestringresourcesyoucanseeinFigure26-1,butforothersandthecodethatisnotincludedhere,pleaseseethedownloadableproject.Asalways,thecodepresentedhereissufficientforthetopicathand.Listing26-2.AnActivityLoadingDatawithLoaders

publicclassTestLoadersActivity

extendsMonitoredListActivity//verysimpleclasstologactivitycallbacksimplementsLoaderManager.LoaderCallbacks<Cursor>//LoaderManagercallbacks,OnQueryTextListener//Searchtextcallbacktofiltercontacts{privatestaticfinalStringtag="TestLoadersActivity";

//Adapterfordisplayingthelist'sdata

//InitializedtonullcursorinonCreateandsetonthelist//Useitinlatercallbackstoswapcursor//ThisisreinitializedtonullcursorwhenrotationoccursSimpleCursorAdaptermAdapter;

//SearchfilterworkingwithOnQueryTextListener

StringmCurFilter;

//Contactscolumnsthatwewillretrieve

staticfinalString[]PROJECTION=newString[]{ContactsContract.Data._ID,ContactsContract.Data.DISPLAY_NAME};

//selectcriteriaforthecontactsURI

staticfinalStringSELECTION="(("+ContactsContract.Data.DISPLAY_NAME+"NOTNULL)AND("+ContactsContract.Data.DISPLAY_NAME+"!=''))";

publicTestLoadersActivity(){super(tag);}@OverrideprotectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

this.setContentView(R.layout.test_loaders_activity_layout);

Page 687: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Initializetheadapterthis.mAdapter=createEmptyAdapter();this.setListAdapter(mAdapter);

//Hidethelistviewandshowtheprogressbar

this.showProgressbar();

//Initializealoaderforanidof0getLoaderManager().initLoader(0,null,this);

}//Createasimplelistadapterwithanullcursor//ThegoodcursorwillcomelaterintheloadercallbackprivateSimpleCursorAdaptercreateEmptyAdapter(){

//Forthecursoradapter,specifywhichcolumnsgointowhichviewsString[]fromColumns={ContactsContract.Data.DISPLAY_NAME};int[]toViews={android.R.id.text1};//TheTextViewinsimple_list_item_1//ReturnthecursorreturnnewSimpleCursorAdapter(this,android.R.layout.simple_list_item_1,null,//cursorfromColumns,toViews);}//ThisisaLoaderManagercallback.ReturnaproperlyconstructedCursorLoader//Thisgetscalledonlyiftheloaderdoesnotpreviouslyexist.//Thismeansthismethodwillnotbecalledonrotationbecause//apreviousloaderwiththisIDisalreadyavailableandinitialized.//Thisalsogetscalledwhentheloaderis"restarted"bycalling//LoaderManager.restartLoader()@OverridepublicLoader<Cursor>onCreateLoader(intid,Bundleargs){

Log.d(tag,"onCreateLoaderforloaderid:"+id);UribaseUri;if(mCurFilter!=null){baseUri=Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(mCurFilter));}else{baseUri=Contacts.CONTENT_URI;

Page 688: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

}String[]selectionArgs=null;StringsortOrder=null;returnnewCursorLoader(this,baseUri,PROJECTION,SELECTION,selectionArgs,sortOrder);}//ThisisaLoaderManagercallback.Usethedatahere.//Thisgetscalledwhenheloaderfinishes.Calledonthemainthread.//Canbecalledmultipletimesasthedatachangesunderneath.//Alsogetscalledafterrotationwithoutrequeryingthecursor.@OverridepublicvoidonLoadFinished(Loader<Cursor>loader,Cursorcursor){

Log.d(tag,"onLoadFinishedforloaderid:"+loader.getId());Log.d(tag,"Numberofcontactsfound:"+cursor.getCount());this.hideProgressbar();this.mAdapter.swapCursor(cursor);

}//ThisisaLoaderManagercallback.Removeanyreferencestothisdata.//Thisgetscalledwhentheloaderisdestroyedlikewhenactivityisdone.//FYI-thisdoesNOTgetcalledbecauseofloader"restart"//Thiscanbeseenasa"destructor"fortheloader.@OverridepublicvoidonLoaderReset(Loader<Cursor>loader){

Log.d(tag,"onLoaderResetforloaderid:"+loader.getId());this.showProgressbar();this.mAdapter.swapCursor(null);

}@OverridepublicbooleanonCreateOptionsMenu(Menumenu){

//Placeanactionbaritemforsearching.MenuItemitem=menu.add("Search");item.setIcon(android.R.drawable.ic_menu_search);item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);SearchViewsv=newSearchView(this);sv.setOnQueryTextListener(this);item.setActionView(sv);returntrue;}

Page 689: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//ThisisaSearchviewcallback.Restarttheloader.//Thisgetscalledwhenuserentersnewsearchtext.//CallLoaderManager.restartLoadertotriggertheonCreateLoader@OverridepublicbooleanonQueryTextChange(StringnewText){

//Calledwhentheactionbarsearchtexthaschanged.Update//thesearchfilter,andrestarttheloadertodoanewquery//withthisfilter.mCurFilter=!TextUtils.isEmpty(newText)?newText:null;Log.d(tag,"Restartingtheloader");getLoaderManager().restartLoader(0,null,this);

returntrue;}@OverridepublicbooleanonQueryTextSubmit(Stringquery){returntrue;}privatevoidshowProgressbar(){//showprogressbarViewpbar=this.getProgressbar();pbar.setVisibility(View.VISIBLE);//hidelistviewthis.getListView().setVisibility(View.GONE);

findViewById(android.R.id.empty).setVisibility(View.GONE);}privatevoidhideProgressbar(){//showprogressbarViewpbar=this.getProgressbar();pbar.setVisibility(View.GONE);//hidelistviewthis.getListView().setVisibility(View.VISIBLE);}privateViewgetProgressbar(){returnfindViewById(R.id.tla_pbar);}}//eof-class

WewillexplaineachsectionfromListing26-2afterweshowyouthesupportinglayoutfortheactivitycodeinListing26-3.ThislayoutinListing26-3shouldclarifytheviewinFigure26-1(pleasenotethatanumberofresourcesarenotincludedherebutareavailableinthedownloadablefileatapress.com/9781430246800).

Page 690: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing26-3.ATypicalListActivityLayoutforLoaders

<?xmlversion="1.0"encoding="utf-8"?><!--**********************************************/res/layout/test_loaders_activity_layout.xml

*correspondingactivity:TestLoadersActicity.java*prefix:tla_(Usedforprefixinguniqueidentifiers)**Use:*Demonstrateloadingacursorusingloaders*Structure:*Headermessage:textview(tla_header)*ListViewHeading,ListView(fixed)*ProgressBar(Toshowwhendataisbeingfetched)*EmptyView(Toshowwhenthelistisempty):ProgressBar*Footer:textview(tla_footer)************************************************--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="2dp"android:paddingRight="2dp"><!--HeaderandMaindocumentationtext-->

<TextViewandroid:id="@+id/tla_header"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/box2"android:layout_marginTop="4dp"android:padding="8dp"android:text="@string/tla_header"/><!--Headingforthelistview-->

<TextViewandroid:id="@+id/tla_listview_heading"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/gray"android:layout_marginTop="4dp"android:padding="8dp"android:textColor="@color/black"style="@android:style/TextAppearance.Medium"android:text="ListofContacts"/><!--ListViewusedbytheListActivity.Usesastandardidneededby

alistview-->

<!--Fixtheheightofthelistviewinaproductionsetting--><ListViewandroid:id="@android:id/list"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/box2"android:layout_marginTop="4dp"android:layout_marginBottom="4dp"

Page 691: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

android:drawSelectorOnTop="false"/><!--ProgressBar:Toshowandhidetheprogressbarasloadersload

data-->

<ProgressBarandroid:id="@+id/tla_pbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:indeterminate="true"/><!--EmptyList:Usesastandardidneededbyalistview--><TextViewandroid:id="@android:id/empty"android:layout_width="match_parent"android:layout_height="wrap_content"android:visibility="gone"android:layout_marginTop="4dp"android:layout_marginBottom="4dp"android:padding="8dp"android:text="NoContactstoMatchtheCriteria"/><!--Footer:Additionaldocumentationtextandthefooter--><TextViewandroid:id="@+id/tla_footer"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/box2"android:padding="8dp"android:text="@string/tla_footer"/></LinearLayout>

Let’snowturntounderstandingthecodeinListing26-2.Wewillexplainthiscodethroughaseriesofstepsyouwouldfollowtocodewithloaders.Let’sstartwithstep1,wheretheactivityneedstobeextendedtosupporttheLoaderManagercallbacks.

Step1:PreparingtheActivitytoLoadDataCodenecessarytoloaddatausingloadersisremarkablysmall,becausemostoftheworkisdonebytheCursorLoader.ThefirstthingyouneedtodoistohaveyouractivityextendtheLoaderManager.LoaderCallbacks<Cursor>andimplementthethreeneededmethods:onCreateLoader(),onLoadFinished(),andonLoaderReset().YoucanseehowinListing26-2.Byimplementingthisinterface,youhaveenabledtheactivitytobecomeareceiverfortheLoaderManagereventsthroughthesethreecallbacks.

Step2:InitializingtheLoaderNext,youhavetotelltheactivitythatyouwantaLoaderobjecttoloadthedata.ThisisdonebyregisteringandinitializingaLoaderduringtheonCreate()methodoftheactivityasshowninListing26-4.YoucanalsoseethisintheonCreate()ofListing

Page 692: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

26-3aswell,incontextoftheoverallcode.

Listing26-4.InitializingaLoader

intloaderid=0;BundleargBundle=null;LoaderCallbacks<Cursor>loaderCallbacks=this;//thisactivityitselfgetLoaderManager().initLoader(loaderid,argBundle,loaderCallbacks);

Theloaderidargumentisadeveloper-assigneduniquenumberinthecontextofthisactivitytouniquelyidentifythisLoaderfromotherLoadersregisteredwiththisactivity.Notethatintheexamplehere,weareusingonlyoneLoader.

ThesecondargsBundleargumentisusedtopassadditionalargumentstotheonCreateLoader()callbackifneeded.This“bundleofarguments”approachfollowstheusualpatternofdifferedfactoryobjectconstructioninmanyofthemanagedcomponentsinAndroid.Activities,fragments,andloadersareallexamplesofthispattern.

Thethirdargument,loaderCallbacks,isareferencetoanimplementationofthecallbacksrequiredbytheLoaderManager.InListings26-2and26-4,theactivityitselfisplayingthisrole,sowepassthisvariablereferringtotheactivityastheargumentvalue.

OncetheLoaderisregisteredandinitialized,theLoaderManagerwillscheduleacalltotheonCreateLoader()callbackifnecessary.IfacallwaspreviouslymadetotheonCreateLoader()andaloaderobjectisavailablecorrespondingtothisloaderID,thenthemethodonCreateLoader()willnotbetriggered.Asstatedearlier,theexceptionisifthedeveloperoverridesthisbehaviorbycallingLoaderManager.restartLoader().Youwillseethiscallexplainedlaterwhenwetalkedaboutprovidingsearch-basedfilteringcapabilitiestolocateasub-selectionofcontacts.

DelvingintotheStructureofListActivityTheListActivityinFigure26-1isextendingalistactivitywithacontentviewthatisacustomlayoutthroughsetContentView().Thisgivesusalotmoreflexibilitytoplaceothercontrolsinadditiontothelistviewontheactivity.Forexample,wehaveprovidedaheaderview,afooterview,andalsoaprogressbartoshowthatweareintheprocessoffetchingdata.TheonlyconstraintplacedbyaListActivityistonameacontrolwiththereserved@android:id/listviewtoidentifythelistviewthatthelistactivitywouldbeusing.InadditiontothelistviewID,wecanalsoprovideaviewthatthelistactivityusesifthelistisempty.ThisviewisidentifiedbythepredefinedID@android:id/empty.

WorkingwithAsynchronousLoadingofDataLoadersloaddataasynchronously.Becauseofthiswehaveanaddedresponsibilityin

Page 693: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

theActivity.onCreate()tohidethelistviewandshowtheprogressindicatoruntilthelistdataisready.Todothis,wehaveaProgressBarcomponentinthelayoutinListing26-3.IntheActivity.onCreate()method,wesettheinitialstateofthelayoutsothatthelistviewishiddenandtheprogressbarisshown.ThisfunctionalityiscodedinthemethodshowProgressbar()inListing26-2.InthesameListing26-2,whenthedataisreadywecallhideProgressbar()tohidetheprogressbarandshowthepopulatedlistvieworanemptylistviewifthereisnodata.

Step3:ImplementingonCreateLoader()TheonCreateLoader()istriggeredbytheinitializationoftheloader.YoucanseethesignatureandimplementationofthismethodinListing26-2.ThismethodconstructsaLoaderobjectforthecorrespondingloaderIDthatispassedinfromtheinitializationstemmingfromthecalltoLoaderManager.initLoader().ThismethodalsoreceivestheargumentbundlethatisprovidedduringtheloaderinitializationforthisloaderID.

Thismethodreturnsaproperlytyped(throughJavagenerics)LoaderobjecttotheLoaderManager.InourcasethistypeisLoader<Cursor>.TheLoaderManagercachestheLoaderobjectandwillreuseit.ThisisusefulbecausewhenthedevicerotatesandtheloaderisreinitializedduetoActivity.onCreate(),LoaderManagerrecognizestheloaderIDandthepresenceofanexistingloader.TheLoaderManagerthenwillnottriggeraduplicatecalltotheonCreateLoader().However,iftheactivityistorealizethattheinputdatatotheloaderhaschanged,theactivitycodecancalltheLoaderManager.restartLoader(),whichwilltriggeracalltotheonLoaderCreate()again.Inthatcase,theLoaderManagerwillfirstdestroytheoldloaderandusethenewonereturnedbytheonLoaderCreate().TheLoaderManagerdoesguaranteethattheolderloaderwillhangarounduntilthenewloaderiscreatedandavailable.

TheonCreateLoader()methodhasfullaccesstothelocalvariablesoftheactivity.Soitcanusetheminanyconceivablemannertoconstructtheneededloaders.IncaseofaCursorLoaderthisconstructionislimitedtotheargumentsavailabletotheconstructoroftheCursorLoader,whichisspecificallybuilttoallowcursorsfromanAndroidcontentprovider.

Inourexample,wehaveusedthecontentURIsprovidedbythecontactscontentprovider.RefertoChapter25,oncontentprovider,forhowtousecontentURIstoretrievecursorsfromcontentproviderdatasources.Itisquitesimple:justindicatetheURIyouwanttogetthedatafrom,supplythefilterstringasanargumentorapathsegmentonthatURIasperthedocumentationavailableforthecontactscontentprovider,specifythecolumnsyouwant,specifythewhereclauseasastring,andconstructtheCursorLoader.

Step4:ImplementingonLoadFinished()

Page 694: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

OncetheCursorLoaderisreturnedtotheLoaderManager,theCursorLoaderwillbeinstructedtostartitsworkonaworkerthreadandthemainthreadwillgoontotheUIchores.AtalaterpointthismethodonLoadFinished()iscalledwhenthedataisready.

Thismethodcouldbecalledmultipletimes.Whenthedatafromacontentproviderchanges,astheCursorLoaderhasregistereditselfwiththedatasource,itwillbealerted.CursorLoaderthenwilltriggertheonLoadFinished()again.

IntheonLoadFinished()method,allyouneedtodoistoswapthedatacursorthatisheldbythelistadapter.Thelistadapterwasinitializedoriginallywithanullcursor.Swappingwithapopulatedcursorwillshowthenewdataonthelistview.AswehavehiddenthelistviewinActivity.onCreate(),weneedtoshowthelistviewandhidetheprogressbar.Subsequentlywecangoonswappingthenewcursorsforoldcursorsasdatachanges.Thechangeswillreflectautomaticallyonthelistview.

Whenthedevicerotates,acoupleofthingshappen.TheActivity.onCreate()willbecalledagain.Thiswillsetthelistcursortonullandalsohidethelistview.ThecodeinActivity.onCreate()willalsoinitializetheloaderagain.TheLoaderManagerisprogrammedsothatthisrepeatinitializationisharmless.TheonCreateLoader()willnotbecalled.TheCursorwillnotberequeried.However,theonLoadFinished()getscalledagain,whichiswhatweneededtobreakoutofthisconundrumofinitializingthedatatonullfirstandwonderinghowandwhenitwillbepopulatedifwewerenottorequery.AstheonLoadFinished()getscalledagainonrotation,weareabletoremovetheProgressBar,showthelistview,andswapthevalidcursorfromthenullcursor.Allworks.Yes,itissneakyandround-about,butitworks.

Step5:ImplementingonLoaderReset()Thiscallbackisinvokedwhenapreviouslyregisteredloaderisnolongernecessaryandhencedestroyed.Thiscanhappenwhenanactivityisdestroyedduetoabackbuttonorexplicitlyinstructedtobefinishedbycode.Insuchcases,thiscallbackallowsanopportunitytocloseresourcesorreferencesthatarenolongerneeded.However,itisimportantnottoclosethecursorsastheyaremanagedbythecorrespondingloadersandwillbeclosedforyoubytheframework.ThismightsuggestthattheLoaderManager.restartLoader()mightresultinacalltotheonLoaderReset()astheargumentstotheoldloaderarenolongervalid.Buttestsshowthatthisisnotthecase.ThemethodLoaderManager.restartLoader()willnottriggeracalltothemethodonLoaderReset().TheonLoaderReset()methodisonlycalledwhentheloaderisactivelydestroyedbytheactivitynolongerbeingneeded.YoucanalsoexplicitlyinstructtheLoaderManagertodestroytheloaderbycallingLoaderManager.destroyLoader(loaderid).

UsingSearchwithLoaders

Page 695: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Wewillusesearchinoursampleapplicationtodemonstratethedynamicnatureofloaders.Wehaveattachedasearchviewtothemenu.YoucanseethisinthemethodonCreateOptionsMenu()inListing26-2.HerewehaveattachedaSearchViewtothemenuandprovidedtheactivityasthecallbacktotheSearchViewwhennewtextisprovidedintheSearchView.TheSearchViewcallbackishandledinthemethodonQueryTextchange()ofListing26-2.

IntheonQueryTextChange()method,wetakethenewsearchtextandsetthelocalvariablemCurFilter.WethencallLoaderManager.restartLoader()withthesameargumentsastheLoaderManager.initializeLoader().ThiswilltriggertheonCreateLoader()again,whichwillthenusethemCurFiltertoaltertheparameterstotheCursorLoaderresultinginanewcursor.ThisnewcursorwillreplacetheoldoneintheonLoadFinished()method.

UnderstandingtheOrderofLoaderManagerCallbacksBecauseAndroidprogrammingislargelyevent-based,itisimportanttoknowtheorderofeventcallbacks.TohelpyouunderstandthetimingoftheLoaderManagercallbacks,wehaveriggedthesampleprogramwithlogmessages.Herearesomeresultsshowingtheorderofcallbacks.

Listing26-5showstheorderofcallswhentheactivityisfirstcreated.

Listing26-5.LoaderCallbacksonActivityCreation

Application.onCreate()Activity.onCreate()LoaderManager.LoaderCallbacks.onCreateLoader()Activity.onStart()Activity.onResume()LoaderManager.LoaderCallbacks.onLoadFinished()

Whenthesearchviewfiresanewsearchcriteriathroughitscallback,theorderofcallbacksisasshowninListing26-6.

Listing26-6.LoaderCallbacksonaNewSearchCriteriatriggeredbyRestartLoader

RestartLoader//logmessagefromonQueryTextChangeLoaderManager.LoaderCallbacks.onCreateLoader()LoaderManager.LoaderCallbacks.onLoadFinished()//Notice,nocalltoonLoaderReset()

Listing26-7showstheorderofcallsonconfigurationchange.

Listing26-7.LoaderCallbacksonaConfigurationChange

Application:configchanged

Page 696: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Activity:onCreateActivity.onStart[NocalltotheonCreateLoader]LoaderManager.LoaderCallbacks.onLoadFinished[optionallyifsearchviewhastextinit]SearchView.onQueryChangeTextRestartLoader//justalogmessageLoaderManager.LoaderCallbacks.onCreateLoaderLoaderManager.LoaderCallbacks.onLoadFinished

Listing26-8showstheorderofcallbacksonnavigatingbackornavigatingHomeasthoseactionresultsintheactivityarebeingdestroyed.

Listing26-8.LoaderCallbackswhentheActivityisdestroyed

ActivityonStop()Activity.onDestroy()LoaderManager.LoaderCallbacks.onLoaderReset()//Noticethismethodiscalled

WritingCustomLoadersAsyouhaveseenwiththeCursorLoader,Loadersarespecifictotheirdatasources.Soyoumayneedtowriteyourownloaders.VerylikelyyouwillneedtoderivefromtheAsyncTaskLoaderandspecializeitusingtheprinciplesandcontractslaidoutbytheLoaderprotocol.SeetheSDKdocumentationfortheLoaderclasstogetmoredetails.YoucanalsousetheCursorLoadersourcecodeasaguideinwritingyourownloaders.Thesourcecodeisavailableonlinefrommultiplesources(youcanjustgoogleit)oraspartoftheAndroidsourcedownload.

ResourcesHereareadditionalresourcesforthetopicscoveredinthischapter:

http://www.androidbook.com/item/4890:Researchnotesonloaders.Youwillseeherelinkstoreferences,research,samplecode,images,keyquestions,andongoingnotes.

http://developer.android.com/guide/components/loaders.htmlPrimaryguideforloadersfromAndroid.

http://developer.android.com/guide/components/loaders.html#callbackKeyloaderAPIcallbackstobeimplementedbyanactivityorafragment.

http://developer.android.com/reference/android/content/Loader.htmlLoaderJavaclassAPItounderstandwhatmethodsareavailableona

Page 697: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

loaderobjectwhichisoftenpassedtotheloaderAPIcallbacks.

http://developer.android.com/reference/android/app/LoaderManager.htmlLoaderManagerJavaclassAPIwhichisusefultocontroltheloader,suchasinitialing,restarting,orremoving.

http://developer.android.com/reference/android/content/CursorLoader.htmlCursorLoaderJavaclassAPIwhichisusefultoloaddatausingcursors.CursorLoadersarealsopassedasargumentstotheLoaderManagercallbacks.YoucanusethepublicAPIontheCursorLoadertogetitsID,canceltheload,andgettheinputargumentsusedtostartthecursor.

http://developer.android.com/guide/topics/ui/layout/listview.htmlYouwillfindherehowtouseloaderstopopulateandworkwithaListView.

http://developer.android.com/reference/android/provider/ContactsContract.Contacts.htmlContentproviderAPIsavailabletoworkwiththeAndroidcontactsdatabase.

http://developer.android.com/reference/android/app/Activity.html#startManagingCursor(android.database.CursorAPIdocumentationofwhatamanagedcursoris.Thisisusefultoseewhatisdonetoacursorinamanagedenvironment.Thisappliestocursorsmanagedbyloadersaswell.

http://www.androidbook.com/proandroid5/projects:DownloadabletestprojectforthischapterisaccessiblefromthisURL.ThenameofthezipfileisProAndroid5_Ch26_TestLoaders.zip.

SummaryLoadersareessentialtoloaddatafromdatasourcesbothfromatimingperspectiveandalsointermsoftheabilitytodealwiththemanagedlifecycleofactivitiesandfragments.Youhaveseeninthischapterhoweasyitistouseloaderstoloaddatafromcontentproviders.Theresultingcodeisresponsive,abletodealwithconfigurationchanges,andsimple.

Page 698: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter27

ExploringtheContactsAPIInChapters25and26,wecoveredcontentprovidersandtheirclosecousins,theloaders.Welistedthebenefitsofexposingdatathroughcontentproviderabstraction.Inacontentproviderabstraction,dataisexposedasaseriesofURLs.ThesedataURLscanbeusedtoread,query,update,insert,anddelete.TheseURLsandtheircorrespondingcursorsbecometheAPIforthatcontentprovider.

TheContactsAPIisonesuchcontentproviderAPIforworkingwithcontactdata.ContactsinAndroidaremaintainedinadatabaseandexposedthroughacontentproviderwhoseauthorityisrootedat

content://com.android.contacts

TheAndroidSDKdocumentsthevariousURLsandthedatatheyreturnusingasetofJavainterfacesandclassesthatarerootedattheJavapackage

android.provider.ContactsContract

YouwillseenumerousclasseswhoseparentcontextisContactsContract;theseareusefulinquerying,reading,updating,andinsertingcontactsintoandfromthecontentdatabase.TheprimarydocumentationforusingtheContactsAPIisavailableontheAndroidsiteat

https://developer.android.com/guide/topics/providers/contacts-provider.html

TheprimaryAPIentrypointContactsContractisappropriatelynamedbecausethisclassdefinesthecontractbetweentheclientsofthecontactsandtheproviderandprotectorofthecontactsdatabase.

Thischapterexploresthiscontractinafairamountofdetailbutdoesnotcovereverynuance.TheContactsAPIislargeanditstentaclesfar-reaching.However,whenyouapproachtheContactsAPI,itwilltakeafewweeksofresearchtorealizethatitissimpleinitsunderlyingstructure.Thisiswherewewouldliketocontributethemostandexplainthesebasicsinthetimeittakestoreadthischapter.

Android4.0hasextendedtheideaofcontactstoincludeauserprofile,similartoauserprofileinasocialnetwork.Auserprofileisadedicatedcontactthatrepresentstheownerofthedevice.Mostofthegeneralcontact-basedconceptsremainthesame.WewillcoverhowtheContactsAPIisextendedtosupportauserprofile.

UnderstandingAccountsAllcontactsinAndroidworkinthecontextofanaccount.Whatisanaccount?Well,for

Page 699: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

example,ifyouhaveyoure-mailthroughGoogle,youaresaidtohaveanaccountwithGoogle.IfyousetupyourselfasauserofFacebook,youaresaidtohaveanaccountwithFacebook.Youwillbeabletosetuptheseaccountsthroughthe“Accounts&sync”Settingsoptiononthedevice.SeetheAndroidUser’sGuidetogetmoredetailsaroundaccountsandhowtosetthemup.

Thecontactsyoumanagearetiedtoaspecificaccount.Anaccountownsitssetofcontacts—oranaccountissaidtobetheparentofacontact.Anaccountisidentifiedbytwostrings:theaccountnameandtheaccounttype.IncaseofGoogle,youraccountnameisyoure-mailusernameatGmailandyouraccounttypeiscom.google.Theaccounttypemustbeuniqueacrossthedevice.Youraccountnameisuniquewithinthataccounttype.Together,anaccounttypeandanaccountnameformanaccount,andonlyoncetheaccountisformedcanasetofcontactsbeinsertedforthataccount.

EnumeratingAccountsTheContactsAPIprimarilydealswithcontactsthatexistinvariousaccounts.ThemechanismofcreatingaccountsisoutsideoftheContactsAPI,soexplainingtheabilitytowriteyourownaccountprovidersandhowtosyncthecontactswithinthoseaccountsisoutsidethescopeofthischapter.Youcanunderstandandbenefitfromthischapterwithoutgoingintothedetailsofhowaccountsgetsetup.However,whenyouwanttoaddacontactoralistofcontacts,youdoneedtoknowwhataccountsexistonthedevice.YoucanusethecodeinListing27-1toenumeratetheaccountsandtheirproperties(theaccountnameandtype).CodeinListing27-1liststheaccountnameandtypegivenacontextvariablesuchasanactivity.

Listing27-1.CodetoDisplayaListofAccounts

publicvoidlistAccounts(Contextctx){AccountManageram=AccountManager.get(ctx);Account[]accounts=am.getAccounts();for(Accountac:accounts){Stringaccount_name=ac.name;Stringaccount_type=ac.type;Log.d("accountInfo",account_name+":"+account_type);}}

TorunthecodeinListing27-1,themanifestfileneedstoaskforpermissionusingthelineinListing27-2.

Listing27-2.PermissiontoReadAccounts

<uses-permissionandroid:name="android.permission.GET_ACCOUNTS"/>

ThecodefromListing27-1willprintsomethinglikethefollowing:

Page 700: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Your-email-at-gmail:com.google

Thisassumesthatyouhaveonlyoneaccount(Google)configured.Ifyouhavemorethanoneaccount,allofthoseaccountswillbelistedinasimilarmanner.

Usingthecontactsapplicationonthedeviceyoucanadd,edit,anddeletecontactstoanyofyourexistingaccounts.

UnderstandingContactsContactsownedbyanaccountarecalledrawcontacts.Arawcontacthasavariablesetofdataelements(forexample,e-mailaddress,phonenumber,name,andpostaladdress).Androidpresentsanaggregatedviewofrawcontactsbylistingonlyonceanyrawcontactsthatseemstomatch.Theseaggregatedcontactsformthesetofcontactsyouseewhenyouopenthecontactsapplication.

Wewillnowexaminehowcontactsandtheirrelateddataarestoredinvarioustables.UnderstandingthesecontacttablesandtheirassociatedviewsiskeytounderstandingtheContactsAPI.

ExaminingtheContactsSQLiteDatabaseOnewaytounderstandandexaminethecontactsdatabasetablesistodownloadthecontactsdatabasefromthedeviceortheemulatorandopenitusingoneoftheSQLiteexplorertools.

Todownloadthecontactsdatabase,usetheFileExplorershowninFigure30-17andnavigatetothefollowingdirectoryonyouremulator:

/data/data/com.android.providers.contacts/databases

Dependingontherelease,thedatabasefilenamemaydifferslightly,butitshouldbecalledcontacts.db,contacts2.db,orsomethingsimilar.In4.0,thecontactsproviderusesasimilarlystructuredbutseparatedatabasefilecalledprofile.dbtoholdthecontactsrelatedtothepersonalprofile.

UnderstandingRawContactsThecontactsyouseeinthecontactsapplicationarecalledaggregatedcontacts.Underneatheachaggregatedcontactliesasetofcontactscalledrawcontacts.Anaggregatedcontactisaviewonasetofsimilarrawcontacts.

Thesetofcontactsbelongingtoanaccountarecalledrawcontacts.Eachrawcontactpointstothedetailsofonepersoninthecontextofthataccount.Thisisincontrasttoanaggregatedcontact,whichcrossesaccountboundariesandbelongstothedeviceasawhole.Thisrelationshipbetweenanaccountanditssetofrawcontactsismaintainedintherawcontactstable.Listing27-3showsthestructureoftherawcontactstableinthe

Page 701: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

contactsdatabase.

Listing27-3.RawContactTableDefinition

CREATETABLEraw_contacts(_idINTEGERPRIMARYKEYAUTOINCREMENT,is_restrictedINTEGERDEFAULT0,account_nameSTRINGDEFAULTNULL,account_typeSTRINGDEFAULTNULL,sourceidTEXT,versionINTEGERNOTNULLDEFAULT1,dirtyINTEGERNOTNULLDEFAULT0,deletedINTEGERNOTNULLDEFAULT0,contact_idINTEGERREFERENCEScontacts(_id),aggregation_modeINTEGERNOTNULLDEFAULT0,aggregation_neededINTEGERNOTNULLDEFAULT1,custom_ringtoneTEXTsend_to_voicemailINTEGERNOTNULLDEFAULT0,times_contactedINTEGERNOTNULLDEFAULT0,last_time_contactedINTEGER,starredINTEGERNOTNULLDEFAULT0,display_nameTEXT,display_name_altTEXT,display_name_sourceINTEGERNOTNULLDEFAULT0,phonetic_nameTEXT,phonetic_name_styleTEXT,sort_keyTEXTCOLLATEPHONEBOOK,sort_key_altTEXTCOLLATEPHONEBOOK,name_verifiedINTEGERNOTNULLDEFAULT0,contact_in_visible_groupINTEGERNOTNULLDEFAULT0,sync1TEXT,sync2TEXT,sync3TEXT,sync4TEXT)

AswithmostAndroidtables,therawcontactstablehasthe_IDcolumnthatuniquelyidentifiesarawcontact.Together,thefield’saccount_nameandaccount_typeidentifytheaccounttowhichthiscontact(specifically,therawcontact)belongs.Thesourceidfieldindicateshowthisrawcontactisuniquelyidentifiedintheaccount.

Thefieldcontact_idreferstotheaggregatedcontactthatthisrawcontactisoneof.Anaggregatedcontactpointstooneormoresimilarcontactsthatareessentiallythesamepersonsetupamongmultipleaccounts.

Thefielddisplay_namepointstothedisplaynameofthecontact.Thisisprimarilyaread-onlyfield.Itissetbytriggersbasedonthedatarowsaddedinthedatatable(whichiscoveredinthenextsubsection)forthisrawcontact.

Thesyncfieldsareusedbytheaccounttosynccontactsbetweenthedeviceandtheserver-sideaccountsuchasGooglemail.

AlthoughwehaveusedSQLitetoolstoexplorethesefields,thereismorethanonewayto

Page 702: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

discoverthesefields.TherecommendedwayistofollowtheclassdefinitionsasdeclaredintheContactsContractAPI.Toexplorethecolumnsbelongingtoarawcontact,youcanlookattheclassdocumentationforContactsContract.RawContacts.

Thereareadvantagesanddisadvantagestothisapproach.AsignificantadvantageisthatyougettoknowthefieldspublishedandacknowledgedbytheAndroidSDK.Thedatabasecolumnsmaygetaddedordroppedwithoutchangingthepublicinterface.Soifyouusethedatabasecolumnsdirectly,theymayormaynotbethere.Instead,ifyouusethepublicdefinitionsforthesecolumns,youaresafebetweenreleases.

Onedisadvantage,however,isthattheclassdocumentationhasmanyotherconstantsinterspersedwithcolumnnames;wekindofgotlostinfiguringoutwhatwaswhat.ThesenumerousclassdefinitionsgivetheimpressionthattheAPIiscomplexwhen,inreality,80%oftheclassdocumentationfortheContactsAPIistodefineconstantsforthesecolumnsandtheURIstoaccesstheserows.

WhenweexercisetheContactsAPIinlatersections,wewillusetheclass-documentation-basedconstantsinsteadofdirectcolumnnames.However,wefeltthedirectexplorationofthetableswasthequickestwaytohelpyouunderstandtheContactsAPI.

Let’stalknextabouthowthedatarelatingtoacontact(suchase-mailandphonenumber)isstored.

UnderstandingtheContactsDataTableAsseenfromtherawcontacttabledefinition,therawcontact(inananticlimacticsense)isjustanIDindicatingwhataccountitbelongsto.Datapertainingtothecontactisnotintherawcontacttablebutsavedinthedatatable.Eachdataelement,suchase-mailandphonenumber,isstoredasseparaterowsinthedatatabletiedbytherawcontactID.Thedatatable,whosedefinitionisshowninListing27-4,contains16genericcolumnsthatcanstoreanytypeofdataelementsuchasane-mail.

Listing27-4.ContactDataTableDefinition

CREATETABLEdata(_idINTEGERPRIMARYKEYAUTOINCREMENT,package_idINTEGERREFERENCESpackage(_id),mimetype_idINTEGERREFERENCESmimetype(_id)NOTNULL,raw_contact_idINTEGERREFERENCESraw_contacts(_id)NOTNULL,is_primaryINTEGERNOTNULLDEFAULT0,is_super_primaryINTEGERNOTNULLDEFAULT0,data_versionINTEGERNOTNULLDEFAULT0,data1TEXT,data2TEXT,data3TEXT,data4TEXT,data5TEXT,data6TEXT,data7TEXT,data8TEXT,data9TEXT,data10TEXT,data11TEXT,data12TEXT,data13TEXT,data14TEXT,data15TEXT,data_sync1TEXT,data_sync2TEXT,data_sync3TEXT,data_sync4TEXT)

Page 703: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Theraw_contact_idpointstotherawcontacttowhichthisdatarowbelongs.Themimetype_idpointstotheMIMEtypeentryindicatingoneofthetypesidentifiedinthecontactdatatypesinListing27-4.Thecolumnsdata1throughdata15aregenericstring-basedtablesthatcanstoreanythingthatisnecessarybasedontheMIMEtype.Thesyncfieldssupportcontactsyncing.ThetablethatresolvestheMIMEtypeIDsisinListing27-5.

Listing27-5.ContactsMIMETypeLookupTableDefinition

CREATETABLEmimetypes(_idINTEGERPRIMARYKEYAUTOINCREMENT,mimetypeTEXTNOTNULL)

Aswiththerawcontactstable,youcandiscoverthedatatablecolumnsthroughthehelperclassdocumentationforContactsContract.Data.Althoughyoucanfigureoutthecolumnsfromthisclassdefinition,youwillnotknowwhatisstoredineachofthegenericcolumnsfromdata1throughdata15.Toknowthis,youwillneedtoseetheclassdefinitionsforanumberofclassesunderthenamespaceContactsContract.CommonDataKinds.

Someexamplesoftheseclassesfollow:

ContactsContract.CommonDataKinds.Email

ContactsContract.CommonDataKinds.Phone

Infact,youwillseeoneclassforeachofthepredefinedMIMEtypes.Theseclassesareasfollows:Email,Event,GroupMembership,Identity,Im,Nickname,Note,Organization,Phone,Photo,Relation,SipAddress,StructuredName,StructuredPostal,Website.Ultimately,alltheCommonDataKindsclassesdoisindicatewhichgenericdatafields(data1throughdata15)areinuseandwhatfor.

UnderstandingAggregatedContactsUltimately,acontactanditsrelateddataareunambiguouslystoredintherawcontactstableandthedatatable.Anaggregatedcontact,ontheotherhand,isheuristicandcouldbeambiguous.

Whenthereisacontactthatisthesamebetweenmultipleaccounts,youmaywanttoseeonenameinsteadofseeingthesameorsimilarnamerepeatedonceforeveryaccount.Androidaddressesthisbyaggregatingcontactsintoaread-onlyview.Androidstorestheseaggregatedcontactsinatablecalledcontacts.Androidusesanumberoftriggersontherawcontacttableandthedatatabletopopulateorchangethisaggregatedcontacttable.

Beforegoingintoexplainingthelogicbehindaggregation,letusshowyouthecontacttabledefinition(seeListing27-6).

Listing27-6.AggregatedContactTableDefinition

Page 704: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

CREATETABLEcontacts(_idINTEGERPRIMARYKEYAUTOINCREMENT,name_raw_contact_idINTEGERREFERENCESraw_contacts(_id),photo_idINTEGERREFERENCESdata(_id),custom_ringtoneTEXT,send_to_voicemailINTEGERNOTNULLDEFAULT0,times_contactedINTEGERNOTNULLDEFAULT0,last_time_contactedINTEGER,starredINTEGERNOTNULLDEFAULT0,in_visible_groupINTEGERNOTNULLDEFAULT1,has_phone_numberINTEGERNOTNULLDEFAULT0,lookupTEXT,status_update_idINTEGERREFERENCESdata(_id),single_is_restrictedINTEGERNOTNULLDEFAULT0)

Noclientdirectlyupdatesthistable.Whenarawcontactisaddedwithitsdetail,Androidsearchesotherrawcontactstoseeiftherearesimilarrawcontacts.Ifthereisone,itwillusetheaggregatedcontactIDofthatrawcontactastheaggregatedcontactIDofthenewrawcontactaswell.Noentryismadeintotheaggregatedcontacttable.Ifnoneisfound,itwillcreateanaggregatedcontactandusethataggregatedcontactasthecontactIDforthatrawcontact.

Androidusesthefollowingalgorithmtodeterminewhichrawcontactsaresimilar:

1. Thetworawcontactshavematchingnames,bothfirstandlast.

2. Thewordsinthenamearethesamebutvaryinorder:“firstlast”or“first,last”or“last,first.”

3. Theshorterversionsofthenamesmatch,suchas“Bob”for“Robert.”

4. Ifoneoftherawcontactshasjustafirstorlastname,thiswilltriggerasearchforotherattributes,suchasphonenumberore-mail,andiftheotherattributesmatch,thecontactwillbeaggregated.

5. Ifoneoftherawcontactsismissingthenamealtogether,thiswillalsotriggerasearchforotherattributesasinstep4.

Becausetheserulesareheuristic,somecontactsmaybeaggregatedunintentionally.Theclientapplicationsneedtoprovideamechanismtoseparatethecontactsinsuchacase.IfyourefertotheAndroidUser’sGuide,youwillseethatthedefaultcontactsapplicationallowsyoutoseparatecontactsthatareunintentionallymerged.

Youcanalsopreventtheaggregationbysettingtheaggregationmodewhenyouinserttherawcontact.TheaggregationmodesareshowninListing27-7.

Listing27-7.AggregationModeConstants

AGGREGATION_MODE_DEFAULT

Page 705: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AGGREGATION_MODE_DISABLEDAGGREGATION_MODE_SUSPENDED

Thefirstoptionisobvious;itishowaggregationworks.

Thesecondoption(disabled)keepsthisrawcontactoutofaggregation.Evenifitisaggregatedalready,AndroidwillpullitoutofaggregationandallocateanewaggregatedcontactIDdedicatedtothisrawcontact.

Thethirdoption(suspended)indicatesthateventhoughthepropertiesofthecontactmaychange,whichwillmakeitinvalidfortheaggregationintothatbatchofcontacts,itshouldbekepttiedtothataggregatedcontact.

Thelastpointbringsoutthevolatiledimensionoftheaggregatedcontact.Sayyouhaveauniquerawcontactwithafirstnameandalastname.Rightnow,itdoesn’tmatchanyotherrawcontact,sothisuniquerawcontactgetsitsownallocationofanaggregatedcontact.TheaggregatedcontactIDwillbestoredintherawcontacttableagainstthatrawcontactrow.

However,yougoandchangethelastnameofthisrawcontact,whichmakesitamatchtoanothersetofcontactsthatareaggregated.Inthatcase,Androidwillremovetherawcontactfromthisaggregatedcontactandmoveittotheotherone,abandoningthissingleaggregatedcontactbyitself.Inthiscase,theIDoftheaggregatedcontactbecomesentirelyabandoned,asitwillnotmatchanythinginthefuturebecauseitisjustanIDwithoutanunderlyingrawcontact.

Soanaggregatedcontactisvolatile.ThereisnotasignificantvaluetoholdontothisaggregatedcontactIDovertime.

Androidofferssomerespitefromthispredicamentbyprovidingafieldcalledlookupintheaggregatedcontactstables.Thislookupfieldisanaggregation(concatenation)oftheaccountandtheuniqueIDofthisrawcontactinthataccountforeachrawcontact.ThisinformationisfurthercodifiedsothatitcanbepassedasaURLparametertoretrievethelatestaggregatedcontactID.AndroidlooksatthelookupkeyandseeswhichunderlyingrawcontactIDsarethereforthislookupkey.Itthenusesabest-fitalgorithmtoreturnasuitable(orperhapsnew)aggregatedcontactID.

Whileweareexplicitlyexaminingthecontactsdatabase,let’sconsideracoupleofcontact-relateddatabaseviewsthatareuseful.

Exploringview_contactsThefirstoftheseviewsistheview_contacts.Althoughthereisatablethatholdstheaggregatedcontacts(contactstable),theAPIdoesn’texposethecontactstabledirectly.Instead,itusesview_contactsasthetargetforreadingtheaggregatedcontacts.WhenyouquerybasedontheURIContactsContract.Contacts.CONTENT_URI,thecolumnsreturnedarebasedonthisviewview_contacts.Thedefinitionofview_contactsviewisshowninListing27-8.

Listing27-8.AViewtoReadAggregatedContacts

Page 706: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

CREATEVIEWview_contactsAS

SELECTcontacts._idAS_id,contacts.custom_ringtoneAScustom_ringtone,name_raw_contact.display_name_sourceASdisplay_name_source,name_raw_contact.display_nameASdisplay_name,name_raw_contact.display_name_altASdisplay_name_alt,name_raw_contact.phonetic_nameASphonetic_name,name_raw_contact.phonetic_name_styleASphonetic_name_style,name_raw_contact.sort_keyASsort_key,name_raw_contact.sort_key_altASsort_key_alt,name_raw_contact.contact_in_visible_groupASin_visible_group,has_phone_number,lookup,photo_id,contacts.last_time_contactedASlast_time_contacted,contacts.send_to_voicemailASsend_to_voicemail,contacts.starredASstarred,contacts.times_contactedAStimes_contacted,status_update_id

FROMcontactsJOINraw_contactsASname_raw_contactON(name_raw_contact_id=name_raw_contact._id)

Noticethattheview_contactsviewcombinesthecontactstablewiththerawcontacttablebasedontheaggregatedcontactID.

Exploringcontact_entities_viewAnotherusefulviewisthecontact_entities_viewthatcombinestherawcontactstablewiththedatatable.Thisviewallowsustoretrieveallthedataelementsofagivenrawcontactonetime,oreventhedataelementsofmultiplerawcontactsbelongingtothesameaggregatedcontact.Listing27-9presentsthedefinitionofthisviewbasedoncontactentities.

Listing27-9.ContactEntitiesView

CREATEVIEWcontact_entities_viewAS

SELECTraw_contacts.account_nameASaccount_name,raw_contacts.account_typeASaccount_type,raw_contacts.sourceidASsourceid,raw_contacts.versionASversion,

Page 707: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

raw_contacts.dirtyASdirty,raw_contacts.deletedASdeleted,raw_contacts.name_verifiedASname_verified,packageASres_package,contact_id,raw_contacts.sync1ASsync1,raw_contacts.sync2ASsync2,raw_contacts.sync3ASsync3,raw_contacts.sync4ASsync4,mimetype,data1,data2,data3,data4,data5,data6,data7,data8,data9,data10,data11,data12,data13,data14,data15,data_sync1,data_sync2,data_sync3,data_sync4,

raw_contacts._idAS_id,

is_primary,is_super_primary,data_version,data._idASdata_id,raw_contacts.starredASstarred,raw_contacts.is_restrictedASis_restricted,groups.sourceidASgroup_sourceid

FROMraw_contactsLEFTOUTERJOINdataON(data.raw_contact_id=raw_contacts._id)LEFTOUTERJOINpackagesON(data.package_id=packages._id)LEFTOUTERJOINmimetypesON(data.mimetype_id=mimetypes._id)LEFTOUTERJOINgroupsON(mimetypes.mimetype='vnd.android.cursor.item/group_membership'ANDgroups._id=data.data1)

TheURIsneededtoaccessthisviewareavailableintheclassContactsContract.RawContactsEntity.

WorkingwiththeContactsAPISofar,wehaveexploredthebasicideabehindtheContactsAPIbyexploringitstablesandviews.Wewillnowpresentanumberofcodesnippetsthatcanbeusedtoexplorecontacts.Thesesnippetsaretakenfromthesampleapplicationthatisdevelopedtosupportthischapter.Althoughthesnippetsaretakenfromthesampleapplication,theyaresufficienttoaidtheunderstandingofhowtheContactsAPIwork.YoucandownloadthefullsampleprogramusingtheprojectdownloadURLattheendofthischapter.

Page 708: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ExploringAccountsWewillstartourexercisebywritingaprogramthatcanprintoutthelistofaccounts.Wehavealreadygiventhecodesnippetsnecessarytogetalistofaccounts.ConsidertheclassAccountsFunctionTesterinListing27-10.

Listing27-10.AccountsFunctionTesterThatPrintsAvailableAccounts

//Javaclass:AccountsFunctionTester.java//Menutoinvokethis:Accounts//BaseTesterisasupportingbaseclassholdingtheparentactivity//andsomereusedcommonvariables.Seethesourcecodeifyouaremorecurious.publicclassAccountsFunctionTesterextendsBaseTester{privatestaticStringtag="tc>";

//IReportBackisasimplelogginginterfacethatwriteslogmessages//tothemainactivityandalsotothelog.publicAccountsFunctionTester(Contextctx,IReportBacktarget){super(ctx,target);}publicvoidtestAccounts(){AccountManageram=AccountManager.get(this.mContext);Account[]accounts=am.getAccounts();for(Accountac:accounts){Stringacname=ac.name;Stringactype=ac.type;this.mReportTo.reportBack(tag,acname+":"+actype);}}}

NoteAswepresentandexploretheJavacodenecessarytoworkwithcontacts,youwillseethreevariablesrepeatedlyusedinthepresentedsourcecode:

mContext:Avariablepointingtoanactivity

mReportTo:Avariableimplementingalogginginterface(IReportBack—youcanseethisJavafileinthedownloadableproject)thatcanbeusedtologmessagestothetestactivitythatisusedforthischapter

Utils:Astaticclassthatencapsulatesverysimpleutilitymethods

WehavechosennottolisttheseclassesherebecausetheywilldistractyoufromunderstandingthecorefunctionalityoftheContactsAPI.Youcanexaminetheseclassesinthedownloadableproject.

Page 709: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Allthecodeinthischapterusesanunmanagedqueryagainstthecontentprovider.ThisisdonebycallingActivity.getContentResolver().query().Thisisbecausewemerelyreadthedataandprintouttheresultsrightaway.IfyourgoalinsteadistouseUI(throughactivitiesorfragments)asatargettodisplayyourcontactsthenreadChapter27onloaders.Loadersshowtherightwaytodisplaycursorsfromanycontentprovider.

Whenyourunthesampleprogramthatyoucandownloadforthischapter,youwillseeamainactivitythatappearswithanumberofmenuoptions.Themenuoption“Accounts”willprintthelistofaccountsavailableonthedevice.

ExploringAggregatedContactsLet’sseehowwecanexploreaggregatedcontactsthroughcodesnippets.Toreadcontacts,youneedtorequestthefollowingpermissioninthemanifestfile:

android.permission.READ_CONTACTS

Asthefunctionalitywearetestingdealswithcontentproviders,URIs,andcursors,let’slookatsomeusefulcodesnippetspresentedinListing27-11.(Thesecodesnippetsareavailableeitherinutils.javaorinsomeofthebaseclassesderivedfromBaseTesterinthechapter’sdownloadableproject.)

Listing27-11.GettingaCursorGivenaURIandawhereClause

//Utils.java//RetrieveacolumnfromacursorpublicstaticStringgetColumnValue(Cursorcc,Stringcname){inti=cc.getColumnIndex(cname);returncc.getString(i);}//SeewhatcolumnsarethereinacursorprotectedstaticStringgetCursorColumnNames(Cursorc){intcount=c.getColumnCount();StringBuffercnamesBuffer=newStringBuffer();for(inti=0;i<count;i++){Stringcname=c.getColumnName(i);cnamesBuffer.append(cname).append(';');}returncnamesBuffer.toString();}

//FromURIFunctionTester.java,baseclassofsomeoftheothertesters

//GivenaURIandawhereclausereturnacursorprotectedCursorgetACursor(Uriuri,Stringclause){Activitya=(Activity)this.mContext;//mContextcoming

Page 710: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

fromBaseTesterreturna.getContentResolver().query(uri,null,clause,null,null);}

Inthissection,weareprimarilyexploringthecursorreturnedbyaggregatedcontactURIs.Eachrowreturnedbytheresultingcontactcursorwillhaveanumberoffields.Forourexample,wearenotinterestedinallthefieldsbutonlyafew.YoucanabstractthisoutintoanotherclasscalledanAggregatedContact.Listing27-12showsthisclass.

Listing27-12.AnObjectDefinitionforaFewFieldsofanAggregatedContact

//AggregatedContact.javapublicclassAggregatedContact{publicStringid;publicStringlookupUri;publicStringlookupKey;publicStringdisplayName;publicvoidfillinFrom(Cursorc){id=Utils.getColumnValue(c,"_ID");lookupKey=Utils.getColumnValue(c,ContactsContract.Contacts.LOOKUP_KEY);lookupUri=ContactsContract.Contacts.CONTENT_LOOKUP_URI+"/"+lookupKey;displayName=Utils.getColumnValue(c,ContactsContract.Contacts.DISPLAY_NAME);}}

InListing27-12weusethecursortoloadupthefieldsthatweareinterestedin.

GettingtheAggregatedContactsCursorListing27-13showshowtoretrieveacursorthatisacollectionofaggregatedcontacts.

Listing27-13.GettingaCursorforAllAggregatedContacts

//Getacursorofallcontacts.Specifythewhereclauseasnulltoindicateallrows.//Javaclass:AggregatedContactFunctionTester.java//Menuitemtoinvoke:ContactsCursorprivateCursorgetContacts(){Uriuri=ContactsContract.Contacts.CONTENT_URI;//SpecifyascendingordescendingwaytosortnamesStringsortOrder=ContactsContract.Contacts.DISPLAY_NAME+"COLLATELOCALIZEDASC";Activitya=(Activity)this.mContext;//Localvariablepointingtoanactivity

Page 711: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

returna.getContentResolver().query(uri,null,null,null,sortOrder);}

TheURIusedtoreadallthecontactsisContactsContract.Contacts.CONTENT_URI.YoucanpassthisURItothequery()functiontoretrieveacursor.Youcanpassnullasthecolumnprojectiontoreceiveallcolumns.Althoughthisisnotrecommendedinpractice,inourcase,itmakessensebecausewewanttoknowaboutallthecolumnsitreturns.Wehavealsousedthedisplaynameofthecontactasthesortorder.Noticehow,again,wehaveusedContactContract.Contactstogetthecolumnnameforthecontactdisplayname.IfyouweretoprintthefieldnamesfromthiscursoryouwillseethereturnedfieldsasthoseshowninListing27-14.Dependingonthereleasetheordermaybedifferentandmorecolumnsmaybeadded.Itisagoodpracticetoexplicitlyspecifyaprojectiontothequeryclause;thatwayyourcodewillworkacrossreleases.

Listing27-14.AggregatedContactsContentURICursorColumns

times_contacted;contact_status;custom_ringtone;has_phone_number;phonetic_name;phonetic_name_style;contact_status_label;lookup;contact_status_icon;last_time_contacted;display_name;sort_key_alt;in_visible_group;_id;starred;sort_key;display_name_alt;contact_presence;display_name_source;contact_status_res_package;contact_status_ts;photo_id;send_to_voicemail;

ReadingAggregatedContactDetailsNowthatwe’veexploredthecolumnsavailablewiththecontactscontentURI,let’spickafewcolumnsandseewhatcontactrowsareavailable.Weareinterestedinthefollowingcolumnsfromacontactcursor:displayname,lookupkey,andlookupURI.WeareconsideringthesefieldsbecausewewanttoseewhatthelookupkeyandlookupkeyURIlooklikebasedonwhatiscoveredinthetheorypartofthischapter.Specifically,weareinterestedinfiringoffthelookupURItoseewhattypeofacursoritreturns.

ThefunctionlistContacts()inListing27-15getsacontactscursorandprintsthesethreecolumnsforeachrowofthecursor.NotethatthislistingistakenfromaclassthatholdsalocalvariablecalledmContexttoindicatetheactivityandalocalvariablecalledmReportTotobeabletologanymessagestotheactivity.

Listing27-15.PrintingtheLookupKeysforanAggregatedContact

//Javaclass:AggregatedContactFunctionTester.java//Menuitemtoinvoke:ContactspublicvoidlistContacts(){

Cursorc=null;try{

Page 712: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

c=getContacts();inti=c.getColumnCount();this.mReportTo.reportBack(tag,"Numberofcolumns:"+i);this.printLookupKeys(c);}finally{if(c!=null)c.close();}}privatevoidprintLookupKeys(Cursorc){for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){Stringname=this.getContactName(c);StringlookupKey=this.getLookupKey(c);Stringluri=this.getLookupUri(lookupKey);this.mReportTo.reportBack(tag,name+":"+lookupKey);//logthis.mReportTo.reportBack(tag,name+":"+luri);//log}}privateStringgetLookupKey(Cursorcc){intlookupkeyIndex=cc.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);returncc.getString(lookupkeyIndex);}privateStringgetContactName(Cursorcc){returnUtils.getColumnValue(cc,ContactsContract.Contacts.DISPLAY_NAME);}privateStringgetLookupUri(Stringlookupkey){Stringluri=ContactsContract.Contacts.CONTENT_LOOKUP_URI+"/"+lookupkey;returnluri;}

ExploringtheLookupURI-BasedCursorNowthatweknowhowtoextractlookupURIsforagivenaggregatedcontact,let’sseewhatwecandowithalookupURI.

ThefunctionlistLookupUriColumns()inListing27-16willtakethefirstcontactfromthelistofallcontactsandthenformulatealookupURIforthatcontactandfireofftheURItoseewhatkindofacursoritreturnsbyprintingthecolumnnamesfromthatcursor.

Listing27-16.ExploringtheLookupURICursor

//Class:AggregatedContactFunctionTester.java,Menuitemto

Page 713: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

invoke:SingleContactCursorpublicvoidlistLookupUriColumns(){

Cursorc=null;try{c=getContacts();StringfirstContactLookupUri=getFirstLookupUri(c);printLookupUriColumns(firstContactLookupUri);}finally{if(c!=null)c.close();}}privateStringgetFirstLookupUri(Cursorc){

c.moveToFirst();if(c.isAfterLast()){Log.d(tag,"Norowstogetthefirstcontact");returnnull;}StringlookupKey=this.getLookupKey(c);returnthis.getLookupUri(lookupKey);}publicvoidprintLookupUriColumns(Stringlookupuri){

Cursorc=null;try{c=getASingleContact(lookupuri);inti=c.getColumnCount();this.mReportTo.reportBack(tag,"Numberofcolumns:"+i);intj=c.getCount();this.mReportTo.reportBack(tag,"Numberofrows:"+j);this.printCursorColumnNames(c);}finally{if(c!=null)c.close();}}//Usethelookupuri,retrieveasingleaggregatedcontactprivateCursorgetASingleContact(StringlookupUri){

Activitya=(Activity)this.mContext;returna.getContentResolver().query(Uri.parse(lookupUri),null,null,null,null);}

Asitturnsout,itjustreturnsacursor(asinListing27-14)thatisidenticalincolumnsforthatoftheaggregatedcontactcursorasinListing27-13,exceptthatithasonlyonerowpointingtothecontactforwhichthisisthelookupkey.AlsonoticethatwehaveusedthefollowinglookupURIdefinition:

ContactsContract.Contacts.CONTENT_LOOKUP_URI

YouknowfromthediscussionofthecontactlookupURIsthateachlookupURIrepresentsacollectionofrawcontactidentitiesthathavebeenconcatenated.Thatbeing

Page 714: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

thecase,youmighthaveexpectedthelookupURItoreturnaseriesofmatchingrawcontacts.However,thetestinListing27-16isshowingthatitisnotreturningacursorofrawcontactsbutinsteadacursorofcontacts.

NoteAlookupbasedonthecontactlookupURIreturnsanaggregatedcontactandnotarawcontact.

AnothertidbitisthatthelookupprocessfortheaggregatedcontactbasedonthelookupURIisnotlinearorexact.ThismeansAndroidwillnotlookforanexactmatchofthelookupkey.Instead,AndroidparsesthelookupkeyintoitsconstituentrawcontactsandthenfindstheaggregatedcontactIDthatmatchesthemostoftherawcontactrecordsandreturnsthataggregatedcontactrecord.

Oneconsequenceofthisisthatnopublicmechanismisavailabletogofromthelookupkeytoitsconstituentrawcontacts.Instead,youhavetofindthecontactIDforthatlookupkeyandthenfireoffarawcontactURIforthatcontactIDtoretrievethecorrespondingrawcontacts.

Hereisanothercodesnippetthatshowswhatisreturnedfromacursorasanobjectinsteadofasasetofcolumns.ThecodeinListing27-17returnsthefirstaggregatedcontactasanobject.

Listing27-17.CodeTestingAggregatedContacts

//Javaclass:AggregatedContactFunctionTester.javaprotectedAggregatedContactgetFirstContact(){

Cursorc=null;try{c=getContacts();c.moveToFirst();if(c.isAfterLast()){Log.d(tag,"Nocontacts");returnnull;}AggregatedContactfirstcontact=newAggregatedContact();firstcontact.fillinFrom(c);returnfirstcontact;}finally{if(c!=null)c.close();}}

ExploringRawContactsInListing27-18,thefileRawContact.java,capturesafewimportantfieldsfromtherawcontactstablecursor.(Thisfile,likeallothercodesnippetsinthischapter,isavailableinthedownloadableprojectforthischapter.)

Listing27-18.SourcecodeforRawContact.java

Page 715: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Class:RawContact.javapublicclassRawContact{

publicStringrawContactId;publicStringaggregatedContactId;publicStringaccountName;publicStringaccountType;publicStringdisplayName;

publicvoidfillinFrom(Cursorc){rawContactId=Utils.getColumnValue(c,"_ID");accountName=Utils.getColumnValue(c,ContactsContract.RawContacts.ACCOUNT_NAME);accountType=Utils.getColumnValue(c,ContactsContract.RawContacts.ACCOUNT_TYPE);aggregatedContactId=Utils.getColumnValue(c,ContactsContract.RawContacts.CONTACT_ID);displayName=Utils.getColumnValue(c,"display_name");}publicStringtoString(){//..printsthepublicfields.Seethedownloadprojectfordetails}}//eof-class

ShowingtheRawContactsCursorAswiththeaggregatedcontactURIs,let’sfirstexaminethenatureoftherawcontactURIandwhatitreturns.ThesignaturefortherawcontactURIisdefinedasfollows:

ContactsContract.RawContacts.CONTENT_URI

ThefunctionshowRawContactsCursor()inListing27-19printsthecursorcolumnsforarawcontactsURI.

Listing27-19.ExploringtheRawContactsCursor

//Javaclass:RawContactFunctionTester.java;Menuitem:RawContactsCursorpublicvoidshowRawContactsCursor(){

Cursorc=null;try{c=this.getACursor(ContactsContract.RawContacts.CONTENT_URI,null);this.printCursorColumnNames(c);}finally{if(c!=null)c.close();}}

CodeinListing27-19willshowthattherawcontactcursorhasthefieldsshowninListing27-20(thislistseemtovarysomewhatwitheachdevice).

Page 716: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing27-20.RawContactsCursorFields

times_contacted;phonetic_name;phonetic_name_style;contact_id;version;last_time_contacted;aggregation_mode;_id;name_verified;display_name_source;dirty;send_to_voicemail;account_type;custom_ringtone;sync4;sync3;sync2;sync1;deleted;account_name;display_name;sort_key_alt;starred;sort_key;display_name_alt;sourceid;

SeeingtheDataReturnedbyaRawContactsCursorListing27-21showsthemethodshowAllRawContacts(),whichprintsalltherowsintherawcontactscursor.

Listing27-21.DisplayingRawContacts

//Javaclass:RawContactFunctionTester.java;Menuitem:AllRawContactspublicvoidshowAllRawContacts(){

Cursorc=null;try{c=this.getACursor(getRawContactsUri(),null);this.printRawContacts(c);}finally{if(c!=null)c.close();}}privatevoidprintRawContacts(Cursorc){for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){RawContactrc=newRawContact();rc.fillinFrom(c);this.mReportTo.reportBack(tag,rc.toString());//log}}

ConstrainingRawContactswithaCorrespondingSetofAggregatedContactsUsingthecolumnsofthecursorinListing27-20,let’sseeifwecanrefineourquerytoretrievethecontactsforagivenaggregatedcontactID.ThecodeinListing27-22willlookupthefirstaggregatedcontactandthenissuearawcontactURIwithawhereclausespecifyingavalueforthecontact_idcolumn.

Listing27-22.GettingRawContactsforanAggregatedContact

//Javaclass:RawContactFunctionTester.java;Menuitem:RawContactspublicvoidshowRawContactsForFirstAggregatedContact(){

Page 717: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AggregatedContactac=getFirstContact();Cursorc=null;try{c=this.getACursor(getRawContactsUri(),getClause(ac.id));this.printRawContacts(c);}finally{if(c!=null)c.close();}}privateStringgetClause(StringcontactId){return"contact_id="+contactId;}

ExploringRawContactDataBecauseadatarowbelongingtoarawcontactcontainsanumberoffields,wehavecreatedaJavaclasscalledContactData.java,showninListing27-23,tocapturearepresentativesetofthecontactdata,andnotallfields.

Listing27-23.SourcecodeforContactData.java

//ContactData.javapublicclassContactData{publicStringrawContactId;publicStringaggregatedContactId;publicStringdataId;publicStringaccountName;publicStringaccountType;publicStringmimetype;publicStringdata1;

publicvoidfillinFrom(Cursorc){rawContactId=Utils.getColumnValue(c,"_ID");accountName=Utils.getColumnValue(c,ContactsContract.RawContacts.ACCOUNT_NAME);accountType=Utils.getColumnValue(c,ContactsContract.RawContacts.ACCOUNT_TYPE);aggregatedContactId=

Utils.getColumnValue(c,ContactsContract.RawContacts.CONTACT_ID);mimetype=Utils.getColumnValue(c,ContactsContract.RawContactsEntity.MIMETYPE);data1=Utils.getColumnValue(c,ContactsContract.RawContactsEntity.DATA1);dataId=Utils.getColumnValue(c,ContactsContract.RawContactsEntity.DATA_ID);}

Page 718: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

publicStringtoString(){//justaconcatenationoffieldsforlogging}}

AndroidusesaviewcalledaRawContactEntityviewtoretrievedatafromarawcontacttableandthecorrespondingdatatablesasindicatedinthesection“contact_entities_view”inthischapter.TheURItoaccessthisviewisinListing27-24.

Listing27-24.RawEntitiesContentURI

ContactsContract.RawContactsEntity.CONTENT_URI

Let’sseehowthisURIcanbeusedtodiscoverfieldnamesreturnedbythisURI:

//Javaclass:ContactDataFunctionTester.java;Menuitem:ContactEntityCursorpublicvoidshowRawContactsEntityCursor(){Cursorc=null;try{Uriuri=ContactsContract.RawContactsEntity.CONTENT_URI;c=this.getACursor(uri,null);this.printCursorColumnNames(c);}finally{if(c!=null)c.close();}}

ThecodeinListing27-24printsoutthelistofcolumnsshowninListing27-25.SothecolumnsinListing27-25arethecolumnsthatarereturnedbytherawcontactsentitycursor.Theremaybeadditionalcolumnsdependingonvendor-specificimplementations.

Listing27-25.ContactEntitiesCursorColumns

data_version;contact_id;version;data12;data11;data10;mimetype;res_package;_id;data15;data14;data13;name_verified;is_restricted;is_super_primary;data_sync1;dirty;data_sync3;data_sync2;data_sync4;account_type;data1;sync4;sync3;data4;sync2;data5;sync1;data2;data3;data8;data9;deleted;group_sourceid;data6;data7;account_name;data_id;starred;sourceid;is_primary;

Onceyouknowthissetofcolumns,youcanfiltertheresultsetofthiscursorbyformulatingaproperwhereclause.However,youwanttousetheContactsContractJavaclasstousethedefinitionsforthesecolumnnames.Forexample,inListing27-26weretrievethedataelementspertainingtocontactIDs3,4,and5.

Listing27-26.DisplayingDataElementsfromRawContactsEntity

Page 719: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Javaclass:ContactDataFunctionTester.java;Menuitem:ContactDatapublicvoidshowRawContactsData(){Cursorc=null;try{Uriuri=ContactsContract.RawContactsEntity.CONTENT_URI;c=this.getACursor(uri,"contact_idin(3,4,5)");this.printRawContactsData(c);}finally{if(c!=null)c.close();}}protectedvoidprintRawContactsData(Cursorc){for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){ContactDatadataRecord=newContactData();dataRecord.fillinFrom(c);this.mReportTo.reportBack(tag,dataRecord.toString());}}

CodeinListing27-26willprintsuchthingsasname,e-mailaddress,andMIMEtypeasdefinedintheContactDataobjectinListing27-23.

AddingaContactwithItsDetailsLet’slookatacodesnippettoaddacontactwithname,e-mail,andphonenumber.Towritetocontacts,youneedthefollowingpermissioninthemanifestfile:

android.permission.WRITE_CONTACTS

CodeinListing27-27addsarawcontactfollowedbyaddingtwodatarows(nameandphonenumber)forthatcontact.

Listing27-27.AddingaContact

//Javaclass:AddContactFunctionTester.java;Menuitem:AddContactpublicvoidaddContact(){

longrawContactId=insertRawContact();this.mReportTo.reportBack(tag,"RawcontactId:"+rawContactId);insertName(rawContactId);insertPhoneNumber(rawContactId);showRawContactsDataForRawContact(rawContactId);}privatelonginsertRawContact(){ContentValuescv=newContentValues();cv.put(RawContacts.ACCOUNT_TYPE,"com.google");

Page 720: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

cv.put(RawContacts.ACCOUNT_NAME,"--useyourgmailid—");UrirawContactUri=this.mContext.getContentResolver().insert(RawContacts.CONTENT_URI,cv);longrawContactId=ContentUris.parseId(rawContactUri);returnrawContactId;}privatevoidinsertName(longrawContactId){ContentValuescv=newContentValues();cv.put(Data.RAW_CONTACT_ID,rawContactId);cv.put(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE);cv.put(StructuredName.DISPLAY_NAME,"JohnDoe_"+rawContactId);this.mContext.getContentResolver().insert(Data.CONTENT_URI,cv);}privatevoidinsertPhoneNumber(longrawContactId){ContentValuescv=newContentValues();cv.put(Data.RAW_CONTACT_ID,rawContactId);cv.put(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE);cv.put(Phone.NUMBER,"123123"+rawContactId);cv.put(Phone.TYPE,Phone.TYPE_HOME);this.mContext.getContentResolver().insert(Data.CONTENT_URI,cv);}privatevoidshowRawContactsDataForRawContact(longrawContactId){Cursorc=null;try{Uriuri=ContactsContract.RawContactsEntity.CONTENT_URI;c=this.getACursor(uri,"_id="+rawContactId);this.printRawContactsData(c);}finally{if(c!=null)c.close();}}

CodeinListing27-27doesthefollowing:

1. Addsanewrawcontactforapredefinedaccountusingtheaccount’snameandtype,representedbythemethodinsertRawContact().NoticehowitusestheURIRawContact.CONTENT_URI.

2. TakestherawcontactIDfromstep1andinsertsanamerecordusingtheinsertName()methodinthedatatable.NoticehowitusestheURIData.CONTENT_URI.

Page 721: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

3. TakestherawcontactIDfromstep1andinsertsaphonenumberrecordusingtheinsertPhoneNumber()methodinthedatatable.Beingadatarow,itusesData.CONTENT_URIastheURI.

Listing27-27alsodemonstratesthecolumnaliasesusedininsertingrecords.NoticehowconstantslikePhone.TYPEandPhone.NUMBERpointtothegenericdatatablecolumnnamesdata1anddata2.

ControllingAggregationofContactsClientsthatupdateorinsertcontactsdonotexplicitlychangethecontactstable.Thecontactstableisupdatedbytriggersthatlookintotherawcontacttableandrawcontactdatatable.

Rawcontactsthatgetaddedorchanged,inturn,affecttheaggregatedcontactsinthecontactstable.However,youmaynotwanttoallowtwocontactstobeaggregated.

Youcancontroltheaggregationbehaviorofarawcontactbysettingtheaggregationmodewhenthatcontractiscreated.AsyoucanseefromtherawcontacttablecolumnsinListing27-20,therawcontacttablecontainsafieldcalledaggregation_mode.ValuesfortheaggregationmodeareshowninListing27-7andexplainedinthesection“AggregatedContacts.”

Youcanalsokeeptwocontactsalwaysapartbyinsertingrowsintoatablecalledagg_exceptions.TheURIsneededtoinsertintothistablearedefinedintheJavaclassContactsContract.AggregationExceptions.Thetablestructureofagg_exceptionsisshowninListing27-28.

Listing27-28.AggregateExceptionsTableDefinition

CREATETABLEagg_exceptions(_idINTEGERPRIMARYKEYAUTOINCREMENT,typeINTEGERNOTNULL,raw_contact_id1INTEGERREFERENCESraw_contacts(_id),raw_contact_id2INTEGERREFERENCESraw_contacts(_id))

ThetypecolumninListing27-28holdsoneoftheintegerconstantsinListing27-29.

Listing27-29.AggregationTypesintheAggregationExceptionTable

ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHERContactsContract.AggregationExceptions.TYPE_KEEP_SEPARATEContactsContract.AggregationExceptions.TYPE_AUTOMATIC

TYPE_KEEP_TOGETHERsaysthetworawcontactsshouldneverbebrokenapart.TYPE_KEEP_SEPARATEsaysthattheserawcontactsshouldneverbejoined.TYPE_AUTOMATICsaystousethedefaultalgorithmtoaggregatecontacts.

TheURIyouwillusetoinsert,read,andupdatethistableisdefinedas

Page 722: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContactsContract.AggregationExceptions.CONTENT_URI

ConstantsforfielddefinitionstoworkwiththistablearealsoavailableintheJavaclassContactsContract.AggregationExceptions.

UnderstandingPersonalProfileApersonalprofile,introducedinAPI14,islikeacontact,exceptthereisonlyonepersonalprofilecontact.Thatisthesingularyou,onyourdevice.

However,asanimplementationdetail,alldatapertainingtothesingularpersonalprofilecontactismaintainedinaseparatedatabasecalledprofile.db.Ourresearchshowsthatthisdatabasehasastructureidenticaltocontacts2.db.Thismeansyoualreadyknowwhatrelevanttablesareavailableandwhatthecolumnsofeachtableare.

Beingasinglecontact,theaggregationisstraightforward.Everyrawcontactthatisaddedtothepersonalprofileisexpectedtobelongtothesingularaggregatedcontact.Ifonedoesn’texist,thenanewaggregatedcontactiscreatedandplacedinthenewrawcontact.Ifoneexists,thatcontactIDisusedastheaggregatedcontactIDfortherawcontact.

TheAndroidSDKusesthesamebaseclassContactsContracttodefinethenecessaryURIstoread/update/delete/addrawcontactstothepersonalprofile.TheseURIsparalleltheircounterpartsbutwiththestring“PROFILE”somewhereinthem.Listing27-30showsafewoftheseURIs.

Listing27-30.Profile-BasedURIsIntroducedin4.0

//RelatestoprofileaggregatedcontactContactsContract.Profile.CONTENT_URI

//RelatestoprofilebasedrawcontactContactsContract.Profile.CONTENT_RAW_CONTACTS_URI

//Relatestoprofilebasedrawcontact+profilebaseddatatableContactsContract.RawContactsEntity.PROFILE_CONTENT_URI

Listing27-30showswehaveseparateURIswhendealingwithaggregatedcontactandarawcontact.However,thereisn’tacorrespondingpersonalprofileURIfortheDatatable.ThesameDataURI,Data.CONTENT_URI,isapplicabletobothregularcontactdataandalsotheprofilecontactdata.

Alsonotethatthesamecontentproviderservestheneedsofboththepersonalprofileandregularcontacts.Internally,thiscontentproviderknowsbasedontherawcontactIDifthedataURIbelongstotheprofiledataortheregularcontactdata.

Let’slooknextatcodesnippetstoreadandaddcontactdatatothepersonalprofile.YouwillneedthepermissionsfromListing27-31toreadfromandwritetotheprofiledata.

Listing27-31.PermissionsReading/WritingProfileData

Page 723: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

<uses-permissionandroid:name="android.permission.READ_PROFILE"/><uses-permissionandroid:name="android.permission.WRITE_PROFILE"/>

ReadingProfileRawContactsLet’susethefollowingURItoreadtherawcontactsthatbelongtothepersonalprofile:

ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI

Listing27-32showshowtoreadprofilerawcontactentries.

Listing27-32.ShowingAllProfileRawContacts

//Javaclass:ProfileRawContactFunctionTester.java;Menuitem:PRawContacts//InthedownloadthismethodisnamedshowAllRawContacts//Itisexpandedhereforclarity.publicvoidshowAllRawProfileContacts(){Cursorc=null;try{StringwhereClause=null;c=this.getACursor(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI,whereClause);this.printRawContacts(c);}finally{if(c!=null)c.close();}}//InthedownloadthismethodisnamedprintRawContacts//Itisexpandedhereforclarity.privatevoidprintRawProfileContacts(Cursorc){for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){RawContactrc=newRawContact();rc.fillinFrom(c);this.mReportTo.reportBack(tag,rc.toString());}}

Noticethatonceweretrievethecursor,thedataitcontainsmatchestheRawContactthatwedefinedearlierforaregularrawcontact.

ReadingProfileContactDataLet’susethefollowingURItoreadthevariousdataelements(suchase-mail,MIMEtype,andsoon)ofrawcontactsthatbelongtothepersonalprofile:

Page 724: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContactsContract.RawContactsEntity.PROFILE_CONTENT_URI

Noticehowweareusingasimilarviewasinthecaseofregularcontacts.TheRawContactEntityisajoinbetweenrawcontactsandthedatarowsbelongingtothatrawcontact.Wewillseeonerowforeachdataelementsuchasname,e-mail,MIMEtype,andsoon.

Listing27-33showsthecodesnippettoreadprofilerawcontactentries.

Listing27-33.ShowingDataElementsforProfileContacts

//Javaclass:ProfileContactDataFunctionTester.java;Menuitem:allprawcontactspublicvoidshowProfileRawContactsData(){

Cursorc=null;try{Uriuri=ContactsContract.RawContactsEntity.PROFILE_CONTENT_URI;StringwhereClause=null;c=this.getACursor(uri,whereClause);this.printProfileRawContactsData(c);}finally{if(c!=null)c.close();}}protectedvoidprintProfileRawContactsData(Cursorc){for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){ContactDatadataRecord=newContactData();dataRecord.fillinFrom(c);this.mReportTo.reportBack(tag,dataRecord.toString());}}

Noticethatonceweretrievethecursor,thedataitcontainsmatchestheContactDataobject(Listing27-23)thatwedefinedearlierforaregularrawcontactdataelement.

AddingDatatothePersonalProfileLet’susethefollowingURItoaddarawcontacttoapersonalprofile:

ContactsContract.RawContactsEntity.PROFILE_CONTENT_URI

Wewillalsoaddafewdataelementssuchasaphonenumberandanicknametothatrawcontactsotheyappearinthedetailsofyourpersonalprofileonthedevice.Listing27-34showsthecodesnippet.

Listing27-34.AddingaProfileRawContact

//Javaclass:AddProfileContactFunctionTester.java;Menuitem:allprawcontacts

Page 725: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

//Inthesourcecodeyouwon'tseetheword"profile"inthefollowingmethodnames//ItisaddedheretoaddclarityasthewholeclassisnotincludedpublicvoidaddProfileContact(){

longrawContactId=insertProfileRawContact();this.mReportTo.reportBack(tag,"RawcontactId:"+rawContactId);insertProfileNickName(rawContactId);insertProfilePhoneNumber(rawContactId);showProfileRawContactsDataForRawContact(rawContactId);}privatevoidinsertProfileNickName(longrawContactId){

ContentValuescv=newContentValues();cv.put(Data.RAW_CONTACT_ID,rawContactId);//cv.put(Data.IS_USER_PROFILE,"1");

cv.put(Data.MIMETYPE,CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);cv.put(CommonDataKinds.Nickname.NAME,"PJohnNickname_"+rawContactId);this.mContext.getContentResolver().insert(Data.CONTENT_URI,cv);}privatevoidinsertProfilePhoneNumber(longrawContactId){

ContentValuescv=newContentValues();cv.put(Data.RAW_CONTACT_ID,rawContactId);cv.put(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE);cv.put(Phone.NUMBER,"P123123"+rawContactId);cv.put(Phone.TYPE,Phone.TYPE_HOME);this.mContext.getContentResolver().insert(Data.CONTENT_URI,cv);}privatelonginsertProfileRawContact(){

ContentValuescv=newContentValues();cv.put(RawContacts.ACCOUNT_TYPE,"com.google");cv.put(RawContacts.ACCOUNT_NAME,"--useyourgmailid--");UrirawContactUri=this.mContext.getContentResolver()

.insert(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI,cv);longrawContactId=ContentUris.parseId(rawContactUri);returnrawContactId;}privatevoidshowProfileRawContactsDataForRawContact(longrawContactId){

Cursorc=null;

Page 726: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

try{Uriuri=ContactsContract.RawContactsEntity.PROFILE_CONTENT_URI;c=this.getACursor(uri,"_id="+rawContactId);this.printRawContactsData(c);}finally{if(c!=null)c.close();}}

ThecodeinListing27-34parallelsthecodeweusedtoaddaregularcontactanditsdetails(Listing27-27).Althoughwehaveusedaprofile-specificURItoaddarawcontact,wehaveusedthesameData.CONTENT_URItoaddtheindividualdataelements.

Notethefollowingcommented-outcodeinListing27-34:

//cv.put(Data.IS_USER_PROFILE,"1");

BecauseData.CONTENT_URIisnotspecifictotheprofile,howdoestheunderlyingcontentproviderknowwhethertoinsertthisdataintoaregularrawcontactorapersonalprofilerawcontact?WethoughtthatspecifyingacolumncalledIS_USER_PROFILEwouldhelpthecontentprovider.Apparentlynot.Thisnewcolumnisavailableprimarilyforreadpurposes.Yourinsertswillfailifyouspecifythisduringinserts.TheonlyconclusionthenisthatthecontentproviderisrelyingontherawcontactIDtoseewhetherthatrawcontactcamefromprofile.dborcontacts2.db.

RoleofSyncAdaptersSofar,wehavemainlytalkedaboutmanipulatingthecontactsonthedevice.However,accountsandtheircontactsonAndroidworkhandinhandwithserver-basedcontacts.Forexample,ifyouhavecreatedaGoogleaccountonyourAndroidphone,theGoogleaccountwillpullyourGmailcontactsandmakethemavailableonthedevice.TodothissyncingAndroidprovidesasynchronizationframeworkwhichdoesmostofthegroundworkaslongasyouwriteaconformingSyncadapter.Android’ssynchronizationframeworktakescareofnetworkavailability,optionalauthentication,andscheduling.

ImplementingasyncadapterinvolvesimplementingaservicebyextendingtheSDKclassAbstractThreadedSyncAdapteranddoingtheworkinthemethodonPerformSync().WorkinvolvedinthismethodistoloaddatafromserversandupdatethecontactsusingtheContactsAPIthatisdiscussedinthischapter.Then,async-adapterresourcefile(XML)needstobecreatedonthedevicethatwilldescribehowthisserviceistiedtotheaccountthatneedstobesynched.

Outsideofthisbasicunderstanding,duetospacelimitationswehavenotcoveredthesyncingAPIinthiseditionofthebook.AndroidSDKdocumentationhassomedocumentationandsamples.

Synchronizationofcontactshasimpactsondeletingcontactsonthedevice.Whenyou

Page 727: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

deleteacontactusingtheaggregatedcontactURI,itwilldeleteallitscorrespondingrawcontactsandthedataelementsofeachofthoserawcontacts.However,Androidwillonlymarkthemasdeletedonthedeviceandexpectsthebackgroundsynctoactuallysyncwiththeserverandthendeletethecontactspermanentlyfromthedevice.Thiscascadingofdeletesalsohappensattherawcontactlevelwherethecorrespondingdataelementsofthatrawcontactaredeleted.

UsingBatchOperationstoOptimizeContentProviderUpdatesWhilecoveringcontentprovidersinChapter26weindicatedthatwewouldcoverthebatchoperationsinthischapter.

Reconsiderhowarawcontactanditsassociateddataelementsarecreatedearlierinthechapter.Noticethemultiplecommandsweneedtosendtothecontactsprovidertoinsertarawcontact.Firstwehavetoinsertrawcontact.ThenusethatIDtoinsertmultipledataelementsbelongingtothatrawcontact.Eachoftheseinsertsisaseparatecommandsenttothecontentproviderindependently.

Therearetwoissueswhenwesendthesemultiplecommandssequentially.Thefirstissueisthatthecontentproviderisnotawarethattheybelongtoasinglecommitunit.Thesecondissueisthatitwilltakelongertoupdatethecontentproviderdatabaseaseachtransactioniscommittedbyitself.

ThesetwoissuesareaddressedbythebatchupdateAPIavailableforanycontentproviderincludingthecontactprovider.

IdeaofBatchingContentProviderUpdatesInthebatchingapproach,eachcontentproviderupdateoperationisencapsulatedinanobjectcalled“ContentProviderOperation”alongwiththeURIandallthenecessarykey/valuepairstoperformthatoperation.Thenyougathertheseoperationsintoalistobject.Youthentellthecontentresolvertosendtheentirebatchorlistofcommandstothecontentprovideratthesametime.Becausethecontentproviderknowsthesecommandsareinabatch,itappliesthetransactionsappropriatelyeitherattheendorsooftenbasedonhints.

Ifanoperationindicatesthatatransactioncanbeappliedattheendofthatoperation,thentheoperationscompletedthusfarwillbecommitted.Thisallowsyoutosub-batchlongupdatesofmanyrowsintosmallersetofsub-rows.Youcanalsoindicateinanoperationthatoneofthecolumnstobeupdatedneedstousethekeyreturnedbyanindexedpreviousoperation.Wewillpresentnowsomesamplecodeshowinghowtheseideaswork.

Listing27-35showsanexampleofcreatingalistobjecttoholdalistofoperations.

Listing27-35.AContainerforContentProviderOperations

Page 728: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ArrayList<ContentProviderOperation>ops=newArrayList<ContentProviderOperation>();

LetusseenowhowtoconstructtheindividualoperationstobeaddedtothatlistinListing27-36.

Listing27-36.BatchingContentProviderOperations

ContentProviderOperation.Builderop=ContentProviderOperation.newInsert(acontentURI);op.withValue(key,value);//...moreoftheseContentProviderOperationop1=op.build();ops.add(op1);

ThekeyclassisContentProviderOperationanditscorrespondingBuilderobject.Intheexamplehereweareusingtheinsertoperation.Fortherestofthemethodsseetheclassreference.OncewehaveabuilderalongwithitsassociatedcontentURI,wetellthebuildertoaddsetofkey/valuepairsthatgoalongwiththatcontentURI.Oncefinishedaddingallthekey/valuepairsweproducetheContentProviderOperationfromthebuilderandaddittothelist.WethenaskthecontentresolvertoapplythebatchofoperationsusingthecodeinListing27-37.

Listing27-37.UsingaContentResolvedtoApplytheBatchofOperations

activity.getContentResolver().applyBatch(contentProviderAuthority,ops);

InListing27-37theargumentcontentProviderAuthorityistheauthoritystringpointingthecontentproviderandtheargumentopsisthelistofoperationsthatshouldbeappliedasabatchtothatcontentprovider.Thisisanexampleofaddingaseriesofupdateoperationsasasingletransaction.Letusseenowhowtoprovidecommithintstosothatcommitoperationscanbedoneonsmallersubsetsfromthegivenbatch.

BatchingCommitsbyYieldingOneproblemwithcommittingalargebatchofcommandsasasingletransactionisthatthisworkcanblockotheroperationsonthedatabase.Tohelpwiththisandalsotohelpwithtoomuchworktobecommittedinasingletransactionyoucaninstructanoperationtoyield.Whenthecontentproviderrecognizestheyieldparameteronanoperationitcommitstheworkdoneandpausestoyieldforotherprocessestorun.

NoticehowinthecodeinListing27-38oneoftheoperationsissettoallowyield.

Listing27-38.UsingYieldinaContentProviderOperation

ContentProviderOperation.BuilderoperationBuilder=ContentProviderOperation.newInsert(acontentURI);operationBuilder.withValue(key,value);//...moreofthesekey/valuepairswhenyouhavethem

Page 729: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ContentProviderOperationop1=operationBuilder.build();

//...AddMoreoperations

//MarkthenextoperationasyieldallowedoperationBuilder=ContentProviderOperation.newInsert(acontentURI);operationBuilder.withValue(key,value);operationBuilder.withYieldAllowed(true);//itisoktocommitContentProviderOperationoperationWithYield=operationBuilder.build();ops.add(operationWithYield);

//...AddMoreoperationsandyieldpointsasneeded

//Finallyapplythelistofoperationsactivity.getContentResolver().apply(contentProviderAuthority,ops);

UsingBackReferencesForoneoftheoperationsaboveyoucanuseabackreferenceasshowninListing27-39.

Listing27-39.UsingaBackReferenceinaContentProviderOperation

//Takethekeycomingoutofop1andadditasthevalueintindexOfTheOperationWhoseKeyYouNeed=0;op.withValueBackReference(mykey,indexOfTheOperationWhoseKeyYouNeed);

CodeinListing27-39isaskingthecontentprovidertoruntheoperationindicatedbylistindexindexOfTheOperationWhoseKeyYouNeedandtakeitsgeneratedprimarykeyanduseitasavalueforthecolumnthatissetonthetargetoperation.Thisishowyoutaketheinsertfromrawcontactanduseitsprimarykeyasthekeyvalueforthedataitemsbelongingtothatrawcontact.

OptimisticLockingInoptimisticlocking,youfirstapplythetransactionswithoutlockingtheunderlyingrepositoryandseeifanyupdateshavebeenmadesinceyouknowitsvaluebefore.Ifso,cancelthetransactionandretryit.

Tomakethisinthebatchmode,theAPIoffersatypeofoperationcalledanassertquery.Inthistypeofoperationthecontentprovidermakesthequeryandcomparesthevaluesoftheretrievedcursorforeitherthecountorthevaluesofcertainkeys.Iftheydon’tmatch,itrollsbackthetransactionandraisesanexceptionbreakingthecodeflow.SeethisdemonstratedinthecodeshowninListing27-40.

Page 730: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Listing27-40.UsingOptimisticLockingthroughnewAssertQuery

try{//ReadarawcontactforaparticularrawcontactidContentProviderOperation.BuilderassertOpBuilder=ContentProviderOperation.newAssertQuery(rawContactUri);//MakesurethereisonlyonerawcontactwiththatdetailsassertOpBuilder.withExpectedCount(1);//Makesuretheversioncolumnmatcheswithyoustartedwith//Ifnotthrowanexception.Wechosetocomparetheversionnumber//column(field)intherawcontactstabletoassert.assertOpBuilder.withValue(SyncColumns.VERSION,mVersion);//getthisoperationandaddittotheoperationslistattheend//Applythebatch…activityInstance.getContentResolver().applyBatch(...);}//forthisorotherexceptionscatch(OperationApplicationExceptione){//Thebatchisalreadycancelled//Telltheusertheupdatefailed//Showtheuserthenewdetailsandrepeattheprocess}

ReusingtheContactProviderUIContactprovidercapabilityinAndroidalsodefinesasetofintentsthatcanbeusedtoreusetheUIavailableinthecontactsapplication.

Therearethreekindsofintents.ThereisasetofintentsthatthecontactproviderfiresbasedontheeventstakingplaceinthecontentproviderUIapplication.Forexample,theintentINVITE_CONTACTisfiredwhentheuserclicksthe“invitetothenetwork”buttononacontactinthecontactapplication.Anapplicationcanregisterforthiseventandreadthecontactdetails.

Thereisanothersetofintentsthatareusedwhenthecontactprovideractsasasearchproviderforyourcustomactivities.Usingthisfacilityyoucansearchforacontactinyourcustomapplicationthroughsearchsuggestions.

ThereisanothersetofintentsthatexternalapplicationscanfiretoreusetheUIthatisprovidedbythecontactapplication.Youcanusetheseintentstopickfromalistofcontacts,orfromalistofphonenumbers,orfromalistofaddresses,orfromalistofe-mails.YoucanalsousetheseintentstoupdateacontactorcreateacontactusingtheUIprovidedtheAndroidapplication.

Page 731: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheseintentsaredocumentedintheclassreferenceforContactsContract.Intents.

UsingGroupFeaturesContactsAPIprovidesthecontractsshowninListing27-41toworkwiththeGroupFeaturesofcontacts

Listing27-41.GroupContactContracts

ContactsContract.GroupsContactsContract.CommonDataKinds.GroupMembership

Thegroupstableholdsthingslikenameofthegroup,notesaboutthatgroup,andsomegrouplevelcountsofthemembership.Thegroupsarawcontactbelongstoarekeptinthedatatables.

UsingPhotoFeaturesYoucanexplorethephoto-relatedinformationforacontactusingtheclasscontractshowninListing27-42.

Listing27-42.ContactPhotoContracts

ContactsContract.Contacts.PhotoContactsContract.RawContacts.DisplayPhoto

Theclassdocumentationforthesecontractshassamplecodethatdescribeshowtousethesefeatures.

ReferencesHereareadditionalresourcesforthetopicscoveredinthischapter:

https://developer.android.com/guide/topics/providers/contacts-provider.html:TheprimarydocumentationforallaspectsoftheContactsAPIfromGoogle.ThisURLalsoincludesasectiononperformingbatchoperationsonthecontactsdatabase,optimisticlocking,andreusingthecontactsapplicationUI.

http://developer.android.com/reference/android/provider/ContactsContract.htmlJavadocforthekeyJavaclassContactsContract.YouwillneedthisURLoftenasyoucodetotheContactsAPI.

https://play.google.com/store/books/details/Google_Android_Quick_Start_Guide_Android_5_0_Lolli?id=dnzVBAAAQBAJ:Android5.0QuickStartguide.TheseAndroiduserguidesthatarepreparedforeachreleaseareusefulin

Page 732: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

understandinghowthestockcontactsapplicationworkfromaUIperspective.

https://developer.android.com/guide/topics/providers/contacts-provider.html#SyncAdapters:SyncAdaptersaredocumentedhere.

http://developer.android.com/sdk/android-4.0.html#Contacts:DocumentationforthechangestotheContactsAPIin4.0.

http://developer.android.com/reference/android/provider/ContactsContract.Profile.htmlAreferenceonhowtousethenewProfileURIsintroducedin4.0.

http://www.androidbook.com/item/3917:EntrypointforourresearchontheContactsAPI.Youwillfindhereourresearch,asummaryoftheContactsAPI,tablesusedinthecontactsdatabase,howtoexplorethecontactsdatabases,contactsapplicationscreenshots,howtoexploresourcesforcontactproviders,andotherusefullinks.

http://developer.android.com/guide/topics/search/index.htmlSDKdocsonSearchAPI.Usefultoreviewthistoknowhowtosearchforcontacts.

http://www.androidbook.com/proandroid5/projects:YoucanusethisURLtodownloadthetestprojectdedicatedforthischapter.ThenameoftheZIPfileisProAndroid5_ch27_TestContacts.zip.

SummaryInthischapter,wehavecoveredthefollowing:thenatureoftheContactsAPI,exploringthecontactsdatabase,exploringtheContactsAPIURIsandtheircursors,readingandaddingcontacts,aggregatingrawcontacts,therelationshipbetweenthepersonalprofileandcontacts,andreadingandaddingcontactstoapersonalprofile.Wehavealsobrieflycoveredbatchingprovideroperations,usingthecontactproviderasasearchproviderforcontacts.

Page 733: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter28

ExploringSecurityandPermissionsNoexplorationofmoderndevelopmentplatformsoroperatingsystemsiscompletewithoutdiscussingsecurity.InAndroid,securityspansallphasesoftheapplicationlifecycle—fromdesign-timepolicyconsiderationstoruntimeboundarychecks.Inthischapteryou’lllearnAndroid’ssecurityarchitectureandunderstandhowtodesignsecureapplications.

Let’sgetstartedwiththeAndroidsecuritymodel.

UnderstandingtheAndroidSecurityModelLet’sdiverightin,tocoversecurityduringthedeploymentandexecutionofanyAndroidapplication.TodeployanAndroidapplication,itmustbesignedwithadigitalcertificateinorderforyoutoinstallitontoadevice.Withrespecttoexecution,Androidrunseachapplicationwithinaseparateprocess,whereeachprocesshasauniqueandpermanentuserID(assignedatinstalltime).Thisplacesaboundaryaroundtheprocessandpreventsoneapplicationfromhavingdirectaccesstoanother’sdata.Moreover,Androiddefinesadeclarativepermissionmodelthatprotectssensitivefeatures(suchasthecontactlist).

Inthenextseveralsections,wearegoingtodiscussthesetopics.Butbeforewegetstarted,let’sprovideanoverviewofsomeofthesecurityconceptsthatwe’llrefertolater.

OverviewofSecurityConceptsAndroidrequiresthatapplicationsbesignedwithadigitalcertificate.Oneofthebenefitsofthisrequirementisthatanapplicationcannotbeupdatedwithaversionthatwasnotpublishedbytheoriginalauthororholderofthesigningcertificate.Ifwepublishanapplication,forexample,thenyoucannotupdateourapplicationwithyourversion(unless,ofcourse,yousomehowobtainourcertificate).Thatsaid,whatdoesitmeanforanapplicationtobesigned?Andwhatistheprocessofsigninganapplication?

Yousignanapplicationwithadigitalcertificate.Adigitalcertificateisanartifactthatcontainsinformationaboutyou,suchasyourcompanyname,address,andsoon.Afewimportantattributesofadigitalcertificateincludeitssignatureandpublic/privatekey.Apublic/privatekeyisalsocalledakeypair.Notethatalthoughyouusedigitalcertificatesheretosign.apkfiles,youcanalsousethemforotherpurposes(suchasencryptedcommunication,signingdocuments,andsoforth).Youcanobtainadigitalcertificatefromatrustedcertificateauthority(CA)andyoucanalsogenerateoneyourselfusingtoolssuchasthekeytool,whichwe’lldiscussshortly.Digitalcertificatesarestoredinkeystores.Akeystorecontainsalistofdigitalcertificates,eachofwhichhasanaliasthatyoucanuse

Page 734: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

torefertoitinthekeystore.

SigninganAndroidapplicationrequiresthreethings:adigitalcertificate,the.apkfilefortheapplicationyouwishtosign,andautilitythatknowshowtoapplyadigitalsignaturetothe.apkfile.WeuseafreeutilitythatispartoftheJavaDevelopmentKit(JDK)distributioncalledthejarsigner.Thisutilityisacommand-linetoolthatknowshowtosigna.jarfileusingadigitalcertificate,andan.apkfileisreallyjustazip-formattedfilethatcollectstogether.jarfilesandafewotherresourcesforyourproject.Othersigningtoolsareavailable,soyouarefreetochoosethetoolthatworksbestforyou.

Now,let’smoveonandtalkabouthowyoucansignan.apkfilewithadigitalcertificate.

SigningApplicationsforDeploymentToinstallanAndroidapplicationontoadevice,youfirstneedtosigntheAndroidpackage(.apkfile)usingadigitalcertificate.Thecertificate,however,canbeself-signed—youdonotneedtopurchaseacertificatefromacertificateauthoritysuchasVeriSign.Beawarethatself-signedcertificatesaregenerallyconsideredlesstrustworthy,andinsomeenvironmentsareconsideredinsecure.

Signingyourapplicationfordeploymentinvolvesthreesteps.Thefirststepistogenerateacertificateusingkeytool(orasimilartool).Thesecondstepinvolvesusingthejarsignertooltosignthe.apkfilewiththegeneratedcertificate.Thethirdstepalignsportionsofyourapplicationonmemoryboundariesformoreefficientmemoryusagewhenrunningonadevice.Notethatduringdevelopment,boththeADTplug-inforEclipseandAndroidDeveloperStudiotakecareofeverythingforyou:signingyour.apkfileanddoingthememoryalignment,beforedeployingontotheemulatororadevice.

GeneratingaSelf-SignedCertificateUsingtheKeytoolThekeytoolutilitymanagesadatabaseofprivatekeysandtheircorrespondingX.509certificates(astandardfordigitalcertificates).ThisutilityshipswiththeJDKandresidesundertheJDKbindirectory.IfyoufollowedtheinstructionsinChapter2regardingchangingyourPATH,theJDKbindirectoryshouldalreadybeinyourPATH.Inthissection,we’llshowyouhowtogenerateakeystorewithasingleentry,whichyou’lllaterusetosignanAndroid.apkfile.Togenerateakeystoreentry,dothefollowing:

1. Createafoldertoholdthekeystore,suchasc:\android\release\.or/opt/android/release(dependingonyouroperatingsystem).

2. Openashellorcommandwindow,andexecutethekeytoolutilitywiththeparametersshowninListing28-1.

Listing28-1.GeneratingaKeystoreEntryUsingthekeytoolUtility

Page 735: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

keytool-genkey-v-keystore"c:\android\release\release.keystore"-aliasandroidbook-keyalgRSA-validity14000

AlloftheargumentspassedtothekeytoolaresummarizedinTable28-1.

Table28-1.ArgumentsPassedtothekeytoolUtility

Argument Description

genkey Tellskeytooltogenerateapublic/privatekeypair.

v Tellskeytooltoemitverboseoutputduringkeygeneration.

keystore Pathtothekeystoredatabase(inthiscase,afile).Thefilewillbecreatedifnecessary.

alias Uniquenameforthekeystoreentry.Thisaliasisusedlatertorefertothekeystoreentry.

keyalg Algorithm.

validity Validityperiod.

keytoolwillpromptyoufortwopasswordsduringthecreationofthekeystoreandtheentryyouarecreating.Thefirstpasswordpromptedisforthekeystoreitselfandcontrolsaccesstoallthekeymaterialyouwillstore.Thiscanalsobespecifiedusingthestorepassparameter.Thesecondpasswordisthepasswordfortheprivatekeyandrelatedcertificateyouarecreating,alsoavailableviathekeypassparameter.Youshouldgetusedtonotincludingtheseasparametersonthecommandline,andinsteadprefertoallowkeytooltopromptyouasgoodgeneralsecuritypractice.

Beaware,thatifyoudousetheparametersforpasswordtokeytool,anyonewhogetsaccesstoyourshellorcommand-linehistorycanseethepasswords,ascananyonewhocanlisttherunningprocessesonyourmachinewhilekeytoolruns.ThecommandinListing28-1willgenerateakeystoredatabasefileinyourkeystorefolder.Thedatabasewillbeafilenamedrelease.keystore.Thevalidityoftheentrywillbe14,000days(orapproximately38years)—whichisalongtimefromnow.Youshouldunderstandthereasonforthis.TheAndroiddocumentationrecommendsthatyouspecifyavalidityperiodlongenoughtosurpasstheentirelifespanoftheapplication,whichwillincludemanyupdatestotheapplication.Itrecommendsthatthevaliditybeatleast25years.IfyouplantopublishtheapplicationonGooglePlay,yourcertificatewillneedtobevalidthroughatleastOctober22,2033.GooglePlaycheckseachapplicationwhenuploadedtomakesureitwillbevalidatleastuntilthen.

CautionBecauseyourcertificateinanyapplicationupdatemustmatchthecertificateyouusedthefirsttime,makesureyousafeguardyourkeymaterial.Keepeitheryourkeystorefile,orthekeypairifyouchoosetoexportthem,safe!Ifyouloseaccesstothekeystoreorunderlyingkeys,andyoucan’tre-createit,youwon’tbeabletoupdateyourapplication,andyou’llhavetoissueawholenewapplicationinstead.

Page 736: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Goingbacktothekeytool,theargumentaliasisauniquenamegiventotheentryinthekeystoredatabase;youwillusethisnamelatertorefertotheentry.WhenyourunthekeytoolcommandinListing28-1,keytoolwillaskyouafewquestions(seeFigure28-1)andthengeneratethekeystoredatabaseandentry.

Figure28-1.Additionalquestionsaskedbykeytool

Onceyouhaveakeystorefileforyourproductioncertificates,youcanreusethisfiletoaddmorecertificates.Justusekeytoolagain,andspecifyyourexistingkeystorefile.

TheDebugKeystoreandtheDevelopmentCertificateWementionedthattheADTplug-inforEclipse,andAndroidDeveloperStudio,bothtakecareofsettingupadevelopmentkeystoreforyou.However,thedefaultcertificateusedforsigningduringdevelopmentcannotbeusedforproductiondeploymentontoarealdevice.Thisispartlybecausetheautomaticallygenerateddevelopmentcertificateisonlyvalidfor365days,whichclearlydoesnotgetyoupastOctober22,2033.Sowhathappensonthethreehundredsixty-sixthdayofdevelopment?You’llgetabuilderror.Yourexistingapplicationsshouldstillrun,buttobuildanewversionofanapplication,youneedtogenerateanewcertificate.Theeasiestwaytodothisistodeletetheexistingdebug.keystorefile,andassoonasitisneededagain,theADT(forinstance)willgenerateanewfileandcertificatevalidforanother365days.

Tofindyourdebug.keystorefile,assumingyouareusingEclipsewithADT,openthePreferencesscreenofEclipseandgotoAndroid Build.Thedebugcertificate’slocationwillbedisplayedintheDefaultDebugKeystorefield,asshowninFigure28-2(seeChapter2ifyouhavetroublefindingthePreferencesmenu).

Page 737: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure28-2.Thedebugcertificate’slocation

Ofcourse,nowthatyou’vegotanewdevelopmentcertificate,youcannotupdateyourexistingapplicationsinAndroidVirtualDevices(AVDs)orondevicesusinganewdevelopmentcertificate.EclipsewillprovidemessagesintheConsoletellingyoutouninstalltheexistingapplicationfirstusingadb,whichyoucancertainlydo.IfyouhavealotofyourapplicationsinstalledontoanAVD,youmayfeelitiseasiertosimplyre-createtheAVD,soitdoesnotcontainanyofyourapplicationsandyoucanstartfresh.Toavoidthisproblemayearfromnow,youcouldgenerateyourowndebug.keystorefilewithwhatevervalidityperiodyoudesire.Obviously,itneedstohavethesamefilenameandbeinthesamedirectoryasthefilethatADTwouldcreate.Thecertificatealiasisandroiddebugkey,andthestorepassandkeypassareboth“android”.ADTsetsthefirstandlastnameonthecertificateas“AndroidDebug”,theorganizationalunitas“Android”,andthetwo-lettercountrycodeas“US”.Youcanleavetheorganization,city,andstatevaluesas“Unknown”.

Ifyouacquiredamap-apikeyfromGoogleusingtheolddebugcertificate,youwillneedtogetanewmap-apikeytomatchthenewdebugcertificate.Wecoveredmap-apikeysinChapter19.

Nowthatyouhaveadigitalcertificatethatyoucanusetosignyourproduction.apkfile,youneedtousethejarsignertooltodothesigning.Here’showtodothat.

UsingtheJarsignerTooltoSignthe.apkFileThekeytoolutilitydescribedintheprevioussectioncreatedadigitalcertificate,whichisoneoftheparametersforthejarsignertool.TheotherparameterforjarsigneristheactualAndroidpackagetobesigned.TogenerateanAndroidpackage,youneedtousetheExportUnsignedApplicationPackageutilityintheADTplug-inforEclipse(orequivalentfunctioninAndroidDeveloperStudio).Youaccesstheutilitybyright-clicking

Page 738: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

anAndroidprojectinEclipse,selectingAndroidTools,andselectingExportUnsignedApplicationPackage.RunningtheExportUnsignedApplicationPackageutilitywillgeneratean.apkfilethatwillnotbesignedwiththedebugcertificate.

Toseehowthisworks,runtheExportUnsignedApplicationPackageutilityononeofyourAndroidprojects,andstorethegenerated.apkfilesomewhere.Forthisexample,we’llusethekeystorefolderwecreatedearlierandgeneratean.apkfilecalledc:\android\release\myappraw.apk.

Withthe.apkfileandthekeystoreentry,runthejarsignertooltosignthe.apkfile(seeListing28-2).Usethefullpathnamestoyourkeystorefileand.apkfileasappropriatewhenyourunthis.

Listing28-2.UsingjarsignertoSignthe.apkFile

jarsigner-keystore"PATHTOYOURrelease.keystoreFILE"-storepasspaxxword-keypasspaxxword"PATHTOYOURRAWAPKFILE"androidbook

Tosignthe.apkfile,youpassthelocationofthekeystore,thekeystorepassword,theprivate-keypassword,thepathtothe.apkfile,andthealiasforthekeystoreentry.Thejarsignerwillthensignthe.apkfilewiththedigitalcertificatefromthekeystoreentry.Torunthejarsignertool,youwillneedtoeitheropenatoolswindow(asexplainedinChapter2)oropenacommandorTerminalwindowandeithernavigatetotheJDKbindirectoryorensurethatyourJDKbindirectoryisonthesystempath.Forsecurityreasons,itissafertoleaveoffthepasswordargumentstothecommandandsimplyletjarsignerpromptyouasnecessaryforpasswords.Figure28-3showswhatthejarsignertoolinvocationlookslike.YoumayhavenoticedthatjarsignerpromptedforonlyonepasswordinFigure28-3.Jarsignerfiguresoutnottoaskforthekeypasspasswordwhenthestorepassandkeypassarethesame.Strictlyspeaking,thejarsignercommandinListing28-2onlyneeds–keypassifithasadifferentpasswordthan–storepass.

Figure28-3.Usingjarsigner

Aswepointedoutearlier,Androidrequiresthatanapplicationbesignedwithadigitalsignaturetopreventamaliciousprogrammerfromupdatingyourapplicationwiththeirversion.Forthistowork,Androidrequiresthatupdatestoanapplicationbesignedwiththesamesignatureastheoriginal.Ifyousigntheapplicationwithadifferentsignature,Androidtreatsthemastwodifferentapplications.Soweremindyouagain,becarefulwithyourkeystorefilesoit’savailabletoyoulaterwhenyouneedtoprovideanupdatetoyour

Page 739: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

application.

AligningYourApplicationwithzipalignYouwantyourapplicationtobeasmemoryefficientaspossiblewhenrunningonadevice.Ifyourapplicationcontainsuncompresseddata(perhapscertainimagetypesordatafiles)atruntime,Androidcanmapthisdatastraightintomemoryusingthemmap()call.Forthistowork,though,thedatamustbealignedona4-bytememoryboundary.TheCPUsinAndroiddevicesare32-bitprocessors,and32bitsequals4bytes.Themmap()callmakesthedatainyour.apkfilelooklikememory,butifthedataisnotalignedona4-byteboundary,itcan’tdothatandextracopyingofdatamustoccuratruntime.Thezipaligntool,foundintheAndroidSDKbuildorbuild-tools/<version>directory,looksthroughyourapplicationandmovesslightlyanyuncompresseddatanotalreadyona4-bytememoryboundarytoa4-bytememoryboundary.Youmayseethefilesizeofyourapplicationincreaseslightlybutnotsignificantly.Toperformanalignmentonyour.apkfile,usethiscommandinatoolswindow(seealsoFigure28-4):

zipalign–v4infile.apkoutfile.apk

Figure28-4.Usingzipalign

Notethatzipaligndoesnotmodifytheinputfile,sothisiswhywechosetouse“raw”aspartofourfilenamewhenexportingfromEclipse.Now,ouroutputfilehasanappropriatenamefordeployment.Ifyouneedtooverwriteanexistingoutfile.apkfile,youcanusethe–foption.Alsonotethatzipalignperformsaverificationofthealignmentwhenyoucreateyouralignedfile.Toverifythatanexistingfileisproperlyaligned,usezipaligninthefollowingway:

zipalign–c–v4filename.apk

Itisveryimportantthatyoualignaftersigning;otherwise,signingcouldcausethingstogobackoutofalignment.Thisdoesnotmeanyourapplicationwouldcrash,butitcouldusemorememorythanitneedsto.

UsingtheExportWizardInEclipse,youmayhavenoticedamenuchoiceunderAndroidToolscalledExport

Page 740: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SignedApplicationPackage.Thislauncheswhatiscalledtheexportwizard,anditdoesallofthepreviousstepsforyou,promptingonlyforthepathtoyourkeystorefile,keyalias,thepasswords,andthenameofyouroutput.apkfile.Itwillevencreateanewkeystoreornewkeyifyouneedone.Youmayfinditeasiertousethewizard,oryoumayprefertoscriptthestepsyourselftooperateonanexportedunsignedapplicationpackage.Nowthatyouknowhoweachworks,youcandecidewhichisbetterforyou.

ManuallyInstallingAppsOnceyouhavesignedandalignedan.apkfile,youcaninstallitontothevirtualdevicemanuallyusingtheadbtool.Asanexercise,startthevirtualdevicefromtheAVDManager,whichwillstartwithoutcopyingoveranyofyourdevelopmentprojectsfromEclipse.Now,openatoolswindowandruntheadbtoolwiththeinstallcommand:

adbinstall"PATHTOAPKFILEGOESHERE"

Thismayfailforacoupleofreasons,butthemostlikelyarethatthedebugversionofyourapplicationwasalreadyinstalledontheemulator,givingyouacertificateerror,orthereleaseversionofyourapplicationwasalreadyinstalledontheemulator,givingyouan“INSTALL_FAILED_ALREADY_EXISTS”error.Inthefirstcase,youcanuninstallthedebugapplicationwiththiscommand:

adbuninstallpackagename

Notethattheargumenttouninstallistheapplication’spackagenameandnotthe.apkfilename.ThepackagenameisdefinedintheAndroidManifest.xmlfileoftheinstalledapplication.

Forthesecondcase,youcanusethiscommand,where–rsaystoreinstalltheapplicationwhilekeepingitsdataonthedevice(oremulator):

adbinstall–r"PATHTOAPKFILEGOESHERE"

Now,let’sseehowsigningaffectstheprocessofupdatinganapplication.

InstallingUpdatestoanApplicationandSigningEarlier,wementionedthatacertificatehasanexpirationdateandthatGooglerecommendsyousetexpirationdatesfarintothefuture,toaccountforalotofapplicationupdates.Thatsaid,whathappensifthecertificatedoesexpire?WouldAndroidstillruntheapplication?Fortunately,yes—Androidteststhecertificate’sexpirationonlyatinstalltime.Onceyourapplicationisinstalled,itwillcontinuetorunevenifthecertificateexpires.

Butwhataboutupdates?Unfortunately,youwillnotbeabletoupdatetheapplicationoncethecertificateexpires.Inotherwords,asGooglesuggests,youneedtomakesurethelifeofthecertificateislongenoughtosupporttheentirelifeoftheapplication.Ifacertificatedoesexpire,Androidwillnotinstallanupdatetotheapplication.Theonlychoiceleftwillbeforyoutocreateanotherapplication—anapplicationwithadifferentpackagename—

Page 741: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

andsignitwithanewcertificate.Soasyoucansee,itiscriticalforyoutoconsidertheexpirationdateofthecertificatewhenyougenerateit.

Nowthatyouunderstandsecuritywithrespecttodeploymentandinstallation,let’smoveontoruntimesecurityinAndroid.

PerformingRuntimeSecurityChecksRuntimesecurityinAndroidhappensattheprocessandoperationlevels.Attheprocesslevel,Androidpreventsoneapplicationfromdirectlyaccessinganotherapplication’sdata.ItdoesthisbyrunningeachapplicationwithinadifferentprocessandunderauniqueandpermanentuserID.Attheoperationallevel,Androiddefinesalistofprotectedfeaturesandresources.Foryourapplicationtoaccessthisinformation,youhavetoaddoneormorepermissionrequeststoyourAndroidManifest.xmlfile.Youcanalsodefinecustompermissionswithyourapplication.

Inthesectionsthatfollow,wewilltalkaboutprocess-boundarysecurityandhowtodeclareandusepredefinedpermissions.Wewillalsodiscusscreatingcustompermissionsandenforcingthemwithinyourapplication.Let’sstartbydissectingAndroidsecurityattheprocessboundary.

UnderstandingSecurityattheProcessBoundaryUnlikeyourdesktopenvironment,wheremostoftheapplicationsrununderthesameuserID,eachAndroidapplicationgenerallyrunsunderitsownuniqueID.ByrunningeachapplicationunderadifferentID,Androidcreatesanisolationboundaryaroundeachprocess.Thispreventsoneapplicationfromdirectlyaccessinganotherapplication’sdata.

Althougheachprocesshasaboundaryaroundit,datasharingbetweenapplicationsisobviouslypossiblebuthastobeexplicit.Inotherwords,togetdatafromanotherapplication,youhavetogothroughthecomponentsofthatapplication.Forexample,youcanqueryacontentproviderofanotherapplication,youcaninvokeanactivityinanotherapplication,or—asyou’llseeinChapter15—youcancommunicatewithaserviceofanotherapplication.Allofthesefacilitiesprovidemethodsforyoutoshareinformationbetweenapplications,buttheydosoinanexplicitmannerbecauseyoudon’tdirectlyaccesstheunderlyingdatabase,files,andsoon.

Android’ssecurityattheprocessboundaryisclearandsimple.Thingsgetinterestingwhenwestarttalkingaboutprotectingresources(suchascontactdata),features(suchasthedevice’scamera),andourowncomponents.Toprovidethisprotection,Androiddefinesapermissionscheme.Let’sdissectthatnow.

DeclaringandUsingPermissionsAndroiddefinesapermissionschememeanttoprotectresourcesandfeaturesonthedevice.Forexample,applications,bydefault,cannotaccessthecontactslist,makephonecalls,andsoon.Toprotecttheuserfrommaliciousapplications,Androidrequires

Page 742: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

applicationstorequestpermissionsiftheyneedtouseaprotectedfeatureorresource.FromtheintroductionofAndroidKitKat,andcontinuinginAndroidLollipop,permissionswhenpresentedtotheenduserarenowclusteredintogroupstoaddresstheirconstantlygrowingnumberandcomplexity.Thisgroupingbringswithitsomecompromisesasyouwillobserve.

Aswewillcovershortly,permissionrequestsgointhemanifestfile.Atinstalltime,theAPKinstallereithergrantsordeniestherequestedpermissionsbasedonthesignatureofthe.apkfileand/orfeedbackfromtheuser.Ifpermissionisnotgranted,anyattempttoexecuteoraccesstheassociatedfeaturewillresultinapermissionfailure.

Table28-2showssomecommonlyusedfeaturesandthepermissionstheyrequire.Althoughyouarenotyetfamiliarwithallthefeatureslisted,youwilllearnaboutthemlater(eitherinthischapterorinsubsequentchapters).

Table28-2.FeaturesandResourcesandthePermissionsTheyRequire

Feature/ResourceRequiredPermission Description

Camera android.permission.CAMERA Enablesyoutoaccessthedevice’scamera.

Internet android.permission.INTERNET Enablesyoutomakeanetworkconnection.

User’scontactdata

android.permission.READ_CONTACTS

android.permission.WRITE_CONTACTSEnablesyoutoreadfromorwritetotheuser’scontactdata.

User’scalendardata

android.permission.READ_CALENDAR

android.permission.WRITE_CALENDAREnablesyoutoreadfromorwritetotheuser’scalendardata.

Recordingaudio

android.permission.RECORD_AUDIO Enablesyoutorecordaudio.

Wi-Filocationinformation

android.permission.ACCESS_COARSE_LOCATIONEnablesyoutoaccesscoarse-grainedlocationinformationfromWi-Fiandcelltowers.

GPSlocationinformation

android.permission.ACCESS_FINE_LOCATION

Enablesyoutoaccessfine-grainedlocationinformation.ThisincludesGPSlocationinformation.ItisalsosufficientforWi-Fiandcelltowers.

Batteryinformation

android.permission.BATTERY_STATS Enablesyoutoobtainbattery-stateinformation.

Bluetooth android.permission.BLUETOOTH EnablesyoutoconnecttopairedBluetoothdevices.

Foracompletelistofpermissions,seethefollowingURL:

http://developer.android.com/reference/android/Manifest.permission.html

Applicationdeveloperscanrequestpermissionsbyaddingentriestothe

Page 743: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AndroidManifest.xmlfile.Forexample,Listing28-3askstoaccessthecameraonthedevice,toreadthelistofcontacts,andtoreadthecalendar.

Listing28-3.PermissionsinAndroidManifest.xml

<manifest…><application>...</application><uses-permissionandroid:name="android.permission.CAMERA"/><uses-permissionandroid:name="android.permission.READ_CONTACTS"/><uses-permissionandroid:name="android.permission.READ_CALENDAR"/></manifest>

Notethatyoucaneitherhard-codepermissionsintheAndroidManifest.xmlfileorusethemanifesteditor.Themanifesteditoriswireduptolaunchwhenyouopen(double-click)themanifestfile.Themanifesteditorcontainsadrop-downlistthathasallofthepermissionspreloadedtopreventyoufrommakingamistake.AsshowninFigure28-5,youcanaccessthepermissionslistbyselectingthePermissionstabinthemanifesteditor.

Figure28-5.TheAndroidmanifesteditortoolinEclipse

YounowknowthatAndroiddefinesasetofpermissionsthatprotectsasetoffeaturesandresources.Similarly,youcandefineandenforcecustompermissionswithyourapplication.Let’sseehowthatworks.

UnderstandingandUsingURIPermissions

Page 744: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Contentproviders(discussedinChapter4)oftenneedtocontrolaccessatafinerlevelthanallornothing.Fortunately,Androidprovidesamechanismforthis.Thinkaboute-mailattachments.Theattachmentmayneedtobereadbyanotheractivitytodisplayit.Buttheotheractivityshouldnotgetaccesstoallofthee-maildataanddoesnotneedaccesseventoallattachments.ThisiswhereURIpermissionscomein.

PassingURIPermissionsinIntentsWheninvokinganotheractivityandpassingaURI,yourapplicationcanspecifythatitisgrantingpermissionstotheURIbeingpassed.Butbeforeyourapplicationcandothis,itneedspermissionitselftotheURI,andtheURIcontentprovidermustcooperateandallowthegrantingofpermissionstoanotheractivity.ThecodetoinvokeanactivitywithgrantingofpermissionslookslikeListing28-4,whichisactuallyfromtheAndroidEmailprogram,whereitislaunchinganactivitytoviewane-mailattachment.

Listing28-4.CodetoLaunchanActivitywithGrantingofPermission

try{Intentintent=newIntent(Intent.ACTION_VIEW);intent.setData(contentUri);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);startActivity(intent);}catch(ActivityNotFoundExceptione){mHandler.attachmentViewError();//TODO:Addaproperwarningmessage(andlotsofupstreamcleanuptoprevent//itfromhappening)inthenextrelease.}

TheattachmentisspecifiedbycontentUri.NoticehowtheintentiscreatedwiththeactionIntent.ACTION_VIEW,andthedataissetusingsetData().Theflagissettograntreadpermissionoftheattachmenttowhateveractivitywillmatchontheintent.Thisiswherethecontentprovidercomesintoplay.Justbecauseanactivityhasreadpermissiontocontentdoesn’tmeanitcanpassalongthatpermissiontosomeotheractivitythatdoesnothavethepermissionalready.Thecontentprovidermustallowitaswell.AsAndroidfindsamatchingintentfilteronanactivity,itconsultswiththecontentprovidertomakesurethatpermissionscanbegranted.Inessence,thecontentproviderisbeingaskedtoallowaccesstothisnewactivitytothecontentspecifiedbytheURI.Ifthecontentproviderrefuses,thenaSecurityExceptionisthrown,andtheoperationfails.InListing28-4,thisparticularapplicationisnotcheckingforaSecurityException,becausethedeveloperisnotexpectinganyrefusalstograntpermission.That’sbecausetheattachmentcontentproviderispartoftheEmailapplication!Thereisapossibilitythoughthatnoactivitycanbefoundtohandletheattachment,sothatistheonlyexceptionbeingwatchedfor.

InthecasewheretheactivitybeingcalledtoprocesstheURIalreadyhaspermissiontoaccessthatURI,thecontentproviderdoesnotgettodenyaccess.Thatis,thecallingactivitycangrantpermission,andiftheactivityonthereceivingendoftheintentalready

Page 745: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

hasthenecessarypermissionsforcontentURI,thecalledactivitywillbeallowedtoproceedwithnoproblems.

InadditiontoIntent.FLAG_GRANT_READ_URI_PERMISSION,thereisaflagforwritepermissions:Intent.FLAG_GRANT_WRITE_URI_PERMISSION.ItispossibletospecifybothinanIntent.Also,theseflagscanapplytoservicesandBroadcastReceiversaswellasactivitiesbecausetheycanreceiveintentstoo.

SpecifyingURIPermissionsinContentProvidersSohowdoesacontentproviderspecifyURIpermissions?ItdoessointheAndroidManifest.xmlfileinoneoftwoways:

Inthe<provider>tag,theandroid:grantUriPermissionsattributecanbesettoeithertrueorfalse.Iftrue,anycontentfromthiscontentprovidercanbegranted.Iffalse,thesecondwayofspecifyingURIpermissionscanhappen,orthecontentprovidercandecidenottoletanyoneelsegrantpermissions.

Specifypermissionswithchildtagsof<provider>.Thechildtagis<grant-uri-permission>,andyoucanhavemorethanonewithin<provider>.<grant-uri-permission>hasthreepossibleattributes:

Usingtheandroid:pathattribute,youcanspecifyacompletepathwhichwillthenhavepermissionsthataregrantable.

Similarly,android:pathPrefixspecifiesthebeginningofaURIpath.

android:pathPatternallowswildcards(theasterisk,*,character)tospecifyapath.

Aswestatedbefore,thegrantingentitymustalsohaveappropriatepermissionstothecontentbeforebeingallowedtograntthemtosomeotherentity.Contentprovidershaveadditionalwaysofcontrollingaccesstotheircontent,throughtheandroid:readPermissionattributeofthe<provider>tag,theandroid:writePermissionattribute,andtheandroid:permissionattribute(aconvenientwaytospecifybothreadandwritepermissionswithonepermissionStringvalue).ThevalueforanyofthesethreeattributesisaStringthatrepresentsthepermissionacallermusthaveinordertoreadorwritewiththiscontentprovider.BeforeanactivitycouldgrantreadpermissiontoacontentURI,thatactivitymusthavereadpermissionfirst,asspecifiedbyeithertheandroid:readPermissionattributeortheandroid:permissionattribute.Theentitywantingthesepermissionswoulddeclarethemintheirmanifestfilewiththe<uses-permissions>tag.

Page 746: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://developer.android.com/guide/topics/security/security.htmlTheAndroidDeveloper’sGuidesection“SecurityTips.”Itprovidesanoverviewwithlinkstolotsofreferencepages.

http://developer.android.com/guide/publishing/app-signing.html:TheAndroidDeveloper’sGuidesection“SigningYourApplications.”

SummaryThissecuritychaptercoveredthefollowingtopics:

UniqueapplicationuserIDsthathelpseparateappsfromeachothertoprotectprocessinganddata

DigitalcertificatesandtheiruseinsigningAndroidapplications

Thatanapplicationcanonlybeupdatediftheupdateissignedwiththesamedigitalcertificateastheoriginal

Managingcertificatesinakeystoreusingkeytool

Runningjarsignertoapplyacertificatetoanapplication.apkfile

zipalignandmemoryboundaries

TheEclipseplug-inwizardtakescareofgeneratingtheapk,applyingthecertificateandzipalign-ingforyou

Manuallyinstallingappsontodevicesandemulators

Permissionsthatapplicationscandeclareanduse

URIpermissionsandhowcontentprovidersusethem

Page 747: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter29

UsingGoogleCloudMessagingwithAndroidAsweapproachtheendofthebook,youwillhavealreadydevelopedagoodunderstandingof,andappreciationfor,themanycommunicationprotocolsandarchitecturaloptionsyouhaveavailablewithinAndroidwhenitcomestodealingwithoff-deviceservices.Inthischapter,wewillexploreGoogle’sCloudMessaging(orGCM)platformandhowyoucanuseitastheplumbingforyourapplication’sremotecommunicationandserviceinteractionneeds.

WhatIsGoogleCloudMessaging?GCMisaserviceofferedbyGoogletoenableyoutowritemultipleapplicationsacrossdifferentplatformsthatexchangemessagesinordertofurthertheirfunctionality.TheprimaryexamplesofthemultipleapplicationsareanAndroidclientapplicationexchangingmessageswitharemoteserverapplication.

Theactualmessagessent,andtheirpurpose,areuptoyouasadeveloper.Itcouldbeamessagefromtheremoteserverlettingyourclientapplicationknow(a“downstream”message)thatanewupdatetoanewsfeed,musicservice,orsimilarsubscriptionisavailable.Messagesfromtheclienttotheserver(an“upstream”message)couldbesendingachatmessage,picturethumbnail,orothernewpieceofdatayouruserhascapturedorgeneratedontheclient.Thesearejustexamples—youarefreetoimagineanyuse,andanypayload,forthemessagesexchangedinGCM.

UnderstandingtheKeyBuildingBlocksofGCMHavingreadtheintroductiontoGCM,youarealreadyawareoftwoofthekeycomponentsinanycompleteGCMconfiguration.ThefinalparttocompletethepictureistheGCMserver(infact,servers)hostedbyGooglethatperformthemessagequeuing,forwarding,andsoforth.

Torecap,thethreekeybuildingblocksforGCMareasfollows:

ClientApplication—Anapplicationyouwrite,suchasanAndroidapplication,thatsendsand/orreceivesmessagesfromaremoteservertohelpwithfunctionality.

GCMConnectionServers—Google’smessaginginfrastructure,whichmanagesallmessagingtraffic,messagequeuingintheeventofdeliverydelays,ultimatedeliveryguarantees,etc.

Page 748: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RemoteApplicationServer—Anapplicationyourwriteasaserver,hostedinanInternet-accessiblefashion,responsibleforsendingand/orreceivingmessagesfromclientapplications.

Wecanalsorepresentthisarchitectureinvisualform.Figure29-1showsthecomponentsandmessageflowinacompleteGCMsetup.

Figure29-1.GCMarchitecturaloverview

PreparingtoUseGCMinYourApplicationWherepreviouslywehavejumpedstraightintoJavacode,layoutXML,andsoforthwhenconstructingexampleapplications,forGCM-baseddevelopmentweneedtoundertakeafewpreparatorystepsinordertohaveGoogle’sserversaccepttrafficfromourclientandserver.

CreatingorConfirmingYourGCMProjectinGoogleDeveloperConsoleTouseanyofGoogle’sonlineservicesandAPIs,includingGCM,youwillneedtocreateanAPIProjectwithintheGoogleDeveloperConsole,atcloud.google.com/console.Youmightalreadyhaveaprojectyoucanreuse,butlet’sassumeyouarecreatingoneforthefirsttime.NavigatetotheconsoleURLandclicktheCreateProjectbutton.Followthepromptsforaccountandbillingdetails,etc.,andyoushouldendupwithanewproject(orconfirmanexistingone)asshowninFigure29-2.

Page 749: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure29-2.YourGoogleDeveloperConsolewithAPIProjectinPlace

ActivatingtheGCMAPIsforYourProjectWiththeAPIProjectinplace,younowneedtoactivatethespecificGCMAPIs.GooglesupportsdozensofseparateAPIs,allofwhicharedisabledbydefaulttoensureyoudonotaccidentallytriggerbehaviororincurcostsyouwerenotexpecting.ClickonyourAPIProject(inourcase,api-project-589435632025)andundertheAPIs&Authsectionontheleftside,selectAPIsandscrolluntilyouseeGoogleCloudMessagingforAndroid.TurnthisonusingtheEnableAPIbutton.YouwillknowyouhavesuccessfullyenabledtheGCMAPIwhenthebuttonchangesfromEnableAPItoDisableAPI,asshowninFigure29-3.

Page 750: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Figure29-3.YourGoogleDeveloperConsoleAPIProjectwithGCMEnabled

GeneratingYourAPIKeyAswithotherGoogleAPIs,accesstotheGCMAPIforyourprojectrequiresyourkey.Thishelpsensureeverythingfromtrafficseparation,soyourGCMmessagesarenotinadvertentlymixedwiththoseofotherapplications,throughtobilling,analytics,andsoforth.

Togenerateyourkey,choosetheCredentialsoptionunderAPIs&Auth.ChoosetheCreateNewKeyoption,andwhenpromptedforkeyproperties,selectServerforthekeytype.IfyouknowthepublicIPaddressofyourintendedserver,youcanusethatintheconfigurationsection,otherwiseyoucanuse0.0.0.0/0fortestingpurposes.ThenchooseCreatetohavethekeygenerated.Whenyouarereturnedtotheconsole,youshouldseeyourAPIkeyavailableundertheCredentialssubmenu.Notedownthekeyvalueasyouwillneeditshortly.

AuthenticatingGCMCommunicationTheAPIkeyisnottheonlypieceofidentifyinginformationusedtoauthenticateandauthorizemessagetransferwithinaGCMenvironment.YoucanfindmoredetailontheusesofGCMtokensandkeysonthedeveloper.google.comwebsite.Inbrief,thefollowingfourtokentypesareusedinyourGCMapplications:

SenderIDTheprojectIDcodeavailablefromtheGoogledeveloper

Page 751: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

console.YourserverapplicationwillusethisaspartoftheregistrationprocesswithGoogle’sGCMserverstoenableittosendmessagestotheAndroidclientapplicationandyourusers.

SenderAuthTokenYourAPIkey,usedineverymessagesenttotheGCMserverstodemonstratetheauthenticityofthemessageanditsprovenancefromyourserverapplication.

ApplicationIDForyourAndroidapplication,thisisthefullyqualifiedJavapackagename,forinstancecom.androidbook.gcm.BecausethisisuniqueacrossallAndroidapplications,itallowstheGCMecosystemtoknowwhichapplicationsreceivewhichtypesofmessages.

RegistrationIDAllocatedtoyourclientAndroidapplicationwhenitregisterswiththeGCMserversformessagedelivery.TheregistrationIDissensitiveinformationandshouldbestoredsecurelyandnotdisclosed.

AlloftheseitemsincombinationallowclientandserverapplicationstoregisterwithGCMandbeidentifiedbyit,andalsotouniquelyidentifytheapplicationsandtheirmessages.

BuildinganAndroidGCM-EnabledApplicationBuildingameaningfulGCM-basedAndroidapplicationandthesupportingserver-sidethird-partyserviceisalargeundertaking—solargethatwecouldalmostwriteasmallbookjustonthattopic.Belowwewillcoverthemainconfigurationandcodingpointsyouneedtoconsiderwhenbuildingtheapplication,andyoucancheckthebookwebsiteforamorein-depthdiscussiononGCMwithfullexamples.

CodingtheClientComponentforGCMTheclientAndroidapplicationneedstoconsiderthreebroadareas.First,haveyourdevelopmentenvironmentsetupcorrectly.Second,configuretheAndroidprojecttoincludetherightdependenciesandprivileges.Lastly,writetheGCMregistrationmethodsandmessagehandlingmethodsintoyourJavacodeforyouractivity(oractivities).

ConfigureProjectDependenciesforYourProjectBeforewecanwritetheactualJavacodeandanyrelatedXMLlayoutforourdesiredGCM-basedapplication,weneedtoconfigureourprojecttohavethenecessaryAPIsavailableandinvokeyourIDE’sbuildtool(e.g.,gradle)withthenecessarydependenciestoensureasuccessfulbuild.

Yourdevelopmentenvironment(AndroidStudio,Eclipse,etc.)willneedtohavethe

Page 752: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

GooglePlayServicesSDKinstalled.Double-checkthiswiththeSDKManagerfromtheIDEorcommandprompt.

Next,yourprojectwillneedtobeconfiguredtoworkwiththeGoogleCloudMessagingAPIprovidedbytheGooglePlayServicesSDK.Asanexample,toaddthistoanAndroidStudioproject,openyourproject’sbuild.gradlefileandensuretheAPIisincludedasadependency,asshowninListing29-1.

Listing29-1.build.gradlefileFragmentShowingPlayServicesDependency

dependencies{//yourotherdependenciesherecompile"com.google.android.gms:play-services:3.1.+"}

ForEclipseusers,theequivalenttaskistoaddgoogle-play-services.jarasanexternallibrarydependencytoyourproject,fromyourGooglePlayServiceslibrarycollection.Lastly,anyGCMapplicationmustrunonAndroid2.2(withPlayStoreinstalled)orlater.Updateyourmanifest’suses-sdkelementtosetandroid:minSdkVersiontoatleast8.

SettingManifestPropertiesforGCMOverandabovetheminimumSDKversionrequiredforGCM,yourapplicationwillrequirespecificpermissionsinordertodothefollowing:

RegisterwithGCMserverstoreceivemessages,usingcom.google.android.c2dm.permission.RECEIVEpermission.

Usethedevice’sinternetconnectiontosendmessages,usingandroid.permission.INTERNETpermission.

Exclusivelyreservemessagesintendedfortheapplicationandpreventotherapplicationsregisteringforthem.ThisusesthecustomC2D_MESSAGEpermissionblockwiththeapplicationnameprepended.

GCM-specificpermissionsforthereceiveryouwillalsodefine,sothattheGCMserversareallowedtosendmessagestoyourapplication.Thisusesthecom.google.android.c2dm.permission.RECEIVEsetting.

NoteTheearlierincarnationofGCMwasknownasC2DM,orCloudtoDeviceMessaging.ThusthereferencestotheearliernameofC2DMandC2D.

Thereceiveryoudefineshoulddeclareitsintent-filtertoactoncom.google.android.c2dm.intent.RECEIVEandusetheapplicationPackagenameasitscategory.

Page 753: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ItcanoftenbebettertoperuseasnippetofanexampleAndroidManifest.xmlfiletoseeallofthesesettingsinplace.Listing29-2showsexamplesettingsfromthefourkeypermissionsyourGCMapplicationwillrequire.

Listing29-2.SampleAndroidManifest.xmlEntriesforaGCMAndroidApplication

<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.androidbook.gcm">

...

<uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="21"/><uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.GET_ACCOUNTS"/><uses-permissionandroid:name="com.google.android.c2dm.permission.RECEIVE"/>

...

<permissionandroid:name="com.androidbook.gcm.permission.C2D_MESSAGE"android:protectionLevel="signature"/><uses-permissionandroid:name="com.androidbook.gcm.permission.C2D_MESSAGE"/>

...

<application…><receiverandroid:name=".GcmBroadcastReceiver"android:permission="com.google.android.c2dm.permission.SEND"><intent-filter><actionandroid:name="com.google.android.c2dm.intent.RECEIVE"/><categoryandroid:name="com.androidbook.gcm"/></intent-filter></receiver><serviceandroid:name=".GcmIntentService"/></application>...</manifest>

CodingYourMainActivitytoRegisterforGCM

Page 754: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

BeforeyourapplicationcanreceivemessagesfromGCMservers(andyourserver-sideapplicationthatsendsthem),andbeforeitcansendmessagesofitsownbackthroughGCM,yourapplicationmustregisterwiththeGCMservers.ThisissotheGCMinfrastructureknowshowtorouteyourmessages,preventtrafficmix-ups,andsoon.Listing29-3showsanexampleactivityfragmentthatinitiatesregistrationintheonCreate()override.ThisexamplecodeismodeledonthegithubexampleGCMprojectGooglemakesavailableatdeveloper.android.com.

Listing29-3.RegisteringwithGCMfromJava

packagecom.google.android.gcm.demo.app;//importsfromadefaultactivity,andtheGCMspecificlibraries

publicclassGCMExampleActivityextendsActivity{

publicstaticfinalStringEXTRA_MESSAGE="message";publicstaticfinalStringPROPERTY_REG_ID="registration_id";privatestaticfinalintPLAY_SERVICES_RESOLUTION_REQUEST=9000;

StringSENDER_ID="a123b456c789d012";//RemembertouseyourID

TextViewmyMessageDisplay;GoogleCloudMessaginggcm;AtomicIntegermessageID=newAtomicInteger();Contextcontext;StringregistrationID;

@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

setContentView(R.layout.main);myMessageDisplay=(TextView)findViewById(R.id.display);context=getApplicationContext();

//RegisterwithGCMserversgcm=GoogleCloudMessaging.getInstance(this);finalSharedPreferencesmyAppPrefs=getGcmPreferences(context);registrationID=myAppPrefs.getString(PROPERTY_REG_ID,"");//youcouldalsoperformversionandotherchecksifdesired

Page 755: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

if(registrationID.isEmpty()){//Notregistered,dosoasyncsoasnottoblockmainthreadtry{registerAppInBackground();}catch(NameNotFoundExceptione){//logdetailshere,assomethingfailedduringregistration}}}

privatevoidregisterAppInBackground(){newAsyncTask<Void,Void,String>(){@OverrideprotectedStringdoInBackground(Void…params){StringregStatus="Unregistered";try{if(gcm==null){gcm=GoogleCloudMessaging.getInstance(context);}registrationID=gcm.register(SENDER_ID);regStatus="RegisteredwithID:"+registrationID;//addyourcalltosecurelystoretheregistrationIDforlaterreuse//...}catch(IOExceptionex){//performyourerrorhandlinghere,e.g.retry}returnregStatus;}

}.execute(null,null,null);}...

Thisisagreatlysimplifiedexamplesoyoucanfocusontheabsolutelymandatorycomponentsandbuildfromthere.OuronCreate()methodfirstinstantiatesagcmobjectandaSharedPreferencesobject.Itthenretrievestheregistration_idfromthepreferences.Atthispointyourapplicationmaynotberegistered,whichwouldmeanthereturnedvaluefromthepreferenceswouldbeempty.Wetestforthisemptyvalue,andwhereanemptyregistration_idisdetectedweinitiateourregistrationprocessbyinvokingtheprivatemethodregisterAppInBackground().

Page 756: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TheimplementationofregisterAppInBackground()followsGoogle’srecommendationofperformingthefirst-timeregistrationasynchronously.Wedothisbecausewedon’twanttoblockthemainthreadwhilewewaitforthehandshakeandregistrationprocesstocomplete.Theprocesscouldpotentiallytakeseveralsecondsormore.Youcouldenhancetheapplicationherebyaddingarangeofintermediatestatusupdates,errorchecking,andmore.

Oncewehaveanapplicationthat’sregistered,wecancarryoutmessageexchange,andthenalltheotherlogicyoumightwantyourapplicationtohave,basedonordrivenbythemessagingaspect.Listing29-4showsanexamplemethodtosendamessagebasedonaBundleobjectconstructedtoholdyourmessagedetails.

Listing29-4.ExampleMessageSendingfromYourAndroidClient

privatevoidsendMessage(BundlemessagePayload){newAsyncTask<Void,Void,String>(){@OverrideprotectedStringdoInBackground(Void…params){Stringstatus="";try{Stringid=Integer.toString(messageID.incrementAndGet());gcm.send(SENDER_ID+"@gcm.googleapis.com",id,messagePayload);status="messagesent";}catch(IOExceptionex){//yourerrorhandlinghere//setstatusstring}returnstatus;}}}

ThelogicofthesendMessage()methodisentirelyconcernedwithsendingwhateveritisyouhaveconstructedinthemessagePayloadparameter.ThisBundleobjectislefttoyourimagination,butitcouldbetheinstantmessage,photo,voicemessage,orothercontentthatyourapplicationisactuallyhelpingtheuserwith.

WeonceagainuseAsyncTasktoensurewedon’tblockonmessagedelivery.Thisisauniversaldesignpatternwhenworkingwithanykindofmessagebusormessagedeliveryservice.Withintheasynchronouslogic,wegenerateauniquemessageidentifierwiththemessageID.incrementAndGet()methodandtheninvokethegcm.send()method,passingittheuniqueIDandourmessagepayload.

Errortrappingandretrylogicareeasytoaddatthispoint.IfyouaregoingtoassumeanyhighervaluetothemessageID(whichisnormallynotrecommended),itisbesttoplacetheretrylogicwithinthesendMessage()methodsoastobeabletoreusethemessage

Page 757: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IDgeneratedbeforeitfallsoutofscopeonmethodreturn.

CodingtheServerComponentforGCMYourthird-partyservicecanbewritteninbasicallyanylanguage,solongasitcanmakecallstotheGCMcloudendpointsandsupporttheauthorizationmessageprotocolswehavedescribedintheearliersectionsofthischapter.

BecausesuchservicesarenotstrictlyAndroidproductsorcode,wewillsavesomepreciouspagesfromthebookandpointyoutoexcellentexamplesthatGoogleprovidestogiveyouinspirationintowritingtheback-endservices.

Youcanreviewtheoptionsandapproachesforthisnon-Androidthird-partyserviceatdeveloper.android.com/google/gcm/server.html.

MovingBeyondtheGCMIntroductionSuchashortchaptercannotcovertheenormousbreadthofpossibilitiesandnuancesforGCM-basedapplications.Formoredetailsonwhatispossible,checkouttheAndroidStackExhangesite,android.stackechange.com,andthedeveloper.android.comsite.

Page 758: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Chapter30

DeployingYourApplication:GooglePlayStoreandBeyondCreatingagreatapplicationthatpeoplewillloveisonething,butyoualsoneedaneasywayforpeopletofindanddownloadit.GooglecreatedthePlayStoreforthispurpose.Fromaniconrightonthedevice,userscanclickstraightintothePlayStoretobrowse,search,review,anddownloadapplications.UserscanalsoaccessPlayStoreovertheInternettodothosesamethings,althoughthedownloadingisnottothecomputerbutratherappsaresentdirectlytotheuser’sdevice.Manyapplicationsarefree;forthosethatarenot,thePlayStoreprovidespaymentmechanismsforeasypurchasing.

ThePlayStoreisevenaccessiblefromintentsinsideofapplications,makingiteasyforapplicationstoreachouttothePlayStoretoguideusersintogettingwhattheyneedforyourapplicationtobesuccessful.Forexample,whenanewversionofyourapplicationbecomesavailable,youcanmakeiteasyfortheusertogostraighttothatPlayStorepagetogetorbuythenewversion.GooglePlayStoreisnottheonlywaytogetapplicationstodevices,however;otherchannelsareallovertheInternet.

TheGooglePlayStoreapplicationisnotavailablefromwithintheemulator(althoughhacksexisttomakeitavailable).Thismakesthingsalittlemoredifficultforadeveloper.IdeallyyouwillhaveadeviceofyourownthatyoucanusewithGooglePlayStore.Inthischapter,we’llexplorehowtogetyousetupforpublishingapplicationstothePlayStore;howtoprepareyourapplicationforsalethroughthePlayStore;howyoucanprotectyourselffrompiracy;howuserswillfind,download,anduseyourapplications;andfinally,alternativewaystomakeyourapplicationsavailable.

BecomingaPublisherBeforeyoucanuploadanapplicationtoGooglePlayStore,youneedtobecomeapublisher.Todoso,youmustcreateaGooglePlayPublisherAccount.Oncethat’sdone,youwillbeabletouploadyourapplicationstothePlayStoresotheycanbefoundanddownloadedbyusers.Ifyouwillbechargingmoneyforyourapp,oracceptingin-apppurchases,youwillalsoneedtosetupaGoogleWalletMerchantAccount.Googlehasmadetheprocesstogettheseaccountsrelativelypainlessandreasonablypriced.

Agoodplacetostartisthispage:http://developer.android.com/distribute/googleplay/start.htmlFromhereyoucanclickthebigStartbuttontobegintheprocess.Ifyoudon’talreadyhaveaGoogleAccountyouwillbepromptedtocreateone.Tobeapublisher,youwillalsoneedtoprovideadevelopername,ane-mailaddress,awebsiteaddress,andaphonenumberwhereyoucanbecontacted.Youwillbeabletochangethesevalueslater,onceyouraccountissetup.Youwillalsoneedtopaytheregistrationfee.Thisisdonevia

Page 759: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

GoogleWallet.Inordertocompletethepaymenttransaction,youwillneedtouseyourGoogleaccount.

Oneoftheoptionspresentedtoyouduringthepaymentprocessis“Keepmyemailaddressconfidential.”ThisreferstothecurrenttransactionbetweenyouandGooglePlayStoretopurchasepublisheraccess.Ifyouchooseyes,you’llkeepyoure-mailaddresssecretfromGooglePlayStore.Thishasnothingtodowithkeepingyoure-mailaddresssecretfrombuyersofyourapplication.Buyers’abilitytoseeyoure-mailaddresshasnothingtodowiththisoption.Moreonthatlater.

NextupistheGooglePlayDeveloperDistributionAgreement(GPDDA).ThisisthelegalcontractbetweenGoogleandyou.Itspellsouttherulesfordistributingapps,collectingpayments,grantingrefunds,feedback,ratings,userrights,developerrights,andsoon.There’smoreontheseinthe“FollowingtheRules”sectionofthischapter.

UponacceptingtheAgreement,youwillbetakentoapagecommonlycalledtheDeveloperConsoleathttps://play.google.com/apps/publish/.

FollowingtheRulesTheGPDDAspellsoutalotofrules.Youmightwantlegalcounseltoreviewthecontractbeforeagreeingtoit,dependingonhowseriouslyyouplantooperatewithintheGooglePlayStore.Thissectiondescribessomehighlightsyoumightbeinterestedin:

YouhavetobeadeveloperingoodstandingtousetheGooglePlayStore.Thismeansyoumustgothroughtheprocessasdescribedtogetregistered,youmustaccepttheAgreement,andyoumustabidebytherulesintheAgreement.BreakingtherulescouldgetyoubarredandyourproductsremovedfromthePlayStore.

Youcandistributeproductsforfreeorforaprice.TheAgreementapplieseitherway.PaymentsmustbecollectedviaanauthorizedGooglePlayStorePaymentProcessor.ThisincludesGoogleCheckout(credit,debit,GooglePlaygiftcards),carrierbilling(e.g.,Verizon,AT&T),andPayPal.

Paidappswillincuratransactionfee,andpossiblyafeefromthedevicecarrier,tobedeductedfromthesaleprice.AsofMarch2015,thetransactionfeeis30percent,soifthesalepriceis$10,Googlecollects$3andyouget$7(assumingnocarrierfees).

ForEUcountries,Googleisrequiredtoremitthetaxesforyou.OutsideoftheEU,itisyourresponsibilitytoremitappropriatetaxestoyourtaxingauthorities.Forsomeofthosenon-EUcountries,youcanchoosetoletGoogleremitthetaxesforyou.Whenyousetupyourmerchantaccount,youspecifytheappropriatetaxratestoapplytopurchases.GoogleCheckoutwillcollecttheappropriatetaxesbasedonhowyousetupGoogleCheckout.ThismoneywillbeprovidedtoyouifGoogleisnotremittingforyou,andyoumust

Page 760: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

remititappropriately.ForadditionalinformationonsalestaxesintheUnitedStates,tryhttp://biztaxlaw.about.com/od/businesstaxes/f/onlinesalestax.htmandwww.thestc.com.

Youareallowedtodistributeafreedemoversionofyourapplication,withanoptiontopaytounlocktheapplication’sfullsetoffeatures;however,youmustcollectthepaymentviaanauthorizedGooglePlayStorePaymentProcessor.Youarenotallowedtoredirectusersofyourfreeapplicationtosomeotherpaymentprocessortocollectupgradefees.Youcouldthinkofitthisway:ifyou’remakingmoneyviaGooglePlayStore,Googlewantsitsshare.

In-appbillingallowsanapplicationtochargefordigitalgoodsorassetsusedwithintheapplication.Adigitalassetcouldbesomethinglikeavirtualweaponornewlevelsforagame,oramusicorgraphicsfile.Thecheckoutprocessisthesameasforpurchasingapplications.

Ifyourapplicationrequiresausertohavealoginonawebserversomewhere,andthatwebserverchargestheuserasubscriptionfee,thatwebservercouldcollectthesubscriptionfeeanywayitwantsto.Inthisway,youhavedisconnectedthesubscriptionfeefromtheapplication,andit’sOKbyGoogletomaketheapplicationavailableinGooglePlayStore—aslongasyourfreeapplicationisnotdirectinguserstothewebsite.SomepeoplejustdecidetodistributetheirfreeAndroidappfromthesamewebserverastheservice,butthisdoesrequiretheusertoenableinstallationofappsfromunknownsources,whichcandiscouragesomeusersfrominstalling.

Itseemsthatyoucanusealternatepaymentprocessorstoacceptdonationsfromusersofyourfreeapp,butyoucannotcreateincentiveswithinyourapptoencouragethosedonations.

WhiletheGPDDAsaysrefundscanberequestedupto48hoursafterpurchase,asofMarch2015refundscanberequestedbytheuserupto2hoursafterpurchasingforanautomaticrefund.Refundsarenotgiventouserswhocanpreviewtheproductpriortodownload.Thisincludesringtonesandwallpapers.

GoogleCheckout,however,doesallowthedevelopertoissuearefundeveniftherefundwindowhaspassed.TheusercangototheirGooglePlayactivityhistory,andfromtherecanrequestarefundevenwellaftertheinitial2hours.Ifitislessthan48hoursfromthepurchase,therefundwillprobablybeautomatic.Otherwise,itisuptothedeveloperwhetherornottoreturnanymoney.

Youarerequiredtoprovideadequatesupportforyourproduct.Ifadequatesupportisnotprovided,userscanrequestrefundsthroughGoogle,andthesewillbechargedbacktoyou,possiblyincluding

Page 761: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

handlingfees.

UsersgetunlimitedreinstallsofapplicationsdownloadedfromtheGooglePlayStore.Ifauserdoesafactoryresetoftheirdevice,thisfeatureallowsthemtogetalltheirappsbackwithouthavingtorepurchase.

Developersagreetoprotecttheprivacyandlegalrightsofusers.Thisincludesprotecting(securing)anydatathatmightbecollectedintheprocessofusingtheapplication.Itispossibletochangetherulesregardingusers’dataprotection,butonlybydisplayingandhavingtheuseracceptaseparateagreementbetweenyouandthatuser.

YourapplicationmustnotcompetewiththeGooglePlayStore.GoogledoesnotwantanapplicationfromwithinGooglePlayStoretosellAndroidproductsfromoutsideGooglePlayStore,thusbypassingitspaymentprocessor.Thisdoesnotmeanthatyoucan’talsosellyourapplicationthroughotherchannels,butyourapplicationonGooglePlayStorecannotitselfbedoingthesellingofAndroidproductsoutsideofGooglePlayStore.

Googlewillassignproductratingstoyourproducts.Theratingscouldbebasedonuserfeedback,installrates,uninstallrates,refundrates,and/oraDeveloperCompositeScore.TheDeveloperCompositeScoremaybecalculatedbyGoogleusingpasthistoryacrossapplications,andthiscouldinfluencetheratingofnewapplications.Forthisreason,itisimportanttoreleasegood-qualityapplicationsassociatedwithyou,eventhefreeones.It’snotclearthattheDeveloperCompositeScoreevenexists,butifitdoesthere’snowaytoseeyours.

BysellingyourapplicationthroughGooglePlayStore,youaregrantingtheusera“non-exclusive,worldwide,perpetuallicensetoperform,displayandusetheProductonthedevice.”However,itisquitealrightforyoutowriteaseparateEndUserLicenseAgreement(EULA)thatsupersedesthisstatement.MakethisEULAavailableonyourwebsite,orprovideanotherwayforshoppersanduserstobeabletoreadit.

GooglerequiresthatyouabidebythebrandingrulesforAndroid.TheseincluderestrictionsontheuseofthewordAndroid,aswellasuseoftherobotgraphic,logo,andcustomtypeface.Formoredetails,gotohttp://developer.android.com/distribute/tools/promote/brand.html

DeveloperConsoleTheDeveloperConsoleisyourlandingpageforcontrollingyourapplicationsinGooglePlayStore.FromtheDeveloperConsole,youcansetupamerchantaccountinGoogle

Page 762: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Checkout(soyoucanchargeforyourapplications),uploadapplications,andgetinformationaboutyouruploadedapplications.Youcanalsoedityouraccountdetailsincludingdevelopername,e-mailaddress,webaddress,andphonenumber.Figure30-1showstheDeveloperConsole.

Figure30-1.TheGooglePlayStoreDeveloperConsole

Ifyoudonotsetupamerchantaccount,youwillbeunabletochargeforyourproductsinGooglePlayStore.Settingupamerchantaccountisnotdifficult.ClickthelinkfromtheDeveloperConsole,fillouttheapplication,agreetotheTermsofService,andyou’reallset.YouwillneedtoprovideaUSFederaltaxID(EIN),acreditcardnumberplusaUSSocialSecurityNumber(SSN),orjustacreditcardnumber.Thetaxinformationisusedtoverifyyourcreditstatustoensuretimelydeposits.ThecreditcardinformationisusedtohandlechargebacksduetobuyerdisputeswhenthereareinsufficientfundsinyourGoogleCheckoutaccount.Youcanalsosupplybankaccountinformationtoenableelectronicfundstransfersfromtheproceedsofyoursales.

NotethatGoogleCheckoutisaserviceformorethanjustGooglePlayStore.Therefore,donotgetconfusedbythetransactionfeeinformationforGoogleCheckoutfornon–GooglePlayStoresales.The30percentmentionedpreviouslyisthetransactionfeerateforGooglePlayStore.ThereisalsoadditionalGoogleCheckouttransactionfeeinformationfornon–GooglePlayStoresales,andthosedonotapplytoGooglePlayStore.

UploadingandmonitoringyourapplicationsareprobablythemainfunctionsoftheDeveloperConsolethatyouwilluse,althoughtheConsoleisalsowhereyoucansignupforaccesstoGoogleAPIsandgameservicesandlinktoyourAdWordsaccount(s).

Formonitoring,thePlayStoreprovidestoolstoseehowyourapplicationisdoingintermsoftotaldownloadsandhowmanyusersstillhaveitinstalled.Youcanseetheoverallratingofyourappsintermsof0to5stars,andhowmanypeoplehavesubmittedarating.Therearevariousreports,charts,andgraphsintheDeveloperConsolesoyoucanseehowyourapplicationisdoingindifferentversionsofAndroid,ondifferentdevices,indifferentcountries,andindifferentlanguages.

Userscansubmitcommentsinadditiontoratingyourapplication.Itisinyourbestinteresttoreadthecommentsinordertoaddressanyproblemsquickly.Includedwithacommentistheuser’sratingofyourapp,anameoftheuserastypedbythem,andthedatethecommentwassubmitted.Youareabletoreplytospecificcommentsandthatuserwillreceiveane-mailtoletthemknow.Youcanonlyleaveonereplyperreview,butyoucanalwaysedityourreplylater.Inanextremecase,whereacommentisparticularlyharmfulorinappropriate,youcancontactGooglesupportbystartinghereattheHelp

Page 763: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Centerwebsite:https://support.google.com/googleplay/android-developer/.

TheDeveloperConsoleallowsyoutorepublishyourapplication—forupgrades,forexample—ortounpublishtheapplication.Unpublishingdoesnotremoveitfromdevices,nordoesitevennecessarilyremovetheappfromtheGoogleservers,especiallyifit’sapaidapp.Auserwhohaspaidforyourapplicationandwhohasuninstalledit,butnotrequestedarefund,isallowedtoreinstallitlaterevenifyou’veunpublishedit.TheonlywayitistrulyunavailabletousersisifGooglepullsitduetoaviolationoftherules.

Youcanalsolookaterrorsthatweregeneratedbyyourapplicationandseeapplicationfreezesandcrashes.Figure30-2showstheCrashes&ANRsscreen.

Figure30-2.TheCrashes&ANRsscreen

Drillingintothedetailsofacrashreport,youcanseethestacktraceofthecrash,aswellaswhichtypeofdevicewasrunningtheapplicationandthetimeofthecrash.Unfortunately,youcannotcommunicatebacktotheuserwhoexperiencedtheproblemtogetadditionaldetailsortohelpthemgettheissueresolved.Youhavetohopethattheaffecteduserswillgetintouchwithyouthroughcomments,e-mail,oryourwebsite.Otherwise,you’lljusthavetofigureoutfromthecrashreportwhatwentwrongandtrytofixit.

Ifyoureallywanttoknowhowausergottoacrash,you’llwanttoimplementoneofthemobileanalyticspackagesintoyourapp.Thesewillgenerateeventrecordsasauserstepsthroughyourapplication,andwillalsoreportcrashes.Thebreadcrumbs(eventrecords)willletyouknowthestepsausertookuptothepointofthecrash.ThiscapabilityisseparatefromtheGooglePlayStore,however.

There’sonemorefeatureoftheDeveloperConsoleyoumayneedtouse:theHelpportionofthewebsite.TheHelpbuttonisintheupper-rightcorner.Clickingitshowsyousomeinlinehelp,butalsohasalinktotheHelpCenterwebsite.Therearealsolinksfor

Page 764: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

submittinge-mailorforanonlinechat(duringbusinesshours).

We’venowintroducedyoutosomeofthenicefeaturesoftheDeveloperConsole,butyouprobablywanttogetintothemostusefulpart,whichisgettingyourapplicationsintotheGooglePlayStoresouserscanfindthemanddownloadthem.Butbeforewedothat,let’sgooverhowtoprepareyourapplicationforuploadandsale.

PreparingYourApplicationforSaleTherearequiteafewthingstothinkaboutanddototakeanapplicationfromcodecompletetoGooglePlayStore.Thissectionwillhelpyouthroughthoseitems.

TestingforDifferentDevicesWithmoreandmoreAndroiddevicesbecomingavailable,andeachonepotentiallyhavingsomenewhardwareconfiguration,itisveryimportantthatyoutestforavarietyofdevicesyouwanttosupport.Youcouldpurchasesomeofthedevicesthatyouwanttosupport,butyouprobablycan’tpurchasethemall.TherearesomeonlineservicesthatmakerealdevicesavailableovertheInternet.YourotheroptionistoconfigureAndroidVirtualDevices(AVDs)foreachtypeofdevice,specifytheappropriatehardwareconfiguration,andthentestwiththeemulatorandeachAVD.SomedevicemanufacturersmakeAndroidemulatorpackagesavailablethatarespecifictotheirdevices,socheckouttheirwebsitesfordownloadoptions.

TheAndroidSDKprovidesvariousclassestoassistwithtesting,aswellastheUI/ApplicationExerciserMonkey.Thesetoolswillhelpyoudoautomatedtestingsoyoudon’tspendforevertestingyourapplicationmanually.Seethesewebpagesformoredetails:

https://developer.android.com/tools/testing/index.htmlhttps://developer.android.com/tools/testing-support-library/index.html

Beforeyoubegintesting,youprobablywanttoremovefromyourcodeanydevelopmentartifactsthatyounolongerneed,andalsoanydevelopmentartifactsfrom/res.Youwantyourapplicationtobeassmallaspossibleandtorunasquicklyaspossiblewiththeleastamountofmemory.Finally,besuretodisableorremoveanydebuggingfeaturesfromyourapplicationthatyoudon’twantdistributedtoproduction.

SupportingDifferentScreenSizesAndroidsupportsmanyscreensizes.Inordertorunonthesmallestsize,youmustsetaspecific<supports-screens>elementasachildelementof<manifest>withintheAndroidManifest.xmlfile.Withoutthistagspecifyingthatyourapplicationsupportsthesmallscreensize,yourapplicationwillnotbevisibleinthePlayStoretodevicesthathaveasmallscreen.

Page 765: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Tosupportdifferentscreensizes,youmayneedtocreatealternateresourcefilesunder/res.Forexample,forfilesin/res/layout,youmayneedtocreatecorrespondingfilesin/res/layout-smalltosupportsmallscreens.Thisdoesnotmeanyoumustalsocreatecorrespondingfilesin/res/layout-largeand/res/layout-normal,sinceAndroidwilllookin/res/layoutifitcan’tfindwhatitneedsinamorespecificresourcedirectorysuchas/res/layout-large.Remember,too,thatyoucanhavecombinationsofqualifiersfortheseresourcefiles;forexample,/res/layout-small-landwouldcontainlayoutsforsmallscreensinlandscapemode.Supportingsmallscreensprobablymeanscreatingalternateversionsofdrawablessuchasicons,too.Fordrawables,youmayneedtocreatealternateresourcedirectories,takingintoaccountscreenresolutionaswellasscreensize.

Tabletsofcoursegointheoppositedirectionintermsofscreensize,usingthelabelxlarge.Thesame<supports-screens>tagasbeforeisusedtospecifyifyourapplicationwillrunonextra-largescreens,andtheattributetouseinsideofthistagisandroid:xlargeScreens.Insomecases,youmayhaveatablet-onlyapplication,inwhichcaseyouwouldspecificallyindicatethatfortheothersizes,theattributevalueisfalse.

PreparingAndroidManifest.xmlforUploadingYourAndroidManifest.xmlfilemayneedtobetweakedalittlebitbeforeyoucanuploadittoGooglePlayStore.ADTnormallyputstheandroid:iconattributeinthe<application>tag,andnotin<activity>tags.Ifyouhavemorethanoneactivitythatcanbelaunched,you’llwanttospecifyseparateiconsforeachactivitysotheusercanmoreeasilytellthemapart.Butyou’llstillneedaniconspecifiedin<application>,whichalsoservesasthedefaultactivityiconforanyactivitiesthatdon’tspecifytheirownicon.Yourapplicationwillworkfineondevicesandintheemulatorwiththeandroid:icononlyspecifiedinthe<activity>tags,butwhenGooglePlayStoreinspectsyourapplication’s.apkfilewhenuploading,itlooksforiconinformationinthe<application>tag.

GooglePlayStorepreventsuploadingyourapplicationifthepackagenameyou’veusedstartswithcom.google,com.android,android,orcom.example,butwehopeyoudidn’tuseoneofthoseinyourapplication.

Therearemanyothercompatibilitiestoconsiderforyourapplication.Somedeviceshavecameras,somedon’thavephysicalkeyboards,andsomehavetrackballsinsteadofdirectionalpads.Use<uses-configuration>and<uses-feature>tagsinyourAndroidManifest.xmlfileasneededtodefinewhathardware/platformrequirementsyourapplicationhas.GooglePlayStorewillenforcethisandnotletyourapplicationbeshowntoauseronadevicethatwon’tsupportyourapplication.Notethatthesetagsaredifferentandseparatefromthe<uses-permission>tagsoftheAndroidManifest.xmlfile.Inmostcases,youwouldendupwithbothtagsinyourAndroidManifest.xmlfile,forspecifyingthatacameraisrequired,andforspecifyingthatpermissiontousethecameraisrequired.Butnotallfeaturesrequire

Page 766: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

permission,soitisinyourbestinteresttospecifythefeaturesyouneed.

Thereisanotherbigdifferencebetween<uses-permission>and<uses-feature>:the<uses-feature>tagcansaythatyourapplicationrequiresthatfeatureorthatyourapplicationcanfunctionwithoutit.Thatis,thereisanattributecalledandroid:requiredthatcanbesettoeithertrueorfalse;bydefaultit’strue.Ifthereisapermissionforafeature,butyoudon’tsupplythecorresponding<uses-feature>tag,thenbydefaultit’sasifyouspecified<uses-feature>andthefeatureisrequired.Forexample,yourapplicationmaytakeadvantageofBluetoothifit’savailable,butwillworkjustfineifitisnot.Therefore,inthemanifestfile,inadditiontotheBluetoothpermissionelement,you’dhavesomethinglikethis:

<uses-featureandroid:name="android.hardware.bluetooth"android:required="false"/>

Withinyourapplication’scode,youshouldmakeacalltothePackageManagertofindoutifBluetoothisavailableornot,whichyoucoulddowiththefollowing:

booleanhasBluetooth=getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);

ThentakeappropriateactioninyourapplicationifBluetoothisnotthere.TheAndroiddocumentationcanbeconfusinginthisarea.IfyoulookattheDeveloperGuidepagefor<uses-feature>,youwillnotseeasmanyfeaturesasaredescribedonthePackageManagerreferencepage,whichdefinesaFEATURE_*constantforeachavailablefeature.

The<uses-configuration>tagisalittledifferent.Itspecifieswhatsortofkeyboard,touchscreen,and/ornavigationalcontrolsthedevicemusthave.Butinsteadofbeingindependentchoicessuchas<uses-feature>,youwouldputthecombinationsofconfigurationchoicestogetherintowhatyourapplicationrequires.Forexample,ifyourapplicationrequiresafive-waynavigationcontrol(thatis,aD-padoratrackball)andatouchscreen(usingeitherastylusorafinger),youwouldspecifytwotagsasfollows:

<uses-configurationandroid:reqFiveWayNav="true"android:reqTouchScreen="stylus"/><uses-configurationandroid:reqFiveWayNav="true"android:reqTouchScreen="finger"/>

LocalizingYourApplicationIfyourapplicationwillbeusedinothercountries,youmightwanttoconsiderlocalizingit.Thisisrelativelyeasytodotechnically.Findingsomeonetodothelocalizingisanothermatter.Fromthetechnicalpointofview,yousimplycreateanotherfolderunder/res—forexample,/res/values-frtoholdaFrenchversionofstrings.xml.Takeyourexistingstrings.xmlfile,translatethestringvaluestothenewlanguage,andsavethenewtranslatedfileunderthenewresourcefolderusingthesamefilenameastheoriginal

Page 767: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

file.Atruntime,ifthedevice’slanguageissettoFrench,Androidwilllookforstringsthatwereplacedunder/res/values-fr.Ifitcan’tfindstringsfromthere,itwillthenlookforstringsfrom/res/values.

Thesametechniqueworksfortheothertypesofresourcefiles—forexample,drawablesandmenus.Imagesandcolorsmayworkbetterforyourusersiftheyaredifferentfordifferentcountriesorcultures.Forthisreason,itisagoodideatonotusetruecolornamesforyourresourcenamesforcolors.Intheonlinedocumentationforcolors,itiscommontoseesomethinglikethis:

<colorname="solid_red">#f00</color>

Thismeansthatinyourcodeorotherresourcefiles,you’rereferringtothecolorbytheactualnameofthecolor,inthiscase,solid_red.Inordertolocalizethecolortosomethingmoreappropriatefortheothercountryorculture,itwouldbebettertouseacolornamesuchasaccent_color1oralert_color.InEnglish,redmightbetheappropriatecolorvaluetouse,whileinSpanishitmightbebettertouseashadeofyellow.Becauseacolornamelikealert_colordoesnotrevealtheactualcolorthatyou’reusing,itislessconfusingwhenyouwanttochangetheactualcolorvaluetosomethingelse.Atthesametime,youcandesignapleasingcolorscheme,withbasecolorsandaccentcolors,andbemoreconfidentthatyou’reusingthecorrectcolorsinthecorrectplaces.

Menuchoicesmightneedtobechangedindifferentcountries,usingfewerormoremenuitems,orbeorganizeddifferently,dependingonwheretheapplicationisbeingused.Menusaretypicallystoredunder/res/menu.Ifyouarefacedwiththissituation,youareprobablybetteroffputtingallyourstringtextintostrings.xml,orotherfileslocatedunderthe/res/valuesdirectory,andusingstringIDsintheappropriateresourcefileseverywhereelse.Thismakesitfarlesslikelythatyouwillmisstranslatingastringvalueinsomeobscureresourcefile.Yourlanguagetranslationworkisthenlimitedtothefilesunder/res/values.

PreparingYourApplicationIconShoppersandyouruserswillseeyourapplication’siconandlabelprominentlyinbothGooglePlayStoreandontheirdeviceoncethey’vedownloadedit.Pleasetakespecialcaretocreategoodiconsandgoodlabelsforyourapplicationanditsactivities.Localizethemasnecessaryordesired.Andrememberthatfordifferentscreensizes,youriconsmayneedtobetweakedtolookgood.Checkoutwhatotherdevelopershavedonewiththeiricons,especiallythoseapplicationsinthesamecategoryasyourapplication.Youwantyourapplicationtogetnoticed,soit’sbetternottoblendinwithalltheothers.Atthesametime,youwantyouriconandlabeltoworkwellonadevicewhensurroundedbylotsofotherapplicationiconsthatdootherthings.Youdon’twantausertobeconfusedaboutwhatyourapplicationdoes,somaketheiconrepresentativeofthefunctionalityofyourapplication.

Whencreatinganyimageforyourapplication,butespeciallyyouricon,youneedto

Page 768: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

considerthescreendensityofthetargetdevice.Densitymeansthenumberofpixelsperinch.Don’tthinkthatasmallscreenislowdensityandalargescreenishighdensity—youcouldseeanycombinationofsizeanddensity.Forahigh-densityscreen,youwillprobablychooseaniconwith72×72pixels.Themedium-densityiconwillusuallybeofsize48×48pixels.Andforextra-highdensity,it’s96×96pixels.Foralow-densityscreen,makinganiconappeartobetherightsizemeansmakingtheiconwithfewerpixels,typically36×36.Androidhelpsyouinthelow-densitycasebecauseitwillautomaticallydownscaleyourHDPIiconbyhalf,soyoudon’tneedtoprovidealow-densityiconyourself.Ingeneral,you’llfinditeasiesttoonlyworryaboutdensityforimagessuchasicons.You’llworryaboutscreensizewhendefininglayouts.

DirectingUsersBacktothePlayStoreAndroidhasaURIschemetohelpfacilitatefindingapplicationsinGooglePlayStore:market://.[GooglePlayStorewasformerlycalledAndroidMarket.]Forexample,ifyouwanttodirectyouruserstothePlayStoretolocateaneededcomponent,ortoupselltoanadditionalappthatunlocksfeaturesinyourapplication,youwoulddosomethingasshownhere,whereMY_PACKAGE_NAMEwouldbereplacedbyyourrealpackagename:

Intentintent=newIntent(Intent.ACTION_VIEW,Uri.parse("market://search?q=pname:MY_PACKAGE_NAME"));startActivity(intent);

ThiswilllaunchthePlayStoreapponthedeviceandtaketheusertothatpackagename.Theusercanthenchoosetodownloadorbuytheapplication.Notethatthisschemedoesnotworkinanormalwebbrowser.Inadditiontosearchingusingpackagename(pname),youcansearchbydevelopernameusingmarket://search?q=pub:\“FnameLname\”oragainstanyofthepublicfields(applicationtitle,developername,andapplicationdescription)inGooglePlayStoreusingmarket://search?q=<querystring>.

TheAndroidLicensingServiceThewaythatAndroidappsareconstructedunfortunatelymakesthemtargetsforpiracy.ItispossibletomakecopiesofAndroidappsthatcanthenbedistributedtootherdevices.Sohowcanyouensurethatuserswhohavenotpurchasedyourapplicationcannotrunit?TheAndroidteamhascreatedsomethingcalledtheLicenseVerificationLibrary(LVL)tomeetthisneed.Here’showitworks.

IfyourapplicationwasdownloadedviaGooglePlayStore,thentheremustbeacopyoftheGooglePlayStoreapponthedevice.Inaddition,theGooglePlayStoreapphaselevatedpermissionstobeabletoreadvaluesfromthedevicesuchastheuser’sGoogleaccountname,theIMSI,andotherinformation.TheGooglePlayStoreappwillrespondtoalicenseverificationrequestfromanapplication.YoumakecallsintotheLVLfromyourapplication,LVLcommunicateswiththeGooglePlayStoreapp,theGooglePlay

Page 769: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

StoreappcommunicateswithGoogleservers,andyourapplicationgetsananswerbackindicatingwhetherornotthisuseronthisdeviceislicensedtouseyourapplication.ThismeanstheappmusthavebeenpurchasedthroughGooglePlayStore;otherwisetheGoogleserverswon’tknowaboutit.Therearesettingsunderyourcontroltodecidewhattodoifthenetworkisunavailable.AfulldescriptionoftheprocessofimplementingLVLcanbefoundathttps://developer.android.com/google/play/licensing/index.html

Onethingtobeawareof,though,isthattheLVLmechanismissubjecttohacking.Ifsomeonecangettoyourapplication’s.apkfile,theycandisassembletheappandthenpatchitiftheyknowwheretolookforthereturnvaluefromtheLVLcall.IfyouusetheobviouspatternofaswitchstatementaftergettingtheresponsefromLVL,tobranchtotheappropriatelogicbasedonthereturncode,ahackercansimplyforceasuccessfulreturncodevalue,andtheyownyourapp.Forthisreason,theAndroidteamhighlyrecommendsthatyouimplementobfuscationofyourapptohidethepartofyourapplicationwhereyoucheckthereturncodefromLVL.Thisgetsfairlycomplicated,asyoucanimagine.

UsingProGuardforOptimization,FightingPiracyGoogleprovidessomesupportforobfuscationintheformoftheProGuardfeature.ProGuardisnotaGoogleproduct,buthasbeenintegratedintoADTandAndroidStudiosoit’seasytouse.ProGuarddoesmorethanjustprovideobfuscationforfightingpiracy;italsomakesyourapplicationsmallerandfaster.Itdoesallthisbystrippingoutdebugginginformation,cuttingoutcodethatwillneverrun,andchangingnames(ofclasses,methods,andsoon)tomeaninglessstrings.Examplesofcodethatwillneverrunincludelibraryclassesandmethodsthatarenevercalled,andloggingthatdependsonaconstantthatyousettofalse(forproduction).Itcanalsorecognizeoptimizationssuchasbinary-shiftingavalueleftbyonebitpositioninsteadofmultiplyingitby2.Bystrippingoutdebugginginformationandchangingthenames,theresultingcompiled.apkfilewon’trevealvariablenames,classnames,methods,andsoon,soitbecomesextremelydifficulttofigureoutwhatthecodedoesandthereforehowtostealit,modifyit,andreleaseitassomethingelse.

Whenyoucreateyourapplication,itshouldautomaticallygetaproguard-project.txtfile.ThedefaultfilewilllooksomethinglikeListing30-1.

Listing30-1.Sampleproguard-project.txtFile

#ToenableProGuardinyourproject,editproject.properties#todefinetheproguard.configpropertyasdescribedinthatfile.##AddprojectspecificProGuardruleshere.#Bydefault,theflagsinthisfileareappendedtoflagsspecified

Page 770: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

#in${sdk.dir}/tools/proguard/proguard-android.txt#YoucanedittheincludepathandorderbychangingtheProGuard#includepropertyinproject.properties.##Formoredetails,see#http://developer.android.com/guide/developing/tools/proguard.html

#Addanyprojectspecifickeepoptionshere:

#IfyourprojectusesWebViewwithJS,uncommentthefollowing#andspecifythefullyqualifiedclassnametotheJavaScriptinterface#class:#-keepclassmembersclassfqcn.of.javascript.interface.for.webview{#public*;#}

Youalsoneedtouncommenttheproguard.configpropertyintheapplication’sproject.propertiesfiletothelocationoftheproguard-project.txtfile.Thelinelookslikethis:

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

Asyoucansee,thereisastocksetofProGuardconfigurationsprovidedtoyoubyafileunderthetools/proguarddirectoryoftheAndroidSDK.YoucanthenaugmenttheProGuardconfigurationintheproguard-project.txtfileaspartofyourapplicationproject.Notethattheprovidedconfigurationdoesnotinfactenableoptimizations,astheserequiremoretestingtobesurethatyourapplicationstillworkscorrectly.Ifyouwanttotryoptimizations,changethereferenceintheproject.propertiesfileto${sdk.dir}/tools/proguard/proguard-android-optimize.txt.

Asmentioned,ProGuarddoesitsworkbystrippingstuffout.Sometimesitstripsouttoomuch,andthatiswhyyouseethe-keepoptionsspecifiedintheproguard-android.txtfile.Whenyouproducean.apkfile,youneedtotestittomakesureProGuarddidn’ttakeouttoomuch.Ifyoufinderrorsduetomissingclassesormethods,youcanedittheproguard-project.txtfiletoincludeanother-keepoptionfortheitemyou’remissing.Rebuildyour.apkfile,andtestagain.WerecommendusingtheExportSignedApplicationPackageoptionundertheAndroidToolsmenuoptioninEclipse,becauseitwilltakecareofcallingProGuardforyouasitbuildsthe.apkfile.Exportingiscoveredinthenextsection.

YoucanalsoconfigureAnttoobfuscateusingProGuardifyouuseAnttodoyourbuilds.

Page 771: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

WhenProGuarddoesitsthing,you’llgetafilecalledmapping.txtalongwithyour.apkfile.Hangontothisfilebecauseyouwillneedittode-obfuscateastacktracefromyourapplication.IfyouuseEclipsetoexportyour.apkfile,youwillseeanewproguarddirectorycreatedwithinyourEclipseproject.Themapping.txtfilewillbeinthere.Thecommandtouseisretrace,andit’slocatedintheAndroidSDKdirectoryundertools/proguard/bin.Theargumentstoretraceincludethemapping.txtfileandthestacktracefile,butbeawarethatyouneedtospecifythefullpathnametoeach.Also,youshouldkeeptrackofwhichversionofyourapplicationgoeswithwhichmapping.txtfile.

Onemorecautionabouttestingyourapplication.AndroidKitKatintroducedanexperimentalruntimeenginecalledtheAndroidRunTime(ART),andinLollipopitbecametheoneandonlyruntimeengine.Youshouldtestyourapplicationwithboth,especiallyifyouuseProGuardanddooptimizations.

PreparingYour.apkFileforUploadingTogetyourtestedapplicationreadyforuploading—thatis,tocreatethe.apkfiletoupload—youneedtocreateasignedexportofyourapplication.Thiscanbedoneanumberofways,butthesimplestaretousethebuilt-inIDEfeatures.ForEclipseyouwouldright-clickontheprojectnameandchooseAndroidTools ExportSignedApplicationPackage….ForAndroidStudio,youwouldselecttheprojectnameandchoosetheBuildmenu GenerateSignedAPK…FollowthedialogstochooseapropersigningcertificatekeyandcreateyourproductionAPK.

UploadingYourApplicationUploadingiseasytodobuttakessomepreparation.Beforeyoubeginanupload,therearesomethingsyouwillneedtohavereadyanddecisionsyouhavetomake.Thissectioncoversthatpreparationandthosedecisions.Then,whenyou’vegoteverythingyouneed,gototheDeveloperConsoleandchoose+Addnewapplication.You’llbepromptedtosupplylotsofinformationaboutyourapplication,thePlayStorewillrunsomeprocessingonyourapplicationandtheinformation,andthenyourapplicationwillbereadytopublishtothePlayStore.

Theprevioussectioncoveredpreparingyourapplication.apkfileforuploading.Makingyourapplicationattractivetoshoppersrequiressomemarketingonyourpart.Youneedgooddescriptionsofwhatitisanddoes,andyouneedgoodimagessoshoppersunderstandwhattheymightdownload.

TheGooglePlayStoreunderstandsthatyoucouldmarketyourapplicationindifferentcountries.Therefore,youhavetheabilitytoprovidetextandgraphicslocalizedforthedifferentcountrieswithjustoneapplication.

Graphics

Page 772: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

You’llbeaskedtouploadscreenshotsforyourapplication.TheeasiestwaytocapturescreenshotsofyourapplicationistouseDDMS.FireupEclipse,launchyourapplicationintheemulatororonarealdevice,andthenswitchEclipseperspectivestoDDMSandtheDeviceview.FromwithintheDeviceview,selectthedevicewhereyourapplicationisrunningandthenclicktheScreenCapturebutton(itlookslikealittlecameraintheupper-rightcorner)orchooseitfromtheViewmenu.Ifyouhaveachoicewhensaving,choose24-bitcolor.TheAndroidDeviceMonitorisverysimilartoDDMSandisavailableasastand-alonetool(calledmonitor)fromundertheSDKtoolsdirectory,orfromtheToolsmenuofAndroidStudio.

GooglePlayStorewillconvertyourscreenshotstocompressedJPEG;startingwith24-bitwillproducebetterresultsthanstartingwith8-bitcolor.Choosescreenshotsthatwillmakeyourapplicationstandoutfromtherestbutthatalsoshowtheimportantfunctionality.Youmustsupplyatleasttwoscreenshots,andyoucanprovideuptoeight.Beawarethatyouhavetheabilitytouploadscreenshotsforyourapplicationforotherlanguages.Ifyourapplicationhasbeenlocalizedforanothercountryand/orlanguage,you’llwantthescreenshotstocorrespond.

Nextupisahigh-resapplicationicon.Thiscouldbetheexactsamedesignasyourapplicationicon,butGooglePlayStorewantsa512×512pixeliconimage.Thisisrequired.

Thefeaturegraphicisrequiredandisalarge1024×500pixelsinsize.ThisgraphicisusedintheFeaturedsectionofGooglePlayStoresoyouwantthistolookreallygood.

Youcanprovideapromotionalgraphicaswell,butitssizeissmallerthanascreenshot.Althoughthisgraphicisoptional,itisagoodideatoincludeit.Youneverknowwhenthegraphiccouldbedisplayed;withoutone,youdon’tknowwhatwillbedisplayedinitsplace,ifanything.OneplacethePromoGraphicappearsisatthetopofyourapplication’sDetailspageinGooglePlayStore.

Bythetimeyoureadthis,therecouldbeothergraphicsyoucouldupload.Forexample,GooglenowacceptsaTVBannergraphicforappsthatwouldbeviewedonaTV.

ThelastbitofgraphicsrelatedtoyourapplicationisanoptionalvideothatyoucanputoutonYouTubeandlinktofromyourGooglePlayStorepage.

ListingDetailsTheGooglePlayStoreasksfortextualinformationaboutyourapplicationtodisplaytoshoppers,includingthetitle,shortdescription(formerlycalledpromotionaltext),andfulldescription.

There’saShortDescriptionfieldthathasonly80characters,andit’smandatory.WhenyourappisshownatthetopofalistinGooglePlayStore,it’sthePromoGraphicandtheShortDescriptionthatgetdisplayed.

Thefulldescriptionisalsomandatory,anditallowsupto4,000characters.IfyouhavewrittenaseparateEULAforyourusers,providealinktoitinyourfulldescriptiontextsoshopperscanviewitpriortodownloadingyourapplication.Considerthatshopperswill

Page 773: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

likelyusesearchtolocateapplications,sobesuretoputappropriatewordsintoyourtexttomaximizeyourhitrateonsearchesrelatedtoyourapplication’sfunctionality.It’sworthwhiletoputashortcommentinthetextthatsaystoe-mailyouiftheuserrunsintoproblems.Withoutthissimpleprompt,peoplearemorelikelytoleaveanegativecomment,andanegativecommentreallylimitsyourabilitytotroubleshootandsolvetheproblem,ascomparedtoane-mailexchangewiththeaffecteduser.

Onedrawbacktotheusercommentsmechanismdescribedearlieristhatitdoesnotdistinguishtousersthespecificversionofyourapplication.Ifnegativereviewsarereceivedagainstversion1,andyoureleaseversion2witheverythingfixed,thereviewsfromversion1arestillthere,andshoppersmaynotrealizethatthosecommentsdon’tapplytothenewversion.Whenreleasinganewversionofanapplication,theapplicationrating(numberofstars)doesnotgetreset,either.Partlyforthisreason,GooglestartedprovidingaRecentChangestextfieldwhereyoucandescribewhat’snewinthisrelease.Thisiswhereyoucouldindicatethatacertainproblemhasbeenfixedortellwhatthenewfeaturesare.ThePlayStorealsoprovidestheabilitytoseejustthereviews/commentsforthelatestversion,butbydefaultthereviewsandcommentsareshownforallversions.

Oneofyourresponsibilitieswhenwritingthetextforyourapplicationistodisclosethepermissionsthatarerequired.Thesearethesamepermissionsassetinthe<uses-permission>tagsofyourAndroidManifest.xmlfilewithinyourapplication.Whentheuserdownloadsyourapplicationtotheirdevice,AndroidwillchecktheAndroidManifest.xmlfileandasktheuseraboutalloftheuses-permissionrequirementsbeforecompletingtheinstall.Soyoumightaswelldisclosethisupfront.Otherwise,yourisknegativereviewsfromuserssurprisedthatanapplicationrequiressomepermissionthattheyarenotpreparedtogrant,nottomentiontherefunds,whichalsocountagainstyourDeveloperCompositeScore.Similartopermissions,ifyourapplicationrequiresacertaintypeofscreen,acamera,orotherdevicefeature,thisshouldbedisclosedinyourtextdescriptionsofyourapplication.Asabestpractice,youshoulddisclosenotonlywhatpermissionsandfeaturesyourapplicationneeds,butalsowhatyourapplicationwilldowiththem.Youshouldanswertheuser’squestioninadvance:whydoesthisapprequireX?

Whenuploadingyourapplication,youwillneedtochooseanapplicationtypeandacategory.Asthesevalueschangewithtime,wewon’tlistthemhere,butit’seasytogototheAddnewapplicationscreentoseewhattheyare.

PublishingOptionsYoumustchoosetwocontentratings.Theideaistogiveconsumersanideaoftheappropriatenessofanapplicationforcertainagegroups.Thescaleforthefirst(older)contentratingincludesHigh,Medium,andLowMaturity,andEveryone.Choosingtherightleveldependsonthecontentinyourapplicationandhowmuchofthatcontentthereis.Googlehasrulesaboutlocation-awarenessandpostingorpublishinglocations.It’sbesttoreadtherulesforyourselfhere:https://support.google.com/googleplay/android-developer/answer/188189.Thesecondcontentratingisderivedafteryou

Page 774: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

completeaquestionnaire.Youwillactuallygetseveralcontentratings,bycountry,dependingonhowyouanswerthequestionnaire.Thequestionnairetakessomeofthesubjectivityoutofthecontentrating.

Nextyousetthepriceofyourapplication.BydefaultthepriceisFree,andyoumusthavepreviouslysetupaMerchantAccountinGoogleCheckoutifyouwanttochargeforyourapplication.Settingtherightpriceforanapplicationistricky,unlessyou’vegotsomesophisticatedmarketresearchcapabilities,andeventhenit’sstilltricky.Pricessettoohighcouldturnpeopleoff,andyourisktheeffectsofrefundsifpeopledon’tfeelthepricewasworthit.Pricessettoolowcouldalsoturnpeopleoffbecausetheymightthinkit’sacheapapplication.

Oneofthelastdecisionstomakebeforeuploadingyourapplicationistochoosethelocationsandcarriersforyourapplicationtobevisibleto.BychoosingAll,yourapplicationwillbeavailableeverywhere.However,youmaywanttorestrictdistributiongeographicallyorbycarrier.Dependingonwhatfunctionalityisinyourapplication,youmayneedtorestrictbylocationinordertocomplywithUSexportlaw.Youmaychoosetorestrictyourapplicationbycarrierifyourapplicationhascompatibilityissueswithcertaincarriers’devicesorpolicies.Toseecarriers,clicktheShowoptionslinknexttothecountry,andtheavailablecarriersforthatcountrywillbedisplayed,allowingyoutochoosetheonesyouwant.ChoosingallalsomeansthatanynewlocationsorcarriersthatGoogleaddswillautomaticallyseeyourapplicationwithnointerventionfromyou.

Inadditiontocountryandcarrierchoices,GooglePlayStorealsoallowsyoutorestrictyourapplicationtocertaindevices.Bydefault,thedeviceslistisfilteredbasedonyourmanifestfile,inwhichyou’vespecifiedthefeaturesandsoonthatyourapplicationrequires.ThissectionoftheUploadscreenallowsyoutofurtherrestrictotherdevices.Youwouldprobablyonlywanttodothisiftherewasaknownissuewithaparticulardevicesuchthatyouwereunabletogetyourapplicationtoworkonthatdeviceeventhoughitoughtto.

AndroidalsoofferstheoptiontouploadmultipleAPKsforthesameapplication.ItenablesyoutohaveasingleentryonGooglePlayStorebuttohaveseparatebuildforphonesandtablets.Seehttp://android-developers.blogspot.com/2011/07/multiple-apk-support-in-android-market.htmlandhttp://developer.android.com/google/play/publishing/multiple-apks.html.

ContactInformationEventhoughyourdeveloperprofilecontainsyourcontactinformation,youcansetdifferentinformationwhenuploadingeachapplication.ThePlayStoreasksforawebsite,e-mailaddress,andphonenumberascontactinformationrelatedtothisapplication.Youmustsupplyatleastoneofthesesobuyerscangetsupport,butyoudon’tneedtosupplyallthree.Itisagoodideatonotuseyourpersonale-mailaddresshere,justasyouprobablywouldn’treallywanttogiveoutyourpersonalphonenumber.Whenyou’vemademillionsofdollarsfromsellingyourapplication,you’llwanttoletsomeoneelse

Page 775: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

receiveanddealwiththee-mailsfromusers.Bysettingupanapplication-supporttypeofe-mailaddressinadvance,youcaneasilyseparatethesupporte-mailsfromyourpersonale-mails.Ofcourse,youcanalwayschangethesevalueslaterifyouneed/wantto.

ConsentWithallthesedecisionsmade,youmustthenattestthatyourapplicationabidesbyAndroid’sContentGuidelines(basicallynonastystuff)andmakeasecondattestationthatthesoftwareisOKforexportfromtheUnitedStates.USexportlawsapplybecauseGoogle’sserversarelocatedinsidetheUnitedStates,evenifyouareoutsideoftheUnitedStates,andevenifbothyouandyourcustomerareoutsideoftheUnitedStates.Rememberthatyoucanalwayschoosetodistributeyourapplicationthroughotherchannels.Whenallyourinformationisinandyourgraphicsareuploaded,goaheadandclicktheSavebutton.Thiswillprepareeverythingforyourapplicationtobereadytogolive.

YoucanthenpublishyourapplicationbyclickingthePublishbutton.GooglePlayStorewillperformsomechecksonyourapplication—forinstance,checkingyourapplication’scertificatefortheexpirationdate.Ifallgoeswell,yourapplicationwillsoonbeavailablefordownload.Congratulations!

UserExperienceonGooglePlayStoreThePlayStoreapphasbeenavailableondevicesforsometimenow,anditisavailableovertheInternet.Developersdon’thaveanycontroloverhowGooglePlayStoreworks,otherthantoprovidegoodtextandgraphicsfortheirapplication’slistinginthePlayStore.Therefore,theuserexperienceisprettymuchuptoGoogle.Fromadevice,ausercansearchbykeyword;lookattopdownloadedapplications(bothfreeandpaid),featuredapplications,ornewapplications;orbrowsebycategories.Oncetheyfindanapplicationtheywant,theysimplyselectit,whichpopsupanitemdetailsscreenallowingthemtoinstallitorbuyit.BuyingwilltaketheusertoGoogleCheckouttoconductthefinancialpartofthetransaction.Oncedownloaded,thenewapplicationshowsupwithalltheotherapplications.

FromtheInternetwebsiteforGooglePlayStore(https://play.google.com),theuserinterfacelooksaboutthesame,albeitmuchlargerthanmostdevicescreens.Onedifferenceisthattheweb-basedGooglePlayStoreexpectstheusertologintotheirGoogleaccounttousethePlayStore.ThisallowsGoogletoconnectyourwebexperienceonGooglePlayStoretoyouractualdevice.Thismeanstwothings:whenusingthewebsite,GooglePlayStoreknowswhatapplicationsarealreadyinstalledonyourdevice;andwhenyoumakeapurchaseontheGooglePlayStorewebsite,thedownloadcanbesenttoyourdevice(ordevices)andnottowhatevercomputeryouhappentobebrowsingon.

GooglePlayStorehasanoptiontoviewdownloadedapplicationsinMyApps.Thisareacontainsallinstalledappsandanyappsthatyou’vepurchased,evenifyou’veremovedthem(perhapsyouremovedthemjusttomakeroomforotherapplications).Thismeansyoucoulddeleteapaidappfromyourphoneandthenreinstallitlaterwithouthavingto

Page 776: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

repurchaseit.Ofcourse,ifyouoptedforarefund,theappwillnotshowupinMyApps.

ThelistofappsinMyAppsistiedtoyourGoogleAccountusedacrossallyourdevices.Thismeansyoucouldswitchtoanewphysicaldeviceandstillhaveaccesstoalltheappsyou’vepaidfor.Butbeware.SinceyoumighthavemultipleidentitieswithGoogle,youmustusetheexactsameidentityasbeforetogetyourappsonanewdevice.WhenviewingappsinMyApps,anythathaveupgradesavailablewillindicatethisandallowyoutogettheupgrade.

GooglePlayStorefiltersapplicationsavailabletousers.Itdoesthisinanumberofways.UsersinsomecountriescanonlyseefreeapplicationsbecauseofthecommercelegalitiesinvolvedforGoogleinthatcountry.Googleistryinghardtoovercomecommercehurdlessoallpaidappswillbeavailableeverywhere.Untilthattimecomes,usersinsomecountrieswillbeunabletoaccesspaidapps.UserswithdevicesrunningolderversionsofAndroidwillnotbeabletoseeapplicationsthatrequireanewerversionoftheAndroidSDK.Userswithdeviceconfigurationsthatarenotcompatiblewiththerequirementsoftheapplication(expressedvia<uses-feature>tagsintheAndroidManifest.xmlfile)willnotbeabletoseethoseapplications.Forexample,applicationsnotspecificallysupportingsmallscreenscannotbeseeninGooglePlayStorebyusersondeviceswithsmallscreens.Thisfilteringismostlyintendedtoprotectusersfromdownloadingapplicationsthatwillnotworkontheirdevice.

IfyouarepurchasingappsinGooglePlayStorefromothercountries,yourtransactionmaybesubjecttocurrencyconversion,whichcanalsocarryanadditionalfee,unlessthesellerhasspecifiedpricinginyourlocalcurrency.You’rereallypurchasingusingtheGoogleCheckoutfromtheseller’scountry.GooglePlayStorewilldisplayanapproximateamount,buttheactualchargescouldvarydependingonwhenthetransactionisplacedandwithwhichpaymentprocessor.Buyersmaynoticeapendingtransactionagainsttheiraccountforasmallamount(forexample,US$1).ThisisdonebyGoogletoensurethatthepaymentinformationprovidediscorrect,andthispendingchargewillnotactuallygothrough.

AfewwebsitesareavailablethatmirrortheGooglePlayStoreapplistings.Shopperscansearch,browsecategories,andfindoutaboutGooglePlayStoreapplicationsovertheInternetwithouthavingadevice.ThisgetsaroundthefilteringthatGooglePlayStoredoesbasedonyourdeviceconfigurationandlocation.However,thisdoesnotgetappsontoyourdevice.Examplesofthesemirrorsitesarewww.androlib.com,andwww.appszoom.com.

BeyondGooglePlayStoreGoogle’sPlayStoreisnottheonlygameintown.YouarenotforcedintousingGooglePlayStoreatall.Youshouldconsiderutilizingotherchannelsofdistribution,notonlytomakeyourappavailabletomorepeopleinmorecountries,butalsototakeadvantageofotherpaymentprocessorsandopportunitiestomakemoney.

ThereareAndroidappstorescompletelyseparatefromGooglePlayStore,thebiggestofwhichisprobablyAmazon.OtherexamplesofAndroidappstoresare

Page 777: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

http://mall.soc.io/apps,http://slideme.org,www.getjar.com,andhttps://f-droid.org/.Fromthesesites,youcansearch,browse,findoutaboutapps,andalsodownloadapps,eitherfromadeviceorviaawebbrowser.Thesesitesdon’thavetoabidebyGoogle’srules,includingthetransactionfeesforpaidappsandmethodsofpayment.PayPalandotherpaymentprocessorscanbeusedtopurchaseappsontheseseparatesites.Thesesitesalsodon’tnecessarilyrestrictbylocationordeviceconfiguration.SomeofthemprovideanAndroidclientthatcanbeinstalled,orinsomecasesmaycomepreinstalledonadevice.Userscansimplylaunchabrowserontheirdeviceandfindtheapptheywanttodownloadviathewebsite;whenthefileissavedtothedevice,Androidknowswhattodowithit.Thatistosay,adownloaded.apkfileistreatedasanAndroidapplication.IfyouclickitintheDownloadhistoryofthebrowser(nottobeconfusedwithMyApps,coveredearlier),youwillbepromptedtoseeifyouwanttoinstallitornot.ThisfreedommeansyoucansetupyourownmethodsofdownloadingAndroidapplicationstousers,evenfromyourownwebsiteandwithyourownpaymentmethods.Youmuststilldealthoughwithcollectinganynecessarysalestaxandremittingittotheappropriateauthorities.

WhilenotrestrictedbyGoogle’srules,thesealternatemethodsofappdistributionmaynotofferthesamesortofbuyerprotectionsthatarefoundinGooglePlayStore.Itmaybepossibletopurchaseanapplicationthroughanalternatemarketthatwillnotworkonthebuyer’sdevice.Buyersmaybeatgreaterriskofmalwareonthealternatemarkets.Thebuyermayalsoberesponsibleforcreatingbackups,incasetheylosetheapplicationfromtheirdevice,orfortransferringapplicationsiftheyswitchtoanewdevice.

Theseothermarketsallowyoutomakemoneyonthesaleofeachapp.You’vealsogottheabilitywithintheseothermarketstoimplementalternatepaymentmechanisms,ortoimplementadsandmakemoneythatway.

RememberthatGoogledoesnotrestrictdevelopersfromsellingtheirapplicationsinmultiplemarketsatthesametimetheysellthroughGooglePlayStore.Soconsiderallyouroptionstomakethemostofyourefforts.

ReferencesHerearesomehelpfulreferencestotopicsyoumaywishtoexplorefurther:

http://developer.android.com/guide/topics/manifest/manifest-intro.html:TheDeveloperGuidepagetotheAndroidManifest.xmlfile,withdescriptionsofhowtousethesupports-screens,uses-configuration,anduses-featuretags.

http://developer.android.com/guide/practices/screens_support.htmlTheDeveloperGuidepage“SupportingMultipleScreens,”whichcontainslotsofgoodinformationondealingwithdifferentscreensizesanddensities.

Page 778: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

http://developer.android.com/design/style/iconography.htmlTheDesignGuidepage“Iconography,”whichcontainslotsofgoodinformationondesigningeffectiveiconsforyourapplication.

http://android-developers.blogspot.com/2010/09/securing-android-lvl-applications.htmlandhttp://android-developers.blogspot.com/2010/09/proguard-android-and-licensing-server.html:BlogpostsonhowtousetheLicenseVerificationLibrary(LVL)inwaysthatpreventpiracy.

http://proguard.sourceforge.net/:ThemainsiteforProGuard,whichincludesdocumentation.

SummaryYouarenowequippedtotakeontheworldwithyourAndroidapplications!Hereisarundownofthetopicswecoveredinthischapter:

HowtogetestablishedasaGooglePlayStorePublisher(thatis,Developer)soyoucanpublishtoGooglePlayStore.

TherulesaslaidoutintheGooglePlayDeveloperDistributionAgreement.

GivingGoogleitsshareofyourrevenueifyouaresellingthroughGooglePlayStore.WealsodiscussedhowGoogledoesnotwanttoseecompetitionfromwithinthePlayStore.

Yourresponsibilityforpayingtaxesonrevenuesfromyourapplications.

TheGooglePlayStorerefundpolicy,boththepublishedandtherealone.

Howuserscangetcopiesofyourapplicationanytimeinthefutureaslongastheypaidforitonce.

TheAndroidbrandingrules.Makesureyoudon’tviolateanycopyrightassociatedwithAndroid,images,orfonts.

TheDeveloperConsoleanditsfeatures.TheDeveloperConsolecollectsuserfeedbackanderrorreportsfromusers.

Preparingyourapplicationforproduction,includingtesting,LVLandProGuardtofightpiracy,andusingresourcevariationsandtagsinAndroidManifest.xmltofilterwhichdevicesyourapplicationwillbeavailableto.

Page 779: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Adviceregardinglocalizingyourapplicationbylanguageand/orculture.

TheGooglePlayStoreuserinterface,bothondeviceandontheInternet/Web.

ThefactthatGooglePlayStoreisnottheonlygameintown,andthatyoucansellyourapplicationinotherplacesontheInternet,allatthesametime.

Page 780: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

IndexA

Accelerometers

coordinatesystem

deviceangle

displayorientation

gravity

landscapemode

magneticfieldsensor

AccountsFunctionTester

acos()method

Actionbar

definition

list-basedactionbar

searchviewwidget

manifestfile

menuitem

searchableXMLfile

searchresultsactivity

searchtarget

standardactionbar

tabbedactionbar

ACTION_DOWNevent

ACTION_DRAG_ENDED

ACTION_DRAG_ENTERED

ACTION_DRAG_EXITED

ACTION_DRAG_LOCATION

ACTION_DRAG_STARTED

ACTION_DROP

ACTION_MOVEevent

ACTION_UPevent

Activity.getResources()

Activity.managedQuery()method

Activity.onCreate()

Adapters

ArrayAdapter

createFromResource()method

notifyDataSetChanged()method

Page 781: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

classhierarchy

GalleryControl

GridViewcontrol

definition

JavaImplementation

ListAdapter

setContentView()

ListViewcontrol

AcceptUserInput

additionalbutton

codeimplementation

doClick()method

getCheckItemIds()method

getItemAtPosition()method

LinearLayout

ListActivity

makeText()method

notifyDataSetChanged()method

onItemClick()method

setListAdapter()method

simple_list_rowlayout

UIdefinition

SimpleCursorAdapter

SpinnerControl

addProfileContact()

AggregatedContact()

Aggregatedcontacts

cursorfor

URI-basedcursor

definition

listContacts()

LookupURI-BasedCursor

Alarmmanager

broadcastreceiver

Calendarobject

IntentPointing

PendingIntentclass

persistence

repeatingalarm

RTCtime

setExact()method

set()method

Page 782: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

TestReceiver

am.getAccounts()

@android\:id/empty

@android\:id/listview

Androidactivitylifecycle

activitycallbacks

ObjectonRetainNonConfigurationInstance()

voidonCreate

voidonDestroy()

voidonPause()

voidonRestart()

voidonRestoreInstanceState

voidonResume()

voidonSaveInstanceState

voidonStart()

voidonStop()

Androidappstores

Androidarchitecture

calculatorapplication

ACTION_GET_CONTENT

activitylifecycle.Androidactivitylifecycle

directorystructure

implicit/explicit

intentactivities

intent/activities

intents

ProgrammingLogic(seeProgrammingLogic)

realdevice

savingstate

UI.UserInterface(UI)

finesseapps

integration

robustapplications

UIessentials

Androidcustomadapter

ManateeAdapter

GridView

javaimplementation

XMLlayout

AndroidDevelopmentTools(ADT)

Androideclipseenvironment

AndroidSDK

Page 783: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

eclipse4.2

installingADT

JDK6

PATH

pointingADT

toolswindow

AndroidInterfaceDefinitionLanguage(AIDL)

definition

IStockQuoteServiceinterface

bindService()method

Compiler-GeneratedJavaFile

implementation

MainActivity.javafile

manifestdeclaration

ServiceConnectioninterface

StockQuoteClient

unbindService()method

Messenger/Handler

clientactivitycode

clientfragmentcode

servicecode

nonprimitivetypes

Parcelableinterface

AndroidManifest.xmlfile

implementation

IStockQuoteService.aidl

MainActivity.java

main.xml

Person.aidlfile

StockQuoteService2implementation

StockQuoteService2layout

Androidlayoutmanagers

definition

FrameLayout

GridLayout

LinearLayout

gravity

gravityvs.layout_gravity

horizontalconfiguration

textfields

weight

weightconfigurations

Page 784: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RelativeLayout

TableLayout

AndroidManifest.xmlfile

Androidresources

applicationclass

applicationcontext

arbitraryXMLfile

assetsdirectory

directorystructure

drawableXMLresourcefile

Javacode

qualifiers

rawresourcefile

AndroidRunTime(ART)

Androidsecuritymodel

digitalcertificate

keypair

keystore

runtimesecurity

Androidmanifesteditortool

featuresandresources

processboundary

requiredpermission

URIpermissions

signingapplications

adbtool

debug.keystorefile

exportwizard

installingupdates

jarsignertool

self-signedcertificate

VeriSign

zipaligntool

Androidservice

AIDL(seeAndroidInterfaceDefinitionLanguage)

AsyncTask

local

AndroidManifest.xmlfile

BackgroundService.java

bindService()

Context.startService()

definition

Page 785: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

displayNotificationMessage()method

drawablefile

e-mailapplication

IntentService

interrupt()method

MainActivity

main.xmllayoutfile

onBind()method

onCreate()method

onDestroy()method

onStartCommand()method

ServiceWorkerclass

startIdparameter

startService()

stop*()methods

ThreadGroupclass

remote

bindService()

definition

languagetranslationapplication

RPCmechanism

Android’sfundamentalcomponents

activity

AndroidManifest.xml

AVD

contentprovider

fragment

intent

service

view

Androidsoftwaredevelopmentkit(SDK)

JDK

packages

savingstate

contentproviders

externalfiles

internalfiles

networkstorage

O/Rmappinglibraries

sharedpreferences

SQLite

tools

Page 786: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Androidstudio

definition

homescreen

Javainstallation

Androidstyles

definition

EditText

parentstyle

TextView

Androidthemes

Androidvirtualdevice(AVD)

animate()method

Animation

APIresource

types

AnimationBuilder

AnimatiorSetBuilder

AnimatorSet

apkfile

ApplicationNotResponding(ANR)

Applicationprogramminginterface(API)

AppWidgetProviderInfoclass

argsBundleargument

AsyncTask

activitypointer

devicerotation

implementation

concretetypes

definition

doInBackground()method

execute()method

onPostExecute()callbackmethod

onPreExecute()method

parameters

progressdialog

publishProgress()method

sourcecode

threadpools

manageddialogs

pseudocode

retainedobjectsandfragmentdialogs

activitylifecycle

Page 787: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

AsyncTesterFragmentobject

attach()method

fragmentapproach

keycodesnippets

layoutfile

onCreateDialog()method

onDestroy()method

onRetainNonConfigurationInstance()method

onStart()method

pseudocode

releaseResources()method

retainedheadlessfragment

rootRADO

sampling

setProgress()method

AsyncTaskLoader

autoPause()method

BBackgroundService’sonDestroy()method

BaseAdapter

BDayWidgetModelclass

bindService()method

BirthdayWidget

Bluedot

BooleanButtonclass

Broadcastreceiver

in-processreceivers

long-runningservices

abstractclass

ALongRunningReceiver

codeexecution

getLRSClass()method

handleBroadcastIntent()method

IntentService

LightedGreenRoomabstraction

nonstickyservice

onCreate()method

onDestroy()method

onStartCommand()method

protocols

redelivermode

Page 788: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

stickyservice

Test60SecBCR

Test60SecBCRService

manifestfile

notificationmanager

monitoring

sendingnotification

startActivity()method

out-of-processreceivers

sendBroadcast()method

sendOrderBroadcastmethod

TestReceiver2

Broadcastreceiversamplecode

CCalendar.getInstance()

c.close()

c.getColumnCount()

c.getCount()

Chronometer

clearCheck()method

Clientapplication

ClipData

c.moveToFirst()

cnamesBuffer.toString()

Compatibilitylibrary

APIs

retrofitting

tablets

v4supportlibrary

v7supportlibrary

v8supportlibrary

v13supportlibrary

Complementaryfilters

Configurationchanges

configurationfactors

destroy/createcycle

FragmentManager

fragments

onCreate()callback

onRestoreInstanceState()callback

onSaveInstanceState()callback

Page 789: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

putInt()

putParcelable()

putString()

saveFragmentInstanceState()

setInitialSavedState()

setRetainInstance()

features

getLastNonConfigurationInstance()

onConfigurationChanged()callback

onRetainNonConfigurationInstance()

UIelements

Consumingservices

Android(seeAndroidservice)

HTTP(seeHttpClient)

ContactData()

contact_entities_viewdatabaseview

ContactsAPI

accounts

AccountsFunctionTester

aggregatedcontacts

cursorfor

URI-basedcursorfor

contact_entities_viewdatabaseview

ContactProviderUI

ContentProviderOperation

backreferences

committingviayielding

containerfor

definition

optimisticlocking

controllingaggregation

detailsadding

groupfeatures

personalprofile

contactdata

dataadding

profile-basedURIs

rawcontacts

reading/writing

photofeatures

rawcontacts(seeRawcontacts)

syncadapters

Page 790: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Contentproviders

Androidresources

bookdatabase

BookProvidercontentprovider

deletemethod

implementation

insertmethod

MIME-typecontracts

projectionmaps

querymethod

register

structureof

updatemethod

UriMatcherclass

ContentValues

ContentValues()

CONTEXT_INCLUDE_CODEflag

Contextmenu

onContextItemSelected()

Populating

TextView

Context.NOTIFICATION_SERVICE

CONTEXT_RESTRICTEDflag

createPackageContext()API

createScaledBitmap()method

cursor

foraggregatedcontacts

URI-basedcursor

CursorLoader

DDalvikDebugMonitorService(DDMS)

databaseviews

contact_entities_view

dataRecord.toString()

Datatable

describeEvent()method

DetailsFragment.java

DeveloperConsole

DialogFragment

AlertDialogFragment

communication

Page 791: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

construction

newInstance()method

dismiss()method

implications

onCancel()callback

onDismiss()callback

embeddeddialogs

HelpDialogFragment

MainActivity

MyDialogFragment

onCreateDialog()

onCreateView()

OnDialogDoneListener

PromptDialogFragment

show()method

Dialogs

Android

dialogfragments(seeDialogFragment)

toast

Digitalcertificate

DirectAccessBookDBHelper

Display.getRotation()

doInBackground()method

Dot.java

doWhenMapIsReady()method

Drag-and-dropimplemention

ACTION_UPevent

Android3.0

ACTION_DRAG_ENDED

ACTION_DRAG_ENTERED

ACTION_DRAG_EXITED

ACTION_DRAG_LOCATION

ACTION_DRAG_STARTED

ACTION_DROP

DragEventobject

ClipData

customview

Dot

Dot.java

DragShadowBuilder

draw()method

DropZone.java

Page 792: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

dropzone.xml

FrameLayout

invalidate()method

layout_height

layout_width

layoutXML

LinearLayout

main.xmlfile

ObjectAnimatorclass

onCreateView()method

onDrag()

onMeasure()method

palette.xml

startDrag()

TextView

TouchDragDemo

userinterface

Viewobject

DragEvent.getResult()method

DragShadowBuilder

draw()method

DropTarget

DropZone.java

dropzone.xml

Dynamicmenus

EEndUserLicenseAgreement(EULA)

execute()method

executeOnExecutor()method

Expandedmenu

FfalseBtnTop

FILL_PARENTvs.MATCH_PARENT

findViewById()

for(c.moveToFirst()

Fragments

definition

FragmentManager

enableDebugLogging()method

getFragment()method

Page 793: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

MainActivity

onCreateView()method

persistence

portraitmode

putFragment()method

referencingfragments

saveFragmentInstanceState()method

setContentView()

setRetainInstance()

showDetails()method

TitlesFragmentclass

FragmentTransactions

findFragmentById()method

FrameLayout

setCustomAnimations()method

setTransition()method

showDetails()method

ViewGroupclass

lifecycle

newInstance()method

onActivityCreated()callback

onAttach()callback

onCreate()callback

onCreateView()callback

onDestroy()callback

onDestroyView()callback

onDetach()callback

onInflate()callback

onPause()callback

onResume()callback

onSaveInstanceState()callback

onStart()callback

onStop()callback

onViewCreated()callback

onViewStateRestored()callback

setRetainInstance()

StaticFactoryMethod

setTargetFragment()

startActivity()

structure

tabletandsmartphoneUI

tabletUI

Page 794: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

XMLlayout

DetailsFragmentclass

FrameLayout

getShownIndex()method

landscapemode

MainActivity

newInstance()method

onCreateView()method

Shakespeareclass

Frame-by-frameanimation

addFrame()method

AnimationDrawableclass

setOneShot(true)method

sourcecode

GgatherControls()

GCMConnectionServers

Geocoding

definition

latitudeandlongitude

mapfragment

methods

Geofencing

addProximityAlert()method

GeofencingApiDemo

geoMagField.getDeclination()

Gestures

GestureDetectorandOnGestureListeners

pinchgesture

getActionBar()

getAction()method

getContacts()

getCount()method

getEdgeFlags()method

getFirstContact()

getFragmentManager()method

getFragment()method

getFromLocationName()method

getHttpClient()method

getItemId()method

getItem()method

Page 795: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

getItemViewType()method

getLastNonConfigurationInstance()

getMinDelay()

getOrientation()

getPointerCount()

getProgressBar()method

getQuaternionFromVector()

getResult()

getRotationMatrix()

getSearchableInfo

getSupportFragmentManager()

getView()method

getViewTypeCount()method

getXVelocity()method

getYVelocity()method

GoogleCloudMessaging(GCM)

authenticatingGCMcommunication

buildingAndroidapplication

configureprojectdependencies

gcm.send()method

manifestproperties

messageID.incrementAndGet()method

onCreate()method

registerAppInBackground()

registering

sendMessage()method

third-partyservice

clientapplication

componentsandmessageflow

definition

GCMAPI

GCMConnectionServers

GoogleDeveloperConsole

remoteapplicationserver

GooglePlayDeveloperDistributionAgreement(GPDDA)

GooglePlayServices

GooglePlayStore

AndroidManifest.xmlfile

apkfile

applicationicon

developerconsole

GPDDArules

Page 796: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

licensingservice

localizing

ProGuard

publisher

screensizes

testing

uploading

consent

contactinformation

graphics

listingdetails

publishingoptions

URIscheme

userexperience

Gravitysensors

Gyroscopesensor

HHandlers

AsyncTaskclass

DeferWorkHandlersourcecode

definition

doDeferredWork()method

handleMessage

messageobject

obtainMessage()method

respondToMenuItem()call

setData()method

sleepmethod

workerthread

HelloAndroidApp

artifacts

debuggingtools

launchoptions

lifecycle

realdevice

structure

hideProgressbar()

Homescreenwidgets

AppWidgetProviderclass

BDayWidgetProviderclass

collections

Page 797: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

configurationactivity

BDayWidgetModelobject

BirthdayWidget

ConfigureBDayWidgetActivity

layoutdefinition

tasks

configureattribute

definition

filesimplementation

initialLayoutattribute

onClickarea

onDeleted()method

onDisabled()method

onEnabled()method

onUpdate()method

previewImageattribute

resizemodeattribute

uninstallingpackages

userexperience

viewmouseclickeventcallbacks

widgetinstancedeletion

widgetprovider

BDayWidgetModel

boundaryboxshape

ConfigureBDayWidgetActivityactivity

implementation

layoutfile

XMLfile

howRawContactsDataForRawContact()

HttpClient

AndroidHttpClient

Apacheversion

HTTPGETrequest

ANR

HttpGetDemo.java

parameters

HTTPPOSTrequest

execute()method

HTTPPOSTcall

MultipartPOSTCall

NameValuePairobject

setEntity()method

Page 798: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UrlEncodedFormEntityobject

HttpURLConnection

JSON

multithreadingissues

BasicResponseHandler

getHttpClient()method

ThreadSafeClientConnManager

protocolexceptions

SOAPwebservice

timeouts

transportexceptions

XMLPullParser

IIconmenu

inflate()method

insertName()method

insertPhone()method

insertProfileRawContact()

insertRawContact()

Interpolators

interrupt()method

invalidate()method

invokePick()

isEnabled()method

J,KJavafile

JavaScriptObjectNotation(JSON)

JavaSEDevelopmentKit(JDK)

LLAUNCHER

Layoutanimation

AccelerateInterpolator

ActivityCode

alpha.xmlfile

BounceInterpolator

interpolators

list_layout.xmlfile

ListView

Page 799: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ListViewXMLfile

rotateXMLfile

scaleanimationXMLfile

translateandalphaanimationsfile

types

XMLfile

LicenseVerificationLibrary(LVL)

Lightsensor

Linearaccelerationsensor

listContacts()

listLookupUriColumns()

ListPreference

entryValuesarray

flight_sort_options_valuesarray

userinterface

XML

loaderCallbacks

LoaderManager

LoaderManager.destroyLoader(loaderid)

LoaderManager.initLoader()

LoaderManager.LoaderCallbacks

LoaderManager.restartLoader()

Loaders

activity/fragment

activityloadingdata

Activity.onCreate()

APIclasses

argsBundleargument

AsyncTaskLoader

characteristics

cursor

CursorLoader

developer-assigneduniquenumber

ListActivity

ListActivityLayout

loaddata

loaderCallbacks

LoaderManagerCallbacks

LoaderManagerobject

onCreateLoader()method

onCreate()method

onCreateOptionsMenu()method

Page 800: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

onLoaderReset()method

onLoadFinished()method

resources

stringresources

Location-basedservices

AVD

DDMS

emulatorconsole

FusedLocationProviderApi

geocoding

definition

latitudeandlongitude

mapfragment

methods

geofencing

addProximityAlert()method

GeofencingApiDemo

getLastLocation()method

GoogleDirections

GooglePlayServices

GoogleClientApiclient

intentslaunching

isGooglePlayServicesAvailable()method

isUserRecoverableError()method

onConnectionFailed()callback

showErrorDialogFragment()method

tryToConnect()method

hasAccuracy()method

locationproviders

locationupdates

MapFragment

coding

FragmentActivity

FrameLayout

locationupdation

mapdisplay

maptiles

maptypes

MyLocation

panmaps

trafficlayer

WhereAmI

Page 801: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

zoom

MapsAPIkey

Google

manifestfile

markers

CameraUpdateFactoryclass

LatLngBoundsobject

MarkerOptionsfeatures

MyMapFragment.java

onConnected()callback

requestLocationUpdates()method

Settings.Secureclass

staticmethod

WhereAmILocationAPI

LogCat

Long-runningreceiversandservices

abstractclass

ALongRunningReceiver

codeexecution

getLRSClass()method

handleBroadcastIntent()method

IntentService

LightedGreenRoomabstraction

nonstickyservice

onCreate()method

onDestroy()method

onStartCommand()method

protocols

redelivermode

stickyservice

Test60SecBCR

Test60SecBCRService

Low-passfilter

MMagneticfieldsensor

accelerometers

compass

MainActivity’sstopService()method

Mapping.txtfile

MediaAPIs

android.media.MediaPlayerclass

Page 802: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

contentformats

playingaudio

AsyncPlayer

AudioTrack

create()method

getExternalStoragePublicDirectory()method

JetPlayer

killMediaPlayer()method

layoutandcode

onCreate()method

playAudio()method

prepareAsync()method

release()method

setDataSource()method

setLooping()method

setVolume()method

SoundPool

stop()method

userinterface

playingvideo

SDCards

Menu.addSubMenu()

Menugroups

creation

removeGroup()

setGroupCheckable()

setGroupEnabledmethod()

setGroupVisible()

MenuInflater

MenuItem

icon

intent

JavaCode

listener

MenuXMLresourcefile

creation

menuitems

populatingactivity

MotionEvents

ACTION_CANCELevent

ACTION_DOWNevent

ACTION_MOVEevent

Page 803: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ACTION_OUTSIDEevent

ACTION_UPevent

LogCatrecords

mainactivity,Javacode

onTouchEvent()method

onTouch()method

recycle()method

ReturnsFalsebutton

setOnTouchListener()method

TouchDemo1application

Javacode,Buttonclasses

sampleLogCatmessages

UI

XMLlayoutfile

VelocityTracker

Multitouch

ACTION_MOVEevent

ACTION_SCROLL

ACTION_UPvalue

getAction()method

LogCatmessages

XMLlayout

MusicalInstrumentDigitalInterface(MIDI)

NnewInstance()method

Non-configurationinstancereference

Non-streamingsensor

OObjectAnimator

ObjectonRetainNonConfigurationInstance()

obtain()

onAccuracyChanged()

onActivityCreated()callback

onAttach()callback

onBind()method

onCheckedChanged()method

onContextItemSelected()

onCreate()

onCreate()callback

onCreateContextMenu()

Page 804: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

onCreateLoader()method

onCreate()method

onCreateOptionsMenu()method

onCreateView().callback

onCreateView()method

onDestroy()callback

onDestroy()method

onDestroyView()callback

onDetach()callback

onDrag()

onHandleIntent()call

onLoaderReset()method

onLoadFinished()method

onLocationChanged()method

onMapReady()callback

onMeasure()method

onMenuItemClick()

onOptionsItemSelected()

onPause()

onPause()callback

onPerformSync()method

onPostExecute()callbackmethod

onPreExecute()method

onPrepareOptionsMenu()

onProgressUpdate()method

onQueryTextchange()method

onReceive()method

onRestoreInstanceState()

onResume()callback

onResume()method

onRetainNonConfigurationInstance()

onSaveInstanceState()callback

onScale()

onSensorChanged()method

onStart()callback

onStartCommand()method

onStop()callback

onTouchEvent()method

onTouch()method

onUpdate()method

onViewCreated()callback

onViewStateRestored()callback

Page 805: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

O/Rmapping

PPackages

libraryproject

compile-timeconcept

design

hard-codedconstants

propertiesdialog

switchstatement

LinuxuserID

manifestfile

shareduserID

shareresourcesanddata

palette.xml

parseResult()

PendingIntentclass

Pop-upmenus

PreferenceActivity

Preferences

AndroidManifest.xml

application’ssavedpreferences

CheckBoxPreference

dependency

DialogPreference

EditTextPreference

flight_sort_option

getSharedPreferences()method

headers

ListPreference(seeListPreference)

mainsettings

main.xml

MultiSelectListPreference

onCreate()method

OnPreferenceChangeListenerinterface

packagename

PreferenceCategory

PreferenceScreens

setOptionText()method

stringresourcevalue

SwitchPreference

XML

Page 806: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Pressuresensor

Processmodel.SeePackages

ProgrammingLogic

activityclass

AndroidManifest.xml

calculatorbuttons

gatheringcontrols

intentobject

layoutfile

onClick()method

placementfiles

ProgressBar

ProGuard

PropertyanimationAPI

activity

AnimatiorSetBuilder

AnimatorListener

AnimatorSet

AnimatorSetBuilderclass

AnimatorSetclass

class

Keyframes

layouttransitionclass

layouttransitionmethods

ObjectAnimator

PropertyValueHolderclass

PropertyValuesHolder

toggleAnimation(View)method

TypeEvaluatormethod

ValueAnimator

ViewPropertyAnimator

ViewPropertyAnimatorclass

XMLfile

XMLtags

PropertyValuesHolder

Proximitysensor

publishProgress()method

Qquery()function

queueSound()method

Page 807: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

RRatingBar

RawContact()

Rawcontacts

advantagesanddisadvantages

aggregatedcontacts

ContactData.java

contact_entities_view

cursor

datatable

definition

RawContact.java

SQLiteDatabase

structureof

view_contacts

rc.toString()

ReceiveTransitionsIntentServicemethod

registerListener()method

Remoteapplicationserver

Remoteprocedurecall(RPC)

RemoteViewsclass

removeGroup()

requestLocationUpdates()method

Rotationvectorsensor

SScaleGestureDetector

ScrollView

searchable.xml

SearchManager.QUERY

sendBroadcast()method

Sensors

accelerometers(seeAccelerometers)

definition

detectionmethods

GeomagneticField

gettingsensordata

gravitysensor

gyroscopesensor

lightsensor

LightSensorMonitorApp

Page 808: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

linearaccelerationsensor

magneticdeclination

magneticfieldsensor

pressuresensor

proximitysensor

rotationvectorsensor

SensorListApp

javacode

output

temperaturesensor

types

setContentView()

setCustomAnimations()method

setDataSource()method

setEdgeFlags()method

setEntity()method

setGroupCheckable()

setGroupEnabledmethod()

setGroupVisible()

setIntent(intent)

setMapType()method

setMeasureAllChildren()

setMyLocationEnabled()method

setOnClickListener()method

setOnTouchListener()method

setRepeating()method

setResult()

setRetainInstance()method

setTabListener()

setTrafficEnabled()method

setTransition()method

setupButtons()

showAllRawContacts()

showAllRawProfileContacts()

showDetails()method

showProfileRawContactsData()

showProgressbar()method

showRawContactsCursor()

Sleepmethod

SOAPwebservice

SpinnerAdapterinterface

SQLException

Page 809: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

SQLite

databasecreation

databasemigration

DDLs

deletingrows

insertingrows

packagesandclasses

readingrows

sampleSQLcode

SQLitesqlite_masterTable

transactionsmethod

updatingrows

SQLiteCursor

SQLiteDatabase

SQLiteOpenHelper

SQLiteQueryBuilder

startDrag()

Statusbar

stop*()methods

Streamingsensor

StringBuffer()

Styles

Android-providedstyle

attributename

collectionofViewattributes

dynamicstyling

ErrorText.Danger

errorTextView

parentandchildstyle

spannable

staticstyling

SubMenu

SupportMapFragment

System-levelservices

TTabListenerinterface

Temperaturesensor

testAccounts()

Themes

this.getACursor(getRawContactsUri()

this.mContext.getContentResolver()

Page 810: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

Threads

Activity.startService

broadcastreceiver

components

TitlesFragment.java

Toast

toString()

TouchDragDemo

Touchscreens

gestures

GestureDetectorandOnGestureListeners

pinchgesture

MotionEventobject

ACTION_CANCELevent

ACTION_DOWNevent

ACTION_MOVEevent

ACTION_OUTSIDEevent

ACTION_UPevent

Javacode,Buttonclasses

LogCatrecords

mainactivity,Javacode

onTouchEvent()method

recycle()method

ReturnsFalsebutton

sampleLogCatmessages

setOnTouchListener()method

UIobjects

VelocityTracker

XMLlayoutfile

multitouch

ACTION_MOVEevent

ACTION_SCROLL

ACTION_UPvalue

getAction()method

LogCatmessages

XMLlayout

Transformationmatrix

trueLayoutTop

Tweeninganimation

TYPE_AMBIENT_TEMPERATURE

TypeEvaluator

Page 811: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

UudpateAppWidgetfunction

unbindService()method

URI-basedcursor

foraggregatedcontacts

URLparameter

Userinterfacesandcontrols

buttoncontrols

basicbutton

CheckBox

clickhandler

ImageButton

ImageViews

RadioButton

switch

ToggleButton

dateandtimecontrols

AnalogClock/DigitalClock

DatePicker/TimePicker

MapView

textcontrols

AutoCompleteTextView

EditText

MultiAutoCompleteTextView

TextView

UIdevelopment

android.view.View

android.view.ViewGroup

code

XML

XMLwithcode

UserInterface(UI)layout

autogeneratedIDs

backgroundproperty

calculatorXML

colorresource

customcontrols

EditTextcontrol

file-basedresources

TextViewcontrol

value-basedresources

Page 812: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

ViewGroup

widthandheight

XMLcommentspecification

Utils.logThreadSignature()method

VValueAnimator

VelocityTracker

Viewanimation

activity

AnimationListenerclass

Cameraobject

preandposttranslatemethod

rotatemethod

translatemethod

class

initializemethod

interpolatedTime

ListView

Matrixclass

preandposttranslatemethod

PreandPosttranslatepattern

preandposttranslatematrix

setScalemethod

ViewPropertyAnimator

voidonCreate

voidonDestroy()

voidonPause()

voidonRestart()

voidonRestoreInstanceState

voidonResume()

voidonStart()

voidonStop()

WWakefulIntentService

WhereAmI

WhereAmIMarkers

Whitedot

X,Y

Page 813: Pro Android 5 - Lagout Android 5 [MacLean... · Pro Android 5 Dave MacLean Satya Komatineni ... and zest for life fills me with sadness and joy. ... Setting Up Your Eclipse Environment

XMLPullParser

ZZIPfile