Android開發之網絡通訊詳解

  1. WebView的用法

      Android提供了一個WebView控件,藉助它我們就可以在自己的應用程序裏嵌入一個瀏覽器,從而非常輕鬆地展示各種各樣的網頁。WebView的用法也是相當簡單,下面我們就通過一個例子來學習一下吧。新建一個WebViewTest項目,然後修改activity_main.xml中的代碼,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

  然後修改MainActivity中的代碼,如下所示:

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 public class MainActivity extends Activity {
  private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView=(WebView) findViewById(R.id.web_view);
             webView.getSettings().setJavaScriptEnabled(true);//調用了setJavaScriptEnabled()
        //方法來讓WebView支持JavaScript腳本
        webView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {    
                    view.loadUrl(url); // 根據傳入的參數再去加載新的網頁
                    return true; // 表示當前WebView可以處理打開新網頁的請求,不用藉助系統瀏覽器
                    }
        });
        webView.loadUrl("http://www.baidu.com/");
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

***MainActivity中的代碼也很短,首先使用findViewById()方法獲取到了WebView的實例,然後調用WebView的getSettings()方法可以去設置一些瀏覽器的屬性,這裏我們並不去設置過多的屬性,只是調用了setJavaScriptEnabled()方法來讓WebView支持JavaScript腳本。
接下來是非常重要的一個部分,我們調用了WebView的setWebViewClient()方法,並傳入了WebViewClient的匿名類作爲參數,然後重寫了shouldOverrideUrlLoading()方法。這就表明當需要從一個網頁跳轉到另一個網頁時,我們希望目標網頁仍然在當前WebView中顯示,而不是打開系統瀏覽器。
最後一步就非常簡單了,調用WebView的loadUrl()方法,並將網址傳入,即可展示相應網頁的內容,這裏就讓我們看一看百度的首頁是長什麼樣的吧。
另外還需要注意,由於本程序使用到了網絡功能,而訪問網絡是需要聲明權限的,因此我們還得修改AndroidManifest.xml文件,並加入權限聲明,如下所示:


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.webviewtest"
    android:versionCode="1"
    android:versionName="1.0" >
<uses-permission **android:name="android.permission.INTERNET"/>**
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="17" />

效果如圖1所示:
2. 使用HTTP協議訪問網絡
  它的工作原理特別的簡單,就是客戶端向服務器發出一條HTTP請求,服務器收到請求之後會返回一些數據給客戶端,然後客戶端再對這些數據進行解析和處理就可以了。
  2.1 使用HttpURLConnection
  在Android上發送HTTP請求的方式一般有兩種,HttpURLConnection和HttpClient,本小節我們先來學習一下HttpURLConnection的用法。
  首先需要獲取到HttpURLConnection的實例,一般只需new出一個URL對象,並傳入目標的網絡地址,然後調用一下openConnection()方法即可,如下所示:
