Android WiFi開發教程(三)——WiFi熱點數據傳輸

在上一篇文章中介紹了WiFi的搜索和連接,如果你還沒閱讀過,建議先閱讀上一篇Android WiFi開發教程(二)——WiFi的搜索和連接。本篇接着簡單介紹手機上如何通過WiFi熱點進行數據傳輸。

跟藍牙通訊一樣,WiFi熱點數據傳輸也是要運用到Socket。這裏我創建了兩個線程ConnectThread和ListenerThread,分別去處理數據傳輸和監聽連接。

ConnectThread

**
 * 連接線程
 * Created by 坤 on 2016/9/7.
 */
public class ConnectThread extends Thread{

    private final Socket socket;
    private Handler handler;
    private InputStream inputStream;
    private OutputStream outputStream;

    public ConnectThread(Socket socket, Handler handler){
        setName("ConnectThread");
        this.socket = socket;
        this.handler = handler;
    }

    @Override
    public void run() {
        if(socket==null){
            return;
        }
        handler.sendEmptyMessage(MainActivity.DEVICE_CONNECTED);
        try {
            //獲取數據流
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();

            byte[] buffer = new byte[1024];
            int bytes;
            while (true){
                //讀取數據
                bytes = inputStream.read(buffer);
                if (bytes > 0) {
                    final byte[] data = new byte[bytes];
                    System.arraycopy(buffer, 0, data, 0, bytes);

                    Message message = Message.obtain();
                    message.what = MainActivity.GET_MSG;
                    Bundle bundle = new Bundle();
                    bundle.putString("MSG",new String(data));
                    message.setData(bundle);
                    handler.sendMessage(message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 發送數據
     */
    public void sendData(String msg){
        if(outputStream!=null){
            try {
                outputStream.write(msg.getBytes());
                Message message = Message.obtain();
                message.what = MainActivity.SEND_MSG_SUCCSEE;
                Bundle bundle = new Bundle();
                bundle.putString("MSG",new String(msg));
                message.setData(bundle);
                handler.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                Message message = Message.obtain();
                message.what = MainActivity.SEND_MSG_ERROR;
                Bundle bundle = new Bundle();
                bundle.putString("MSG",new String(msg));
                message.setData(bundle);
                handler.sendMessage(message);
            }
        }
    }
}

在ConnectThread的構造中,傳入了Socket和Handler。Socket用來獲取數據以及發送數據,Handler用來更新UI了。在run方法中,我們從Socket中獲取到了輸入流和輸出流,然後循環地讀取InputStream的數據,當讀取到數據時,則通過Handler將數據更新到UI上。在sendData方法中主要是通過OutputStream寫入數據,然後將寫入結果通過Handler更新到UI上。

ListenerThread

/**
 * 監聽線程
 * Created by 坤 on 2016/9/7.
 */
public class ListenerThread extends Thread{

    private ServerSocket serverSocket = null;
    private Handler handler;
    private int port;
    private Socket socket;

    public ListenerThread(int port, Handler handler){
        setName("ListenerThread");
        this.port = port;
        this.handler = handler;
        try {
            serverSocket=new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void run() {
        while (true){
            try {
                //阻塞,等待設備連接
                socket = serverSocket.accept();
                Message message = Message.obtain();
                message.what = MainActivity.DEVICE_CONNECTING;
                handler.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public Socket getSocket() {
        return socket;
    }
}

監聽線程處理的邏輯就比較簡單,通過端口號獲取ServerSocket後調用accept()阻塞線程,直到有設備連接上後就通過Handler更新UI。這裏需要注意的是連接上的設備的端口號必須與這裏的端口號相同。接着我們看看Hander獲取到消息後做了哪些處理。

private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DEVICE_CONNECTING:
                    connectThread = new ConnectThread(listenerThread.getSocket(),handler);
                    connectThread.start();
                    break;
                    ... ...
            }
        }
    };

可以看到Handler獲取到數據後,通過listenerThread.getSocket()將獲取到Socket和handler一同創建了ConnectThread實例。

接下來就是用這兩個線程來處理數據傳輸了。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ... ...
        listenerThread = new ListenerThread(PORT, handler);
        listenerThread.start();
    }

在onCreate中我們創建ListenerThread並啓動它,讓它監聽是否有設備連接上來。當然這裏需要先開啓WiFi熱點後纔會有設備連接上來。這是開啓熱點並等待設備連接的情況。當然我們也可以主動去連接其他開啓着熱點的設備。

在監聽WiFi連接情況的廣播接收者中加入下面的代碼

if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
                    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                    final WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                    text_state.setText("已連接到網絡:" + wifiInfo.getSSID());

                    if (wifiInfo.getSSID().equals(WIFI_HOTSPOT_SSID)) {
                        //如果當前連接到的wifi是熱點,則開啓連接線程
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    ArrayList<String> connectedIP = getConnectedIP();
                                    for (String ip : connectedIP) {
                                        if (ip.contains(".")) {

                                            Socket socket = new Socket(ip, PORT);
                                            connectThread = new ConnectThread(socket, handler);
                                            connectThread.start();
                                        }
                                    }

                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                } else {
                    ...
                    }
            }

這裏本地固定了其他設備WiFi熱點的SSID,如果當前連接的WiFi的SSID跟我們之前保存的SSID一致,則證明我們連上了我們需要的WiFi熱點。然後通過getConnectedIP()獲取WiFi熱點的IP地址,通過這個IP地址和端口號創建一個Socket,然後創建ConnectThread來處理數據傳輸。到這裏我們可以看到,PORT和SSID這兩個數據是需要兩個設備事先協議好的。

最後再看看Handler完整的代碼

private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DEVICE_CONNECTING:
                    connectThread = new ConnectThread(listenerThread.getSocket(),handler);
                    connectThread.start();
                    break;
                case DEVICE_CONNECTED:
                    textview.setText("設備連接成功");
                    break;
                case SEND_MSG_SUCCSEE:
                    textview.setText("發送消息成功:" + msg.getData().getString("MSG"));
                    break;
                case SEND_MSG_ERROR:
                    textview.setText("發送消息失敗:" + msg.getData().getString("MSG"));
                    break;
                case GET_MSG:
                    textview.setText("收到消息:" + msg.getData().getString("MSG"));
                    break;
            }
        }
    };

至此,WiFi熱點數據傳輸也就介紹完了。如果有什麼疑問,歡迎和本人一起探討。

最後附上源碼地址

——————————————————————————————

github

csdn

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