Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android socket在系統休眠情況下調研

Android socket在系統休眠情況下調研

編輯:關於Android編程

做了3年的IM應用,一直沒有確認過socket在系統休眠的情況下會不會就收不到消息了,網上也搜過一些資料說android手機分為AP和BP兩個部分,系統休眠的時候AP是休眠的,而BP是不休眠的,網絡協議棧是運行在BP層的,所以當BP收到數據包的時候,系統會喚醒AP,但是AP運行的時間是很短的。雖然聽起來很有道理的樣子,但是沒有親手測試過,還是一塊心病~~~,今天又想起這事,索性動手自己寫代碼測試看看結果。

Server端code:
public class TestServer {
    public static void main(String[] argv) {
        ServerSocket serverSocket;
        try {
            serverSocket = new ServerSocket(4444);
            Socket client;
            while((client = serverSocket.accept()) != null) {
                new ClientThread(client).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static class ClientThread extends Thread {
        private Socket socket;
        private OutputStream outputStream;
        public ClientThread(Socket client) {
            socket = client;
            try {
                outputStream = socket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void run() {
            int index = 0;
            while(true) {
                try {                                        outputStream.write((hello+index+
).getBytes());
                    index++;
                    System.out.println(send);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(60*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

代碼很簡單,Server每隔60s給client發送一句hello跟index序號。

Client端code:

public class TestActivity extends Activity {

    private FileOutputStream outputStream = null;
    private WakeLock mWakelock;

    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            try {
                outputStream.write((new Date().toString() + ((String) msg.obj) +   savelocal
)
                        .getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
//            releaseWakeLock();
        }
    };

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new Thread(new Runnable() {

            @Override
            public void run() {
                File file = new File(/sdcard/testlog-lock.txt);
                if (file.exists()) {
                    file.delete();
                }
                try {
                    file.createNewFile();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }

                try {
                    outputStream = new FileOutputStream(file);
                } catch (FileNotFoundException e2) {
                    e2.printStackTrace();
                }
                try {

                    Socket socket = new Socket();
                    socket.connect(new InetSocketAddress(10.140.82.31, 4444));
                    InputStream inputStream = socket.getInputStream();
                    BufferedReader inputStream2 = new BufferedReader(new InputStreamReader(
                            inputStream));
                    String lineString;
                    while ((lineString = inputStream2.readLine()) != null) {
//                        acquireWakeLock();
                        outputStream.write((new Date().toString() + lineString +  receive
)
                                .getBytes());
                        Message msgMessage = handler.obtainMessage(1, lineString);
                        handler.sendMessageDelayed(msgMessage, 5000);
                    }
                } catch (UnknownHostException e) {          
                    try {
                        outputStream.write(e.getMessage().getBytes());
                    } catch (IOException e1) {             
                        e1.printStackTrace();
                    }
                } catch (IOException e) {                   
                    try {
                        outputStream.write(e.getMessage().getBytes());
                    } catch (IOException e1) {                       
                        e1.printStackTrace();
                    }
                }
            }
        }).start();

    }

    private void acquireWakeLock() {
        if (mWakelock == null) {
            PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lock);
        }
        mWakelock.acquire();
    }

    private void releaseWakeLock() {
        if (mWakelock != null && mWakelock.isHeld()) {
            mWakelock.release();
        }
        mWakelock = null;
    }
}

代碼也不復雜,Client啟動的時候會建立一個Thread去連接Server,每收到一個包就馬上往文件裡寫入收到的內容和時間戳,然後過5s後再次往文件裡寫入相同的內容和時間戳。為什麼要5s呢?因為我想驗證一下socket讀取到包之後,是不是運行一會就馬上又休眠了,如果是的,那麼5s後,第2次是不會准時寫入文件的,因為系統休眠了,程序是不會執行的, Handler裡面的Message也就不能執行了。重要的地方是那句acquireWakelock和releaseWakelock, 如果wake了,那麼第2次寫入肯定是5s內完成。

    所以我們注釋wakelock和打開wakelock測試兩次,驗證3件事情:

1. 系統休眠後還能不能收到包,
2. 收到包之後,注釋wakelock,是什麼行為,
3. 打開wakelock,是什麼行為。

注意測試的時候要斷開usb,因為連著usb的時候手機是不會休眠的,然後運行App,把App放後台關閉手機屏幕,分別測試半小時,看看log來驗證下猜想。
下面是測試下次的Client的log,

1. 不加wakelock

1 Mon Jul 20 22:37:16 CDT 2015hello0 receive
2 Mon Jul 20 22:37:21 CDT 2015hello0 savelocal
3 Mon Jul 20 22:38:15 CDT 2015hello1 receive
4 Mon Jul 20 22:39:15 CDT 2015hello2 receive
5 Mon Jul 20 22:40:15 CDT 2015hello3 receive
6 Mon Jul 20 22:40:15 CDT 2015hello1 savelocal
7 Mon Jul 20 22:41:15 CDT 2015hello4 receive
8 Mon Jul 20 22:42:15 CDT 2015hello5 receive
9 Mon Jul 20 22:42:15 CDT 2015hello2 savelocal
10 Mon Jul 20 22:43:15 CDT 2015hello6 receive
11 Mon Jul 20 22:43:15 CDT 2015hello3 savelocal
12 Mon Jul 20 22:44:15 CDT 2015hello7 receive
13 Mon Jul 20 22:45:15 CDT 2015hello8 receive
14 Mon Jul 20 22:46:15 CDT 2015hello4 savelocal
15 Mon Jul 20 22:47:15 CDT 2015hello10 receive
16 Mon Jul 20 22:48:15 CDT 2015hello11 receive
17 Mon Jul 20 22:48:15 CDT 2015hello5 savelocal
18 Mon Jul 20 22:49:15 CDT 2015hello12 receive
19 Mon Jul 20 22:49:15 CDT 2015hello6 savelocal

這裡只貼了部分log,可以看到數據包都以每個60s的間隔收到了,但是那個5s後save的Message代碼並沒有按照5s的頻率執行,而是等到後續的包收到之後,程序被喚醒了一下,逮到個執行空隙執行了一下。

加wakelock

1 Mon Jul 20 23:27:37 CDT 2015hello0 receive
2 Mon Jul 20 23:27:42 CDT 2015hello0 savelocal
3 Mon Jul 20 23:28:37 CDT 2015hello1 receive
4 Mon Jul 20 23:28:42 CDT 2015hello1 savelocal
5 Mon Jul 20 23:29:37 CDT 2015hello2 receive
6 Mon Jul 20 23:29:42 CDT 2015hello2 savelocal
7 Mon Jul 20 23:30:37 CDT 2015hello3 receive
8 Mon Jul 20 23:30:42 CDT 2015hello3 savelocal
9 Mon Jul 20 23:31:37 CDT 2015hello4 receive
10 Mon Jul 20 23:31:42 CDT 2015hello4 savelocal
11 Mon Jul 20 23:32:37 CDT 2015hello5 receive
12 Mon Jul 20 23:32:42 CDT 2015hello5 savelocal
13 Mon Jul 20 23:33:37 CDT 2015hello6 receive
14 Mon Jul 20 23:33:42 CDT 2015hello6 savelocal
15 Mon Jul 20 23:34:37 CDT 2015hello7 receive

可以看到save的代碼是以5s的延遲之後保證得到了運行。

OK,結論:
1. 在系統休眠的情況下,socket是能准時收到包的
2. 收到包之後,程序馬上就會再次休眠,後續想要執行一段長時間的代碼,最好是獲取一下wakelock保證這些代碼能執行到,之後釋放wakelock。這個其實很像BroadcastReceiver,系統在onReceive函數執行期間是會自動幫我們獲取wakelock的,出了這個函數就會釋放wakelock,所以如果自己想要執行一段長時間的代碼,那麼就要自己獲取跟釋放wakelock, 或者Framework裡面有提供一個叫WakefulBroadcastReceiver替我們做了這些事情。

Note:我只測試了wifi的情況下,那個BP好像只是指radio跟wifi芯片不是一個東西,不過感覺跟3g的情況下應該差不多~~~改天試試看

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved