服務的用法

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()

進程優先級

  1. 前臺進程:擁有前臺activity(onResume方法被調用),以下都能成爲前臺進程

    • 擁有一個正在與用戶交互的activity(onResume調用)的進程
    • 擁有一個與正在和用戶交互的activity綁定的服務的進程
    • 擁有一個正在“運行於前臺”的服務——服務的startForeground方法調用
    • 擁有一個正在執行以下三個生命週期方法中任意一個的服務(onCreate(), onStart(), or onDestroy())
    • 擁有一個正在執行onReceive方法的廣播接收者的進程
  2. 可見進程:擁有可見activity(onPause方法被調用)

    • 擁有一個不在前臺,但是對用戶依然可見的activity(onPause方法調用)的進程
    • 擁有一個與可見(或前臺)activity綁定的服務的進程
  3. 服務進程:不到萬不得已不會被回收,而且即便被回收,內存充足時也會被重啓
  4. 後臺進程:擁有後臺activity(activity的onStop方法被調用了),很容易被回收
  5. 空進程:沒有運行任何activity,很容易被回收
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章