ใช้ URI builder ใน Android หรือสร้าง URL ด้วยตัวแปร


202

ฉันกำลังพัฒนาแอพ Android ฉันต้องสร้าง URI สำหรับแอปของฉันเพื่อขอ API หากไม่มีวิธีอื่นในการวางตัวแปรใน URI นี่เป็นวิธีที่ง่ายที่สุดที่ฉันพบ ฉันพบว่าคุณต้องใช้Uri.Builderแต่ฉันไม่แน่ใจว่าจะทำอย่างไร URL ของฉันคือ:

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

โครงการของฉันคือ http อำนาจเป็นlapi.transitchicago.comเส้นทางคือ/api/1.0ส่วนเส้นทาง (s) และสตริงแบบสอบถามเป็นttarrivals.aspxkey=[redacted]&mapid=value

รหัสของฉันอยู่ด้านล่าง:

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

ผมเข้าใจว่าฉันจะทำURI.addแต่ฉันจะบูรณาการเข้ากับUri.Builder? ฉันควรเพิ่มทุกอย่างเหมือนURI.add(scheme), URI.add(authority)และอื่น ๆ ? หรือนั่นไม่ใช่วิธีที่จะทำ? นอกจากนี้ยังมีวิธีอื่นที่ง่ายกว่าในการเพิ่มตัวแปรไปยัง URI / URL หรือไม่

คำตอบ:


426

สมมติว่าฉันต้องการสร้าง URL ต่อไปนี้:

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

เมื่อต้องการสร้างสิ่งนี้ด้วยUri.Builderฉันจะทำต่อไปนี้

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
ด้วยส่วนเส้นทางของฉันมันจะเป็นเส้นทางหรือไม่? หรือมันจะเป็นแบบสอบถามหรือไม่?
hichris123

หากเป็นเส้นทางก็จะเป็นappendPath()วิธีการ ถ้ามันเป็นสตริงแบบสอบถาม (มาหลังจากที่?) appendQueryParameter()แล้วใช้ ดู URL ที่ฉันมีในตัวอย่างและสิ่งที่ฉันทำกับแต่ละกลุ่ม ฉันยังเพิ่มtoString()การbuild()โทรเพื่อรับชนิดที่เหมาะสมกลับ
David

1
มันอยู่ก่อนเครื่องหมายคำถาม แต่ไม่มี / หลัง มันเป็น ttarrivals.aspx สำหรับคำถามของฉันด้านบน นั่นจะเป็นเส้นทางหรือไม่?
hichris123

แก้ไข. มันเพิ่งจะเป็นจุดสิ้นสุดของเส้นทาง ในทางเทคนิคคุณสามารถใส่ "/" ท้ายถ้าคุณต้องการและมันจะถูกต้อง mysite.com/pathเหมือนกับmysite.com/path
David

1
คำตอบที่สมบูรณ์แบบ! สิ่งนี้ควรอยู่ในเอกสาร API แล้ว
robinmitra

259

มีวิธีใช้อีกวิธีหนึ่งUriและเราสามารถบรรลุเป้าหมายเดียวกันได้

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

เพื่อสร้าง Uri คุณสามารถใช้สิ่งนี้:

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

คุณสามารถประกาศทั้งหมดนี้ด้วยวิธีดังกล่าวข้างต้นหรือแม้กระทั่งภายในUri.parse()และ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();

ในที่สุด

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

14
คุณสมควรได้รับคะแนนโหวตมากขึ้น! สำหรับฉันกรณีการใช้งานพื้นฐานคือเมื่อคุณมี URL สตริงที่กำหนดไว้แล้วและคุณต้องการเพิ่ม / ต่อท้ายพารามิเตอร์!
lorenzo-s

1
ฉันกำลังมองหาทางออกสำหรับแสงแดด (สตริงที่แน่นอนนี้) แต่คำถามที่โหวตมากที่สุดให้คำตอบที่มีประสิทธิภาพมากขึ้น
Nahum

1
ขอบคุณสำหรับคำใบ้ Uri.buildUpon ()! ช่วยให้ฉันปวดหัว
chrjs

