Вы находитесь на странице: 1из 10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

GetourbookaboutFunctionalProgramminginSwift

About
Contributors
Subscribe
Snippets
AperiodicalaboutbestpracticesandadvancedtechniquesforiOSandOSXdevelopment.

Android101foriOSDevelopers
Issue#11Android,April2014
ByStephenBarnes
Asthemobilesoftwareindustryevolves,itisbecomingincreasinglyimpracticaltotargetonlyiOSforamobileproduct.Androidmarketshareisapproaching80percentforsmartphones,1andthe
numberofpotentialusersthatitcanbringtoaproductcanhardlybeignored.
Inthisarticle,IwillintroducethecoreconceptsofAndroiddevelopmentwithinthecontextofiOSdevelopment.AndroidandiOSworkonsimilarproblemsets,buttheyapproachmanyofthese
problemsindifferentways.Throughoutthearticle,Iwillbeusingacompanionproject(availableonGitHub)toillustratehowtoaccomplishthesametaskswhendevelopingforbothplatforms.
InadditiontoaworkingknowledgeofiOSdevelopment,IassumethatyouhaveaworkingknowledgeofJavaandareabletoinstallandusetheAndroidDevelopmentTools.Furthermore,ifyou
arenewtoAndroiddevelopment,readingthroughthetutorialbyGoogleaboutbuildingyourfirstappcouldbeveryhelpful.

ABriefWordonUIDesign
ThisarticlewillnotdelvedeeplyintotheuserexperienceanddesignpatterndifferencesbetweeniOSandAndroid.However,itwouldbebeneficialtounderstandsomeofthekeyUIparadigmsin
useonAndroidtoday:theactionbar,theoverflowmenu,thebackbutton,theshareaction,andmore.IfyouareseriouslyconsideringAndroiddevelopment,Ihighlyrecommendinglookinginto
theNexus5fromtheGooglePlayStore.Makeityourfulltimedeviceforaweekandforceyourselftotrytheoperatingsystemtoitsfullestextent.Adeveloperwhodoesntknowthekeyuse
patternsofhisorheroperatingsystemisaliabilitytotheproduct.

LanguageApplicationStructure
Java
TherearemanydifferencesbetweenObjectiveCandJava,andwhileitmaybetemptingtobringsomeofObjectiveCsstylingintoJava,itcanleadtoacodebasethatheavilyclasheswiththe
primaryframeworkthatdrivesit.Inbrief,hereareafewgotchastowatchfor:
LeaveclassprefixesathomeonObjectiveC.Javahasactualnamespacingandpackagemanagement,sothereisnoneedforclassprefixeshere.
Instancevariablesareprefixedwithm,not_.
TakeadvantageofJavaDoctowritemethodandclassdescriptionsforasmuchofyourcodeaspossible.Itwillmakeyourlifeandthelivesofothersbetter.
Nullcheck!ObjectiveCgracefullyhandlesmessagesendingtonilobjects,butJavadoesnot.
Saygoodbyetoproperties.Ifyouwantsettersandgetters,youhavetoremembertoactuallycreateagetVariableName()methodandcallitexplicitly.Referencingthis.objectwillnotcall
yourcustomgetter.Youmustusethis.getObject.
Similarly,prefixmethodnameswithgetandsettoindicategettersandsetters.Javamethodsaretypicallywrittenasactionsorqueries,suchasgetCell(),insteadof
cellForRowAtIndexPath:.

