Lär dig Java för Android Development Reflektion Basics

I denna handledning kommer du att bli bekant med konceptet Java reflektion: en klass eller ett objekt förmåga att granska detaljer om sin egen implementering programmässigt.

Android-applikationer skrivs i Java, ett programmeringsspråk som stöder reflektion - ett objekts förmåga att undersöka sig själv. I denna handledning läser du grunderna i Java-reflektion, bland annat hur man inspekterar metoder och fält i en given klass, kontrollerar tillgängligheten av specifika metoder och andra praktiska uppgifter som du kan behöva använda när du utvecklar för olika versioner av Android SDK.

Vad du behöver

Tekniskt behöver du inga verktyg för att slutföra denna handledning, men du kommer säkert att behöva dem för att utveckla Android-applikationer.

För att utveckla Android-applikationer (eller Java-program, för den delen) behöver du en utvecklingsmiljö för att skriva och bygga applikationer. Eclipse är en mycket populär utvecklingsmiljö (IDE) för Java och den föredragna IDE för Android utveckling. Det är fritt tillgängligt för Windows, Mac och Linux operativsystem.

För fullständiga instruktioner om hur du installerar Eclipse (inklusive vilka versioner som stöds) och Android SDK, se webbplatsen för Android-utvecklaren.

Varför använd Reflektion?

Reflektion ger utvecklare flexibiliteten att inspektera och bestämma API-egenskaper vid körning, istället för att kompilera tiden. Inom säkerhetsbegränsningarna som ålagts av Java (t.ex. användning av offentliga, skyddade, privata) kan du sedan konstruera objekt, åtkomstfält och aktivera metoder dynamiskt. Java-reflektions API är tillgängliga som en del av paketet java.lang.reflect, som ingår i Android SDK för utvecklare att använda.

Så vad har detta att göra med Android utveckling? Tja, med varje ny version av Android SDK läggs klasser, gränssnitt, metoder etc. till, uppdateras och (mindre ofta) tas bort. Men Android-utvecklare vill ofta rikta in sig på enheter som kör olika versioner av Android med ett enkelt applikationspaket. För att göra det kan Android-utvecklare använda reflektionstekniker för att bestämma, vid körning, om en specifik klass eller metod är tillgänglig innan du försöker använda den. Detta gör det möjligt för utvecklaren att utnyttja nya API-er, där de är tillgängliga samtidigt som de stöder de äldre enheterna, allt i samma applikation.

Inspektera klasser

Java klasser representeras vid körning med klassen Klass (java.lang.Class). Denna klass ger utgångspunkten för alla reflektions API. Inom den här klassen hittar du många metoder för inspektion av olika aspekter av en klass, som fält, konstruktörer, metoder, behörigheter och mer. Du kan också använda klassmetoden som heter forName () för att ladda en icke-primitiv klass (t ex inte int men heltal) med namnet dynamiskt vid körning, istället för att kompilera tiden:

 String sClassName = "android.app.NotificationManager"; försök Klass classToInvestigate = Class.forName (sClassName); // Dynamiskt göra saker med den här klassen // Lista konstruktörer, fält, metoder etc. fångst (ClassNotFoundException e) // Klass ej hittad!  fångst (Undantag e) // Okänt undantag 

Klassen (i detta fall NotificationManager) behöver inte ha motsvarande importdeklaration i din kod; du sammanställer inte i denna klass i din ansökan. Istället laddar klasslasteraren klassen dynamiskt vid körning, om möjligt. Du kan sedan inspektera det här klassobjektet och använda de reflexionstekniker som beskrivs i resten av denna handledning.

Inspektera konstruktörerna som är tillgängliga inom en klass

Du kan inspektera konstruktörer som är tillgängliga inom en given klass. För att få bara de konstruktörer som är offentliga tillgängliga, använd getConstructors (). Men om du vill inspektera de metoder som specifikt deklarerats i klassen, oavsett om de är offentliga eller inte, använder du getDeclaredConstructors () istället. Båda metoderna returnerar en rad Constructor-objekt (java.lang.reflect.Constructor).

