android 101 for ios developers - android - objc

Upload: airbus444

Post on 06-Oct-2015

221 views

Category:

Documents


0 download

DESCRIPTION

Android Introduction for iOS Developers

TRANSCRIPT

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 1/10

    GetourbookaboutFunctionalProgramminginSwift

    AboutContributorsSubscribeSnippets

    AperiodicalaboutbestpracticesandadvancedtechniquesforiOSandOSXdevelopment.

    Android101foriOSDevelopers

    Issue#11Android,April2014

    ByStephenBarnes

    Asthemobilesoftwareindustryevolves,itisbecomingincreasinglyimpracticaltotargetonlyiOSforamobileproduct.Androidmarketshareisapproaching80percentforsmartphones,1andthenumberofpotentialusersthatitcanbringtoaproductcanhardlybeignored.

    Inthisarticle,IwillintroducethecoreconceptsofAndroiddevelopmentwithinthecontextofiOSdevelopment.AndroidandiOSworkonsimilarproblemsets,buttheyapproachmanyoftheseproblemsindifferentways.Throughoutthearticle,Iwillbeusingacompanionproject(availableonGitHub)toillustratehowtoaccomplishthesametaskswhendevelopingforbothplatforms.

    InadditiontoaworkingknowledgeofiOSdevelopment,IassumethatyouhaveaworkingknowledgeofJavaandareabletoinstallandusetheAndroidDevelopmentTools.Furthermore,ifyouarenewtoAndroiddevelopment,readingthroughthetutorialbyGoogleaboutbuildingyourfirstappcouldbeveryhelpful.

    ABriefWordonUIDesign

    ThisarticlewillnotdelvedeeplyintotheuserexperienceanddesignpatterndifferencesbetweeniOSandAndroid.However,itwouldbebeneficialtounderstandsomeofthekeyUIparadigmsinuseonAndroidtoday:theactionbar,theoverflowmenu,thebackbutton,theshareaction,andmore.IfyouareseriouslyconsideringAndroiddevelopment,IhighlyrecommendinglookingintotheNexus5fromtheGooglePlayStore.Makeityourfulltimedeviceforaweekandforceyourselftotrytheoperatingsystemtoitsfullestextent.Adeveloperwhodoesntknowthekeyusepatternsofhisorheroperatingsystemisaliabilitytotheproduct.

    LanguageApplicationStructure

    Java

    TherearemanydifferencesbetweenObjectiveCandJava,andwhileitmaybetemptingtobringsomeofObjectiveCsstylingintoJava,itcanleadtoacodebasethatheavilyclasheswiththeprimaryframeworkthatdrivesit.Inbrief,hereareafewgotchastowatchfor:

    LeaveclassprefixesathomeonObjectiveC.Javahasactualnamespacingandpackagemanagement,sothereisnoneedforclassprefixeshere.Instancevariablesareprefixedwithm,not_.

    TakeadvantageofJavaDoctowritemethodandclassdescriptionsforasmuchofyourcodeaspossible.Itwillmakeyourlifeandthelivesofothersbetter.Nullcheck!ObjectiveCgracefullyhandlesmessagesendingtonilobjects,butJavadoesnot.Saygoodbyetoproperties.Ifyouwantsettersandgetters,youhavetoremembertoactuallycreateagetVariableName()methodandcallitexplicitly.Referencingthis.objectwillnotcallyourcustomgetter.Youmustusethis.getObject.Similarly,prefixmethodnameswithgetandsettoindicategettersandsetters.Javamethodsaretypicallywrittenasactionsorqueries,suchasgetCell(),insteadofcellForRowAtIndexPath:.

    ProjectStructure

    Androidapplicationsareprimarilybrokenintotwosections,thefirstofwhichistheJavasourcecode.ThesourcecodeisstructuredviatheJavapackagehierarchy,anditcanbestructuredasyouplease.However,acommonpracticeistousetoplevelcategoriesforactivities,fragments,views,adapters,anddata(modelsandmanagers).

    Thesecondmajorsectionistheresfolder,shortforresourcefolder.Theresfolderisacollectionofimages,XMLlayoutfiles,andXMLvaluefilesthatmakeupthebulkofthenoncodeassets.OniOS,imagesareeither@2xornot,butonAndroidthereareanumberofscreendensityfolderstoconsider.2Androidusesfolderstoarrangeimages,strings,andothervaluesforscreendensity.TheresfolderalsocontainsXMLlayoutfilesthatcanbethoughtofasxibfiles.Lastly,thereareotherXMLfilesthatstoreresourcesforstring,integer,andstyleresources.

    OnelastcorrelationinprojectstructureistheAndroidManifest.xmlfile.ThisfileistheequivalentoftheProjectInfo.plistfileoniOS,anditstoresinformationforactivities,applicationnames,andsetIntents3(systemlevelevents)thattheapplicationcanhandle.FormoreinformationaboutIntents,keeponreading,orheadovertotheIntentsarticle.

    Activities

    ActivitiesarethebasicvisualunitofanAndroidapp,justasUIViewControllersarethebasicvisualcomponentoniOS.InsteadofaUINavigationController,theAndroidOSkeepsanactivitystackthatitmanages.Whenanappislaunched,theOSpushestheappsmainactivityontothestack.Notethatyoucanlaunchotherapps'activitiesandhavethemplacedontothestack.Bydefault,thebackbuttononAndroidpopsfromtheOSactivitystack,sowhenauserpressesback,heorshecangothroughmultipleappsthathavebeenlaunched.

    ActivitiescanalsoinitializeotheractivitieswithIntentsthatcontainextradata.StartingActivitieswithIntentsissomewhatsimilartocreatinganewUIViewControllerwithacustominitmethod.BecausethemostcommonwaytolaunchnewactivitiesistocreateanIntentwithdata,agreatwaytoexposecustominitializersonAndroidistocreatestaticIntentgettermethods.Activitiescanalsoreturnresultswhenfinished(goodbyemodaldelegates!)byplacingextradataonanIntentwhentheactivityisfinished.

    OnelargedifferencebetweenAndroidappsandiOSappsisthatanyactivitycanbeanentrancepointintoyourapplicationifitregisterscorrectlyintheAndroidManifestfile.SettinganIntentfilterintheAndroidManifest.xmlfileforamediaintentonanactivityeffectivelystatestotheOSthatthisactivityisabletobelaunchedasanentrypointwithmediadatainsideoftheIntent.Agoodexamplemightbeaphotoeditingactivitythatopensaphoto,modifiesit,andreturnsthemodifiedimagewhentheactivityfinishes.

    Asasidenote,modelobjectsmustimplementtheParcelableinterfaceifyouwanttosendthembetweenactivitiesandfragments.ImplementingtheParcelableinterfaceissimilartoconformingtotheprotocoloniOS.AlsonotethatParcelableobjectsareabletobestoredinanactivitysorfragmentssavedInstanceState,inordertomoreeasilyrestoretheirstatesaftertheyhavebeendestroyed.

    Letsnextlookatoneactivitylaunchinganotheractivity,andalsorespondingtowhenthesecondactivityfinishes.

    LaunchingAnotherActivityforaResult

    //ArequestcodeisauniquevalueforreturningactivitiesprivatestaticfinalintREQUEST_CODE_NEXT_ACTIVITY=1234;

    protectedvoidstartNextActivity(){//Intentsneedacontext,sogivethiscurrentactivityasthecontextIntentnextActivityIntent=newIntent(this,NextActivity.class);startActivityForResult(nextActivityResult,REQUEST_CODE_NEXT_ACTIVITY);}

    @OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){switch(requestCode){caseREQUEST_CODE_NEXT_ACTIVITY:if(resultCode==RESULT_OK){//ThismeansourActivityreturnedsuccessfully.Fornow,Toastthistext.

    //Thisjustcreatesasimplepopupmessageonthescreen.Toast.makeText(this,"ResultOK!",Toast.LENGTH_SHORT).show();

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 2/10

    Toast.makeText(this,"ResultOK!",Toast.LENGTH_SHORT).show();}return;}super.onActivityResult(requestCode,resultCode,data);}

    ReturningaResultonActivityFinish()

    publicstaticfinalStringactivityResultString="activityResultString";

    /**Oncompletion,placetheobjectIDintheintentandfinishwithOK.*@paramreturnObjectthatwasprocessed*/privatevoidonActivityResult(ObjectreturnObject){Intentdata=newIntent();if(returnObject!=null){data.putExtra(activityResultString,returnObject.uniqueId);}

    setResult(RESULT_OK,data);finish();}

    Fragments

    TheFragmentconceptisuniquetoAndroidandcamearoundsomewhatrecentlyinAndroid3.0.Fragmentsareminicontrollersthatcanbeinstantiatedtofillactivities.Theystorestateinformationandmaycontainviewlogic,buttheremaybemultiplefragmentsonthescreenatthesametimeputtingtheactivityinafragmentcontrollerrole.Alsonotethatfragmentsdonothavetheirowncontextsandtheyrelyheavilyonactivitiesfortheirconnectiontotheapplicationsstate.

    Tabletsareagreatfragmentusecaseexample:youcanplacealistfragmentontheleftandadetailfragmentontheright.4FragmentsallowyoutobreakupyourUIandcontrollerlogicintosmaller,reusablechunks.Butbeware!Thefragmentlifecycle,detailedbelow,ismorenuanced.

    FragmentsarethenewwayofstructuringappsonAndroid,justlikeUICollectionViewisthenewwayofstructuringlistdatainsteadofUITableviewforiOS.5Whileitisinitiallyeasiertoavoidusingfragmentsandinsteadusenothingbutactivities,youcouldregretthisdecisionlateron.Thatsaid,resisttheurgetogiveuponactivitiesentirelybyswappingfragmentsonasingleactivitythiscanleaveyouinabindwhenwantingtotakeadvantageofintentsandusingmultiplefragmentsonthesameactivity.

    LetslookatasampleUITableViewControllerandasampleListFragmentthatshowalistofpredictiontimesforasubwaytrip,courtesyoftheMBTA.

    TableViewControllerImplementation

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 3/10

    @interfaceMBTASubwayTripTableTableViewController()

    @property(assign,nonatomic)MBTATrip*trip;

    @end

    @implementationMBTASubwayTripTableTableViewController

    (instancetype)initWithTrip:(MBTATrip*)trip{self=[superinitWithStyle:UITableViewStylePlain];if(self){_trip=trip;[selfsetTitle:trip.destination];}returnself;}

    (void)viewDidLoad{[superviewDidLoad];

    [self.tableViewregisterClass:[MBTAPredictionCellclass]forCellReuseIdentifier:[MBTAPredictionCellreuseId]];[self.tableViewregisterNib:[UINibnibWithNibName:NSStringFromClass([MBTATripHeaderViewclass])bundle:nil]forHeaderFooterViewReuseIdentifier:[MBTATripHeaderViewreuseId]];}

    #pragmamarkUITableViewDataSource

    (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView{return1;}

    (NSInteger)tableView:(UITableView*)tableViewnumberOfRowsInSection:(NSInteger)section{return[self.trip.predictionscount];}

    #pragmamarkUITableViewDelegate

    (CGFloat)tableView:(UITableView*)tableViewheightForHeaderInSection:(NSInteger)section{return[MBTATripHeaderViewheightWithTrip:self.trip];}

    (UIView*)tableView:(UITableView*)tableViewviewForHeaderInSection:(NSInteger)section{MBTATripHeaderView*headerView=[self.tableViewdequeueReusableHeaderFooterViewWithIdentifier:[MBTATripHeaderViewreuseId]];[headerViewsetFromTrip:self.trip];

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 4/10

    [headerViewsetFromTrip:self.trip];returnheaderView;}

    (UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{UITableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:[MBTAPredictionCellreuseId]forIndexPath:indexPath];

    MBTAPrediction*prediction=[self.trip.predictionsobjectAtIndex:indexPath.row];[(MBTAPredictionCell*)cellsetFromPrediction:prediction];

    returncell;}

    (BOOL)tableView:(UITableView*)tableViewcanEditRowAtIndexPath:(NSIndexPath*)indexPath{returnNO;}

    (void)tableView:(UITableView*)tableViewdidSelectRowAtIndexPath:(NSIndexPath*)indexPath{[tableViewdeselectRowAtIndexPath:indexPathanimated:YES];}

    @end

    ListFragmentImplementation

    publicclassTripDetailFragmentextendsListFragment{

    /***TheconfigurationflagsfortheTripDetailFragment.*/publicstaticfinalclassTripDetailFragmentState{publicstaticfinalStringKEY_FRAGMENT_TRIP_DETAIL="KEY_FRAGMENT_TRIP_DETAIL";}

    protectedTripmTrip;

    /***Usethisfactorymethodtocreateanewinstanceof

    *thisfragmentusingtheprovidedparameters.**@paramtripthetriptoshowdetails*@returnAnewinstanceoffragmentTripDetailFragment.*/publicstaticTripDetailFragmentnewInstance(Triptrip){TripDetailFragmentfragment=newTripDetailFragment();

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 5/10

    TripDetailFragmentfragment=newTripDetailFragment();Bundleargs=newBundle();args.putParcelable(TripDetailFragmentState.KEY_FRAGMENT_TRIP_DETAIL,trip);fragment.setArguments(args);returnfragment;}

    publicTripDetailFragment(){}

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){Prediction[]predictions=mTrip.predictions.toArray(newPrediction[mTrip.predictions.size()]);PredictionArrayAdapterpredictionArrayAdapter=newPredictionArrayAdapter(getActivity(),predictions);setListAdapter(predictionArrayAdapter);returnsuper.onCreateView(inflater,container,savedInstanceState);}

    @OverridepublicvoidonViewCreated(Viewview,BundlesavedInstanceState){super.onViewCreated(view,savedInstanceState);TripDetailsViewheaderView=newTripDetailsView(getActivity());headerView.updateFromTripObject(mTrip);getListView().addHeaderView(headerView);}}

    Inthenextsection,letsdeciphersomeoftheuniqueAndroidcomponents.

    CommonAndroidComponents

    ListViewsandAdapters

    ListViewsaretheclosestapproximationtoUITableViewonAndroid,andtheyareoneofthemostcommoncomponentsthatyouwilluse.JustlikeUITableViewhasahelperviewcontroller,UITableViewController,ListViewalsohasahelperactivity,ListActivity,andahelperfragment,ListFragment.SimilartoUITableViewController,thesehelperstakecareofthelayout(similartothexib)foryouandprovideconveniencemethodsformanagingadapters,whichwelldiscussbelow.OurexampleaboveusesaListFragmenttodisplaydatafromalistofPredictionmodelobjects,similartohowthetableviewsdatasourceusesanarrayofPredictionmodelobjectstopopulatetheUITableView.

    Speakingofdatasources,onAndroidwedonthavedatasourcesanddelegatesforListView.Instead,wehaveadapters.Adapterscomeinmanyforms,buttheirprimarygoalissimilartoadatasourceandtableviewdelegateallinone.AdapterstakedataandadaptittopopulateaListViewbyinstantiatingviewstheListViewwilldisplay.Letshavealookatthearrayadapterusedabove:

    publicclassPredictionArrayAdapterextendsArrayAdapter{

    intLAYOUT_RESOURCE_ID=R.layout.view_three_item_list_view;

    publicPredictionArrayAdapter(Contextcontext){super(context,R.layout.view_three_item_list_view);}

    publicPredictionArrayAdapter(Contextcontext,Prediction[]objects){super(context,R.layout.view_three_item_list_view,objects);}

    @OverridepublicViewgetView(intposition,ViewconvertView,ViewGroupparent){Predictionprediction=this.getItem(position);ViewinflatedView=convertView;if(convertView==null){LayoutInflaterinflater=(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);inflatedView=inflater.inflate(LAYOUT_RESOURCE_ID,parent,false);}

    TextViewstopNameTextView=(TextView)inflatedView.findViewById(R.id.view_three_item_list_view_left_text_view);TextViewmiddleTextView=(TextView)inflatedView.findViewById(R.id.view_three_item_list_view_middle_text_view);TextViewstopSecondsTextView=(TextView)inflatedView.findViewById(R.id.view_three_item_list_view_right_text_view);

    stopNameTextView.setText(prediction.stopName);middleTextView.setText("");stopSecondsTextView.setText(prediction.stopSeconds.toString());

    returninflatedView;}}

    YoullnotethattheadapterhasanimportantmethodnamedgetView,whichisverysimilartocellForRowAtIndexPath:.Anothersimilarityyoullnoticeisapatternforreusingviews,similartoiOS.ReusingviewsarejustasimportantasoniOS,andthissubstantiallyhelpsperformance!Thisadapterisrathersimple,becauseitusesabuiltinsuperclass,ArrayAdapter,foradaptersworkingwitharraydata,butitillustrateshowtopopulateaListViewfromadataset.

    AsyncTasks

    InplaceofGrandCentralDispatchoniOS,onAndroidwehaveaccesstoAsyncTasks.AsyncTasksisadifferenttakeonexposingasynchronoustoolsinamorefriendlyway.AsyncTasksisabitoutofscopeforthisarticle,butIhighlyrecommendlookingoversomeofthedocumentation.

    ActivityLifecycle

    OneoftheprimarythingstowatchoutforcomingfromiOSdevelopmentistheAndroidlifecycle.LetsstartbylookingattheActivityLifecycleDocumentation:

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 6/10

    Inessence,theactivitylifecycleisverysimilartotheUIViewControllerlifecycle.TheprimarydifferenceisthattheAndroidOScanberuthlesswithdestroyingactivities,anditisveryimportanttomakesurethatthedataandthestateoftheactivityaresaved,sothattheycanberestoredfromthesavedstateiftheyexistintheonCreate().ThebestwaytodothisisbyusingbundleddataandrestoringfromthesavedInstanceStateand/orIntents.Forexample,hereisthepartoftheTripListActivityfromoursampleprojectthatiskeepingtrackofthecurrentlyshownsubwayline:

    publicstaticIntentgetTripListActivityIntent(Contextcontext,TripList.LineTypelineType){Intentintent=newIntent(context,TripListActivity.class);intent.putExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE,lineType.getLineName());returnintent;}

    publicstaticfinalclassTripListActivityState{publicstaticfinalStringKEY_ACTIVITY_TRIP_LIST_LINE_TYPE="KEY_ACTIVITY_TRIP_LIST_LINE_TYPE";}

    TripList.LineTypemLineType;

    @OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);mLineType=TripList.LineType.getLineType(getIntent().getStringExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE));}

    Anoteonrotation:thelifecyclecompletelyresetstheviewonrotation.Thatis,youractivitywillbedestroyedandrecreatedwhenarotationoccurs.Ifdataisproperlysavedinthesavedinstancestateandtheactivityrestoresthestatecorrectlyafteritscreation,thentherotationwillworkseamlessly.Manyappdevelopershaveissueswithappstabilitywhentheapprotates,becauseanactivitydoesnothandlestatechangesproperly.Beware!Donotlockyourappsrotationtosolvetheseissues,asthisonlyhidesthelifecyclebugsthatwillstilloccuratanotherpointintimewhentheactivityisdestroyedbytheOS.

    FragmentLifecycle

    TheFragmentLifecycleissimilartotheactivitylifecycle,withafewadditions.

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 7/10

    Oneoftheproblemsthatcancatchdevelopersoffguardisregardingissuescommunicatingbetweenfragmentsandactivities.NotethattheonAttach()happensbeforeonActivityCreated().Thismeansthattheactivityisnotguaranteedtoexistbeforethefragmentiscreated.TheonActivityCreated()methodshouldbeusedwhenyousetinterfaces(delegates)totheparentactivity,ifneeded.

    Fragmentsarealsocreatedanddestroyedaggressivelybytheneedsoftheoperatingsystem,andtokeeptheirstate,requirethesameamountofdiligenceasactivities.Hereisanexamplefromoursampleproject,wherethetriplistfragmentkeepstrackoftheTripListdata,aswellasthesubwaylinetype:

    /***TheconfigurationflagsfortheTripListFragment.*/publicstaticfinalclassTripListFragmentState{publicstaticfinalStringKEY_FRAGMENT_TRIP_LIST_LINE_TYPE="KEY_FRAGMENT_TRIP_LIST_LINE_TYPE";publicstaticfinalStringKEY_FRAGMENT_TRIP_LIST_DATA="KEY_FRAGMENT_TRIP_LIST_DATA";}

    /***Usethisfactorymethodtocreateanewinstanceof*thisfragmentusingtheprovidedparameters.**@paramlineTypethesubwaylinetoshowtripsfor.*@returnAnewinstanceoffragmentTripListFragment.*/publicstaticTripListFragmentnewInstance(TripList.LineTypelineType){TripListFragmentfragment=newTripListFragment();Bundleargs=newBundle();args.putString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE,lineType.getLineName());fragment.setArguments(args);returnfragment;}

    protectedTripListmTripList;protectedvoidsetTripList(TripListtripList){Bundlearguments=this.getArguments();arguments.putParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA,tripList);mTripList=tripList;if(mTripArrayAdapter!=null){mTripArrayAdapter.clear();mTripArrayAdapter.addAll(mTripList.trips);}}

    @OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);if(getArguments()!=null){mLineType=TripList.LineType.getLineType(getArguments().getString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE));mTripList=getArguments().getParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA);}}

    NoticethatthefragmentalwaysrestoresitsstatefromthebundledargumentsinonCreate,andthatthecustomsetterfortheTripListmodelobjectaddstheobjecttothebundledargumentsaswell.Thisensuresthatifthefragmentisdestroyedandrecreated,suchaswhenthedeviceisrotated,thefragmentalwayshasthelatestdatatorestorefrom.

    Layouts

    SimilartootherpartsofAndroiddevelopment,thereareprosandconstospecifyinglayoutsinAndroidversusiOS.LayoutsarestoredashumanreadableXMLfilesintheres/layoutsfolder.

    SubwayListViewLayout

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 8/10

    HereisthesameviewoniOSwithaUITableViewandaUIButtonpinnedtothebottomviaAutoLayoutinInterfaceBuilder:

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 9/10

    YoullnoticethattheAndroidlayoutfileismucheasiertoreadandunderstandwhatisgoingon.TherearemanypartstolayingoutviewsinAndroid,butwellcoverjustafewoftheimportantones.

    TheprimarystructurethatyouwilldealwithwillbesubclassesofViewGroupRelativeLayout,LinearLayout,andFrameLayoutarethemostcommon.TheseViewGroupscontainotherviewsandexposepropertiestoarrangethemonscreen.

    AgoodexampleistheuseofaRelativeLayoutabove.Arelativelayoutallowsustouseandroid:layout_alignParentBottom="true"inourlayoutabovetopinthebuttontothebottom.

    Lastly,tolinklayoutstofragmentsoractivities,simplyusethatlayoutsresourceIDduringtheonCreateView:

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){returninflater.inflate(R.layout.fragment_subway_listview,container,false);}

    LayoutTips

    Alwaysworkindp(densityindependentpixels)insteadofpixelsdirectly.Dontbothernudgingitemsforlayoutsinthevisualeditoroftenthevisualeditorwillputindividualpointsofspacingonobjectsinsteadofadjustingtheheightandwidthasyoumightlike.YourbestbetistoadjusttheXMLdirectly.Ifyoueverseethefill_parentvalueforalayoutheightorwidth,thisvaluewasdeprecatedyearsagoinAPI8andreplacedwithmatch_parent.

    Seethetheresponsiveandroidapplicationsarticleformoretipsonthis.

    Data

    TheDataStorageOptionsavailableonAndroidarealsoverysimilartowhatisavailableoniOS:

    SharedPreferencesNSUserDefaultsInmemoryobjectsSavingtoandfetchingfromfilestructureviatheinternalorexternalfilestoragesavingtothedocumentsdirectorySQLiteCoreData

  • 2/27/2015 Android101foriOSDevelopersAndroidobjc.ioissue#11

    http://www.objc.io/issue11/android_101_for_ios_developers.html 10/10

    TheprimarydifferenceisthelackofCoreData.Instead,AndroidoffersstraightaccesstotheSQLitedatabaseandreturnscursorobjectsforresults.HeadovertothearticleinthisissueaboutusingSQLiteonAndroidformoredetails.

    AndroidHomework

    Whatwevediscussedsofarbarelyscratchesthesurface.ToreallytakeadvantageofsomeofthethingsthatmakeAndroidspecial,Irecommendcheckingoutsomeofthesefeatures:

    ActionBar,OverflowMenu,andtheMenuButtonCrossAppDataSharingRespondtocommonOSactionsTakeadvantageofJavasfeatures:generics,virtualmethodsandclasses,etc.GoogleCompatibilityLibrariesTheAndroidEmulator:installthex86HAXMplugintomaketheemulatorbutterysmooth.

    FinalWordsMuchofwhatwasdiscussedinthisarticleisimplementedintheMBTAsubwaytransitsampleprojectonGitHub.Theprojectwasbuiltasawaytoillustratesimilarconceptssuchasapplicationstructure,handlingdata,andbuildingUIonthesameapplicationforbothplatforms.

    WhilesomeofthepureimplementationdetailsareverydifferentonAndroid,itisveryeasytobringproblemsolvingskillsandpatternslearnedoniOStobear.Whoknows?MaybeunderstandinghowAndroidworksjustalittlebitbettermightprepareyouforthenextversionofiOS.

    1. Source

    2. SeeGooglesdocumentationforsupportingmultiplescreensizeshere.

    3. Intentsdocumentation

    4. SeeGooglesdocumentationformultipanetabletviewformoreinformation.

    5. Thanks,NSHipster.

    Morearticlesinissue#11

    Privacypolicy