3.2 使用 URL 類請求和提交數據詳解

點此進入:從零快速構建APP系列目錄導圖
點此進入:UI編程系列目錄導圖
點此進入:四大組件系列目錄導圖
點此進入:數據網絡和線程系列目錄導圖

URL 對象代表統一資源定位器,它是這指向互聯網“資源”的指針。這裏面的“資源”可以是簡單的文件和目錄,也可以是對更復雜的對象的引用,例如:對數據庫或者搜索引擎的查詢。就通常情況而言,URL 可以由協議、名主機、端口和資源組成,即滿足如下格式:

protocol://host:port/resourceName

例如如下的URL地址:

http://www.baidu.com/index.php

一、使用 URL 讀取網絡資源

URL類提供了多個構造器,用於創建 URL 對象,一旦獲得 URL 對象之後,就可以調用如下常用的方法來訪問 URL 所對應的資源了:
- String getFile():獲取url的資源名。
- String getHost():獲取url的主機名。
- String getPath():獲取url的路徑部分。
- int getPort():獲取url的端口號。
- String getProtocol():獲取url的協議名稱。
- String getQuery():獲取url的查詢字符串部分。
- URLConnection openConnection():返回一個 URLConnection 對象,它表示到 URL 所引用的遠程對象的連接。
- InputStream openStream():打開與此 URL 的鏈接,並返回一個用於讀取該 URL 資源的 InputStream。

1、使用 URL 讀取網絡資源

URL 對象中前面幾個方法都非常容易理解,而該對象提供的 openStream() 可以讀取該資源的 InputStream,通過該方法可以非常方便的讀取遠程資源。

首先我們修改 activity_main ,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wgh.willflowurl.MainActivity">

    <ImageView
        android:id="@+id/action_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

很簡單,這裏面我們只放了一個圖片控件ImageView,用於展示接下來 URL 在網上請求到的圖片。

接下來修改 MainActivity 中的代碼如下:
public class MainActivity extends AppCompatActivity {

