看這裏:Android必備:Android Socket編程的瞭解與學習整理html
最近學習Android的過程當中,因爲項目、業務等因素影響,服務端經過Socket進行通訊,因而開始學習Socket編程,以前的開發中,不多涉及此 方面的知識學習,本篇就來簡單的整理一下,經過Android客戶端進行Socket登陸的demo,來進行Adnroid Socket編程的學習。java
在開始學習以前,先來了解一下Socket,如下內容來自百度百科:android
一般也稱做"套接字",用於描述IP地址和端口,是一個通訊鏈的句柄。在Internet上的主機通常運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket,並綁定到一個端口上,不一樣的端口對應於不一樣的服務。
git
首先,來介紹一下項目的設計,只包含兩個UI佈局文件:login.xml和main.xml,對應登陸頁和主頁,登陸頁包含一個用戶名的輸入框和登陸按 鈕,點擊登陸按鈕,登陸按鈕顯示文字「正在鏈接,請稍候...」,經過Socket進行登陸,並跳轉到主頁,若是用戶名是admin,則在主頁顯示「登陸 成功!」反之顯示「登陸失敗!」。web
下面是demo運行後的具體效果圖:編程
login.xml:
服務器
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:hint="請輸入用戶名" android:ems="10" android:id="@+id/loginName" /> <Button android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="登陸" android:id="@+id/loginBtn" /> </LinearLayout>
main.xml:網絡
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:id="@+id/mainText" /> </LinearLayout>
固然經過Socket進行通訊的時候,咱們須要app擁有網絡訪問即Internet或Wifi的權限,將下面兩行添加到AndroidManifest.xml:app
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET"/>
下面開始進行實例的編寫,本篇的學習基於TCP/ IP 進行Socket通訊,說是Android Socket編程,其實使用的是java.net包下提供的ServerSocket和Socket類,這是一種比較底層的編程方式,Socket類用來創建客戶端程序,ServerSocket用來創建服務端程序,首先來看服務端的代碼:socket
package com.xx566.socket.server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketServer { private static ServerSocket serverSocket; public static void main(String[] args) throws IOException { serverSocket = new ServerSocket(8888); while (true) { final Socket socket = serverSocket.accept(); try { // 獲取輸入流 BufferedReader inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 獲取輸出流 PrintWriter outputStream = new PrintWriter(socket.getOutputStream()); // 讀取輸入 String readString = inputStream.readLine(); if ("admin".equals(readString)) { outputStream.println("登陸成功!"); } else { outputStream.println("登陸失敗!"); } outputStream.flush(); // 關閉 outputStream.close(); inputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
咱們在8888端口,實例化了Socket服務端,經過永真循環,來等待客戶端Socket的鏈接。accept()方法返回一個對應客戶端的Socket,服務端讀取客戶端輸入,若是輸入的是"admin",則輸出"登陸成功!",反之,輸出"登陸失敗!",接下來,咱們主要來看一下客戶端LoginActivity的編寫,須要注意的是,在Android4.0系統以上的系統中,是不容許在主線程中執行網絡相關的請求,不然會拋出NetworkOnMainThreadException異常,因此須要單獨的線程向服務端發送Socket,完整代碼以下:
package com.xx566.socket; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.EditText; import java.io.*; import java.net.Socket; public class LoginActivity extends Activity { private Button loginBtn; private EditText loginName; PrintWriter outputStream; BufferedReader inputStream; Socket socket; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //經過handler處理接收到的消息 if (msg.what == 1) { //跳轉到主頁面,顯示登陸結果 Intent intent = new Intent(LoginActivity.this, MainActivity.class); intent.putExtra("result", msg.getData()); startActivity(intent); } } }; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login); //登陸按鈕點擊事件 loginBtn = (Button) findViewById(R.id.loginBtn); loginName = (EditText) findViewById(R.id.loginName); loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //點擊登陸後,顯示正在鏈接服務器 loginBtn.setText("正在鏈接,請稍候..."); loginBtn.setClickable(false); final String userName = loginName.getText().toString(); //經過Socket登陸服務器,簡單的傳遞用戶名 new Thread() { @Override public void run() { //處理接收到的消息 Message message = new Message(); message.what = 1; Bundle bundle = new Bundle(); String result = ""; try { socket = new Socket("192.168.0.32", 8888); outputStream = new PrintWriter(socket.getOutputStream()); inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); outputStream.println(userName); outputStream.flush(); //讀取結果 while (true) { result = inputStream.readLine(); if (!"".equals(result)) { break; } } //關閉 inputStream.close(); outputStream.close(); socket.close(); } catch (Exception e) { result = "網絡異常!"; } bundle.putString("result", result); message.setData(bundle); //傳遞消息 handler.sendMessage(message); } }.start(); } }); } @Override protected void onResume() { super.onResume(); loginBtn.setText("登陸"); loginBtn.setClickable(true); } }
這裏使用了Android Handler機制進行了線程間消息的傳遞,主要是接收服務端響應的結果,啓動MainActicity。MainActivity裏面顯示登陸結果,代碼以下:
package com.xx566.socket; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class MainActivity extends Activity { private TextView mainText; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mainText = (TextView) findViewById(R.id.mainText); Bundle bundle = getIntent().getExtras().getBundle("result"); mainText.setText(bundle.getString("result")); } }