URL url = new URL(“http://www.baidu.com“);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  得到了HttpURLConnection的實例之後,我們可以設置一下HTTP請求所使用的方法。常用的方法主要有兩個,GET和POST。GET表示希望從服務器那裏獲取數據,而POST則表示希望提交數據給服務器。寫法如下:
connection.setRequestMethod(“GET”);
  接下來就可以進行一些自由的定製了,比如設置連接超時、讀取超時的毫秒數,以及服務器希望得到的一些消息頭等。這部分內容根據自己的實際情況進行編寫,示例寫法如下:
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
  之後再調用getInputStream()方法就可以獲取到服務器返回的輸入流了,剩下的任務就是對輸入流進行讀取,如下所示:
InputStream in = connection.getInputStream();
  最後可以調用disconnect()方法將這個HTTP連接關閉掉,如下所示:
connection.disconnect();

  下面就讓我們通過一個具體的例子來真正體驗一下HttpURLConnection的用法。新建一個NetworkTest項目,首先修改activity_main.xml中的代碼,如下所示:
  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
        <Button
        android:id="@+id/send_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Request" />
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >  
        <TextView
            android:id="@+id/response"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

   </ScrollView>
</LinearLayout>

 藉助ScrollView控件的話就可以允許我們以滾動的形式查看屏幕外的那部分內容。另外,佈局中還放置了一個Button和一個TextView,Button用於發送HTTP請求,TextView用於將服務器返回的數據顯示出來。
 接着修改MainActivity中的代碼,如下所示:
 

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Connection;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
   public static final int SHOW_RESPONSE=0;
   private Button sendRequest;
   private TextView responseText;
   private Handler handler=new Handler(){
       public void handleMessage(Message msg){
           switch (msg.what) {
        case SHOW_RESPONSE:
            String response=(String) msg.obj;//在這裏進行ui操作,將結果顯示在界面上
            responseText.setText(response);
        }
       }
   };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendRequest=(Button) findViewById(R.id.send_request);
        responseText=(TextView) findViewById(R.id.response);
        sendRequest.setOnClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.send_request){
            sendRequestWithHttpURLConnection();
        }

    }

    private void sendRequestWithHttpURLConnection() {
        // TODO Auto-generated method stub
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                HttpURLConnection connection=null;
                try{
                    URL url=new URL("http://www.baidu.com");
                    connection=(HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    //設置鏈接超時的時間  
                    //將讀超時設置爲指定的超時值,以毫秒爲單位。用一個非零值指定在建立到資源的連接後從input流讀入時的超時時間。  
                    //如果在數據可讀取之前超時期滿,則會引發一個 java.net.sockettimeoutexception。超時時間爲零表示無窮大超時。  
                    connection.setReadTimeout(8000);
                    InputStream in=connection.getInputStream();
                    //下面對獲取到的輸入流進行讀取
                    BufferedReader reader=new BufferedReader(new InputStreamReader(in));
                    StringBuilder response=new StringBuilder();
                    String line;
                    while((line=reader.readLine())!=null){
                        response.append(line);
                    }
                    Message message=new Message();
                    message.what=SHOW_RESPONSE;
                    //將服務器返回的結果存放到Message中
                    message.obj=response.toString();
                    handler.sendMessage(message);
                }catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }finally{
                    if(connection!=null){
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }


}

仍然別忘了要聲明一下網絡權限
現在運行一下程序,並點擊Send Request按鈕,結果如圖2所示:
這裏寫圖片描述
2.2 使用HttpClient
  HttpClient是Apache提供的HTTP網絡訪問接口,從一開始的時候就被引入到了Android API中。它可以完成和HttpURLConnection幾乎一模一樣的效果,但兩者之間的用法卻有較大的差別,那麼我們自然要看一下HttpClient是如何使用的了。
  首先你需要知道,HttpClient是一個接口,因此無法創建它的實例,通常情況下都會創建一個DefaultHttpClient的實例,如下所示:
HttpClient httpClient = new DefaultHttpClient();
  接下來如果想要發起一條GET請求,就可以創建一個HttpGet對象,並傳入目標的網絡地址,然後調用HttpClient的execute()方法即可:
  HttpGet httpGet = new HttpGet(“http://www.baidu.com“);
  httpClient.execute(httpGet);
  如果是發起一條POST請求會比GET稍微複雜一點,我們需要創建一個HttpPost對象,並傳入目標的網絡地址,如下所示:
HttpPost httpPost = new HttpPost(“http://www.baidu.com“);
然後通過一個NameValuePair集合來存放待提交的參數,並將這個參數集合傳入到一個UrlEncodedFormEntity中,然後調用HttpPost的setEntity()方法將構建好的UrlEncodedFormEntity傳入,如下所示:
List params = new ArrayList();
params.add(new BasicNameValuePair(“username”, “admin”));
params.add(new BasicNameValuePair(“password”, “123456”));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, “utf-8”);
httpPost.setEntity(entity);
  接下來的操作就和HttpGet一樣了,調用HttpClient的execute()方法,並將HttpPost對象傳入即可:
httpClient.execute(httpPost);
  執行execute()方法之後會返回一個HttpResponse對象,服務器所返回的所有信息就會包含在這裏面。通常情況下我們都會先取出服務器返回的狀態碼,如果等於200就說明請求和響應都成功了,如下所示:
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 請求和響應都成功了
}
  接下來在這個if判斷的內部取出服務返回的具體內容,可以調用getEntity()方法獲取到一個HttpEntity實例,然後再用EntityUtils.toString()這個靜態方法將HttpEntity轉換成字符串即可,如下所示:
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity);
  注意如果服務器返回的數據是帶有中文的,直接調用EntityUtils.toString()方法進行轉換會有亂碼的情況出現,這個時候只需要在轉換的時候將字符集指定成utf-8就可以了,如下所示:
String response = EntityUtils.toString(entity, “utf-8”);

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Connection;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
   public static final int SHOW_RESPONSE=0;
   private Button sendRequest;
   private TextView responseText;
   private Handler handler=new Handler(){
       public void handleMessage(Message msg){
           switch (msg.what) {
        case SHOW_RESPONSE:
            String response=(String) msg.obj;//在這裏進行ui操作,將結果顯示在界面上
            responseText.setText(response);
        }
       }
   };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendRequest=(Button) findViewById(R.id.send_request);
        responseText=(TextView) findViewById(R.id.response);
        sendRequest.setOnClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.send_request){
            sendRequestWithHttpURLConnection();
        }

    }

    private void sendRequestWithHttpURLConnection() {
        // TODO Auto-generated method stub
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                HttpURLConnection connection=null;
                try{
                    HttpClient httpClient = new DefaultHttpClient();
                    HttpGet httpGet = new HttpGet("http://www.baidu.com");
                    HttpResponse httpResponse = httpClient.execute(httpGet);
                    if (httpResponse.getStatusLine().getStatusCode() == 200) {
                        // 請求和響應都成功了
                        HttpEntity entity = httpResponse.getEntity();
                        String response = EntityUtils.toString(entity, "utf-8");
                        Message message = new Message();
                        message.what = SHOW_RESPONSE;
                        // 將服務器返回的結果存放到Message中
                        message.obj = response.toString();
                        handler.sendMessage(message);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


}
發佈了37 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章