    ImageView mImageView;
    // 代表從網絡下載得到的圖片
    Bitmap mBitmap;
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 0) {
                // 使用ImageView顯示該圖片
                mImageView.setImageBitmap(mBitmap);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.action_image);
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getImageFromURL();
            }
        });
    }

    private void getImageFromURL() {
        new Thread() {
            public void run() {
                try {
                    // 定義一個URL對象
                    URL url = new URL("http://www.touxiang.cn/uploads/20131011/11-084718_797.jpg");
                    // 打開該URL對應的資源的輸入流
                    InputStream inputStream = url.openStream();
                    // 從InputStream中解析出圖片
                    mBitmap = BitmapFactory.decodeStream(inputStream);
                    // 發送消息、通知UI組件顯示該圖片
                    mHandler.sendEmptyMessage(0);
                    inputStream.close();
                    // 再次打開URL對應的資源的輸入流
                    inputStream = url.openStream();
                    // 打開手機文件對應的輸出流
                    OutputStream outputStream = openFileOutput("flower.png", MODE_PRIVATE);
                    byte[] buff = new byte[1024];
                    int hasRead = 0;
                    // 將URL對應的資源下載到本地
                    while ((hasRead = inputStream.read(buff)) > 0) {
                        outputStream.write(buff, 0, hasRead);
                    }
                    inputStream.close();
                    outputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

首先,我們找到將XML文件中定義的圖片控件,然後給他添加點擊監聽器。在點擊事件裏我們調用 getImageFromURL() 方法,以此來獲取網絡資源。在這個方法中,我們首先定義一個URL對象,然後打開該URL對應的資源的輸入流,接着發送消息、通知UI組件顯示該圖片,最後將URL對應的資源下載到本地。

最後,我們在清單文件中加入以下網絡申請權限:

<uses-permission android:name="android.permission.INTERNET" />
編譯運行看效果:

二、使用 URLConnection 提交請求

URL 的 openConnection() 方法將返回一個 URLConnection 對象,該對象表示應用程序和 URL 之間的通信連接。我們的程序可以通過 URLConnection 向該 URL 發送請求,讀取他的引用資源。

讀取 URL 引用資源的步驟:

1、設置 URL 對象的 openConnection() 方法來創建 URLConnection 這個對象。
2、設置 URLConnection 的參數和普通請求屬性。
3、如果只是發送 GET 的方式的請求,那麼使用 connect 方法建立和遠程資源之間的實際連接即可;如果是發送 POST 的方式的請求,那麼使用 URLConnection 實例對應的輸出流來發送請求參數。
4、遠程資源變爲可用,這時程序可以訪問遠程資源的頭字段或通過輸入流讀取遠程資源的數據。

設置請求字段的常用方法:
  • setAllowUserInteraction():設置該 URLConnection 的 allowUserInteraction 請求字段的值。
  • setDoInput():設置 URLConnection 的 DoInput 請求字段的值。
  • setDoOutput():設置 URLConnection 的 DoOutput 請求字段的值。
  • setIfModifiedSince():設置 URLConnection 的 IfModifiedSince 請求字段的值。
  • setUseCaches():設置 URLConnection 的 UseCaches 請求字段的值。
  • getInputStream():返回 URLConnection 的輸入流,用於獲取響應內容。
  • getOutputStream():返回 URLConnection 的輸出流,用於向 URLConnection 發送請求參數。
  • getContentEncoding():獲取 URLConnection 的 ContentEncoding 請求字段的值。
  • getContentLength():獲取 URLConnection 的 Length 請求字段的值。
  • getContentType():獲取 URLConnection 的 Type 請求字段的值。
  • getDate():獲取 URLConnection 的 Date 請求字段的值。
  • getExpiration():獲取 URLConnection 的 Expiration 請求字段的值。
  • getLastModified():獲取 URLConnection 的 LastModified 請求字段的值。

下面我們就通過一個例子來展示如何向站點發送請求,並從站點取得響應。

首先,我們創建一個工具類,代碼如下:
/**
 * Created by   : WGH.
 */
public class GetPostUtil {
    /**
     * 向指定URL發送GET方法的請求
     *
     * @param url    發送請求的URL
     * @param params 請求參數,請求參數應該是name1=value1&name2=value2的形式。
     * @return URL所代表遠程資源的響應
     */
    public static String sendGet(String url, String params) {
        String result = "";
        BufferedReader bufferedReader = null;
        try {
            String urlName = url + "?" + params;
            URL realUrl = new URL(urlName);
            // 打開和URL之間的連接
            URLConnection conn = realUrl.openConnection();
            // 設置通用的請求屬性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            // 建立實際的連接
            conn.connect();
            // 獲取所有響應頭字段
            Map<String, List<String>> map = conn.getHeaderFields();
            // 遍歷所有的響應頭字段
            for (String key : map.keySet()) {
                Log.i(TAG, "key : " + key + " --> " + map.get(key));
            }
            // 定義BufferedReader輸入流來讀取URL的響應
            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                result += "\n" + line;
            }
        } catch (Exception e) {
            Log.e(TAG, "發送GET請求出現異常!" + e);
            e.printStackTrace();
        }
        // 使用finally塊來關閉輸入流
        finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 向指定URL發送POST方法的請求
     *
     * @param url    發送請求的URL
     * @param params 請求參數,請求參數應該是name1=value1&name2=value2的形式。
     * @return URL所代表遠程資源的響應
     */
    public static String sendPost(String url, String params) {
        PrintWriter printWriter = null;
        BufferedReader bufferedReader = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打開和URL之間的連接
            URLConnection conn = realUrl.openConnection();
            // 設置通用的請求屬性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            // 發送POST請求必須設置如下兩行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 獲取URLConnection對象對應的輸出流
            printWriter = new PrintWriter(conn.getOutputStream());
            // 發送請求參數
            printWriter.print(params);  // ②
            // flush輸出流的緩衝
            printWriter.flush();
            // 定義BufferedReader輸入流來讀取URL的響應
            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                result += "\n" + line;
            }
        } catch (Exception e) {
            Log.e(TAG, "發送POST請求出現異常!" + e);
            e.printStackTrace();
        }
        // 使用finally塊來關閉輸出流、輸入流
        finally {
            try {
                if (printWriter != null) {
                    printWriter.close();
                }
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}

從上面的程序我們可以看出,如果需要發送GET請求的話,只需要調用URLConnection的connect()這個方法就可以建立實際的連接,而如果需要發送POST請求的話,則需要獲取URLConnection的輸出流,然後在向網絡中的輸出流寫入請求參數。

提供了這個工具類之後,接下來就可以在MainActivity當中進行使用了,使用的方法也很簡單,就是調用這個類當中相應的請求方法並輸入對應格式的請求參數即可,比如GET請求可以這樣輸入:

response = GetPostUtil.sendGet("http://192.168.1.88:6666/abc/a.jsp", null);

而POST請求可以這樣輸入:

response = GetPostUtil.sendPost("http://192.168.1.88:6666/abc/login.jsp", "name=willflow.org&pass=123456");

這樣我們就可以拿到響應的字符串 response 來做之後的操作,比如UI顯示等,而顯示所用到的方法和上一個例子是一樣的,我們這裏就不過多做贅述了。

點此進入:GitHub開源項目“愛閱”,下面是“愛閱”的效果圖:


聯繫方式:

簡書:WillFlow
CSDN:WillFlow
微信公衆號:WillFlow

微信公衆號:WillFlow

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章