Till exempel följer följande kod genom de deklarerade konstruktörerna i en klass:

 Constructor [] aClassConstructors = classToInvestigate.getDeclaredConstructors (); för (Constructor c: aClassConstructors) // Hittade en konstruktör c 

När du har ett giltigt Constructor-objekt kan du inspektera parametrarna och till och med förklara en ny instans av klassen med den här konstruktorn med metoden newInstance ().

Inspektera de fält som finns inom en klass

Du kan inspektera de fält (eller attribut) som är tillgängliga inom en given klass. För att få bara de metoder som är tillgängliga för allmänheten, inklusive ärvda fält, använd getFields (). Om du vill inspektera de fält som specifikt deklarerats i klassen (men inte ärftliga), om de är offentliga eller inte, använder du getDeclaredFields () istället. Båda metoderna returnerar en rad fält (java.lang.reflect.Field) objekt.

Till exempel följande text kodas genom de deklarerade fälten i en klass:

 Fält [] aClassFields = classToInvestigate.getDeclaredFields (); för (Fält f: aClassFields) // Hittade ett fält f 

Du kan också söka efter ett specifikt offentligt fält med namn med getField () -metoden. Om du till exempel söker efter EXTRA_CHANGED_PACKAGE_LIST-fältet i Intent-klassen (som lagts till i API-nivå 8 eller Android 2.2) kan du använda:

 String sClassName = "android.content.Intent"; försök Klass classToInvestigate = Class.forName (sClassName); String strNewFieldName = "EXTRA_CHANGED_PACKAGE_LIST"; Fält newIn22 = classToInvestigate.getField (strNewFieldName);  Fånga (ClassNotFoundException e) // Klass inte hittad fångst (NoSuchFieldException e) // Fältet existerar inte, troligen är vi på Android 2.1 eller äldre // tillhandahålla alternativ funktionalitet för att stödja äldre enheter fånga (SecurityException e)  // Tillträde beviljas ej!  fångst (Undantag e) // Okänt undantag 

När du har ett giltigt fältobjekt kan du få namnet med metGenicString (). Om du har lämpliga behörigheter kan du också få tillgång till värdet för det klassfältet med hjälp av lämpliga get () och set () metoder.

Inspektera de metoder som finns inom en klass

Du kan inspektera tillgängliga metoder inom en given klass. För att få bara de metoder som är tillgängliga för allmänheten, inklusive arvade metoder, använd getMethods (). Om du vill inspektera de metoder som specifikt deklarerats i klassen (utan ärftliga), om de är offentliga eller inte, använd istället GetDeclaredMethods (). Båda metoderna returnerar en rad Metod (java.lang.reflect.Method) -objekt.

Till exempel följer följande kod genom de deklarerade metoderna i en klass:

 Metod [] aClassMethods = classToInvestigate.getDeclaredMethods (); för (Metod m: aClassMethods) // Hittade en metod m 

När du har ett giltigt Metod-objekt kan du få namnet med metGenicString () -metoden. Du kan också undersöka parametrarna som används av metoden och de undantag som den kan kasta. Slutligen, om du har rätt behörigheter, kan du också ringa metoden med metoden invoke ().

Inspektera inre klasser

Du kan inspektera de inre klasserna definierade inom en klass med getDeclaredClasses () -metoden. Den här metoden kommer att returnera en rad klasser (java.lang.class) -objekt som deklarerats i moderklassen. Dessa klasser kan då inspekteras som alla andra.

Inspecting Member Modifiers

Du kan också inspektera flaggor och säkerhetsinställningar, som kallas modifierare, associerade med en given klass, fält eller metod med metoden getModifiers (). Intressanta modifierare inkluderar om komponenten är offentlig, privat, skyddad, abstrakt, slutlig eller statisk (bland annat).

Till exempel kontrollerar följande kod säkerhetsmodifierare för en klass:

 int behörigheter = classToInvestigate.getModifiers (); om (Modifier.isPublic (behörigheter)) // Klass är Public om (Modifier.isProtected (behörigheter)) // Klass är skyddad om (Modifier.isPrivate (behörigheter)) // Klassen är Privat 

