android service與子執行緒之淺談
阿新 • • 發佈:2019-02-06
最近在做一個android的專案,有一個操作是首先將接收的資料處理分析,然後將處理過的資料儲存到資料庫中。這將是一個十分耗時的工作。我直接將這一操作寫在了UI主執行緒中。結果log中提示不要把耗時的工作在主執行緒中完成。於是在網上查閱了一下,發現網上有兩種說法:一種說寫到一個service中去,一種則是開啟子執行緒。於是我就模糊了,到底應該選擇哪一種呢?這 裡首先應該清楚什麼是service,什麼是子執行緒,以及二者的區別。以下是我從網上整理出來的。
“服務不是單一的程序。服務沒有自己的程序,應用程式可以不同,服務執行在相同的程序中。
服務不是執行緒。可以線上程中工作。在應用中,如果是長時間的在後臺執行,而且不需要互動的情況下,使用服務。同樣是在後臺執行,不需要互動的情況下,如果只是完成某個任務,之後就不需要執行,而且可能是多個任務,需需要長時間執行的情況下使用執行緒。如果任務佔用CPU時間多,資源大的情況下,要使用執行緒。” 這段文字讓我最終決定使用執行緒。因為服務也是工作在主執行緒中的,如果服務中要執行耗時的工作也是會阻塞主執行緒,所以得用主執行緒。 “如果需要完成一項比較耗時的工作,應該通過傳送Intent給Service,由Service來完成.這裡不能使用子執行緒來解決,因為BroadcastReceiver的生命週期很短,子執行緒可能還沒有結束,BroadcastReceiver就先結束了.BroadcastReceiver一旦結束,此時BroadcastReceiver的所在程序很容易在系統需要記憶體時被優先殺死,因為它屬於空程序(沒有任何活動元件的程序).如果它的宿主程序被殺死,那麼正在工作的子執行緒也會被殺死.所以採用子執行緒來解決是不可靠的 .”
當看到上面這段文字後,我曾武斷地認為我應該選擇服務。但是我們沒有想到我定義的BroadcastReceiver是在主執行緒定義的,所以是不會出現上面的情況。
下面就來複習一下service和子執行緒的一些需要注意的地方。
service:
開啟服務的2種方法
1. 在同一個應用任何地方呼叫 startService() 方法就能啟動 Service 了,然後系統會回撥 Service 類的 onCreate() 以及 onStart() 方法。這樣啟動的 Service 會一直執行在後臺,直到 Context.stopService() 或者 selfStop() 方法被呼叫。另外如果一個 Service 已經被啟動,其他程式碼再試圖呼叫 startService() 方法,是不會執行 onCreate() 的,但會重新執行一次 onStart() 。
2. 另外一種 bindService() 方法的意思是,把這個 Service 和呼叫 Service 的客戶類綁起來,如果呼叫這個客戶類被銷燬,Service 也會被銷燬。用這個方法的一個好處是,bindService() 方法執行後 Service 會回撥上邊提到的 onBind() 方發,你可以從這裡返回一個實現了 IBind 介面的類,在客戶端操作這個類就能和這個服務通訊了,比如得到 Service 執行的狀態或其他操作。如果 Service 還沒有執行,使用這個方法啟動 Service 就會 onCreate() 方法而不會呼叫 onStart()。
如果我們想保持和 Service 的通訊,又不想讓 Service 隨著 Activity 退出而退出呢?你可以先 startService() 然後再 bindService() 。當你不需要繫結的時候就執行 unbindService() 方法,執行這個方法只會觸發 Service 的 onUnbind() 而不會把這個 Service 銷燬。這樣就可以既保持和 Service 的通訊,也不會隨著 Activity 銷燬而銷燬了。 子執行緒: 如果希望子執行緒呼叫start()方法後立即執行,可以使用Thread.sleep()方式使主執行緒睡眠一夥兒,轉去執行子執行緒。 當執行緒的run()方法執行完,或者被強制性地終止,就認為它死去。這個執行緒物件也許是活的,但是,它已經不是一個單獨執行的執行緒。執行緒一旦死亡,就不能復生。 如果在一個死去的執行緒上呼叫start()方法,會丟擲java.lang.IllegalThreadStateException異常。 sleep是靜態方法,最好不要用Thread的例項物件呼叫它,因為它睡眠的始終是當前正在執行的執行緒,而不是呼叫它的執行緒物件,它只對正在執行狀態的執行緒物件有效。 結束一個程序一般就是要保證run函式能夠執行完,但是如果執行緒處於sleep、wait、join的狀態的時候,則不行,可用interrupt來結束執行緒。
每個Thread都有一箇中斷狀狀態,預設為false。可以通過Thread物件的isInterrupted()方法來判斷該執行緒的中斷狀態。可以通過Thread物件的interrupt()方法將中斷狀態設定為true。當一個執行緒處於sleep、wait、join這三種狀態之一的時候,如果此時他的中斷狀態為true,那麼它就會丟擲一個InterruptedException的異常,並將中斷狀態重新設定為false。
服務不是執行緒。可以線上程中工作。在應用中,如果是長時間的在後臺執行,而且不需要互動的情況下,使用服務。同樣是在後臺執行,不需要互動的情況下,如果只是完成某個任務,之後就不需要執行,而且可能是多個任務,需需要長時間執行的情況下使用執行緒。如果任務佔用CPU時間多,資源大的情況下,要使用執行緒。” 這段文字讓我最終決定使用執行緒。因為服務也是工作在主執行緒中的,如果服務中要執行耗時的工作也是會阻塞主執行緒,所以得用主執行緒。 “如果需要完成一項比較耗時的工作,應該通過傳送Intent給Service,由Service來完成.這裡不能使用子執行緒來解決,因為BroadcastReceiver的生命週期很短,子執行緒可能還沒有結束,BroadcastReceiver就先結束了.BroadcastReceiver一旦結束,此時BroadcastReceiver的所在程序很容易在系統需要記憶體時被優先殺死,因為它屬於空程序(沒有任何活動元件的程序).如果它的宿主程序被殺死,那麼正在工作的子執行緒也會被殺死.所以採用子執行緒來解決是不可靠的
1. 在同一個應用任何地方呼叫 startService() 方法就能啟動 Service 了,然後系統會回撥 Service 類的 onCreate() 以及 onStart() 方法。這樣啟動的 Service 會一直執行在後臺,直到 Context.stopService() 或者 selfStop() 方法被呼叫。另外如果一個 Service 已經被啟動,其他程式碼再試圖呼叫 startService() 方法,是不會執行 onCreate() 的,但會重新執行一次 onStart() 。
2. 另外一種 bindService() 方法的意思是,把這個 Service 和呼叫 Service 的客戶類綁起來,如果呼叫這個客戶類被銷燬,Service 也會被銷燬。用這個方法的一個好處是,bindService() 方法執行後 Service 會回撥上邊提到的 onBind() 方發,你可以從這裡返回一個實現了 IBind 介面的類,在客戶端操作這個類就能和這個服務通訊了,比如得到 Service 執行的狀態或其他操作。如果 Service 還沒有執行,使用這個方法啟動 Service 就會 onCreate() 方法而不會呼叫 onStart()。
如果我們想保持和 Service 的通訊,又不想讓 Service 隨著 Activity 退出而退出呢?你可以先 startService() 然後再 bindService() 。當你不需要繫結的時候就執行 unbindService() 方法,執行這個方法只會觸發 Service 的 onUnbind() 而不會把這個 Service 銷燬。這樣就可以既保持和 Service 的通訊,也不會隨著 Activity 銷燬而銷燬了。 子執行緒: 如果希望子執行緒呼叫start()方法後立即執行,可以使用Thread.sleep()方式使主執行緒睡眠一夥兒,轉去執行子執行緒。 當執行緒的run()方法執行完,或者被強制性地終止,就認為它死去。這個執行緒物件也許是活的,但是,它已經不是一個單獨執行的執行緒。執行緒一旦死亡,就不能復生。 如果在一個死去的執行緒上呼叫start()方法,會丟擲java.lang.IllegalThreadStateException異常。 sleep是靜態方法,最好不要用Thread的例項物件呼叫它,因為它睡眠的始終是當前正在執行的執行緒,而不是呼叫它的執行緒物件,它只對正在執行狀態的執行緒物件有效。 結束一個程序一般就是要保證run函式能夠執行完,但是如果執行緒處於sleep、wait、join的狀態的時候,則不行,可用interrupt來結束執行緒。
每個Thread都有一箇中斷狀狀態,預設為false。可以通過Thread物件的isInterrupted()方法來判斷該執行緒的中斷狀態。可以通過Thread物件的interrupt()方法將中斷狀態設定為true。當一個執行緒處於sleep、wait、join這三種狀態之一的時候,如果此時他的中斷狀態為true,那麼它就會丟擲一個InterruptedException的異常,並將中斷狀態重新設定為false。