android菜鳥學習筆記24----與服務器端交互(一)使用HttpURLConnection和HttpClient請求服務端數據

主要是基於HTTP協議與服務端進行交互。php

涉及到的類和接口有:URL、HttpURLConnection、HttpClient等android

URL安全

 

使用一個String類型的url構造一個URL對象,如:服務器

URL url = new URL(http://10.0.2.2/index.php);

 

 

openConnection()方法返回一個對指定url的資源的鏈接。返回類型是URLConnection,可是,因爲這裏咱們通常用的是http協議,因此返回的實際是HttpURLConnection對象,故通常能夠進行類型轉換。網絡

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

 

HttpURLConnection:ide

繼承自URLConnection,經常使用方法有:函數

 

getInputStream()方法用來獲取用來從網絡鏈接中讀取數據的輸入流。佈局

 

getOutputStream()方法用於獲取用於向網絡鏈接中寫入數據的輸出流。post

 

setDoOutput()和setDoInput()方法分別用來設置是否容許向網絡寫入或讀取數據。學習

 

setReadTimeout()方法用於設置讀取數據超時時限。

 

setConnectTimeout()方法用於設置網絡鏈接超時時限。

 

setRequestMethod()方法用於設置請求的方法,通常經常使用」GET」或」POST」。

 

getResponseCode()和getResponseMessage()方法分別用來獲取服務端的響應碼及響應信息字符串描述。

 

Disconnect()方法用於關閉網絡鏈接。

1.使用HttpURLConnection與服務端進行交互

佈局文件代碼:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2 
 3     xmlns:tools="http://schemas.android.com/tools"
 4 
 5     android:layout_width="match_parent"
 6 
 7     android:layout_height="match_parent"
 8 
 9     android:orientation="vertical"
10 
11     tools:context="cn.csc.start.MainActivity" >
12 
13     <EditText
14 
15         android:id="@+id/et_username"
16 
17         android:layout_width="match_parent"
18 
19         android:layout_height="wrap_content"
20 
21         android:hint="@string/et_username_text"/>
22 
23     <EditText
24 
25         android:id="@+id/et_password"
26 
27         android:layout_width="match_parent"
28 
29         android:layout_height="wrap_content"
30 
31         android:inputType="textPassword"
32 
33         android:hint="@string/et_password_text"/>
34 
35     <Button
36 
37         android:id="@+id/btn_login"
38 
39         android:layout_width="wrap_content"
40 
41         android:layout_height="wrap_content"
42 
43         android:text="@string/btn_text"
44 
45         />
46 
47 </LinearLayout>

一個簡單的php文件,模擬服務器端:

 1 <?php
 2 
 3 if(isset($_REQUEST["username"])&& isset($_REQUEST["password"])){
 4 
 5       $username = $_REQUEST["username"];
 6 
 7       $password = $_REQUEST["password"];
 8 
 9       if($username == "zhangsan" && $password == "123"){
10 
11            echo "login success";
12 
13       }else{
14 
15            echo "login failure";
16 
17       }
18 
19 }else{
20 
21       echo "no field allowed empty string";
22 
23 }
24 
25 ?>

客戶端提交用戶名密碼,客戶端返回登陸的結果。

 注意,在模擬器中用IP:10.0.2.2表明電腦的IP地址。

1.1使用GET方式與服務端進行交互

 1 public class MainActivity extends ActionBarActivity implements OnClickListener {
 2 
 3  
 4 
 5     protected static final int OK = 0;
 6 
 7       protected static final String TAG = "MYLOG";
 8 
 9       private EditText et_username;
10 
11       private EditText et_password;
12 
13       @Override
14 
15     protected void onCreate(Bundle savedInstanceState) {
16 
17         super.onCreate(savedInstanceState);
18 
19         setContentView(R.layout.activity_main);
20 
21         Button btn = (Button) findViewById(R.id.btn_login);
22 
23         btn.setOnClickListener(this);
24 
25         et_username = (EditText) findViewById(R.id.et_username);
26 
27         et_password = (EditText) findViewById(R.id.et_password);
28 
29 }
30 
31   @Override
32 
33   public void onClick(View view) {
34 
35         // TODO Auto-generated method stub
36 
37         if(view.getId() == R.id.btn_login){
38 
39              get_test();
40 
41         }
42 
43   }
44 
45 private void get_test() {
46 
47         // TODO Auto-generated method stub
48 
49         String username = et_username.getText().toString();
50 
51         String password = et_password.getText().toString();
52 
53         try {
54 
55              URL url = new URL("http://10.0.2.2/index.php?username="+username+"&password="+password);
56 
57              HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
58 
59              conn.setRequestMethod("GET");
60 
61              conn.setConnectTimeout(5000);
62 
63              conn.setReadTimeout(5000);
64 
65              if(conn.getResponseCode() == 200){
66 
67                    InputStream is = conn.getInputStream();
68 
69                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
70 
71                    String result = br.readLine();
72 
73                    Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
74 
75                    conn.disconnect();
76 
77              }
78 
79             
80 
81         } catch (Exception e) {
82 
83              // TODO Auto-generated catch block
84 
85              e.printStackTrace();
86 
87         }
88 
89   }
90 
91 }

1.2使用POST方式與服務端進行交互

添加一個post_test方法:

 1 private void post_test(){
 2 
 3         try {
 4 
 5              URL url = new URL("http://10.0.2.2/index.php");
 6 
 7              HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 8 
 9              conn.setRequestMethod("POST");
10 
11              conn.setDoOutput(true);
12 
13              conn.setConnectTimeout(5000);
14 
15              conn.setReadTimeout(5000);
16 
17              String username = et_username.getText().toString();
18 
19              String password = et_password.getText().toString();
20 
21              OutputStream os = conn.getOutputStream();
22 
23              String req = "username="+username+"&password="+password;
24 
25             
26 
27              os.write(req.getBytes());
28 
29              if(conn.getResponseCode()== 200){
30 
31                    InputStream is = conn.getInputStream();
32 
33                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
34 
35                    String result = br.readLine();
36 
37                    Toast.makeText(this, result, Toast.LENGTH_LONG).show();
38 
39                    is.close();
40 
41                    os.close();
42 
43                    conn.disconnect();
44 
45              }              
46 
47         } catch (Exception e) {
48 
49              // TODO Auto-generated catch block
50 
51              e.printStackTrace();
52 
53         }
54 
55 }

而後在onClick()中調用該方法。

注意到,這裏因爲只有一個線程,即在主線程(UI線程)中請求服務器,如有耗時操做,此時應用是不會響應用戶操做的,這就是傳說中的ANR異常

因此,就必須新建一個子線程執行耗時操做。

修改get_test()方法,新建一個線程執行該方法中的操做:

 1 private void get_test() {
 2 
 3         new Thread(new Runnable() {
 4 
 5              @Override
 6 
 7              public void run() {
 8 
 9                    String username = et_username.getText().toString();
10 
11                    String password = et_password.getText().toString();
12 
13                    try {
14 
15                         URL url = new URL("http://10.0.2.2/index.php?username="+username+"&password="+password);
16 
17                         HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
18 
19                         conn.setRequestMethod("GET");
20 
21                         conn.setConnectTimeout(5000);
22 
23                         conn.setReadTimeout(5000);
24 
25                         if(conn.getResponseCode() == 200){
26 
27                               InputStream is = conn.getInputStream();
28 
29                               BufferedReader br = new BufferedReader(new InputStreamReader(is));
30 
31                               String result = br.readLine();
32 
33                               Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
34 
35                               conn.disconnect();
36 
37                         }
38 
39                        
40 
41                    } catch (Exception e) {
42 
43                         // TODO Auto-generated catch block
44 
45                         e.printStackTrace();
46 
47                    }
48 
49              }
50 
51         }).start();
52 
53   }

這時從新運行程序,會發現新的問題:

提示,沒法在非UI線程中進行UI操做,由於這樣不安全

爲了解決這個問題,android提供了一套消息處理機制,很像win32中的消息循環機制。

下面簡單說明下這套機制:

 

引入消息機制後:

 

這套消息機制主要涉及到兩個類:HandlerMessage

Handler

通常須要自定義Handler繼承Handler類,並重寫消息處理方法,通常將其對象在UI線程中定義,這樣就能夠在其消息處理方法中進行UI操做了。

經常使用方法:

 

消息處理回調函數,通常自定義的Handler類都要重寫該方法,添加本身須要的消息處理業務邏輯。

 

sendMessage(Message msg)發送一條消息。

Message

消息類,其對象做爲消息實體被handler對象發送或者接收處理。

 

使用無參構造建立一個消息對象,通常在發送以前還須要設置其兩個主要的屬性:

 

what屬性,能夠用來存放消息的類型

 

obj屬性,能夠用來存放想要傳送的消息內容或者傳遞的其餘參數等。

 

修改上面的應用,添加消息處理機制:

在MainActivity中添加個Handler類型的私有屬性:

 1 private Handler handler = new Handler(){
 2 
 3            public void handleMessage(android.os.Message msg) {
 4 
 5                  if(msg.what == OK){
 6 
 7                       String str = msg.obj.toString();
 8 
 9                       Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
10 
11                      
12 
13                  }
14 
15            }
16 
17 };

重寫的消息處理函數,很簡單,就是把服務端返回的信息經過Toast顯示出來。

添加一個方法,新建線程請求服務端數據,並經過消息機制發送消息:

 1 private void multi_thread_test(){
 2 
 3            new Thread(new Runnable() {
 4 
 5                 
 6 
 7                  @Override
 8 
 9                  public void run() {
10 
11                       // TODO Auto-generated method stub
12 
13                       try {
14 
15                             URL url = new URL("http://10.0.2.2/index.php");
16 
17                             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
18 
19                             conn.setRequestMethod("POST");
20 
21                             conn.setDoOutput(true);
22 
23                             conn.setConnectTimeout(5000);
24 
25                             conn.setReadTimeout(5000);
26 
27                             String username = et_username.getText().toString();
28 
29                             String password = et_password.getText().toString();
30 
31                             OutputStream os = conn.getOutputStream();
32 
33                             String req = "username="+username+"&password="+password;
34 
35                            
36 
37                             os.write(req.getBytes());
38 
39                             if(conn.getResponseCode()== 200){
40 
41                                   InputStream is = conn.getInputStream();
42 
43                                   BufferedReader br = new BufferedReader(new InputStreamReader(is));
44 
45                                   String result = br.readLine();
46 
47                                   Message msg = new Message();
48 
49                                   msg.what = OK;
50 
51                                   msg.obj = result;
52 
53                                   handler.sendMessage(msg);
54 
55                                   is.close();
56 
57                                   os.close();
58 
59                                   conn.disconnect();
60 
61                             }                    
62 
63                       } catch (Exception e) {
64 
65                             // TODO Auto-generated catch block
66 
67                             e.printStackTrace();
68 
69                       }
70 
71                  }
72 
73            }).start();
74 
75 }

 

這樣,在請求服務端數據時,應用還能響應用戶的交互。

 

2.還有另外一種與服務端進行交互的方式,那就是使用HttpClient

通常經過:

 HttpClient client = new defaultHttpClient() 構造出HttpClient對象。

HttpClient類最主要的一個方法就是execute()方法。

 

經常使用的是隻有一個參數的重載形式,注意到其參數類型是HttpUriRequest類型。

查看幫助手冊:

 

HttpUriRequest是一個接口

 

已知的直接實現類,有那麼多個,最經常使用的是HttpGet和HttpPost,從名字中即可知道,一個用於get方式與服務端交互,一個用於post方式與服務端交互。

HttpGet的使用比較簡單

 

通常直接使用傳入String類型的url構造出HttpGet對象,而後做爲execute()的參數便可完成get方式請求。

HttpPost的使用要稍微麻煩一點,由於GET方式直接在URL中傳入了請求參數,而POST方式須要另一種傳參方式。

POST方式的參數須要使用一個List<NameValuePair>類型的對象傳遞,

NameValuePair是一個接口,通常使用的是其直接實現類BasicNameValuPair類:

如:

1 List<NameValuePair> params = new ArrayList<NameValuePair>();
2 
3 params.add(new BasicNameValuePair("username", username));
4 
5 params.add(new BasicNameValuePair("password", password));

要POST的參數存儲完成,如何經過HttpPost提交呢?

注意到,幫助手冊中關於HttpPost的信息:

 

HttpPost是經過繼承HttpEntitiyEnclosingRequestBase類間接實現HttpUriRequest接口的。

該類中有一個方法:

 

能夠經過setEntity()方法將參數傳遞給HttpPost對象,具體作法以下:

1 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,"utf-8");
2 
3 httppost.setEntity(entity);

