Gunakan pembuat URI di Android atau buat URL dengan variabel


202

Saya sedang mengembangkan aplikasi Android. Saya perlu membuat URI untuk aplikasi saya untuk membuat permintaan API. Kecuali ada cara lain untuk meletakkan variabel dalam URI, ini adalah cara termudah yang saya temukan. Saya menemukan bahwa Anda perlu menggunakan Uri.Builder, tetapi saya tidak yakin bagaimana caranya. Url saya adalah:

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

Skema saya adalah http, otoritas adalah lapi.transitchicago.com, path is /api/1.0, segmen path (s) is ttarrivals.aspx, dan string kueri key=[redacted]&mapid=value.

Kode saya di bawah ini:

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

Saya mengerti bahwa saya bisa melakukannya URI.add, tetapi bagaimana saya mengintegrasikannya ke dalam Uri.Builder? Haruskah saya menambahkan semuanya seperti URI.add(scheme), URI.add(authority)dan sebagainya? Atau bukankah itu cara untuk melakukannya? Juga, apakah ada cara lain yang lebih mudah untuk menambahkan variabel ke URI / URL?

Jawaban:


426

Katakanlah saya ingin membuat URL berikut:

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

Untuk membangun ini dengan Uri.Buildersaya akan melakukan hal berikut.

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

1
Dengan segmen jalur saya, apakah ini akan menjadi jalur? Atau apakah itu permintaan?
hichris123

Jika itu adalah jalan, maka itu akan menjadi appendPath()metode. Jika itu adalah string kueri (muncul setelah?) Lalu gunakan appendQueryParameter(). Lihatlah URL yang saya miliki dalam contoh dan apa yang saya lakukan dengan setiap segmen. Saya juga menambahkan toString()ke build()panggilan untuk mendapatkan jenis kembali yang tepat.
David

1
Itu sebelum tanda tanya, tetapi tidak memiliki / setelahnya. Ini ttarrivals.aspx pada pertanyaan saya di atas. Jadi itu akan menjadi jalan?
hichris123

Benar. Kebetulan itu adalah akhir dari jalan. Secara teknis Anda bisa meletakkan "/" di akhir jika Anda mau dan itu akan valid. mysite.com/path sama dengan mysite.com/path
David

1
Jawaban sempurna! Ini seharusnya sudah ada dalam dokumentasi API.
robinmitra

259

Ada cara lain untuk menggunakan Uridan kita dapat mencapai tujuan yang sama

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

Untuk membangun Uri, Anda dapat menggunakan ini:

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

Anda dapat mendeklarasikan semua ini dengan cara di atas atau bahkan di dalam Uri.parse()danappendQueryParameter()

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

Akhirnya

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

14
Anda berhak mendapatkan lebih banyak suara! Bagi saya, kasus penggunaan dasar adalah ketika Anda memiliki URL string yang sudah ditentukan, dan Anda ingin menambahkan / menambahkan parameter!
lorenzo-s

1
Saya sedang mencari solusi untuk sinar matahari (string yang tepat ini) tetapi pertanyaan yang paling banyak dipilih memberikan solusi yang jauh lebih kuat.
Nahum

1
Terima kasih atas petunjuk Uri.buildUpon ()! Menyelamatkan saya beberapa sakit kepala.
chrjs

Saya bingung bagaimana urutan url dibuat, karena tentu saja satu-satunya variabel bukan url lengkap, yang harus kita buat
blackHawk

Bagaimana jika saya tidak memiliki url dasar tetapi url lengkap sebagai gantinya? Menggunakan Parse + BuildUpon + AppendQueryParam + Build Saya mendapatkan url yang tidak valid ([domain] [queryParams] [path] alih-alih [domain] [path] [queryParams])
Giuseppe Giacoppo

20

Jawaban luar biasa dari atas berubah menjadi metode utilitas sederhana.

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

Tidak perlu mengonversi konten UTF8?
Webserveis

15

di sini adalah cara yang baik untuk menjelaskannya:

ada dua bentuk URI

1 - Builder (siap dimodifikasi , tidak siap digunakan )

2 - Dibangun ( tidak siap dimodifikasi , siap digunakan )

Anda dapat membuat pembangun dengan

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

ini akan mengembalikan Builder yang siap dimodifikasi seperti ini: -

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

tetapi untuk menggunakannya Anda harus membangunnya terlebih dahulu

retrun builder.build();

atau bagaimanapun Anda akan menggunakannya. dan kemudian Anda telah membangun yang sudah dibuat untuk Anda, siap digunakan tetapi tidak dapat dimodifikasi.

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

ini siap digunakan tetapi jika Anda ingin memodifikasinya Anda perlu 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

sekarang setiap kali Anda ingin memodifikasinya, Anda perlu buildUpon () dan pada akhirnya build () .

jadi Uri.Builder adalah tipe Builder yang menyimpan Builder di dalamnya. Uri adalah tipe Built yang menyimpan URI yang sudah dibangun di dalamnya.

Uri.Builder baru (); jalankan kembali Builder . Uri.parse ("URI Anda masuk ke sini") mengembalikan Bangun .

dan dengan build () Anda dapat mengubahnya dari Builder ke Built . buildUpon () Anda dapat mengubahnya dari Dibangun ke Builder . Inilah yang dapat Anda lakukan

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

dan juga sebaliknya: -

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

semoga jawaban saya membantu :) <3


6

untuk contoh dalam second Answersaya menggunakan teknik ini untuk URL yang sama

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

lalu setelah selesai membangun itu mendapatkannya URLseperti ini

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

dan buka koneksi

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

dan jika tautannya simpleseperti lokasi uri, misalnya

geo:0,0?q=29203

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

2
URL url = new URL(builder.build().toString());harus dibungkus oleh blok uji coba untuk MalformedURLException
Ali Kazi

2

Menggunakan appendEncodePath()dapat menyelamatkan Anda beberapa baris daripada appendPath(), potongan kode berikut membangun url ini: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());

2

Jawaban terbaik: https://stackoverflow.com/a/19168199/413127

Contoh untuk

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

Sekarang dengan 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()

Terima kasih telah menambahkan versi Kotlin :)
M Mansour

0

Anda dapat melakukannya dengan ekspresi 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();
    }

dan Anda dapat membuat params seperti itu;

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

Btw. Jika Anda akan menghadapi masalah seperti “lambda expressions not supported at this language level”, silakan periksa URL ini;

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.