ฉันสับสนในสิ่งที่ทำตามลำดับเนื่องจากแน่นอนว่ามีเพียงตัวแปรเดียวที่ไม่ใช่ URL ที่สมบูรณ์ที่เราต้องทำ
blackHawk

ถ้าฉันไม่มี URL พื้นฐาน แต่เป็น URL ที่สมบูรณ์แทนล่ะ ใช้ Parse + BuildUpon + AppendQueryParam + Build ฉันได้รับ URL ที่ไม่ถูกต้อง ([domain] [queryParams] [path] แทนที่จะเป็น [domain] [path] [queryParams])
Giuseppe Giacoppo

20

คำตอบที่ยอดเยี่ยมจากด้านบนกลายเป็นวิธีการใช้งานที่ง่าย

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

ไม่จำเป็นต้องแปลงเนื้อหา UTF8 หรือ
Webserveis

15

นี่เป็นวิธีที่ดีในการอธิบาย:

URI มีสองรูปแบบ

1 - Builder (พร้อมที่จะปรับเปลี่ยน , ไม่พร้อมที่จะถูกนำมาใช้ )

2 - สร้างขึ้น ( ไม่พร้อมที่จะแก้ไขพร้อมใช้งาน )

คุณสามารถสร้างตัวสร้างโดย

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

นี่จะส่งคืนตัวสร้างพร้อมที่จะแก้ไขเช่นนี้: -

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

แต่จะใช้มันคุณต้องสร้างมันขึ้นมาก่อน

retrun builder.build();

หรือว่าคุณจะใช้มัน จากนั้นคุณได้สร้างที่สร้างไว้แล้วสำหรับคุณพร้อมใช้งาน แต่ไม่สามารถแก้ไขได้

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

สิ่งนี้พร้อมใช้งาน แต่ถ้าคุณต้องการแก้ไขคุณต้อง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

ตอนนี้เวลาที่คุณต้องการทุกคนที่จะปรับเปลี่ยนคุณต้องbuildUpon ()และในท้ายที่สุดการสร้าง ()

ดังนั้นUri.Builderจึงเป็นตัวสร้างประเภทที่เก็บตัวสร้างมันไว้ Uriเป็นประเภทที่สร้างขึ้นซึ่งเก็บ URI ที่สร้างไว้แล้วในนั้น

ใหม่ Uri.Builder (); rerurns Builder Uri.parse ( "URI ของคุณไปที่นี่")ส่งกลับสร้างขึ้น

และมีการสร้าง ()คุณสามารถเปลี่ยนจากการสร้างที่จะสร้างขึ้น buildUpon ()คุณสามารถเปลี่ยนจากการสร้างขึ้นเพื่อสร้าง นี่คือสิ่งที่คุณสามารถทำได้

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

และสิ่งที่ตรงกันข้าม: -

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

หวังว่าคำตอบของฉันจะช่วย :) <3


6

สำหรับตัวอย่างในsecond Answerฉันใช้เทคนิคนี้สำหรับ 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);

หลังจากสร้างเสร็จแล้วมันจะเป็นURLแบบนี้

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

และเปิดการเชื่อมต่อ

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

และถ้าลิงก์simpleเหมือนตำแหน่ง uri เป็นต้น

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());ต้องห่อด้วยบล็อก catch catch สำหรับ MalformedURLException
Ali Kazi

2

การใช้appendEncodePath()ช่วยให้คุณประหยัดกว่าหลายบรรทัดappendPath()ข้อมูลโค้ดต่อไปนี้สร้าง 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());

2

คำตอบที่ดีที่สุด: https://stackoverflow.com/a/19168199/413127

ตัวอย่างสำหรับ

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

ขณะนี้มี 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()

ขอขอบคุณที่เพิ่มรุ่น Kotlin :)
M Mansour

0

คุณสามารถทำได้ด้วยการแสดงออกแลมบ์ดา

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

และคุณสามารถสร้างพารามิเตอร์เช่นนั้น

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

Btw หากคุณจะประสบปัญหาใด ๆ เช่น“lambda expressions not supported at this language level”โปรดตรวจสอบ URL นี้;

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.