1. 程式人生 > >Android-HttpClient連線網路獲取資料

Android-HttpClient連線網路獲取資料

    大部分Android App都使用HttpURLConnection 和 Apache HTTP Client來發送和接收網路資料(不包括第三方開源專案),這兩者都支援HTTPS,流上傳和下載,可配置超時,IPv6和連線池。     1)關於Apache HTTP Client:     DefaultHttpClient(android5.1\external\apache-http\src\org\apache\http\impl\client\DefaultHttpClient.java)和      AndroidHttpClient(android5.1\frameworks\base\core\java\android\net\http\AndroidHttpClient.java)都繼承於HttpClient。它們有龐大且靈活的API,還比較穩定,儘管有少量的bug。然而在不破壞它們相容性的前提下,它們龐大的API卻阻礙了它們得到進一步的改進和提升。為此,Android 團隊慢慢開始放棄Apache HTTP Client,在Android 6.0中,已經移除了Apache HTTP Client,在Android 官方文件中可查:
http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client。     2)關於HttpURLConnection:     HttpURLConnection的是一個通用的,適用於大多數應用的輕量級HTTP客戶端。這個類出現的時候比較低調,因為其早期版本會有一些bug,但其專注的API使得它們很容易被穩步改善。在升級到Android2.2之前,HttpURLConnection有些令人沮喪的錯誤,特別是,在一個可讀的InputStream中呼叫close(),可能會毒害這個連結池。為此需要禁用連線池:
privatevoid disableConnectionReuseIfNecessary(){
    // HTTP connection reuse which was buggy pre-froyo
    if(Integer.parseInt(Build.VERSION.SDK)<Build.VERSION_CODES.FROYO){
        System.setProperty("http.keepAlive","false");
    }
}
使用HttpURLConnection類::
        (1)使用Url.openConnection()獲得一個新的
HttpURLConnection。         (2)準備request:request主要屬性是它的url。request header可以包括metadata,比如憑證(credentials),首選內容型別和session cookies。         (3)選擇性的上傳request的主體,如果它們包括一個request body,例項物件必須設定setDoOutput(true)。被寫入到stream的傳輸資料通過getOutputStream返回。         (4)讀取response,response header通常包括metadata,如response主體內容型別和長度、修改日期和session cookies。response主體可能從通過getInputStream返回的stream中讀取的。如果response沒有主體,該方法返回一個空的stream。         (5)斷開:一旦response主體被讀取到,HttpURLConnection應該呼叫disconnect()來斷開,釋放連線所持有的資源。
    綜合上述,以HttpURLConnection為例來實現簡單連線網路獲取資料:
    1)首先在Manifest檔案中增加訪問網路的許可權:
 <uses-permissionandroid:name="android.permission.INTERNET"/>
     <uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/>
    2)檢測手機聯網的狀態,手機可能沒有聯網,連線了網路,還要區分是移動資料還是WIFI。同時在網路連線發生變化時,需要接受系統的廣播:           android.net.conn.CONNECTIVITY_CHANGE,所以需要註冊廣播。這裡簡單的用一個類來管理網路連線的狀態:
public class NetConnectMananger {
    private Context mContext;
    private ConnectivityManager cm;
    private NetworkInfo networkInfo;
    private NetWorkChangedReceiver mNetWorkChangedReceiver;
   
    //判斷是否是WIFI連線網路
    private static boolean isWifiConnected = false;
    //判斷是否是移動資料連線網路
    private static boolean isMobileConnected = false;
   
    public NetConnectMananger(Context context){
        mContext = context;
        cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        setMobileType();      
        //動態註冊廣播
        mNetWorkChangedReceiver = new NetWorkChangedReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        context.registerReceiver(mNetWorkChangedReceiver, intentFilter);
    }
   
    public boolean isWifiNetWork(){
        return isWifiConnected;
    }
   
    public boolean isMobileNetWork(){
        return isMobileConnected;
    }
   
    /**
     * 根據當前網路的狀態來設定網路連線的TYPE
     * */
    private void setMobileType(){
        networkInfo = cm.getActiveNetworkInfo();
        if(networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE){
            isMobileConnected = true;
        }else if(networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI){
            isWifiConnected = true;    
        }else{
            isWifiConnected = false;
            isMobileConnected = false;
        }  
    }
    /**
     * 取消廣播的註冊
     * */
    public void unRegisterNetWorkChangedReceiver(){
        mContext.unregisterReceiver(mNetWorkChangedReceiver);
    }
   
    /**
     * 接收網路連線發生改變的廣播:android.net.conn.CONNECTIVITY_CHANGE
     * */
    public class NetWorkChangedReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            setMobileType();
        }
       
    }<span style="font-family: 微軟雅黑; widows: auto; background-color: inherit;"> </span><span style="font-family: 微軟雅黑; widows: auto; background-color: inherit;"> </span>
    3)非同步執行網路操作:因為在主執行緒執行網路操作,如果網路操作執行的時間稍長,就可能導致UI主執行緒執行緒ANR,這裡以Async Task來非同步執行網路操作:
   ...
     private static final String url = http://www.weather.com.cn/data/sk/101010100.html;
     private NetConnectMananger ncm;
       ...

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_start_http:
                if(ncm.isMobileNetWork() || ncm.isWifiNetWork()){
                    new DownLoadTask().execute(url);
                }else{
                    Toast.makeText(getApplicationContext(), "請確認網路是否連線!", Toast.LENGTH_LONG).show();
                }
                break;
               
            default:
                break;
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消ncm中註冊的廣播。
        ncm.unRegisterNetWorkChangedReceiver();
    }
    private class DownLoadTask extends AsyncTask<String, Void, String>{

        @Override
        protected String doInBackground(String... url) {
           
            if(url != null){
                try {
                    return downLoadData(url[0]);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return null;
        }
       
        @Override
        protected void onPostExecute(String result) {
            mTextView.setText(result);
        }
       
        public String downLoadData(String url) throws IOException{
            InputStream stream = null;
            int len = 500;
            if(url == null){
                Toast.makeText(getApplicationContext(), "無效網址!", Toast.LENGTH_LONG).show();
                return null;
            }
            URL mUrl = new URL(url);
            HttpURLConnection urlConnection = (HttpURLConnection) mUrl.openConnection();
            try{
            urlConnection.setReadTimeout(1000);
            urlConnection.setConnectTimeout(20000);
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoInput(true);
           
            urlConnection.connect();
            int response = urlConnection.getResponseCode();
            Log.i(TAG, "The response is: " + response);
            stream = urlConnection.getInputStream();
            String dataString = getStringFromStream(stream, len);
            return dataString;
           
            }finally{
                if(stream != null){
                    stream.close();
                }
                if(urlConnection != null){
                    urlConnection.disconnect();
                }
            }
        }          
        public String getStringFromStream(InputStream in, int len) throws UnsupportedEncodingException, IOException{
            Reader reader = null;
            reader = new InputStreamReader(in, "UTF-8");      
            char[] buffer = new char[len];
            reader.read(buffer);
            return new String(buffer);
        }
    }

參考:http://developer.android.com/training/basics/network-ops/connecting.html       http://developer.android.com/reference/java/net/HttpURLConnection.html       http://developer.android.com/training/basics/network-ops/managing.html