Service概念及用途:
Android中的服務,它與Activity不同,它是不能與用戶交互的,不能自己啟動的,運行在后台的程序,如果我們退出應用時,Service進程並沒有結束,它仍然在后台運行,那我們什么時候會用到Service呢?比如我們播放音樂的時候,有可能想邊聽音樂邊干些其他事情,當我們退出播放音樂的應用,如果不用Service,我們就聽不到歌了,所以這時候就得用到Service了,又比如當我們一個應用的數據是通過網絡獲取的,不同時間(一段時間)的數據是不同的這時候我們可以用Service在后台定時更新,而不用每打開應用的時候在去獲取。
Service生命周期 :
Android Service的生命周期並不像Activity那么復雜,它只繼承了onCreate(),onStart(),onDestroy()三個方法,當我們第一次啟動Service時,先后調用了onCreate(),onStart()這兩個方法,當停止Service時,則執行onDestroy()方法,這里需要注意的是,如果Service已經啟動了,當我們再次啟動Service時,不會在執行onCreate()方法,而是直接執行onStart()方法。
Service與Activity通信:
Service后端的數據最終還是要呈現在前端Activity之上的,因為啟動Service時,系統會重新開啟一個新的進程,這就涉及到不同進程間通信的問題了(AIDL),當我們想獲取啟動的Service實例時,我們可以用到bindService和unBindService方法,它們分別執行了Service中onBind()和onUnbind()方法。
1、添加一個類,在MainActivity所在包之下,繼承自Service
2、在程序界面文件中添加控件
3、修改MainActivity中的方法,以及讓MainActivity類實現OnClickListener接口
public class MainActivity extends Activity implements OnClickListener {
private LService mLService; private TextView mTextView; private Button startServiceButton; private Button stopServiceButton; private Button bindServiceButton; private Button unbindServiceButton; private Context mContext; // 這里需要用到ServiceConnection,在Context.bindService和context.unBindService()里用到 private ServiceConnection mServiceConnection = new ServiceConnection() { // 當bindService時,讓TextView顯示LService里getSystemTime()方法的返回值 @Override public void onServiceConnected(ComponentName name, IBinder service) { mLService = ((LService.LBinder) service).getService(); mTextView.setText("I am from Service :" + mLService.getSystemTime()); } public void onServiceDisconnected(ComponentName name) { } }; public void setupViews() { mContext = MainActivity.this; mTextView = (TextView) findViewById(R.id.text); startServiceButton = (Button) findViewById(R.id.startservice); stopServiceButton = (Button) findViewById(R.id.stopservice); bindServiceButton = (Button) findViewById(R.id.bindservice); unbindServiceButton = (Button) findViewById(R.id.unbindservice); startServiceButton.setOnClickListener(this); stopServiceButton.setOnClickListener(this); bindServiceButton.setOnClickListener(this); unbindServiceButton.setOnClickListener(this); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupViews(); } }
4、注冊Service
<service android:name=".LService" android:exported="true" > </service>
startService:onCreate()->onStart()此時調用程序設置里面可以看到Running Service有一個LService
stopService:onDestory()
bindService:onCreate()->onBind();此時Service已經被關閉
unbindService:onunBind->onDestory()
startService->bindService->unbindService:onCreate()->onStart()->onBind()->onunBind->onDestory();
當采用Context.startService()方法啟動服務,與之有關的生命周期方法:onCreate()->onStart()->onDestory()
1>onCreate()方法在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()或者bindService()方法,服務也只被創建一次;
onStart()方法只有采用Context.startService()方法啟動服務時才會被調用,該方法在服務開始運行時被調用,多次調用startService()方法盡管不會多次創建服務,但onStart()方法會被多次調用。
2>onDestory()方法在服務被終止時被調用;
當采用Context.bindService方法啟動服務,與之有關的生命周期方法:onCreate()->onBind()->onUnbind()->onDestory()
3>onBind()只有采用Context.bindService()方法啟動服務時才會被調用,該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。
4>onUnbind()只有采用Context.unbindService()方法啟動服務時才會回調該方法,該方法在調用者與服務解綁定時被調用;
5>如果先采用startService()方法啟動服務,然后調用bindService()方法綁定到服務,再調用unbindService()方法解除綁定,最后調用bindService()方法再次綁定到服務,觸發的生命周期方法為:onCreate()->onStart()->onBind()->onUnBind()[重載后的方法需返回true]->onRebind();
6>服務不能自己運行,需要通過調用Context.startService()或者Context.bindService()方法啟動服務。這兩個方法都可能啟動服務,但是它們使用場合不同,使用startService()方法啟動服務,訪問者與服務沒有關連,即使訪問者退出了,服務仍然運行,使用bindService()方法啟動服務,訪問者與服務綁定在一起,訪問者一旦,服務也就終止,使用Context.startService()啟動服務,只能調用 Context.stopService()結束服務,服務結束時會調用onDestory()方法;
通過startService()和stopService()啟動關閉服務,適用於服務和訪問者之間沒有交互的情況。如果服務和訪問者之間需要方法調用或者傳遞參數,則需要使用bindService()和unbindService()方法啟動關閉服務;
采用Context.bindService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接着調用onBind()方法,此時訪問者與服務綁定,如果要進行通信,onBind()方法需要返回一個Ibinder對象。如果訪問者退出,系統先調用onUnbind()方法,再調用onDestory()方法。訪問者與服務解除綁定可以通過unbindService()方法解綁。onUnbind()->onDestory()!
一個監聽電話的實例
public class PhoneService extends Service {
@Override
public IBinder onBind(Intent intent) { return null; } private MediaRecorder recorder; private File file = null; @Override public void onCreate() { TelephonyManager manger = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);//內置的服務,通過getSystemService獲取 manger.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING:// 來電 break; case TelephonyManager.CALL_STATE_OFFHOOK:// 接通電話 file = new File(Environment.getExternalStorageDirectory(), incomingNumber + System.currentTimeMillis()); recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 聲音來源 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 保存的聲音類型 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 編碼方式 try { recorder.prepare();// 准備 recorder.start();// 開始錄音 } catch (IOException e) { } break; case TelephonyManager.CALL_STATE_IDLE:// 掛斷電話后回歸到空閑狀態 if (recorder != null) { recorder.stop();// 停止 recorder.release();// 釋放 recorder = null; uploadfile(); } break; } } }, PhoneStateListener.LISTEN_CALL_STATE); } protected void uploadfile() { new Thread(new Runnable() { @Override public void run() { if (file != null && file.exists()) { file.delete(); file = null; } } }).start(); } }
獲取正在運行的Service
public class ServiceList extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) { ActivityManager activityManger = (ActivityManager) getSystemService(ACTIVITY_SERVICE);// 獲取Activity管理器 List<ActivityManager.RunningServiceInfo> serviceList = activityManger.getRunningServices(30);// 從窗口管理器中獲取正在運行的Service } private boolean ServiceIsStart(List<ActivityManager.RunningServiceInfo> list, String className) {// 判斷某個服務是否啟動 for (int i = 0; i < list.size(); i++) { if (className.equals(list.get(i).service.getClassName())) return true; } return false; } private String getServicesName(List<ActivityManager.RunningServiceInfo> list) {// 獲取所有服務的名稱 String res = ""; for (int i = 0; i < list.size(); i++) { res += list.get(i).service.getClassName() + "/n"; } return res; } }