Как вы разрешаете родственника Ури?

Учитывая абсолютный Uri и относительный Uri или относительный путь, как вы получаете абсолютное Uri, указывающее на относительное местоположение?

Например, предположим, что мы имеем Uri для file:///android_asset/dir, указывая на местоположение в наших активах. Предположим далее, что в другом месте мы имеем относительный путь /foo. Абсолютный Uri для этого относительного пути должен быть file:///android_asset/foo. Есть ли что-то на Uri или в другом месте Android SDK, которое мне не хватает, что дает мне этот результат Uri?

Uri.withAppendedPath() не является ответом, поскольку все, что ему кажется, это обработать трейлинг-сепараторы каталога:

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, через buildUpon() на Uri, не является улучшением:

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

В крайнем случае я могу попробовать использовать java.net.URL и его конструктор URL(URL context, String spec), или просто отбросить код для него, но я надеялся остаться в области значений Android Uri, если это возможно, только для любых причуд дифференцируя URL и Uri.

Ответ 1

Android не делает это легко.

В моем случае мне пришлось взять базовый URL-адрес, который может содержать или не включать путь:

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

... и добавьте путь метода API REST, например:

api/where/agencies-with-coverage.json

... для создания всего URL:

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

Здесь, как я это сделал (скомпилированный из различных методов в приложении - может быть, более простой способ сделать это):

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

В моем случае классы Builder для кода клиента API собрали path до объединения его с baseURL, так что объясняет порядок вещей выше.

Если я правильно спрятал вышеуказанный код, он должен обрабатывать номера портов, а также пробелы в строке URL.

Я вытащил этот исходный код из приложения OneBusAway для Android, в частности ObaContext класс. Обратите внимание, что этот код в Github также обрабатывает дополнительный случай, когда пользователь вводил baseURL (String serverName = Application.get().getCustomApiUrl() в приведенном выше коде), который должен переопределять базовый URL-адрес региона (mRegion.getObaBaseUrl()), а введенный пользователем URL-адрес не может перед http://.

Единичные тесты, которые передаются для вышеуказанного кода в Github, включая случаи, когда номера портов и пробелы включены в baseURL и path, а верхний/конечный / могут включать или не включать, являются здесь, на Github. Связанные с этим проблемы в Github, где я стучал головой о стену, чтобы попытаться заставить все это работать - 72, 126, 132.

Я не пробовал это с URI без HTTP, но я считаю, что он может работать в более общем плане.