Tänk på att du inte dynamiskt kan komma åt eller anropa någon klass, metod eller fält med reflektion som du normalt inte skulle kunna komma åt vid kompileringstid. Med andra ord tillämpas stadigvarande säkerhet i säkerhet vid körning.

Inspecting Class Metadata

Du kan också inspektera metadata-anropade anteckningar som är associerade med en given klass, ett fält eller en metod med metoden getAnnotations (). Intressanta metadata i samband med en klass kan innehålla information om avskrivning, varningar och överstyrningar bland annat.

Till exempel kontrollerar följande kod de metadata som är tillgängliga för klassen AbsoluteLayout. Eftersom den här klassen avlägsnades i Android 1.5, är en av de angivna noterna @ java.lang.Deprecated () när den här koden körs på Android 2.2:

 String sClassName = "android.widget.AbsoluteLayout"; försök Klass classToInvestigate = Class.forName (sClassName); Anteckning [] aAnnotations = classToInvestigate.getDeclaredAnnotations (); för (Anteckning a: aAnnotationer) // Hittade en anteckning, använd a.toString () för att skriva ut det fånga (ClassNotFoundException e) // Klass ej hittad!  fångst (Undantag e) // Hantera okänt undantag!  

På samma sätt kan du helt enkelt leta efter förekomsten av en särskild anteckning, t.ex. avskrivning, av dess typ:

 om (classToInvestigate.isAnnotationPresent (java.lang.Deprecated.class) == true) // klassen är avvecklad!  

Reflektion: Praktisk för debugging

Du kan också använda reflektion för att hjälpa till med felsökning. Du kanske till exempel vill använda klass sökord för att få tillgång till underliggande klassdata för en given typ:

 importera android.app.Activity; ... String strClassName = Activity.class.getName (); // android.app.Activity 

Du kan också få klassinformation från en variabel instans med hjälp av metoden getClass () i Objeklassen (som därför ärvs av alla klasser i Java):

 String dumt = "Silly String!"; Klass someKindOfClass = dumt.getClass (); String strSillyClassName = someKindOfClass.getName (); // java.lang.String 

Om du vill kontrollera klassen av en variabel är det lämpligare att använda instanceof. Se förhandsgranskningen av exemplet för mer information.

På samma sätt kan du använda metoden getClass () med det här sökordet för att kontrollera namnet på den klass du befinner dig i och inkludera den här informationen som en del av din debug-loggning på LogCat:

 String strCurrentClass = this.getClass (). GetName (); // t.ex. den aktuella aktivitetsloggen.v (strCurrentClass, "Debug tagg är nuvarande klass."); 

Varför inte använda reflektion

Som du har sett kan reflektion användas till stor effekt, speciellt när du är osäker på om en specifik klass eller metod är tillgänglig vid sammanställningstiden. Reflektion har emellertid vissa nackdelar, inklusive minskad prestanda och förlusten av de starka skrivnings- och säkra kodningspraxis som verkställs vid sammanställningstiden. Det är bäst att använda reflektion sparsamt, men använd det när det behövs.

Avslutar

Reflektion är ett kraftfullt verktyg som Java-utvecklare kan använda för att utforska paket och API-programmatiskt vid körning. Medan reflektionsverksamheten kommer till en kostnad, ger de utvecklaren den flexibilitet som ibland är nödvändig för att få jobbet gjort. Android-utvecklare använder ofta dessa enkla reflektionstekniker för att testa för tillgången till specifika klasser, gränssnitt, metoder och fält vid körning, så att de kan stödja olika versioner.

Om Författarna

Mobila utvecklare Lauren Darcey och Shane Conder har medverkat flera böcker om Android-utveckling: en fördjupad programmeringsbok med titeln Android Wireless Application Development och Sams TeachYourself Android Application Development inom 24 timmar. När de inte skriver, spenderar de sin tid på att utveckla mobil mjukvara hos sina företag och tillhandahålla konsulttjänster. De kan nås via e-post till [email protected], via deras blogg på androidbook.blogspot.com, och på Twitter @ androidwireless.

Behöver du hjälp med att skriva Android Apps? Kolla in våra senaste böcker och resurser!