Android簡單連接到網(wǎng)絡(luò)

2018-08-02 17:41 更新

編寫:kesenhoo - 原文:http://developer.android.com/training/basics/network-ops/connecting.html

這一課會演示如何實現(xiàn)一個簡單的連接到網(wǎng)絡(luò)的程序。它提供了一些我們在創(chuàng)建即使最簡單的網(wǎng)絡(luò)連接程序時也應(yīng)該遵循的最佳示例。

請注意,想要執(zhí)行本課的網(wǎng)絡(luò)操作首先需要在程序的 manifest 文件中添加以下權(quán)限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

選擇一個 HTTP Client

大多數(shù)連接網(wǎng)絡(luò)的 Android app 會使用 HTTP 來發(fā)送與接收數(shù)據(jù)。Android 提供了兩種 HTTP clients:HttpURLConnection 與 Apache HttpClient。二者均支持 HTTPS、流媒體上傳和下載、可配置的超時、IPv6 與連接池(connection pooling)。對于 Android 2.3 Gingerbread 或更高的版本,推薦使用 HttpURLConnection。關(guān)于這部分的更多詳情,請參考 Android's HTTP Clients。

檢查網(wǎng)絡(luò)連接

在我們的 app 嘗試連接網(wǎng)絡(luò)之前,應(yīng)通過函數(shù) getActiveNetworkInfo() 和 isConnected() 檢測當(dāng)前網(wǎng)絡(luò)是否可用。請注意,設(shè)備可能不在網(wǎng)絡(luò)覆蓋范圍內(nèi),或者用戶可能關(guān)閉 Wi-Fi 與移動網(wǎng)絡(luò)連接。關(guān)于這部分的更多詳情,請參考管理網(wǎng)絡(luò)的使用情況

public void myClickHandler(View view) {
    ...
    ConnectivityManager connMgr = (ConnectivityManager)
        getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) {
        // fetch data
    } else {
        // display error
    }
    ...
}

在一個單獨的線程中執(zhí)行網(wǎng)絡(luò)操作

網(wǎng)絡(luò)操作會遇到不可預(yù)期的延遲。為了避免造成不好的用戶體驗,總是在 UI 線程之外單獨的線程中執(zhí)行網(wǎng)絡(luò)操作。AsyncTask 類提供了一種簡單的方式來處理這個問題。這部分的詳情,請參考 Multithreading For Performance。

在下面的代碼示例中,myClickHandler() 方法會執(zhí)行 new DownloadWebpageTask().execute(stringUrl)。DownloadWebpageTask 是 AsyncTask 的子類,它實現(xiàn)了下面兩個方法:

  • doInBackground() 執(zhí)行 downloadUrl() 方法。它以網(wǎng)頁的 URL 作為參數(shù),方法 downloadUrl() 獲取并處理網(wǎng)頁返回的數(shù)據(jù)。執(zhí)行完畢后,返回一個結(jié)果字符串。
  • onPostExecute() 接收結(jié)果字符串并把它顯示到 UI 上。
public class HttpExampleActivity extends Activity {
    private static final String DEBUG_TAG = "HttpExample";
    private EditText urlText;
    private TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        urlText = (EditText) findViewById(R.id.myUrl);
        textView = (TextView) findViewById(R.id.myText);
    }

    // When user clicks button, calls AsyncTask.
    // Before attempting to fetch the URL, makes sure that there is a network connection.
    public void myClickHandler(View view) {
        // Gets the URL from the UI's text field.
        String stringUrl = urlText.getText().toString();
        ConnectivityManager connMgr = (ConnectivityManager)
            getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isConnected()) {
            new DownloadWebpageText().execute(stringUrl);
        } else {
            textView.setText("No network connection available.");
        }
    }

     // Uses AsyncTask to create a task away from the main UI thread. This task takes a
     // URL string and uses it to create an HttpUrlConnection. Once the connection
     // has been established, the AsyncTask downloads the contents of the webpage as
     // an InputStream. Finally, the InputStream is converted into a string, which is
     // displayed in the UI by the AsyncTask's onPostExecute method.
     private class DownloadWebpageText extends AsyncTask {
        @Override
        protected String doInBackground(String... urls) {

            // params comes from the execute() call: params[0] is the url.
            try {
                return downloadUrl(urls[0]);
            } catch (IOException e) {
                return "Unable to retrieve web page. URL may be invalid.";
            }
        }
        // onPostExecute displays the results of the AsyncTask.
        @Override
        protected void onPostExecute(String result) {
            textView.setText(result);
       }
    }
    ...
}

