主要是基於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中的消息循環機制。
下面簡單說明下這套機制:
引入消息機制後:
這套消息機制主要涉及到兩個類:Handler和Message
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方式向服務端請求數據。
以上就是向服務端請求數據的簡單學習。