一、 進程概念介紹
四大組件都是運行在主線程
Service是在一段不定的時間運行在後臺,不和用戶交互應用組件。每個Service必須在manifest中 通過來聲明。可以通過contect.startservice和contect.bindserverice來啓動。
Service和其他的應用組件一樣,運行在進程的主線程中。這就是說如果service需要很多耗時或者阻塞的操作,需要在其子線程中實現。
二、服務的使用
定義一個新的服務,要用一個類去繼承Service這個類,Service類中有一個抽象方法onBind()。
一般處理定義一個服務去處理一些事情需要重新覆寫三個方法
①onCreate()
②onStartCommand(Intent intent , int flags ,int startId)
③onDestroy()
onCreate()方法會在服務創建的時候調用
onStartCommand()方法會在每次服務啓動的時候調用
onDestroy()方法會在服務銷燬的時候調用
onCreate()和 onStartCommand()方法的區別:
答:oncreate()方法是在服務第一次創建的時候調用,而 onStartCommand()方法則在每次啓動服務的時候都會調用。
注意:每一個服務都需要在AndroidManifest.xml文件中註冊
三、啓動服務和停止服務
定義一個自定義服務類,然後在主函數中通過按鈕點擊事件進行服務的啓動和停止
通過startService()方法啓動服務
通過stopService()方法停止服務
代碼如下:
[圖片]
注意:startService()和stopService()方法都是定義在Context類中的,所以在活動中可以直接調用這兩個方法,完全是由活動來決定服務何時停止的。如果想讓服務自己停止,則只需要在服務類MyService中的任何一個位置調用stopSelf()方法就可以讓這個服務停下來
Android中的服務 也是在後臺運行 可以理解成是在後臺運行並且是沒有界面的Activity
五種服務的級別:
(1)Foreground process 前臺進程 用戶正在交互 可以理解成相 當於 Activity執行onResume方法
(2)Visible process 可視進程 用戶沒有在交互 但用戶還一直能看得見頁面 相當於Activity執行了onPause方法
(3)Service Process 服務進程 通過startService()開啓了一個服務
(4)Background process 後臺進程 當前用戶看不見頁面 相當於Activity執行了onStop方法
(5)Empty process 空進程
service的兩種模式(startService()/bindService()不是完全分離的
● 本地服務 Local Service 用於應用程序內部。
它可以啓動並運行,直至有人停止了它或它自己停止。在這種方式下,它以調用Context.startService()啓動,而以調用Context.stopService()結束。它可以調用Service.stopSelf() 或 Service.stopSelfResult()來自己停止。不論調用了多少次startService()方法,你只需要調用一次stopService()來停止服務。
用於實現應用程序自己的一些耗時任務,比如查詢升級信息,並不佔用應用程序比如Activity所屬線程,而是單開線程後臺執行,這樣用戶體驗比較好。
● 遠程服務 Remote Service 用於android系統內部的應用程序之間。
它可以通過自己定義並暴露出來的接口進行程序操作。客戶端建立一個到服務對象的連接,並通過那個連接來調用服務。連接以調用Context.bindService()方法建立,以調用 Context.unbindService()關閉。多個客戶端可以綁定至同一個服務。如果服務此時還沒有加載,bindService()會先加載它。
可被其他應用程序複用,比如天氣預報服務,其他應用程序不需要再寫這樣的服務,調用已有的即可。
生命週期
服務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啓動服務。這兩個方法都可以啓動Service,但是它們的使用場合有所不同。
1. 使用startService()方法啓用服務,調用者與服務之間沒有關連,即使調用者退出了,服務仍然運行。
如果打算採用Context.startService()方法啓動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接着調用onStart()方法。
如果調用startService()方法前服務已經被創建,多次調用startService()方法並不會導致多次創建服務,但會導致多次調用onStart()方法。
採用startService()方法啓動的服務
只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
2. 使用bindService()方法啓用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點。
onBind()只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定
多次調用Context.bindService()方法並不會導致該方法被多次調用。
採用Context.bindService()方法啓動服務時只能調用onUnbind()方法解除調用者與服務解除,服務結束時會調用onDestroy()方法。
看看官方給出的比較流程示意圖:
官方文檔告訴我們,一個service可以同時start並且bind,在這樣的情況,系統會一直保持service的運行狀態如果service已經start了或者BIND_AUTO_CREATE標誌被設置。如果沒有一個條件滿足,那麼系統將會調用onDestory方法來終止service.所有的清理工作(終止線程,反註冊接收器)都在onDestory中完成。
擁有service的進程具有較高的優先級
官方文檔告訴我們,Android系統會盡量保持擁有service的進程運行,只要在該service已經被啓動(start)或者客戶端連接(bindService)到它。當內存不足時,需要保持,擁有service的進程具有較高的優先級。
1. 如果service正在調用onCreate,onStartCommand或者onDestory方法,那麼用於當前service的進程則變爲前臺進程以避免被killed。
2. 如果當前service已經被啓動(start),擁有它的進程則比那些用戶可見的進程優先級低一些,但是比那些不可見的進程更重要,這就意味着service一般不會被killed.
3. 如果客戶端已經連接到service (bindService),那麼擁有Service的進程則擁有最高的優先級,可以認爲service是可見的。
4. 如果service可以使用startForeground(int, Notification)方法來將service設置爲前臺狀態,那麼系統就認爲是對用戶可見的,並不會在內存不足時killed。
如果有其他的應用組件作爲Service,Activity等運行在相同的進程中,那麼將會增加該進程的重要性。
二、start方式開啓服務和bindService方式開啓服務的特點
服務是在後臺運行 可以理解成是沒有界面的activity
定義四大組件的方式都是一樣的
定義一個類繼承Service
1.特點:
(1)服務通過startservice方式開啓 第一次點擊按鈕開啓服務 會執行服務的onCreate 和 onStart方法
(2)如果第二次開始再點擊按鈕開啓服務 服務只會執行onStrat方法
(3)服務被開啓後 會在設置頁面裏面的 running裏面找得到這個服務
*(4)startservice 方式開啓服務 服務就會在後臺長期運行 直到用戶手工停止 或者調用StopService方法 服務纔會被銷燬
bindService()理解:
自定義的Service服務類裏面的onBind()方法是在activity中執行了bindService()綁定服務的操作後執行的。
bindService()方法中藥傳入三個參數:
第一個參數是Intent對象;
第二個參數是建立連接的對象,即ServiceConnection的對象,當執行了bindService()後,服務和activity之間的聯繫便建立起來了,此時會回調Service中的onBind()方法,該方法返回一個IBinder對象,這個對象我們可以在該類中自定義一個MyBinder類繼承Bind抽象類,在裏面實現服務的方法,當onBind()執行後,活動中的ServiceConnection類的onServiceConnection()方法會執行,在該方法裏有傳過來的一個參數IBinder service,將這個參數拿出來,通過這個對象去調用服務中的方法,相當於中間人;
//服務中自定義的中間人對象類
public class MyBinder extends Binder{
public void startDownload(){
xxxxxxxxxx;
};
}
......
//連接服務的對象
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.startDownload();
}
};
第三個參數是一個標誌位,這裏傳入BIND_AUTO_CREATE表示在Activity和Service建立關聯後自動創建Service,這會使得MyService中的onCreate()方法得到執行,但onStartCommand()方法不會執行。
2.bindService 方式開啓服務的特點
(1)當點擊按鈕第一次開啓服務 會執行服務的onCreate方法 和 onBind()方法
(2) 當第二次點擊按鈕在調用bindservice 服務沒有響應
**(3) 當activity銷燬的時候服務也銷燬 不求同時生但求同時死
(4)通過bind方式開啓服務 服務不能再設置頁面裏面找到 相當於是一個隱形的服務
(5)bindservice不能多次解綁 多次解綁會報錯
3 使用服務註冊特殊的廣播接收者
(1)創建我們要註冊的廣播接收者
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//獲取廣播事件的類型
String action = intent.getAction();
if ("android.intent.action.SCREEN_OFF".equals(action)) {
System.out.println("說明屏幕鎖屏了");
}else if("android.intent.action.SCREEN_ON".equals(action)){
System.out.println("說明屏幕解鎖了");
}
}
}
(2)創建一個服務 用來註冊廣播接收者 代碼如下
public class ScreenService extends Service {
private ScreenReceiver receiver;
@Override
public IBinder onBind(Intent intent) {
return null;
}
//當服務第一次啓動的時候調用
@Override
public void onCreate() {
//在這個方法裏面註冊廣播接收者
//[1]獲取ScreenReceiver實例
receiver = new ScreenReceiver();
//[2]創建IntentFilter對象
IntentFilter filter = new IntentFilter();
//[3]添加註冊的事件
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
//[4]通過代碼的方式註冊
registerReceiver(receiver, filter);
super.onCreate();
}
//當服務銷燬的時候調用
@Override
public void onDestroy() {
//當actvivity銷燬的時候 取消註冊廣播接收者
unregisterReceiver(receiver);
super.onDestroy();
}
}`
(3)一定要記得配置service
5 爲什麼要引入bindService
目的爲了調用服務裏面的方法
創建前臺Service
Service幾乎都是在後臺運行的,一直以來它都是默默地做着辛苦的工作。但是Service的系統優先級還是比較低的,當系統出現內存不足情況時,就有可能會回收掉正在後臺運行的Service。如果你希望Service可以一直保持運行狀態,而不會由於系統內存不足的原因導致被回收,就可以考慮使用前臺Service。前臺Service和普通Service最大的區別就在於,它會一直有一個正在運行的圖標在系統的狀態欄顯示,下拉狀態欄後可以看到更加詳細的信息,非常類似於通知的效果。當然有時候你也可能不僅僅是爲了防止Service被回收才使用前臺Service,有些項目由於特殊的需求會要求必須使用前臺Service,比如說墨跡天氣,它的Service在後臺更新天氣數據的同時,還會在系統狀態欄一直顯示當前天氣的信息
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Notification notification = new Notification(R.drawable.ic_launcher,
"有通知到來", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "Title", "Message",
pendingIntent);
startForeground(1, notification);
Log.d(TAG, "onCreate() executed");
}
.........
}
這裏只是修改了MyService中onCreate()方法的代碼。可以看到,首先創建了一個Notification對象,然後調用了它的setLatestEventInfo()方法來爲通知初始化佈局和數據,並在這裏設置了點擊通知後就打開MainActivity。然後調用startForeground()方法就可以讓MyService變成一個前臺Service,並會將通知的圖片顯示出來。