Use o construtor de URI no Android ou crie URL com variáveis

202

Estou desenvolvendo um aplicativo para Android. Preciso criar um URI para meu aplicativo para fazer uma solicitação de API. A menos que haja outra maneira de colocar uma variável em um URI, essa é a maneira mais fácil que eu encontrei. Descobri que você precisa usar Uri.Builder, mas não sei ao certo como. Meu URL é:

http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=[redacted]&mapid=value 

Meu esquema é http, autoridade é lapi.transitchicago.com, caminho é /api/1.0, segmento (s) de caminho éttarrivals.aspx e seqüência de caracteres de consulta é key=[redacted]&mapid=value.

Meu código está abaixo:

Intent intent = getIntent();
String value = intent.getExtras().getString("value");
Uri.Builder builder = new Uri.Builder();
builder.scheme("http")
    .authority("www.lapi.transitchicago.com")
    .appendPath("api")
    .appendPath("1.0")
    .appendPath("ttarrivals.aspx")
    .appendQueryParameter("key", "[redacted]")
    .appendQueryParameter("mapid", value);

Entendo que posso fazer URI.add, mas como faço para integrá-lo ao Uri.Builder? Devo acrescentar tudo como URI.add(scheme), URI.add(authority)e assim por diante? Ou não é assim que se faz? Além disso, existe outra maneira mais fácil de adicionar uma variável a um URI / URL?

hichris123
fonte

Respostas:

426

Digamos que eu quero criar o seguinte URL:

https://www.myawesomesite.com/turtles/types?type=1&sort=relevance#section-name

Para criar isso com o Uri.Buildereu faria o seguinte.

Uri.Builder builder = new Uri.Builder();
builder.scheme("https")
    .authority("www.myawesomesite.com")
    .appendPath("turtles")
    .appendPath("types")
    .appendQueryParameter("type", "1")
    .appendQueryParameter("sort", "relevance")
    .fragment("section-name");
String myUrl = builder.build().toString();
David
fonte
1
Com o meu segmento de caminho, seria um caminho? Ou seria uma consulta?
precisa saber é o seguinte
Se for um caminho, seria appendPath()para o método Se for uma string de consulta (após o?), Use appendQueryParameter(). Veja o URL que tenho no exemplo e o que estou fazendo com cada segmento. Também adicionei toString()à build()chamada para recuperar o tipo adequado.
David
1
É antes do ponto de interrogação, mas não tem um / depois dele. É ttarrivals.aspx na minha pergunta acima. Então isso seria um caminho?
precisa saber é o seguinte
Corrigir. Acontece que é o fim do caminho. Tecnicamente, você pode colocar um "/" no final, se quiser, e isso seria válido. mysite.com/path é o mesmo que mysite.com/path
David
1
Resposta perfeita! Isso já deveria estar na documentação da API.
Robinmitra
259

Existe outra maneira de usar Urie podemos alcançar o mesmo objetivo

http://api.example.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7

Para construir o Uri, você pode usar isso:

final String FORECAST_BASE_URL = 
    "http://api.example.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";

Você pode declarar tudo isso da maneira acima ou mesmo dentro Uri.parse()eappendQueryParameter()

Uri builtUri = Uri.parse(FORECAST_BASE_URL)
    .buildUpon()
    .appendQueryParameter(QUERY_PARAM, params[0])
    .appendQueryParameter(FORMAT_PARAM, "json")
    .appendQueryParameter(UNITS_PARAM, "metric")
    .appendQueryParameter(DAYS_PARAM, Integer.toString(7))
    .build();

Finalmente

URL url = new URL(builtUri.toString());
Amit Tripathi
fonte
14
Você merece mais votos! Para mim, o caso de uso básico é quando você tem um URL de string já definido e deseja adicionar / acrescentar parâmetros!
Lorenzo-s
1
Eu estava procurando uma solução para a luz do sol (essa seqüência exata), mas a pergunta mais votada fornece uma solução muito mais robusta.
Nahum
1
Obrigado pela dica Uri.buildUpon ()! Me salvou algumas dores de cabeça.
chrjs
Eu estava confuso em que ordem url são feitas, porque no curso de suas únicas variáveis não o URL completo, que temos de fazer
Blackhawk
E se eu não tiver o URL base, mas o URL completo? Usando Parse + BuildUpon + AppendQueryParam + Build, recebo um URL inválido ([domain] [queryParams] [path] em vez de [domain] [path] [queryParams])
Giuseppe Giacoppo
20

Excelente resposta acima se transformou em um método utilitário simples.

private Uri buildURI(String url, Map<String, String> params) {

    // build url with parameters.
    Uri.Builder builder = Uri.parse(url).buildUpon();
    for (Map.Entry<String, String> entry : params.entrySet()) {
        builder.appendQueryParameter(entry.getKey(), entry.getValue());
    }

    return builder.build();
}
Chris
fonte
Não é necessário converter conteúdo UTF8?
Webserveis
15

Aqui está uma boa maneira de explicar:

existem duas formas do URI

1 - Construtor (pronto para ser modificado , não pronto para ser usado )

