ChatGPT解决这个技术问题 Extra ChatGPT

Use URI builder in Android or create URL with variables

I'm developing an Android app. I need to build a URI for my app to make an API request. Unless there's another way to put a variable in a URI, this is the easiest way I've found. I found that you need to use Uri.Builder, but I'm not quite sure how to. My url is:

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

My scheme is http, authority is lapi.transitchicago.com, path is /api/1.0, path segment(s) is ttarrivals.aspx, and query string is key=[redacted]&mapid=value.

My code is below:

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

I understand that I can do URI.add, but how do I integrate it into the Uri.Builder? Should I add everything like URI.add(scheme), URI.add(authority) and so on? Or is that not the way to do it? Also, is there any other easier way to add a variable to a URI/URL?


J
JJD

Let's say that I want to create the following URL:

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

To build this with the Uri.Builder I would do the following.

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

With my path segment, would it be a path? Or would it be a query?
If it is a path, then it would be appendPath() for the method. If it is a query string (coming after the ?) then use appendQueryParameter(). Take a look at the URL that I have in the example and what I am doing with each segment. I also added toString() to the build() call to get the proper type back.
It's before the question mark, but it doesn't have a / after it. It's ttarrivals.aspx on my question above. So that would be a path?
Perfect answer! This should have been in the API documentation already.
+1 for explaining url having #... Is there any documentation where we can say that ok, If # then use fragment..if &, then, appendQueryparameter and so on...
A
Amit Tripathi

There is another way of using Uri and we can achieve the same goal

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

To build the Uri you can use this:

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

You can declare all this the above way or even inside the Uri.parse() and appendQueryParameter()

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

At last

URL url = new URL(builtUri.toString());

Source: Udacity Android course / Sunshine app


You deserve more votes! For me, the basic use case is when you have an already defined string URL, and you want to add/append parameters!
I was looking for a solution for sunshine (this exact string) but the most voted question provides much more robust solution.
Thanks for the Uri.buildUpon() hint! Saved me some headaches.
I was confused in what order url are made, because in course its only variables not the complete url, that we have to make
What if I don't have the base url but the complete url instead? Using Parse+BuildUpon+AppendQueryParam+Build I get a non valid url ([domain][queryParams][path] instead of [domain][path][queryParams])
C
Chris

Excellent answer from above turned into a simple utility method.

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

No need convert UTF8 content?
C
Community

here is a good way to explain it:

there are two forms of the URI

1 - Builder(ready to be modified, not ready to be used)

2 - Built(not ready to be modified, ready to be used )

You can create a builder by

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

this gonna return a Builder ready to be modified like this:-

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

but to use it you have to build it first

retrun builder.build();

or however you gonna use it. and then you have built that is already built for you, ready to use but cannot be modified.

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

this is ready to use but if you want to modify it you need to 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

now every time you want to modify it you need to buildUpon() and in the end build().

so Uri.Builder is a Builder type that store a Builder in it. Uri is a Built type that store an already built URI in it.

new Uri.Builder(); rerurns a Builder. Uri.parse("your URI goes here") returns a Built.

and with build() you can change it from Builder to Built. buildUpon() you can change it from Built to Builder. Here is what you can do

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

and also the opposite:-

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

hope my answer helped :) <3


B
Basheer AL-MOMANI

for the example in the second Answer I used this technique for the same 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);

then after finish building it get it as URL like this

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

and open a connection

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

and if link is simple like location uri, for example

geo:0,0?q=29203

Uri geoLocation = Uri.parse("geo:0,0?").buildUpon()
            .appendQueryParameter("q",29203).build();

URL url = new URL(builder.build().toString()); has to wrapped by a try catch block for MalformedURLException
C
Cody

Using appendEncodePath() could save you multiple lines than appendPath(), the following code snippet builds up this 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());

B
Blundell

Best answer: https://stackoverflow.com/a/19168199/413127

Example for

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

Now with 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()

Thank you for adding the Kotlin version :)
y
yusuf

You can do that with lambda expressions;

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

and you can create params like that;

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

Btw. If you will face any issue like “lambda expressions not supported at this language level”, please check this URL;

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


And what to do after setting params?
Params is the parameter of the ’getBaseUrl’ method. For calling this method you need to pass params.
thank you! It would be better if you show a resulting URL (I used another solution).