下面在MainActivity中添加方法,經過HttpClient方法與服務端進行交互:

 1 private void client_get_test(){
 2 
 3            new Thread(new Runnable() {
 4 
 5                 
 6 
 7                  @Override
 8 
 9                  public void run() {
10 
11                       // TODO Auto-generated method stub
12 
13                       String username = et_username.getText().toString();
14 
15                       String password = et_password.getText().toString();
16 
17                       HttpClient client = new DefaultHttpClient();
18 
19                       HttpGet get = new HttpGet("http://10.0.2.2/index.php?username="+username+"&password="+password);
20 
21                       try {
22 
23                             HttpResponse response = client.execute(get);
24 
25                             if(response.getStatusLine().getStatusCode() == 200){
26 
27                                   HttpEntity entity = response.getEntity();
28 
29                                   String result = EntityUtils.toString(entity, "utf-8");
30 
31                                   Message msg = new Message();
32 
33                                   msg.what = OK;
34 
35                                   msg.obj = result;
36 
37                                   handler.sendMessage(msg);
38 
39                             }
40 
41                       } catch (ClientProtocolException e) {
42 
43                             // TODO Auto-generated catch block
44 
45                             e.printStackTrace();
46 
47                       } catch (IOException e) {
48 
49                             // TODO Auto-generated catch block
50 
51                             e.printStackTrace();
52 
53                       }
54 
55                  }
56 
57            }).start();
58 
59       }

 

