2015-09-15 7 views
10

Gegeben eine absolute Uri und eine relative Uri oder relativen Pfad, wie erhalten Sie die absolute Uri zeigt auf die relative Position?Wie lösen Sie einen relativen Uri auf?

Nehmen wir zum Beispiel an, wir haben die Uri für , zeigt auf einen Speicherort in unseren Vermögenswerten. Nehmen wir weiterhin an, dass wir anderswo einen relativen Pfad von /foo haben. Der absolute Uri für diesen relativen Pfad sollte file:///android_asset/foo lauten. Gibt es etwas unter Uri oder anderswo im Android SDK, das ich vermisse, das mir das Ergebnis Uri gibt?

Uri.withAppendedPath() nicht die Antwort ist, wie alle es ist handHinterVerzeichnisTrenn zu tun scheint:

Uri abs=Uri.parse("file:///android_asset/"); 
Uri rel=Uri.withAppendedPath(abs, "/foo"); 
Assert.assertEquals("file:///android_asset/foo", rel.toString()); 
    // actually returns file:///android_asset//foo 

Uri abs2=Uri.parse("file:///android_asset/dir"); 
Uri rel2=Uri.withAppendedPath(abs2, "/foo"); 
Assert.assertEquals("file:///android_asset/foo", rel2.toString()); 
    // actually returns file:///android_asset/dir//foo 

Uri.Builder über buildUpon() auf Uri, ist keine Verbesserung:

Uri rel3=abs.buildUpon().appendPath("/foo").build(); 
Assert.assertEquals("file:///android_asset/foo", rel3.toString()); 
    // actually returns file:///android_asset/%2Ffoo 

Uri rel4=abs.buildUpon().appendEncodedPath("/foo").build(); 
Assert.assertEquals("file:///android_asset/foo", rel4.toString()); 
// actually returns file:///android_asset//foo 

In einem Prise Ich kann java.net.URL und seine URL(URL context, String spec) Konstruktor versuchen, oder nur etwas Code für sie rollen, aber ich hatte gehofft, im Reich von Androidzu bleibenWerte wenn möglich, nur für alle Macken zu unterscheiden URL und Uri.

+0

keine Notwendigkeit, Schrägstrich für appendPath hinzufügen - es tut es für Sie. Ich habe meine Methode getBaseUriBuilder, um Uri.Builder mit schema + root zu erhalten. Alles, was Sie brauchen, ist Pfad- und Abfrageparameter ... –

+0

"Also alles, was Sie brauchen, ist Pfad anhängen" - es gibt viele mögliche relative Pfadstrukturen. '/ foo' ist nur eins. Es gibt auch 'foo','./Foo', '../ foo',' ../../ foo/bar' und so weiter. Viele benutzen einen Teil des Pfades des absoluten 'Uri', andere (z.B.'/foo') nicht. Ich versuche, wenn möglich alle Situationen zu bewältigen. – CommonsWare

+0

siehe File construtors: 'File (Datei dir, String name)' und/oder 'File (String dirPath, String name)' und 'File # getCanonicalPath()' – pskink

Antwort

4

Android macht das nicht einfach.

In meinem Fall hatte ich url eine Basis zu nehmen, die einen eingeschlossenen Pfad nicht haben kann oder auch:

http://www.myurl.com/myapi/

... und eine REST-API-Methode Pfad anhängen, wie:

api/where/agencies-with-coverage.json

... die gesamte uRL zu produzieren:

http://www.myurl.com/myapi/api/where/agencies-with-coverage.json

Hier ist, wie ich es getan hätte (aus verschiedenen Methoden innerhalb der App zusammengestellt - es kann ein einfacher Weg, dies zu tun):

String baseUrlString = "http://www.myurl.com/myapi/"; 
String pathString = "api/where/agencies-with-coverage.json"; 
Uri.Builder builder = new Uri.Builder(); 
builder.path(pathString); 

Uri baseUrl = Uri.parse(baseUrlString); 

// Copy partial path (if one exists) from the base URL 
Uri.Builder path = new Uri.Builder(); 
path.encodedPath(baseUrl.getEncodedPath()); 

// Then, tack on the rest of the REST API method path 
path.appendEncodedPath(builder.build().getPath()); 

// Finally, overwrite builder with the full URL 
builder.scheme(baseUrl.getScheme()); 
builder.encodedAuthority(baseUrl.getEncodedAuthority()); 
builder.encodedPath(path.build().getEncodedPath()); 

// Final Uri 
Uri finalUri = builder.build(); 

In meinem Fall die Builder-Klassen für den API-Client-Code zusammengesetzt die path vor der Kombination mit der baseURL, so dass die Reihenfolge der Dinge oben erklärt.

Wenn ich den obigen Code richtig zusammengezogen habe, sollte es Portnummern sowie Leerzeichen in der URL-Zeichenfolge behandeln.

Ich zog diesen Quellcode aus der OneBusAway Android app, speziell die ObaContext class. Beachten Sie, dass dieser Code auf Github auch den zusätzlichen Fall behandelt, in dem der Benutzer baseUrl (String serverName = Application.get().getCustomApiUrl() im obigen Code) eingab, der die Regionsbasis-URL (mRegion.getObaBaseUrl()) überschreiben sollte und die vom Benutzer eingegebene URL möglicherweise nicht http:// davor hat .

Die Komponententests, die auf Github für den obigen Code übergeben, einschließlich der Fälle, in denen Portnummern und Zwischenräume in der baseUrl und path enthalten sind, und das vordere/hintere / sind here on Github werden kann oder auch nicht enthalten. Verwandte Themen auf Github, wo ich meinen Kopf an die Wand schlug, um zu versuchen, alles zur Arbeit zu bekommen - 72, 126, 132.

Ich habe dies nicht mit Nicht-HTTP-URIs versucht, aber ich glaube, es kann allgemeiner funktionieren.

+0

Whoops, hatte einen Tippfehler im Anfangscode, jetzt behoben. –

+0

Und, ein weiterer Tippfehler behoben. –

+0

Technisch beantwortet dies die Frage nicht. Was du beschreibst, ist das, was ich "nur einen Code dafür" in der Frage genannt habe. Aus diesen und den Kommentaren schließe ich, dass es keine einfache In-SDK-Lösung gibt, die ich vermisst habe. Also, ich werde dir das Kopfgeld gewähren. Danke für die Hilfe! – CommonsWare

Verwandte Themen