ProjectStructure
Androidapplicationsareprimarilybrokenintotwosections,thefirstofwhichistheJavasourcecode.ThesourcecodeisstructuredviatheJavapackagehierarchy,anditcanbestructuredasyou
please.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,theAndroidOSkeepsanactivity
stackthatitmanages.Whenanappislaunched,theOSpushestheappsmainactivityontothestack.Notethatyoucanlaunchotherapps'activitiesandhavethemplacedontothestack.By
default,thebackbuttononAndroidpopsfromtheOSactivitystack,sowhenauserpressesback,heorshecangothroughmultipleappsthathavebeenlaunched.
ActivitiescanalsoinitializeotheractivitieswithIntentsthatcontainextradata.StartingActivitieswithIntentsissomewhatsimilartocreatinganewUIViewControllerwithacustominitmethod.
BecausethemostcommonwaytolaunchnewactivitiesistocreateanIntentwithdata,agreatwaytoexposecustominitializersonAndroidistocreatestaticIntentgettermethods.Activitiescan
alsoreturnresultswhenfinished(goodbyemodaldelegates!)byplacingextradataonanIntentwhentheactivityisfinished.
OnelargedifferencebetweenAndroidappsandiOSappsisthatanyactivitycanbeanentrancepointintoyourapplicationifitregisterscorrectlyintheAndroidManifestfile.SettinganIntent
filterintheAndroidManifest.xmlfileforamediaintentonanactivityeffectivelystatestotheOSthatthisactivityisabletobelaunchedasanentrypointwithmediadatainsideoftheIntent.A
goodexamplemightbeaphotoeditingactivitythatopensaphoto,modifiesit,andreturnsthemodifiedimagewhentheactivityfinishes.
Asasidenote,modelobjectsmustimplementtheParcelableinterfaceifyouwanttosendthembetweenactivitiesandfragments.ImplementingtheParcelableinterfaceissimilartoconforming
tothe<NSCopying>protocoloniOS.AlsonotethatParcelableobjectsareabletobestoredinanactivitysorfragmentssavedInstanceState,inordertomoreeasilyrestoretheirstatesafterthey
havebeendestroyed.
Letsnextlookatoneactivitylaunchinganotheractivity,andalsorespondingtowhenthesecondactivityfinishes.

LaunchingAnotherActivityforaResult
//Arequestcodeisauniquevalueforreturningactivities
privatestaticfinalintREQUEST_CODE_NEXT_ACTIVITY=1234;
protectedvoidstartNextActivity(){
//Intentsneedacontext,sogivethiscurrentactivityasthecontext
IntentnextActivityIntent=newIntent(this,NextActivity.class);
startActivityForResult(nextActivityResult,REQUEST_CODE_NEXT_ACTIVITY);
}
@Override
protectedvoidonActivityResult(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();
http://www.objc.io/issue11/android_101_for_ios_developers.html

1/10

2/27/2015
Android101foriOSDevelopersAndroidobjc.ioissue#11
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.Theystorestate
informationandmaycontainviewlogic,buttheremaybemultiplefragmentsonthescreenatthesametimeputtingtheactivityinafragmentcontrollerrole.Alsonotethatfragmentsdonot
havetheirowncontextsandtheyrelyheavilyonactivitiesfortheirconnectiontotheapplicationsstate.
Tabletsareagreatfragmentusecaseexample:youcanplacealistfragmentontheleftandadetailfragmentontheright.4FragmentsallowyoutobreakupyourUIandcontrollerlogicinto
smaller,reusablechunks.Butbeware!Thefragmentlifecycle,detailedbelow,ismorenuanced.

FragmentsarethenewwayofstructuringappsonAndroid,justlikeUICollectionViewisthenewwayofstructuringlistdatainsteadofUITableviewforiOS.5Whileitisinitiallyeasiertoavoid
usingfragmentsandinsteadusenothingbutactivities,youcouldregretthisdecisionlateron.Thatsaid,resisttheurgetogiveuponactivitiesentirelybyswappingfragmentsonasingleactivity
thiscanleaveyouinabindwhenwantingtotakeadvantageofintentsandusingmultiplefragmentsonthesameactivity.
LetslookatasampleUITableViewControllerandasampleListFragmentthatshowalistofpredictiontimesforasubwaytrip,courtesyoftheMBTA.

TableViewControllerImplementation

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

2/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

@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];
http://www.objc.io/issue11/android_101_for_ios_developers.html

3/10

2/27/2015
[headerViewsetFromTrip:self.trip];
returnheaderView;
}

Android101foriOSDevelopersAndroidobjc.ioissue#11

