1.Service簡單概述
Service(服務)是一個一種可以在后台執行長時間運行操作而沒有用戶界面的應用組件。服務可由其他應用組件啟動(如Activity),服務一旦被啟動將在后台一直運行,即使啟動服務的組件(Activity)已銷毀也不受影響。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而所有這一切均可在后台進行:
Service基本上分為兩種形式
啟動狀態
當應用組件(如 Activity)通過調用 startService() 啟動服務時,服務即處於“啟動”狀態。一旦啟動,服務即可在后台無限期運行,即使啟動服務的組件已被銷毀也不受影響,除非手動調用才能停止服務, 已啟動的服務通常是執行單一操作,而且不會將結果返回給調用方。
綁定狀態
應用組件通過調用 bindService() 綁定到服務時,服務即處於“綁定”狀態。綁定服務提供了一個客戶端-服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信 (IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務才會運行。 多個組件可以同時綁定到該服務,但全部取消綁定后,該服務即會被銷毀。
2.在android studio中創建和配置service
1.使用android studio導航創建service
2.選擇是否可編譯,是否可實例化
需要在manifests進行配置,如果使用導航創建,會自動配置
<service android:name=".service.MyService" android:enabled="true" //是否可以實例化 android:exported="true"></service> //是否可以被調用
配置參數解釋
<service android:enabled=["true" | "false"] android:exported=["true" | "false"] android:icon="drawable resource" android:isolatedProcess=["true" | "false"] android:label="string resource" android:name="string" android:permission="string" android:process="string" > . . . </service>
- android:exported:代表是否能被其他應用隱式調用,其默認值是由service中有無intent-filter決定的,如果有intent-filter,默認值為true,否則為false。為false的情況下,即使有intent-filter匹配,也無法打開,即無法被其他應用隱式調用。
- android:name:對應Service類名
- android:permission:是權限聲明
- android:process:是否需要在單獨的進程中運行,當設置為android:process=”:remote”時,代表Service在單獨的進程中運行。注意“:”很重要,它的意思是指要在當前進程名稱前面附加上當前的包名,所以“remote”和”:remote”不是同一個意思,前者的進程名稱為:remote,而后者的進程名稱為:App-packageName:remote。
- android:isolatedProcess :設置 true 意味着,服務會在一個特殊的進程下運行,這個進程與系統其他進程分開且沒有自己的權限。與其通信的唯一途徑是通過服務的API(bind and start)。
- android:enabled:是否可以被系統實例化,默認為 true因為父標簽 也有 enable 屬性,所以必須兩個都為默認值 true 的情況下服務才會被激活,否則不會激活。
3.Service類方法介紹
public class MyService extends Service { public MyService() { } /* * 綁定服務時才會調用 * 必須要實現的方法 */ @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } /* * 首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。 * 如果服務已在運行,則不會調用此方法。該方法只被調用一次 * */ @Override public void onCreate() { super.onCreate(); } /* * 每次通過startService()方法啟動Service時都會被回調。 * */ @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } /* * 服務銷毀時的回調 * */ @Override public void onDestroy() { super.onDestroy(); } }
- onBind:當另一個組件想通過調用 bindService() 與服務綁定(例如執行 RPC)時,系統將調用此方法。在此方法的實現中,必須返回 一個IBinder 接口的實現類,供客戶端用來與服務進行通信。無論是啟動狀態還是綁定狀態,此方法必須重寫,但在啟動狀態的情況下直接返回 null。
- oncreate:首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或onBind() 之前)。如果服務已在運行,則不會調用此方法,該方法只調用一次
- onstartCommand::當另一個組件(如 Activity)通過調用 startService() 請求啟動服務時,系統將調用此方法。一旦執行此方法,服務即會啟動並可在后台無限期運行。 如果自己實現此方法,則需要在服務工作完成后,通過調用 stopSelf() 或 stopService() 來停止服務。(在綁定狀態下,無需實現此方法。)
- onDestroy:當服務不再使用且將被銷毀時,系統將調用此方法。服務應該實現此方法來清理所有資源,如線程、注冊的偵聽器、接收器等,這是服務接收的最后一個調用。
4.startService開啟音樂播放器的例子
public class MusicService extends Service { public static boolean isPlay; //記錄當前播放狀態 private static MediaPlayer player; //記錄MediaPlay對象 public MusicService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { //創建的時候把資源文件放進去 player= MediaPlayer.create(this, R.raw.music); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //判斷是否在部分,如果沒有就開啟播放,然后把播放狀態存起來 if(!player.isPlaying()){ player.start(); isPlay = player.isPlaying(); } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { //銷毀的時候停止播放,釋放資源 player.stop(); isPlay = player.isPlaying(); player.release();//釋放資源 super.onDestroy(); }
5.bound Service 綁定service實現數據交互
例子:
public class BindService extends Service { private MyBinder binder = new MyBinder(); public BindService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. //throw new UnsupportedOperationException("Not yet implemented"); return binder; //放回MyBinder對象,實現數據 } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } //生成隨機數 public List getRandomNum(){ List resArr = new ArrayList(); String strNum;//用於保存隨機數 for(int i = 0 ;i<7;i++){ int num = new Random().nextInt(33)+1; if(num<10){ strNum = "0"+String.valueOf(num); }else { strNum = String.valueOf(num); } resArr.add(strNum); } return resArr; } //獲取bindService public class MyBinder extends Binder { public BindService getService(){ //創建獲取service的方法 return BindService.this; //放回當前的Service類 } } @Override public void onDestroy() {//銷毀service super.onDestroy(); } }
在Activity中實現綁定的代碼
mBtn_getNum
public class ServiceActivity extends BaseActivity implements View.OnClickListener { private Button mBtn_start; //開啟服務 private Button mBtn_stop; //停止服務 private Button mBtn_play; //播放音樂 private Button mBtn_getNum; //隨機選號 private Button mBtn_intent; //intentservice private Button mBtn_pt; //普通耗時報錯 private BindService bindService; @Override protected int getLayoutId() { return R.layout.activity_service; } @Override protected void initView() { mBtn_start = findViewById(R.id.btn_start); mBtn_stop = findViewById(R.id.btn_stop); mBtn_start.setOnClickListener(this); mBtn_stop.setOnClickListener(this); mBtn_play = findViewById(R.id.btn_play); mBtn_play.setOnClickListener(this); mBtn_getNum = findViewById(R.id.btn_getNum); mBtn_getNum.setOnClickListener(this); mBtn_intent = findViewById(R.id.btn_play); mBtn_intent.setOnClickListener(this); mBtn_pt = findViewById(R.id.btn_getNum); mBtn_pt.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(ServiceActivity.this,MyService.class); Intent intent2 = new Intent(ServiceActivity.this,MusicService.class); switch (v.getId()){ case R.id.btn_start: startService(intent); break; case R.id.btn_stop: stopService(intent); break; case R.id.btn_play: if(MusicService.isPlay==false){ startService(intent2); }else{ stopService(intent2); } break; case R.id.btn_getNum: int[] textId = {R.id.num_1,R.id.num_2,R.id.num_3,R.id.num_4,R.id.num_5,R.id.num_6,R.id.num_7}; List num = bindService.getRandomNum(); for(int i=0;i<num.size();i++){ TextView tv = findViewById(textId[i]); tv.setText(num.get(i).toString()); } break; case R.id.btn_pt: Intent intent3 = new Intent(ServiceActivity.this,PtService.class); startService(intent3); break; case R.id.btn_intent: break; default: break; } } @Override protected void onStart() { super.onStart(); Intent intent = new Intent(this,BindService.class); bindService(intent,con, Service.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(con); } //創建一個服務器關聯對象 private ServiceConnection con = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bindService = ((BindService.MyBinder)service).getService(); } @Override public void onServiceDisconnected(ComponentName name) { } }; }
6.Intent Service
對比普通Service:
普通Service不能自動開啟線程,自動停止線程 ===》使用場景:進行耗時任務,如果不開啟新線程時間超過20s就會出現應用無響應的錯誤,耗時任務完成,不會自動停止線程需要selfstop實現停止服務
IntentService:可以自動開啟線程,自動停止線程 ===》使用場景:進行耗時任務,自動開啟線程,耗時任務完成,自動停止線程停止服務