上面這段代碼的事件順序如下:

  1. 當(dāng)用戶點擊按鈕時調(diào)用 myClickHandler(),app 將指定的 URL 傳給 AsyncTask 的子類 DownloadWebpageTask。
  2. AsyncTask 的 doInBackground() 方法調(diào)用 downloadUrl() 方法。
  3. downloadUrl() 方法以一個 URL 字符串作為參數(shù),并用它創(chuàng)建一個 URL 對象。
  4. 這個 URL 對象被用來創(chuàng)建一個 HttpURLConnection。
  5. 一旦建立連接,HttpURLConnection 對象將獲取網(wǎng)頁的內(nèi)容并得到一個 InputStream。
  6. InputStream 被傳給 readIt() 方法,該方法將流轉(zhuǎn)換成字符串。
  7. 最后,AsyncTask 的 onPostExecute() 方法將字符串展示在 main activity 的 UI 上。

連接并下載數(shù)據(jù)

在執(zhí)行網(wǎng)絡(luò)交互的線程里面,我們可以使用 HttpURLConnection 來執(zhí)行一個 GET 類型的操作并下載數(shù)據(jù)。在調(diào)用 connect() 之后,我們可以通過調(diào)用 getInputStream() 來得到一個包含數(shù)據(jù)的 InputStream 對象。

在下面的代碼示例中,doInBackground() 方法會調(diào)用 downloadUrl()。這個 downloadUrl() 方法使用給予的 URL,通過 HttpURLConnection 連接到網(wǎng)絡(luò)。一旦建立連接后,app 就會使用 getInputStream() 來獲取包含數(shù)據(jù)的 InputStream。

// Given a URL, establishes an HttpUrlConnection and retrieves
// the web page content as a InputStream, which it returns as
// a string.
private String downloadUrl(String myurl) throws IOException {
    InputStream is = null;
    // Only display the first 500 characters of the retrieved
    // web page content.
    int len = 500;

    try {
        URL url = new URL(myurl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(10000 /* milliseconds */);
        conn.setConnectTimeout(15000 /* milliseconds */);
        conn.setRequestMethod("GET");
        conn.setDoInput(true);
        // Starts the query
        conn.connect();
        int response = conn.getResponseCode();
        Log.d(DEBUG_TAG, "The response is: " + response);
        is = conn.getInputStream();

        // Convert the InputStream into a string
        String contentAsString = readIt(is, len);
        return contentAsString;

    // Makes sure that the InputStream is closed after the app is
    // finished using it.
    } finally {
        if (is != null) {
            is.close();
        }
    }
}

請注意,getResponseCode() 會返回連接的狀態(tài)碼(status code)。這是一種獲知額外網(wǎng)絡(luò)連接信息的有效方式。其中,狀態(tài)碼是 200 則意味著連接成功。

將輸入流(InputStream)轉(zhuǎn)換為字符串

InputStream 是一種可讀的 byte 數(shù)據(jù)源。如果我們獲得了一個 InputStream,通常會進(jìn)行解碼(decode)或者轉(zhuǎn)換為目標(biāo)數(shù)據(jù)類型。例如,如果我們是在下載圖片數(shù)據(jù),那么可能需要像下面這樣解碼并展示它:

InputStream is = null;
...
Bitmap bitmap = BitmapFactory.decodeStream(is);
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setImageBitmap(bitmap);

在上面演示的示例中,InputStream 包含的是網(wǎng)頁的文本內(nèi)容。下面會演示如何把 InputStream 轉(zhuǎn)換為字符串,以便顯示在 UI 上。

// Reads an InputStream and converts it to a String.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
    Reader reader = null;
    reader = new InputStreamReader(stream, "UTF-8");
    char[] buffer = new char[len];
    reader.read(buffer);
    return new String(buffer);
}


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號