(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();
http://www.objc.io/issue11/android_101_for_ios_developers.html

4/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

TripDetailFragmentfragment=newTripDetailFragment();
Bundleargs=newBundle();
args.putParcelable(TripDetailFragmentState.KEY_FRAGMENT_TRIP_DETAIL,trip);
fragment.setArguments(args);
returnfragment;
}
publicTripDetailFragment(){}
@Override
publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
BundlesavedInstanceState){
Prediction[]predictions=mTrip.predictions.toArray(newPrediction[mTrip.predictions.size()]);
PredictionArrayAdapterpredictionArrayAdapter=newPredictionArrayAdapter(getActivity(),predictions);
setListAdapter(predictionArrayAdapter);
returnsuper.onCreateView(inflater,container,savedInstanceState);
}
@Override
publicvoidonViewCreated(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(similarto
thexib)foryouandprovideconveniencemethodsformanagingadapters,whichwelldiscussbelow.OurexampleaboveusesaListFragmenttodisplaydatafromalistofPredictionmodel
objects,similartohowthetableviewsdatasourceusesanarrayofPredictionmodelobjectstopopulatetheUITableView.

Speakingofdatasources,onAndroidwedonthavedatasourcesanddelegatesforListView.Instead,wehaveadapters.Adapterscomeinmanyforms,buttheirprimarygoalissimilartoa
datasourceandtableviewdelegateallinone.AdapterstakedataandadaptittopopulateaListViewbyinstantiatingviewstheListViewwilldisplay.Letshavealookatthearrayadapterused
above:
publicclassPredictionArrayAdapterextendsArrayAdapter<Prediction>{
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);
}
@Override
publicViewgetView(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,similarto
iOS.ReusingviewsarejustasimportantasoniOS,andthissubstantiallyhelpsperformance!Thisadapterisrathersimple,becauseitusesabuiltinsuperclass,ArrayAdapter<T>,foradapters
workingwitharraydata,butitillustrateshowtopopulateaListViewfromadataset.

AsyncTasks
InplaceofGrandCentralDispatchoniOS,onAndroidwehaveaccesstoAsyncTasks.AsyncTasksisadifferenttakeonexposingasynchronoustoolsinamorefriendlyway.AsyncTasksisabitout
ofscopeforthisarticle,butIhighlyrecommendlookingoversomeofthedocumentation.

ActivityLifecycle
OneoftheprimarythingstowatchoutforcomingfromiOSdevelopmentistheAndroidlifecycle.LetsstartbylookingattheActivityLifecycleDocumentation:

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

5/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

Inessence,theactivitylifecycleisverysimilartotheUIViewControllerlifecycle.TheprimarydifferenceisthattheAndroidOScanberuthlesswithdestroyingactivities,anditisveryimportant
tomakesurethatthedataandthestateoftheactivityaresaved,sothattheycanberestoredfromthesavedstateiftheyexistintheonCreate().Thebestwaytodothisisbyusingbundleddata
andrestoringfromthesavedInstanceStateand/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;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
mLineType=TripList.LineType.getLineType(getIntent().getStringExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE));
}

Anoteonrotation:thelifecyclecompletelyresetstheviewonrotation.Thatis,youractivitywillbedestroyedandrecreatedwhenarotationoccurs.Ifdataisproperlysavedinthesavedinstance
stateandtheactivityrestoresthestatecorrectlyafteritscreation,thentherotationwillworkseamlessly.Manyappdevelopershaveissueswithappstabilitywhentheapprotates,becausean
activitydoesnothandlestatechangesproperly.Beware!Donotlockyourappsrotationtosolvetheseissues,asthisonlyhidesthelifecyclebugsthatwillstilloccuratanotherpointintimewhen
theactivityisdestroyedbytheOS.

FragmentLifecycle
TheFragmentLifecycleissimilartotheactivitylifecycle,withafewadditions.

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

6/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

