編輯:關於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的頻率執行,而是等到後續的包收到之後,程序被喚醒了一下,逮到個執行空隙執行了一下。
加wakelock1 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的情況下應該差不多~~~改天試試看
今天花了整個下午+晚上的的時間學習了Activity的啟動模式,本來以為這個知識點很簡單,但是在學習的過程中發現,Activity的啟動模式並沒有
搭建JAVA開發環境根據操作系統分為x86或x64位的,下載jdk1.8以上的版本,本機安裝時的java版本:jdk-8u45-windows-x64.exe配置JAVA
剛開始打算做一個簡單的截屏程序時,以為很輕松就能搞定。 在Activity上放一個按鈕,點擊完成截屏操作,並將數據以圖片形式保存
重要的開發者功能 多窗口支持 通知 JIT/AOT 編譯 快速的應用安裝路徑 外出瞌睡模式 後台優化 Data Saver 快速設置圖塊 API 號碼屏蔽 來電過濾 區