使用HttpClient採用GET方式向服務端請求數據

 1 private void client_post_test(){
 2 
 3            new Thread(new Runnable() {
 4 
 5                 
 6 
 7                  @Override
 8 
 9                  public void run() {
10 
11                       // TODO Auto-generated method stub
12 
13                      
14 
15                       try {
16 
17                             String username = et_username.getText().toString();
18 
19                             String password = et_password.getText().toString();
20 
21                             HttpClient client = new DefaultHttpClient();
22 
23                             HttpPost post = new HttpPost("http://10.0.2.2/index.php");
24 
25                             List<NameValuePair> params = new ArrayList<NameValuePair>();
26 
27                             params.add(new BasicNameValuePair("username", username));
28 
29                             params.add(new BasicNameValuePair("password", password));
30 
31                             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,"utf-8");
32 
33                             post.setEntity(entity);
34 
35                             HttpResponse response = client.execute(post);
36 
37                             if(response.getStatusLine().getStatusCode() == 200){
38 
39                                   HttpEntity entity1 = response.getEntity();
40 
41                                   String result = EntityUtils.toString(entity1, "utf-8");
42 
43                                   Message msg = new Message();
44 
45                                   msg.what = OK;
46 
47                                   msg.obj = result;
48 
49                                   handler.sendMessage(msg);
50 
51                             }
52 
53                       } catch (ClientProtocolException e) {
54 
55                             // TODO Auto-generated catch block
56 
57                             e.printStackTrace();
58 
59                       } catch (IOException e) {
60 
61                             // TODO Auto-generated catch block
62 
63                             e.printStackTrace();
64 
65                       }
66 
67                  }
68 
69            }).start();
70 
71 }

使用HttpClient採用POST方式向服務端請求數據。

以上就是向服務端請求數據的簡單學習。

相關文章
相關標籤/搜索