SerVice
- Service就是默默運行在後臺的組件,可以理解爲是沒有前臺的activity,適合用來運行不需要前臺界面的代碼
- 服務可以被手動關閉,不會重啓,但是如果被自動關閉,內存充足就會重啓
開啓方式
- startService
- 該方法啓動的服務所在的進程屬於服務進程
- Activity一旦啓動服務,服務就跟Activity一毛錢關係也沒有了
- bindService
- 該方法啓動的服務所在進程不屬於服務進程
- Activity與服務建立連接,Activity一旦死亡,服務也會死亡
服務的分類
- 本地服務:指的是服務和啓動服務的activity在同一個進程中
- 遠程服務:指的是服務和啓動服務的activity不在同一個進程中
服務的生命週期
onCreate–>onStartCommand–>onDestory,與activity的不同,沒有
onRestart和onResume,這一點注意。
啓動方式示例
建立一個服務時,和廣播一樣,這裏要繼承自Service類
有兩種方式啓動和關閉
//這裏是第一種方式
startService(intent);
stopService(intent);
第二種方式中,綁定服務需要傳遞三個參數,第一個就是要調用服務的意圖對象,
第二個是一個ServiceConnection對象,這裏需要實現該類,裏面有有兩個重寫
的方法;最後一個表示標誌位,一般用BIND_AUTO_CREATE
bindService(intent, conn, BIND_AUTO_CREATE);//綁定服務
//解綁服務
unbindService(conn);
class MyServiceConn implements ServiceConnection{
//服務連接成功時,此方法調用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
}
//服務失去連接時,此方法調用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stu
}
}
簡單示例
需求:如果服務類中有一個方法,怎麼去調用
綁定服務時,會觸發服務的onBind方法,此方法會返回一個Ibinder的對象給
MainActivity,通過這個對象訪問服務中的方法
服務類中的方法
@Override
public IBinder onBind(Intent intent) {
// 返回一個Binder對象,這個對象就是中間人對象
return new Tim();
}
class Tim extends Binder implements PublicBusiness{
public void run(){
banZheng();
}
}
public void banZheng(){
System.out.println("幫你來辦證");
}
PublicBusiness接口中只定義一個未實現的run方法就行
public interface PublicBusiness {
void run();
}
主activity中的調用步驟
private Intent intent;
private MyServiceConn conn;
PublicBusiness pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, LeaderService.class);
conn = new MyServiceConn();
//綁定服務
bindService(intent, conn, BIND_AUTO_CREATE);
}
public void click(View v){
//調用服務的辦證方法
pb.run();
}
class MyServiceConn implements ServiceConnection{
//連接服務成功,此方法調用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pb = (PublicBusiness) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
該示例有點類似於找領導辦事一樣,需要通過一箇中間人與領導進行交流,而小
員工與中間人交流,而中間人就是定義的Tim類。
使用服務註冊廣播接收者
這裏的廣播用的不是在清單文件中操作的方式,而是使用代碼註冊
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(Intent.ACTION_SCREEN_OFF.equals(action)){
System.out.println("屏幕關閉");
}
else if(Intent.ACTION_SCREEN_ON.equals(action)){
System.out.println("屏幕打開");
}
}
}
當點擊按鈕時,開啓服務,並且觸發服務中的廣播接收者代碼
//主activity中
public void start(View v){
startService(intent);
}
public void stop(View v){
stopService(intent);
}
//服務中
@Override
public void onCreate() {
super.onCreate();
//1.創建廣播接收者對象
receiver = new ScreenReceiver();
//2.創建intent-filter對象
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
//3.註冊廣播接收者
registerReceiver(receiver, filter);
}
@Override
public void onDestroy() {
super.onDestroy();
//解除註冊,解除註冊之後,廣播接收者將失去作用
unregisterReceiver(receiver);
}
服務分爲本地和遠程之說,那麼如何啓動遠程的服務內容呢
這裏需要用到一個知識點:AIDL(安卓接口定義語言),是進程間通信接口,
作用就是用於進程間通信。應用場景:遠程服務中的中間人對象,其他應
用是拿不到的,那麼在通過綁定服務獲取中間人對象時,就無法強制轉換,
使用aidl,就可以在其他應用中拿到中間人類所實現的接口
示例步驟
1 創建兩個項目,一個上面部署服務,另外一個在主activity上添加一個按鈕,
當點擊的時候,觸發項目1上的服務。
2 過程和簡單示例中的很相似,只不過相當於把主activity和服務分到兩個項目
中實現,還有一點不同的是:這裏的PayInterface.java接口類,後綴要改
爲:PayInterface.aidl文件,並且服務中實現的部分也要改變:
public class PayService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new Mypay();
}
//這裏是繼承了Stub類
class Mypay extends Stub{
public void pay(){
PayService.this.pay_money();
}
}
public void pay_money(){
System.out.println("調用pay方法");
System.out.println("加密用戶名,密碼");
System.out.println("建立連接");
}
}
主方法中調用
private Intent intent;
private MyServiceConn conn;
private PayInterface pin;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent=new Intent();
conn=new MyServiceConn();
intent.setAction("com.itma.pay");
bindService(intent, conn, BIND_AUTO_CREATE);
}
class MyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pin=Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
public void click(View v){
try {
pin.pay();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
進程間通信的步驟
1. 把遠程服務的方法抽取成一個單獨的接口java文件
2. 把接口java文件的後綴名改成aidl
3. 在自動生成的PayInterface .java文件中,有一個靜態抽象類Stub,它已經繼承了binder類,實現了PayInterface接口,這個類就是新的中間人
4. 把aidl文件複製粘貼到另外一個項目,粘貼的時候注意,aidl文件所在的包名必須跟05項目中aidl所在的包名一致
5. 在另外一個項目中,強轉中間人對象時,直接使用Stub.asInterface()
進程優先級
前臺進程:擁有前臺activity(onResume方法被調用),以下都能成爲前臺進程
- 擁有一個正在與用戶交互的activity(onResume調用)的進程
- 擁有一個與正在和用戶交互的activity綁定的服務的進程
- 擁有一個正在“運行於前臺”的服務——服務的startForeground方法調用
- 擁有一個正在執行以下三個生命週期方法中任意一個的服務(onCreate(), onStart(), or onDestroy())
- 擁有一個正在執行onReceive方法的廣播接收者的進程
可見進程:擁有可見activity(onPause方法被調用)
- 擁有一個不在前臺,但是對用戶依然可見的activity(onPause方法調用)的進程
- 擁有一個與可見(或前臺)activity綁定的服務的進程
- 服務進程:不到萬不得已不會被回收,而且即便被回收,內存充足時也會被重啓
- 後臺進程:擁有後臺activity(activity的onStop方法被調用了),很容易被回收
- 空進程:沒有運行任何activity,很容易被回收