2 - Construído ( não está pronto para ser modificado , pronto para ser usado )

Você pode criar um construtor

Uri.Builder builder = new Uri.Builder();

isso retornará um construtor pronto para ser modificado assim: -

builder.scheme("https");
builder.authority("api.github.com");
builder.appendPath("search");
builder.appendPath("repositories");
builder.appendQueryParameter(PARAMETER_QUERY,parameterValue);

mas para usá-lo você precisa construí-lo primeiro

retrun builder.build();

ou no entanto você vai usá-lo. e então você criou o que já foi criado para você, pronto para usar, mas não pode ser modificado.

Uri built = Uri.parse("your URI goes here");

está pronto para uso, mas se você quiser modificá-lo, precisará buildUpon ()

Uri built = Uri.parse("Your URI goes here")
           .buildUpon(); //now it's ready to be modified
           .buildUpon()
           .appendQueryParameter(QUERY_PARAMATER, parameterValue) 
           //any modification you want to make goes here
           .build(); // you have to build it back cause you are storing it 
                     // as Uri not Uri.builder

Agora, toda vez que você quiser modificá-lo, precisará buildUpon () e, no final, build () .

assim Uri.Builder é um construtor de tipo que armazenar um Builder nele. Uri é um tipo construído que armazena um URI já construído nele.

novo Uri.Builder (); retorna um construtor . Uri.parse ("seu URI vai aqui") retorna um Built .

e com build () você pode alterá-lo de Builder para Built . construir sobre() você pode alterá-lo de Built para Builder . Aqui está o que você pode fazer

Uri.Builder builder = Uri.parse("URL").buildUpon();
// here you created a builder, made an already built URI with Uri.parse
// and then change it to builder with buildUpon();
Uri built = builder.build();
//when you want to change your URI, change Builder 
//when you want to use your URI, use Built

e também o oposto: -

Uri built = new Uri.Builder().build();
// here you created a reference to a built URI
// made a builder with new Uri.Builder() and then change it to a built with 
// built();
Uri.Builder builder = built.buildUpon();

espero que minha resposta tenha ajudado :) <3

Mina Shaker
fonte
6

para o exemplo no second Answereu usei essa técnica para a mesma URL

http://api.example.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7

Uri.Builder builder = new Uri.Builder();
            builder.scheme("https")
                    .authority("api.openweathermap.org")
                    .appendPath("data")
                    .appendPath("2.5")
                    .appendPath("forecast")
                    .appendPath("daily")
                    .appendQueryParameter("q", params[0])
                    .appendQueryParameter("mode", "json")
                    .appendQueryParameter("units", "metric")
                    .appendQueryParameter("cnt", "7")
                    .appendQueryParameter("APPID", BuildConfig.OPEN_WEATHER_MAP_API_KEY);

depois de terminar de construí-lo, obtenha-o URLassim

URL url = new URL(builder.build().toString());

e abrir uma conexão

  HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

e se o link for simplecomo uri de localização, por exemplo

geo:0,0?q=29203

Uri geoLocation = Uri.parse("geo:0,0?").buildUpon()
            .appendQueryParameter("q",29203).build();
Basheer AL-MOMANI
fonte
2
URL url = new URL(builder.build().toString());tem a envolto por um bloco de captura tentativa para MalformedURLException
Ali Kazi
2

Usando appendEncodePath()você pode economizar várias linhas appendPath(), o seguinte snippet de código cria esse URL:http://api.openweathermap.org/data/2.5/forecast/daily?zip=94043

Uri.Builder urlBuilder = new Uri.Builder();
urlBuilder.scheme("http");
urlBuilder.authority("api.openweathermap.org");
urlBuilder.appendEncodedPath("data/2.5/forecast/daily");
urlBuilder.appendQueryParameter("zip", "94043,us");
URL url = new URL(urlBuilder.build().toString());
Cody
fonte
2

Melhor resposta: https://stackoverflow.com/a/19168199/413127

Exemplo para

 http://api.example.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7

Agora com Kotlin

 val myUrl = Uri.Builder().apply {
        scheme("https")
        authority("www.myawesomesite.com")
        appendPath("turtles")
        appendPath("types")
        appendQueryParameter("type", "1")
        appendQueryParameter("sort", "relevance")
        fragment("section-name")
        build()            
    }.toString()
Blundell
fonte
Obrigado por adicionar a versão Kotlin :)
M Mansour
0

Você pode fazer isso com expressões lambda;

    private static final String BASE_URL = "http://api.example.org/data/2.5/forecast/daily";

    private String getBaseUrl(Map<String, String> params) {
        final Uri.Builder builder = Uri.parse(BASE_URL).buildUpon();
        params.entrySet().forEach(entry -> builder.appendQueryParameter(entry.getKey(), entry.getValue()));
        return builder.build().toString();
    }

e você pode criar parâmetros como esse;

    Map<String, String> params = new HashMap<String, String>();
    params.put("zip", "94043,us");
    params.put("units", "metric");

Btw. Se você enfrentar qualquer problema como“lambda expressions not supported at this language level” , verifique este URL;

https://stackoverflow.com/a/22704620/2057154

yusuf
fonte