Oneoftheproblemsthatcancatchdevelopersoffguardisregardingissuescommunicatingbetweenfragmentsandactivities.NotethattheonAttach()happensbeforeonActivityCreated().This
meansthattheactivityisnotguaranteedtoexistbeforethefragmentiscreated.TheonActivityCreated()methodshouldbeusedwhenyousetinterfaces(delegates)totheparentactivity,if
needed.
Fragmentsarealsocreatedanddestroyedaggressivelybytheneedsoftheoperatingsystem,andtokeeptheirstate,requirethesameamountofdiligenceasactivities.Hereisanexamplefromour
sampleproject,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);
}
}
@Override
publicvoidonCreate(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,andthatthecustomsetterfortheTripListmodelobjectaddstheobjecttothebundledargumentsas
well.Thisensuresthatifthefragmentisdestroyedandrecreated,suchaswhenthedeviceisrotated,thefragmentalwayshasthelatestdatatorestorefrom.

Layouts
SimilartootherpartsofAndroiddevelopment,thereareprosandconstospecifyinglayoutsinAndroidversusiOS.LayoutsarestoredashumanreadableXMLfilesintheres/layoutsfolder.

SubwayListViewLayout

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

7/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

<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.example.androidforios.app.activities.MainActivity$PlaceholderFragment">
<ListView
android:id="@+id/fragment_subway_list_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/Button.Default.Height"/>
<Button
android:id="@+id/fragment_subway_list_Button"
android:layout_width="match_parent"
android:layout_height="@dimen/Button.Default.Height"
android:minHeight="@dimen/Button.Default.Height"
android:background="@drawable/button_red_selector"
android:text="@string/hello_world"
android:textColor="@color/Button.Text"
android:layout_alignParentBottom="true"
android:gravity="center"/>
</RelativeLayout>

HereisthesameviewoniOSwithaUITableViewandaUIButtonpinnedtothebottomviaAutoLayoutinInterfaceBuilder:

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

8/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

YoullnoticethattheAndroidlayoutfileismucheasiertoreadandunderstandwhatisgoingon.TherearemanypartstolayingoutviewsinAndroid,butwellcoverjustafewoftheimportant
ones.
TheprimarystructurethatyouwilldealwithwillbesubclassesofViewGroupRelativeLayout,LinearLayout,andFrameLayoutarethemostcommon.TheseViewGroupscontainotherviews
andexposepropertiestoarrangethemonscreen.
AgoodexampleistheuseofaRelativeLayoutabove.Arelativelayoutallowsustouseandroid:layout_alignParentBottom="true"inourlayoutabovetopinthebuttontothebottom.
Lastly,tolinklayoutstofragmentsoractivities,simplyusethatlayoutsresourceIDduringtheonCreateView:
@Override
publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){
returninflater.inflate(R.layout.fragment_subway_listview,container,false);
}

LayoutTips
Alwaysworkindp(densityindependentpixels)insteadofpixelsdirectly.
Dontbothernudgingitemsforlayoutsinthevisualeditoroftenthevisualeditorwillputindividualpointsofspacingonobjectsinsteadofadjustingtheheightandwidthasyoumight
like.YourbestbetistoadjusttheXMLdirectly.
Ifyoueverseethefill_parentvalueforalayoutheightorwidth,thisvaluewasdeprecatedyearsagoinAPI8andreplacedwithmatch_parent.
Seethetheresponsiveandroidapplicationsarticleformoretipsonthis.

Data
TheDataStorageOptionsavailableonAndroidarealsoverysimilartowhatisavailableoniOS:
SharedPreferences<>NSUserDefaults
Inmemoryobjects
Savingtoandfetchingfromfilestructureviatheinternalorexternalfilestorage<>savingtothedocumentsdirectory
SQLite<>CoreData
http://www.objc.io/issue11/android_101_for_ios_developers.html

9/10

2/27/2015

Android101foriOSDevelopersAndroidobjc.ioissue#11

TheprimarydifferenceisthelackofCoreData.Instead,AndroidoffersstraightaccesstotheSQLitedatabaseandreturnscursorobjectsforresults.Headovertothearticleinthisissueabout
usingSQLiteonAndroidformoredetails.

AndroidHomework
Whatwevediscussedsofarbarelyscratchesthesurface.ToreallytakeadvantageofsomeofthethingsthatmakeAndroidspecial,Irecommendcheckingoutsomeofthesefeatures:
ActionBar,OverflowMenu,andtheMenuButton
CrossAppDataSharing
RespondtocommonOSactions
TakeadvantageofJavasfeatures:generics,virtualmethodsandclasses,etc.
GoogleCompatibilityLibraries
TheAndroidEmulator:installthex86HAXMplugintomaketheemulatorbutterysmooth.

FinalWords
MuchofwhatwasdiscussedinthisarticleisimplementedintheMBTAsubwaytransitsampleprojectonGitHub.Theprojectwasbuiltasawaytoillustratesimilarconceptssuchasapplication
structure,handlingdata,andbuildingUIonthesameapplicationforbothplatforms.
WhilesomeofthepureimplementationdetailsareverydifferentonAndroid,itisveryeasytobringproblemsolvingskillsandpatternslearnedoniOStobear.Whoknows?Maybe
understandinghowAndroidworksjustalittlebitbettermightprepareyouforthenextversionofiOS.
1. Source
2. SeeGooglesdocumentationforsupportingmultiplescreensizeshere.
3. Intentsdocumentation
4. SeeGooglesdocumentationformultipanetabletviewformoreinformation.
5. Thanks,NSHipster.

Morearticlesinissue#11
Privacypolicy

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

10/10

Вам также может понравиться