Service是Android中長期在後臺運行的沒有界面的組件,使用服務的優點在於:可以提升進程的優先級,系統不容易回收掉進程,即使回收了,內存充足的時候,會把進程從新建立。java
1.服務的簡單使用示例:android
1.1.定義一個服務:ide
定義一個服務的方式是定義一個類繼承自Service:佈局
1 public class MyService extends Service { 2 3 @Override 4 5 public IBinder onBind(Intent intent) { 6 7 // TODO Auto-generated method stub 8 9 return null; 10 11 } 12 13 }
注意到onBind()方法是個抽象方法,於是必須重寫。測試
1.2.註冊服務:this
四大組件之一的Service,在使用以前也必須在清單文件中註冊。編碼
<service android:name="cn.csc.service.MyService"></service>
1.3.在MainActivity中啓動這個服務:spa
啓動服務的方式很簡單,能夠如同啓動Activity同樣,經過Intent對象進行服務的啓動,啓動服務的方法是startService(Intent intent),下面的代碼在MainActivity的onCreate()方法中啓動服務:3d
1 protected void onCreate(Bundle savedInstanceState) { 2 3 super.onCreate(savedInstanceState); 4 5 setContentView(R.layout.activity_main); 6 7 Intent intent = new Intent(this, MyService.class); 8 9 startService(intent); 10 11 }
1.4.運行效果:code
2.觀察服務的生命週期:
2.1修改MyService及MainActivity代碼,重寫生命週期回調的各個方法,輸出標識信息:
MainActivity.java:
1 public class MainActivity extends ActionBarActivity { 2 3 @Override 4 5 protected void onCreate(Bundle savedInstanceState) { 6 7 super.onCreate(savedInstanceState); 8 9 setContentView(R.layout.activity_main); 10 11 Log.i("MainActivity","onCreate()"); 12 13 Intent intent = new Intent(this, MyService.class); 14 15 startService(intent); 16 17 } 18 19 @Override 20 21 protected void onStop() { 22 23 // TODO Auto-generated method stub 24 25 super.onStop(); 26 27 Log.i("MainActivity","onStop()"); 28 29 } 30 31 @Override 32 33 protected void onDestroy() { 34 35 // TODO Auto-generated method stub 36 37 super.onDestroy(); 38 39 Log.i("MainActivity","onDestroy()"); 40 41 } 42 43 @Override 44 45 protected void onPause() { 46 47 // TODO Auto-generated method stub 48 49 super.onPause(); 50 51 Log.i("MainActivity","onPause()"); 52 53 } 54 55 @Override 56 57 protected void onResume() { 58 59 // TODO Auto-generated method stub 60 61 super.onResume(); 62 63 Log.i("MainActivity","onResume()"); 64 65 } 66 67 @Override 68 69 protected void onStart() { 70 71 // TODO Auto-generated method stub 72 73 super.onStart(); 74 75 Log.i("MainActivity","onStart()"); 76 77 } 78 79 }
MyService.java:
1 public class MyService extends Service { 2 3 @Override 4 5 public IBinder onBind(Intent intent) { 6 7 // TODO Auto-generated method stub 8 9 Log.i("MyService","onBind()"); 10 11 return null; 12 13 } 14 15 @Override 16 17 public void onCreate() { 18 19 // TODO Auto-generated method stub 20 21 super.onCreate(); 22 23 Log.i("MyService","onCreate()"); 24 25 } 26 27 @Override 28 29 public int onStartCommand(Intent intent, int flags, int startId) { 30 31 // TODO Auto-generated method stub 32 33 Log.i("MyService","onStartCommand()"); 34 35 return super.onStartCommand(intent, flags, startId); 36 37 } 38 39 @Override 40 41 public void onDestroy() { 42 43 // TODO Auto-generated method stub 44 45 super.onDestroy(); 46 47 Log.i("MyService","onDestroy()"); 48 49 } 50 51 @Override 52 53 public boolean onUnbind(Intent intent) { 54 55 // TODO Auto-generated method stub 56 57 Log.i("MyService","onUnbind()"); 58 59 return super.onUnbind(intent); 60 61 } 62 63 }
2.2部署安裝應用:
運行結果:
2.3退出當前應用:
查看運行中的進程:
服務仍然在運行。
點擊Stop以後:
服務才中止運行。
總結:
採用startService()方式開啓服務後,前後調用了服務的onCrate()和onStartCommand()方法,Activity被銷燬以後,服務仍然繼續運行,只有當手動中止掉服務時,纔會調用onDestory()方法。
可見,start方式開啓服務時, 一旦服務開啓跟調用者(開啓者)就沒有任何關係了。
開啓者退出後,服務仍然在後臺長期的運行,開啓者與服務沒有任何關聯,於是不能調用服務裏面的方法。
2.4在MainActivity中調用bindService()綁定服務:
1 protected void onCreate(Bundle savedInstanceState) { 2 3 super.onCreate(savedInstanceState); 4 5 setContentView(R.layout.activity_main); 6 7 Log.i("MainActivity","onCreate()"); 8 9 Intent intent = new Intent(this, MyService.class); 10 11 bindService(intent, new MyConn(), BIND_AUTO_CREATE); 12 13 }
查看運行結果:
退出應用:
總結:
採用綁定的方式開啓服務,會前後調用:onCreate()、onBind(),Activity銷燬後,Service緊跟着調用onunbind()、onDestory()也被銷燬。
這種方式的服務跟隨應用的結束而結束,不會長期駐留在後臺,可是,這種方式下,Activity與Service產生了關聯,於是能夠調用Service提供的方法。那麼在Activity中如何調用Service中的方法呢?
3.Activity調用本地服務方法:
主要步驟:
1)在本地服務中添加須要被Activity調用的方法
2)定義一個接口,約定Activity經過該接口的實例調用本地服務的方法,該接口的實例由本地服務的onBind()方法傳遞給Activity
3) 在服務的內部建立一個內部類實現約定的接口,並在onBind()方法中返回該內部類的實例,因爲onBind()方法返回的是IBinder類型的實例,因此該內部類還須要繼承一個Ibinder接口的實現類,通常繼承Binder類
4)在activity 綁定服務:bindService();
5)在服務成功綁定的時候 會執行一個方法 onServiceConnected 傳遞過來一個 IBinder對象
5)將傳回的IBinder對象強制類型轉化成約定接口的實例,從而調用接口裏面的方法。
具體編碼步驟:
1)修改MyService代碼,添加一個供Activity調用的方法:
1 public void serviceMethod(){ 2 3 Toast.makeText(getApplicationContext(), "本地服務方法被調用", Toast.LENGTH_SHORT).show(); 4 5 }
2)定義一個雙方約定的接口,用於調用前面添加的serviceMethod()方法:
1 public interface IMiddlePerson { 2 3 public void callServiceMethod(); 4 5 }
3)在MyService中定義一個內部類繼承自Binder並實現上面的約定接口:
1 private class MiddlePerson extends Binder implements IMiddlePerson{ 2 3 4 5 @Override 6 7 public void callServiceMethod() { 8 9 // TODO Auto-generated method stub 10 11 serviceMethod(); 12 13 } 14 15 16 17 }
4)修改MyService的onBind()方法,返回上面定義的內部類的實例:
1 public IBinder onBind(Intent intent) { 2 3 // TODO Auto-generated method stub 4 5 Log.i("MyService","onBind()"); 6 7 return new MiddlePerson(); 8 9 }
5)在MainActivity中添加一個存放約定接口的引用的字段:
private IMiddlePerson imp;
6)修改MainActivity的佈局文件,添加一個按鈕:
1 <Button 2 3 android:layout_width="wrap_content" 4 5 android:layout_height="wrap_content" 6 7 android:onClick="call" 8 9 android:layout_gravity="center_horizontal" 10 11 android:text="@string/call_native_service" />
在MainActivity中添加public void call(View view)方法,用於按鈕的點擊回調:
1 public void call(View view){ 2 3 imp.callServiceMethod(); 4 5 }
7)修改MyConn的onServiceConnected方法,將IBinder類型的參數賦值給imp:
1 public void onServiceConnected(ComponentName name, IBinder service) { 2 3 // TODO Auto-generated method stub 4 5 Log.i("MainActivity","服務綁定了"); 6 7 imp = (IMiddlePerson) service; 8 9 }
8)查看運行結果:
注: 若是又想服務能長期在後臺運行,又想可以調用服務中的方法,則應以下順序處理:
1)start方式開啓服務(保證服務長期後臺運行)
2)bind方式綁定服務(保證調用服務的方法)
在須要中止服務時,則須要按以下順序:
3)unbind解除綁定服務
4)stopService中止服務。
這裏,就不在測試了。
4.Activity調用遠程服務的方法:
這裏簡單區分下本地服務和遠程服務:
遠程服務:調用者和服務在不一樣的工程代碼裏面。
本地服務:調用者和服務在同一個工程代碼裏面。
若是像調用同一個工程中的本地服務方法同樣,綁定一個遠程服務,直接會報錯。這是由於綁定遠程服務的方法與綁定本地服務的方法有所不一樣:
Android定義了aidl:android interface definition language 安卓接口定義語言來實現遠程服務的綁定。
與綁定本地服務的主要不一樣在於:
約定的接口的定義不能帶有任何訪問修飾符,並且後綴名要改成.aidl,以後會自動生成一個名爲Stub的內部類,服務中定義的內部類繼承該內部類便可。
具體編碼步驟:
4.1定義能遠程綁定的服務:
1)定義IMiddlePeson.aidl:
1 package cn.csc.service; 2 3 4 5 interface IMiddlePerson { 6 7 void callServiceMethod(); 8 9 }
將在gen目錄下自動生成:
打開自動生成的IMiddlePerson.java:
能夠看到自動生成了Stub內部抽象類
2)在服務中添加要被遠程調用的方法:
1 public void serviceMethod(){ 2 3 Log.i("MyService","遠程服務方法被調用了。。。"); 4 5 }
3)在服務中定義內部類繼承IMiddlePerson.Stub:
1 private class MiddlePerson extends IMiddlePerson.Stub{ 2 3 4 5 @Override 6 7 public void callServiceMethod() { 8 9 // TODO Auto-generated method stub 10 11 serviceMethod(); 12 13 } 14 15 16 17 }
4)因爲要被遠程調用,因此不能使用顯示意圖了,須要在清單文件中註冊服務時添加<intent-filter>生命能響應的動做:
1 <service android:name="cn.csc.service.MyService"> 2 3 <intent-filter > 4 5 <action android:name="cn.csc.service.MyService"/> 6 7 </intent-filter> 8 9 </service>
至此,一個能夠被遠程綁定的服務就完成了,先把它部署到模擬器上。
4.2在另外一個項目中綁定該遠程服務:
1)將約定的接口IMiddlePerson.aidl文件連同所在包一同複製到該項目的src目錄中:
能夠看到,一樣自動生成了IMiddlePerson.java文件
2)定義存放接口引用的字段:
private IMiddlePerson imp;
3)使用隱式意圖綁定遠程服務:
1 Intent intent = new Intent(); 2 3 intent.setAction("cn.csc.service.MyService"); 4 5 bindService(intent, new MyConn(), BIND_AUTO_CREATE); 6 7 4)修改MyConn()中的onServiceConnected()方法: 8 9 public void onServiceConnected(ComponentName name, IBinder service) { 10 11 // TODO Auto-generated method stub 12 13 Log.i("MainActivity","服務綁定了"); 14 15 imp = IMiddlePerson.Stub.asInterface(service); 16 17 }
調用遠程服務的應用端也搞定了,而後部署,查看運行結果:
以上,就是今天學到的關於Service的一點知識。