Utilice el generador de URI en Android o cree una URL con variables

202

Estoy desarrollando una aplicación para Android. Necesito crear un URI para que mi aplicación realice una solicitud de API. A menos que haya otra forma de poner una variable en un URI, esta es la forma más fácil que he encontrado. Descubrí que necesita usar Uri.Builder, pero no estoy muy seguro de cómo hacerlo. Mi url es:

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

Mi esquema es http, la autoridad es lapi.transitchicago.com, la ruta es /api/1.0, el segmento (s) de ruta es ttarrivals.aspxy la cadena de consulta es key=[redacted]&mapid=value.

Mi código está abajo:

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

Entiendo que puedo hacerlo URI.add, pero ¿cómo lo integro en el Uri.Builder? ¿Debo agregar todo como URI.add(scheme), URI.add(authority)y así sucesivamente? ¿O esa no es la forma de hacerlo? Además, ¿hay alguna otra manera más fácil de agregar una variable a un URI / URL?

hichris123
fuente

Respuestas:

426

Digamos que quiero crear la siguiente URL:

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

Para construir esto con el Uri.Builderharía lo siguiente.

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
fuente
1
Con mi segmento de ruta, ¿sería una ruta? ¿O sería una consulta?
hichris123
Si es una ruta, entonces sería appendPath()para el método. Si se trata de una cadena de consulta (que viene después de?), Utilice appendQueryParameter(). Eche un vistazo a la URL que tengo en el ejemplo y lo que estoy haciendo con cada segmento. También agregué toString()a la build()llamada para recuperar el tipo adecuado.
David
1
Está antes del signo de interrogación, pero no tiene un / después. Es ttarrivals.aspx en mi pregunta anterior. ¿Entonces ese sería un camino?
hichris123
Correcto. Simplemente es el final del camino. Técnicamente, podría poner un "/" al final si lo desea y sería válido. mysite.com/path es lo mismo que mysite.com/path
David
1
¡Respuesta perfecta! Esto ya debería estar en la documentación de la API.
robinmitra
259

Hay otra forma de usar Uriy podemos lograr el mismo objetivo

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

Para construir el Uri puedes usar esto:

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";

Puede declarar todo esto de la manera anterior o incluso dentro del Uri.parse()yappendQueryParameter()

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

Al final

URL url = new URL(builtUri.toString());
Amit Tripathi
fuente
14
¡Te mereces más votos! Para mí, el caso de uso básico es cuando tiene una URL de cadena ya definida y desea agregar / agregar parámetros.
lorenzo-s
1
Estaba buscando una solución para la luz del sol (esta cadena exacta) pero la pregunta más votada proporciona una solución mucho más robusta.
Nahum
1
¡Gracias por la sugerencia Uri.buildUpon ()! Me ahorró algunos dolores de cabeza.
chrjs
Estaba confundido en qué orden se hacen url, porque en curso sus únicas variables no la URL completa, que tenemos que hacer
Blackhawk
¿Qué sucede si no tengo la url base sino la url completa? Usando Parse + BuildUpon + AppendQueryParam + Build obtengo una URL no válida ([dominio] [queryParams] [ruta] en lugar de [dominio] [ruta] [queryParams])
Giuseppe Giacoppo
20

Excelente respuesta de arriba se convirtió en un método de utilidad simple.

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
fuente
¿No es necesario convertir contenido UTF8?
Webserveis
15

Aquí hay una buena manera de explicarlo:

hay dos formas de URI

1 - Generador (listo para ser modificado , no listo para ser usado )

2 - Construido ( no listo para ser modificado , listo para ser usado )

Puedes crear un constructor por

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

esto devolverá un generador listo para ser modificado de esta manera:

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

pero para usarlo primero debes construirlo

retrun builder.build();

o como lo vayas a usar. y luego ha creado lo que ya está hecho para usted, listo para usar pero no se puede modificar.

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

esto está listo para usar, pero si desea modificarlo, necesita 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

ahora cada vez que quiera modificarlo necesita buildUpon () y al final build () .

por lo Uri.Builder es un constructor de tipo que almacenan un Constructor en ella. Uri es un tipo Construido que almacena un URI ya construido en él.

nuevo Uri.Builder (); vuelve a crear un constructor . Uri.parse ("su URI va aquí") devuelve un Construido .

y con build () puedes cambiarlo de Builder a Built . buildUpon () puede cambiarlo de Construido a Constructor . Esto es lo que puedes hacer.

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

y también lo contrario: -

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 mi respuesta haya ayudado :) <3

Mina Shaker
fuente
6

para el ejemplo en el second Answerutilicé esta técnica para la misma 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);

luego, después de terminar de construirlo, consíguelo URLasí

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

y abrir una conexión

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

y si el enlace es simplecomo la ubicación uri, por ejemplo

geo:0,0?q=29203

Uri geoLocation = Uri.parse("geo:0,0?").buildUpon()
            .appendQueryParameter("q",29203).build();
Basheer AL-MOMANI
fuente
2
URL url = new URL(builder.build().toString());tiene que ser envuelto por un bloque de prueba para MalformedURLException
Ali Kazi
2

El uso appendEncodePath()podría ahorrarle varias líneas que appendPath(), el siguiente fragmento de código acumula esta 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
fuente
2

La mejor respuesta: https://stackoverflow.com/a/19168199/413127

Ejemplo para

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

Ahora con 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
fuente
Gracias por agregar la versión de Kotlin :)
M Mansour
0

Puedes hacerlo con expresiones 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();
    }

y puedes crear parámetros como ese;

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

Por cierto. Si tiene algún problema “lambda expressions not supported at this language level”, consulte esta URL;

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

yusuf
fuente