Als het gaat om het schrijven van mobiele applicaties, is het belangrijk om te integreren met de platformspecifieke functies die voor u beschikbaar zijn als dat logisch is. Als u bijvoorbeeld een navigatie-app schrijft, is het logisch dat u de geolocatiefuncties van het apparaat en platform gebruikt. Als u een app zou maken om mensen met een visuele beperking te helpen, zou u willen integreren met alle beschikbare tekst-naar-spraak-functies.
Het zijn de ontwikkelaars die profiteren van deze functies die zichzelf en hun apps onderscheiden van de rest. Deze eenvoudige dingen nemen slechts een gewone app en maken het geweldig. Maar wat gebeurt er als u van deze functies wilt profiteren, maar u hebt besloten om Xamarin.Forms als uw platformonafhankelijke voorkeursmechanisme te gebruiken? Moet je de hoop op deze functies opgeven alleen omdat je hebt besloten dat je app platformonafhankelijk moet zijn en je zoveel mogelijk logica en gebruikersinterfacekaarten wilt kunnen delen? Absoluut niet.
Dit soort vragen veroorzaakt onvermijdelijk een aantal problemen voor ontwikkelaars die nieuwere technologieën gebruiken, zoals Xamarin.Forms. Voorafgaand aan de release van Xamarin.Forms, toen je rechtstreeks met Xamarin.iOS, Xamarin.Android en Windows Phone projectsjablonen werkte, was toegang tot dit soort functies vrij eenvoudig. Vanuit het Xamarin-perspectief, als je voorbeeld C # - of zelfs moedertaal en SDK-documentatie - voor een bepaalde functie kon vinden, kon je simpelweg je code toewijzen aan de native concepten, omdat Xamarin zo'n spectaculair werk deed door dezelfde native concepten te vertalen op die platforms in C # taalconstructies. Windows Phone-functies waren nog eenvoudiger omdat er geen vertaling nodig was. Het enige wat je moest doen, was de documentatie lezen.
Gelukkig voor ons als ontwikkelaars heeft Xamarin veel tijd en moeite gestoken in het ontwerpen van een mechanisme voor ons om toegang te krijgen tot dezelfde functies, zelfs als we ervoor kiezen om hun Xamarin.Forms-abstractielaag te gebruiken. Dit mechanisme is bekend als de DependencyService
.
DependencyService
OverzichtOp het eerste gezicht een naam als DependencyService
lijkt misschien een beetje intimiderend. Het klinkt als een of andere mooie programmeerterminologie die alleen de elite niet begrijpt. Als je ooit hebt gewerkt Dependency Injection (DI) of Inversie van controller (IoC) containers, je moet je meteen thuis voelen bij de DependencyService
. Als je dat niet hebt gedaan, kan ik je verzekeren dat het een heel eenvoudig concept is om te begrijpen als je het eenmaal hebt opgedeeld in zijn componenten.
DependencyService
?Op zijn eenvoudigst, DependencyService
is een klasse. Het is een klasse waarvan het enige doel van het bestaan is om jou dat toe te staan registreren een willekeurig aantal klassen in uw hele applicatie. Door te registreren, bedoel ik dat je elke les die je hebt moet nemen en het aan de dienst kenbaar moet maken. Zodra de DependencyService
weet van een klasse, het kan gaan en een instantie van die klasse ophalen wanneer dat nodig is. Dat is het andere doel van de DependencyService
. Als u op enig moment in uw toepassing besluit dat u een instantie van een klasse nodig hebt die is geregistreerd in de DependencyService
, u kunt er een exemplaar van aanvragen of er een exemplaar van opvragen.
Wanneer je echt in de moeren en bouten van de DependencyService
, dit is een zeer brede generalisatie. Maar vanuit het oogpunt van een ontwikkelaar is dat bijna alles wat je moet weten. Er is echter een ander concept waar u zich bewust van moet zijn bij het werken met de DependencyService
, interfaces. Als het gaat om de DependencyService
en al dit registreren en ophalen, dat doe je meestal met betrekking tot interfaces. Dit betekent dat wanneer u een klasse registreert, u deze registreert als een implementatie van een bepaalde interface. En als je een klas ophaalt, vraag je dat eigenlijk DependencyService
voor een implementatie van die interface. Op dit punt maakt het u niet zoveel uit wat de implementatie is, u wilt gewoon een klasse die deze interface implementeert.
DependencyService
Werk?Nu je een basisbegrip hebt op een conceptueel niveau van wat de DependencyService
is, laten we een beetje dieper graven en zien hoe het echt werkt.
Om de te gebruiken DependencyService
, je hebt drie dingen nodig:
DependencyService
weet dat een bepaalde klas wenst te worden geregistreerd en later kan worden opgehaald.DependencyService
, en vraag wat functionaliteit, een klasse, zonder direct een nieuw exemplaar te instantiëren.Laten we elk van deze concepten in meer detail bekijken.
Interfaces komen tegenwoordig veel voor in de meeste talen van Object Oriented Programming (OOP). Met behulp van een interface kunt u een contract definiëren dat een reeks eigenschappen, methoden, gebeurtenissen, enz. Bevat, die moeten worden geïmplementeerd door elke klasse die instemt met dat contract.
Hier is een heel eenvoudig voorbeeld van een interface en een klasse die die interface implementeert.
openbare interface IFileGrabber string GetFileContents (string fileUri); public SimpleGrabber: IFileGrabber openbare string GetFileContents (string fileUri) retourneer GetFileFromFileSystem (fileUri);
Dit lijkt een heel eenvoudig voorbeeld, maar het dient heel goed het doel. De IFileGrabber
interface definieert een enkele methode, GetFileContents
. De SimpleGrabber
klasse stemt in met of implementeert het IFileGrabber
interface, wat betekent dat het een implementatie voor de ene methode moet bevatten.
Nu, in plaats van dat u andere code in uw toepassing rechtstreeks tegen een concrete klasse moet implementeren, SimpleGrabber
, je kunt beginnen met de verwijzing naar IFileGrabber
interface in plaats daarvan. Stel je voor dat je een andere klasse in je applicatie hebt die er zo uitziet:
public class DataRetriever private IFileGrabber _fileGrabber; openbare DataRetriever (IFileGrabber-bestandGrabber) _fileGrabber = fileGrabber openbare tekenreeks GetFileContents (string fileUri) return _fileGrabber.GetFileContents (fileUri);
Door de IFileGrabber
interface in plaats van een concrete klasse, heb je de mogelijkheid om andere mechanismen te creëren om bestanden op verschillende plaatsen op te halen en de DataRetriever
klasse zou het niet erg vinden. Laten we aannemen dat we een andere klasse hebben die er zo uitziet:
public class NetworkGrabber: IFileGrabber openbare string GetFileContents (string fileUri) retourneer GetFileFromNetwork (fileUri);
Je geeft er nu minder om hoe de klas of de GetFileContents
methode is geïmplementeerd, u weet gewoon dat ten minste de leden die in de interface zijn gedefinieerd aanwezig zijn en dat betekent dat u kunt blijven coderen met alleen die interface als referentie. Dit is een ongelooflijk belangrijk concept als het gaat om de DependencyService
.
In de context van de DependencyService
, Xamarin heeft het registreren van een klasse vrij eenvoudig gemaakt. Omdat u uw interface al hebt gedefinieerd en er ten minste één klasse is die deze implementeert, kunt u deze registreren in de DependencyService
met behulp van een zeer eenvoudig verzamelattribuut.
Laten we het bovenstaande voorbeeld blijven gebruiken en de SimpleGrabber
klasse. De klassendefinitie ziet er nu ongeveer zo uit:
[assembly: Xamarin.Forms.Dependency (typeof (SimpleFileGrabber))] // Elke naamruimtedeclaratie die kan bestaan public SimpleGrabber: IFileGrabber openbare string GetFileContents (string fileUri) retourneer GetFileFromFileSystem (fileUri);
Het enige wat u hoeft te doen is de assembly-referentie toe te voegen boven uw klassedefinitie en buiten elke naamruimtedefinitie die ook in dat bestand kan voorkomen. Door deze eenvoudige taak te doen, zult u de. Succesvol hebben geregistreerd SimpleGrabber
klasse als een implementatie van de IFileGrabber
interface.
Wanneer u een klasse registreert, moet die klasse een parameterloze constructor bevatten voor de DependencyService
om het te instantiëren. In mijn voorbeeld hierboven heb ik geen constructor gedefinieerd, dus de compiler creëert standaard een parameterloze constructor voor mij.
Het laatste stukje van de puzzel krijgt een exemplaar van een geregistreerde klasse. Dit is eigenlijk het gemakkelijkste deel van het hele proces. Om een instantie van een geregistreerde klasse op te halen, gebruikt u eenvoudig de DependencyService
klasse en het is generiek Get <> ()
methode. Hier is een eenvoudig voorbeeld:
public class FileHelper openbare string GetFileContents (string fileUri) return DependencyService.Get() .GetFileContents (fileUri);
In dit geval maakt het u tijdens runtime niet uit waar het DependencyService
krijgt de concrete klasse die de IFileGrabber
interface. Het enige waar je om geeft, is dat de klas de. Implementeert IFileGrabber
interface.
DependencyService
Nu dat je een conceptueel begrip hebt van wat de DependencyService
is en hoe het te gebruiken, laten we een eenvoudige applicatie maken om het te gebruiken.
Voor dit voorbeeld zal ik Xamarin Studio 5 gebruiken, maar voel je vrij om Visual Studio 2013 te gebruiken als je dat wilt. Begin met het maken van een nieuwe oplossing. In de Nieuwe oplossing dialoogvenster, onder de C # categorie aan de linkerkant, selecteer de Mobiele apps project familie. Selecteer aan de rechterkant de Lege app (Xamarin.Forms Portable) of de Lege app (Xamarin.Forms gedeeld) projectsjabloon. De code en de resulterende toepassing zijn hetzelfde, ongeacht de sjabloon die u kiest.
In dit voorbeeld zal ik de gebruiken Portable Class Library (PCL) -versie van de sjabloon. Geef een naam aan het project. Ik zal de oplossing en het eerste project een naam geven DependencyServiceSample. Klik vervolgens op de OK knop.
Dit proces zal drie afzonderlijke projecten creëren:
Xamarin Studio biedt geen ondersteuning voor het maken van Windows Phone-projecten. Als u Visual Studio gebruikt, maakt dit proces vier projecten. Hiermee worden de bovengenoemde drie projecten gemaakt, evenals een Windows Phone-project met de naam DependencyServiceSample.WinPhone.
In de gedeelde bibliotheek (DependencyServiceSample), maak een nieuw interfacebestand aan en geef het een naam ISampleInterface en geef het de volgende implementatie:
naamruimte DependencyServiceSample public interface ISampleInterface string GetData ();
Het is een standaardinterfacebestand dat een eenvoudige methode met de naam definieert Gegevens verkrijgen
dat zal terugkeren a draad
. Nogmaals, het belangrijke punt om te begrijpen is dat vanuit het perspectief van het gedeelde codebestand het niet uitmaakt hoe de implementatie van deze interface eruit ziet. Het enige dat telt, is dat welke implementatie dan ook wordt geboden voor deze interface, het heeft een methode genaamd Gegevens verkrijgen
dat zal terugkeren a draad
.
Vervolgens wijzigen we de App.cs bestand om de te gebruiken DependencyService
om een instantie van de te krijgen ISampleInterface
te gebruiken in uw Xamarin.Forms-app. Wijzig de GetMainPage
methode om er als volgt uit te zien:
public static Pagina GetMainPage () retourneer nieuwe ContentPage Content = new Label Text = DependencyService.Get() .GetData (), VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand,,;
Merk op dat het enige verschil is dat de Tekst
eigendom van de Label
is gewijzigd in de volgende regel:
DependencyService.Get().Gegevens verkrijgen()
Op deze manier gebruikt u de DependencyService
klasse en de generieke Get <> ()
methode om elke implementatie van de ISampleInterface
wordt geïmplementeerd in het platformspecifieke project dat momenteel wordt uitgevoerd. Zodra die instantie is opgehaald, belt u de Gegevens verkrijgen
methode om een string terug te krijgen en de Tekst
eigendom van de Label
.
De laatste stap bestaat uit twee delen (drie als u Visual Studio gebruikt). Op dit punt moet u het ISampleInterface
interface in alle platformspecifieke projecten in uw oplossing.
Laten we beginnen in de DependencyServiceSample.Android toepassing. Het enige wat u hoeft te doen is een nieuw klassebestand in het project aan te maken en het elke gewenste naam te geven. Ik heb de mijne genoemd Sample_Android. Vervang de standaardimplementatie door het volgende:
systeem gebruiken; gebruik van DependencyServiceSample.Android; [assembly: Xamarin.Forms.Dependency (typeof (Sample_Android))] namespace DependencyServiceSample.Android public class Sample_Android: ISampleInterface #region ISampleInterface implementatie public string GetData () ga terug "Ik kwam uit het Android-project!"; #endregion
Dit is een eenvoudige klasse die de. Implementeert ISampleInterface
interface en de implementatie ervan is eenvoudigweg een draad
waarin staat dat het afkomstig is van het Android-project. Het enige verschil is het gebruik van de bijeenkomst
attribuut bovenaan dat bestand registers deze klasse met de DependencyService
zodat het later kan worden opgehaald.
Laten we nu een andere implementatie van deze interface in het iOS-project maken. Maak een nieuwe klasse in het iOS-project, noem het Sample_iOS, en vervang de standaardimplementatie door het volgende:
systeem gebruiken; gebruik van DependencyServiceSample.iOS; [assembly: Xamarin.Forms.Dependency (typeof (Sample_iOS))] namespace DependencyServiceSample.iOS public class Sample_iOS: ISampleInterface #region ISampleInterface implementatie public string GetData () ga terug "Ik kwam uit het iOS-project!"; #endregion
De implementatie is precies hetzelfde als de Android-versie, behalve dat deze een andere tekenreeks retourneert die aangeeft dat deze deze keer afkomstig is van het iOS-project. De laatste stap is om de applicatie uit te voeren en te zien of u het resultaat krijgt dat u verwacht.
Dit is het resultaat van het draaien van de iOS-applicatie.
Dit is het resultaat van het draaien van de Android-applicatie.
Zoals u kunt zien, zijn beide applicaties succesvol. Niet alleen worden ze uitgevoerd, maar ze kunnen ook worden uitgevoerd vanuit een gedeeld Xamarin.Forms-project dat de gebruikersinterface bestuurt. Vanuit die gebruikersinterfacekode binnen Xamarin.Forms, kun je nu rechtstreeks in de platformspecifieke projecten duiken om toegang te krijgen tot native code.
Nu je de vaardigheden hebt om het te gebruiken DependencyService
om toegang te krijgen tot native functionaliteit van Xamarin.Forms is the sky's the limit. U kunt doorgaan met het schrijven van eenvoudige implementaties zoals u in deze zelfstudie hebt gedaan, of u kunt profiteren van interessantere functies van de platforms.
Een van de meest interessante bronnen om te bekijken voor integratie in uw DependencyService
is het gedeelte Recepten van de Xamarin-website. Hier vindt u platformspecifieke implementaties van toegang krijgen tot een aantal functies, waaronder:
Al deze functies staan tot uw beschikking als het gaat om Xamarin.Forms-toepassingen. Met de DependencyService
, deze functies kunnen binnen een oogwenk worden opgeroepen.
Nu dat u het kent en begrijpt DependencyService
, u hoeft zich niet langer geïntimideerd te voelen wanneer u toegang moet hebben tot platformspecifieke functies van een Xamarin.Forms-toepassing. U beschikt nu over de hulpprogramma's waarmee u kunt profiteren van de geweldige native functies van de apparaten waarmee u uw apps kunt onderscheiden van de rest in de app stores..
Als je meer wilt weten over Xamarin, bekijk dan onze cursus Bouwen met meerdere platform-apps met C # in Xamarin.
In de cursus leert u hoe u een platformonafhankelijke toepassing kunt maken op basis van één code die op drie duidelijk verschillende platforms wordt uitgevoerd: iOS, Android en Windows Phone 8. Denkt u dat dit niet mogelijk is? Binnen een korte tijd zul je het zelf doen. Laten we aan de slag gaan.
Je kunt het meteen nemen met een helemaal gratis 14 dagen proef van een Tuts + abonnement. Bekijk onze abonnementsopties om aan de slag te gaan of, als u alleen geïnteresseerd bent in deze cursus, kunt u deze afzonderlijk kopen voor $ 15! Hier is een voorbeeld om mee te beginnen: