2015-09-15 36 views
10

Biorąc pod uwagę bezwzględną Uri i względną ścieżkę, jak uzyskać wartość bezwzględną Uri wskazującą położenie względne?Jak rozwiązać względne Uri?

Załóżmy na przykład, że mamy Uri dla file:///android_asset/dir, wskazując lokalizację w naszych zasobach. Dalej przypuśćmy, że gdzie indziej mamy względną ścieżkę /foo. Wartość bezwzględna Uri dla tej ścieżki względnej powinna wynosić file:///android_asset/foo. Czy jest coś na Uri lub w innym miejscu w zestawie SDK Androida, którego mi brakuje, aby uzyskać ten wynik: Uri?

Uri.withAppendedPath() nie jest odpowiedzią, jak wszystko wydaje się zrobić to obsługiwać końcowe separatory katalogu:

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 poprzez buildUpon() na Uri, nie jest poprawa:

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 

w A szczypta Mogę spróbować użyć java.net.URL i jego konstruktora URL(URL context, String spec) lub po prostu zrzucić na niego jakiś kod, ale miałem nadzieję pozostać w świecie Androida Uri wartości, jeśli to możliwe, tylko dla wszelkich dziwactw różnicujących URL i Uri.

+0

nie trzeba dodawać slasha dla appendPath - robi to za Ciebie. Mam swoją metodę getBaseUriBuilder, aby uzyskać Uri.Builder ze schematem + root. Więc wszystko, czego potrzebujesz, to dołączanie parametrów ścieżek i zapytań ... –

+0

"Więc wszystko, czego potrzebujesz, to dołączenie ścieżki" - istnieje wiele możliwych względnych struktur ścieżki. '/ foo' jest po prostu jednym. Istnieją również 'foo','./Foo', '../ foo',' ../../ foo/bar', i tak dalej. Wielu użyje części ścieżki absolutnego 'Uri', inni (np.'/Foo') nie będą. Próbuję poradzić sobie w każdej sytuacji, jeśli to możliwe. – CommonsWare

+0

zobacz Konkursy plików: 'Plik (katalog plików, nazwa ciągu)' i/lub 'Plik (String dirPath, Nazwa ciągu)' oraz 'Plik # getCanonicalPath()' – pskink

Odpowiedz

4

Android nie czyni tego łatwym.

W moim przypadku musiałem wziąć bazowy URL, które mogą lub nie mogą mieć włączone ścieżkę:

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

... i dołączyć metodę ścieżki REST API, takich jak:

api/where/agencies-with-coverage.json

... produkować całą URL:

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

Oto jak to zrobiłem (skompilowane z różnych metod w aplikacji - nie może być prostszy sposób to zrobić):

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(); 

W moim przypadku zajęcia Builder dla kodu klienta API złożono path przed połączeniem go z baseURL, co wyjaśnia kolejność powyższych elementów.

Jeśli poprawnie zebrałem powyższy kod, powinien on obsługiwać numery portów oraz spacje w ciągu URL.

Pobrałem ten kod źródłowy z OneBusAway Android app, w szczególności z ObaContext class. Zauważ, że ten kod na Github obsługuje także dodatkowy przypadek, w którym użytkownik wpisał baseUrl (String serverName = Application.get().getCustomApiUrl() w powyższym kodzie), który powinien zastąpić podstawowy adres regionu (mRegion.getObaBaseUrl()), a wprowadzony przez użytkownika adres URL może nie mieć przed sobą http:// .

z testami, które przechodzą przez wyżej kodowi Github, w tym przypadku, gdy numery portów i pomieszczenia są zawarte w baseUrl i path i czołowy/końcowe / mogą lub nie mogą być włączone, są here on Github. Powiązane problemy na Githubie, gdzie waliłem głową w ścianę, aby spróbować i wszystko działało - 72, 126, 132.

Nie próbowałem tego w przypadku identyfikatorów URI innych niż HTTP, ale uważam, że może działać bardziej ogólnie.

+0

Ups, miał literówkę w początkowym kodzie, naprawiono teraz. –

+0

I, naprawiono kolejną literówkę. –

+0

Technicznie nie odpowiada to na pytanie. To, co opisujesz, jest tym, co nazwałem "po prostu zrób trochę kodu" w pytaniu. Z tego i z komentarzy wynika, że ​​nie ma prostego rozwiązania w SDK, które przeoczyłem. Tak więc, dam ci nagrodę. Dzięki za pomoc! – CommonsWare

Powiązane problemy