Service 學(xué)習(xí)

A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding <service> declaration in its package'sAndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().
Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.

從官方文檔上可以看出,Service服務(wù)是不與用戶交互,長(zhǎng)時(shí)間在后臺(tái)運(yùn)行的一個(gè)組件。但是所在線程是在主線程,如果要處理耗時(shí)操作如播放音樂,處理網(wǎng)絡(luò)請(qǐng)求的話需要啟動(dòng)一個(gè)子線程來處理。


一、啟動(dòng)與銷毀

  • 啟動(dòng)Service
    啟動(dòng)Service有兩種方法:
    ①startService()
Intent intent = new Intent(MainActivity.this,TestService.class);
startService(intent);

生命流程:onCreate() → onStartCommand() → onDestory()
注意: onCreate()方法只會(huì)執(zhí)行一次,多次調(diào)用StartService()方法只會(huì)在第一次調(diào)用onCreate(),而onStartCommand()會(huì)多次調(diào)用。
當(dāng)服務(wù)被啟動(dòng)后,Service與Activity就沒有了關(guān)系,Activity退出后Service還會(huì)執(zhí)行。
②bindService()

bindService(intent,mcon,BIND_AUTO_CREATE);
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{     
      @Override    
      public void onServiceConnected(ComponentName name, IBinder service) {        
            myBinder = (TestService.MyBinder)service;    
      }    
      @Override    
      public void onServiceDisconnected(ComponentName name) {

      }
}
onServiceConnected()
系統(tǒng)調(diào)用這個(gè)來傳送在service的onBind()中返回的IBinder.
OnServiceDisconnected()
Android系統(tǒng)在同service的連接意外丟失時(shí)調(diào)用這個(gè).比如當(dāng)service崩潰了或被強(qiáng)殺了.
當(dāng)客戶端解除綁定時(shí),這個(gè)方法不會(huì)被調(diào)用. 類ServiceConnection中的onServiceDisconnected()方法在正常情況下是不被調(diào)用的,
它的調(diào)用時(shí)機(jī)是當(dāng)Service服務(wù)被異外銷毀時(shí),例如內(nèi)存的資源不足時(shí)這個(gè)方法才被自動(dòng)調(diào)用。

生命流程: onCreate() → onBind() → onUnbind() → onDestory()
多次調(diào)用bindService()并不會(huì)再次調(diào)用onCreate() 和onBind()。
當(dāng)服務(wù)被啟動(dòng)后,Service與Activity就綁定在了一起,當(dāng)Activity退出之后Service也退出。

  • 銷毀service
    使用startService()啟動(dòng)之后調(diào)用stopService()來銷毀服務(wù)。
    使用bindService()綁定之后調(diào)用unbindService()來銷毀服務(wù)。
    如果同時(shí)調(diào)用startService()與bindService(),銷毀時(shí)需要同時(shí)調(diào)用stopService()與unbindService()來銷毀。
           
    1.如果先bindService,再startService:
    在bind的Activity退出的時(shí)候,Service會(huì)執(zhí)行unBind方法而不執(zhí)行onDestory方法,因?yàn)橛衧tartService方法調(diào)用過,所以Activity與Service解除綁定后會(huì)有一個(gè)與調(diào)用者沒有關(guān)連的Service存在
    2.如果先bindService,再startService,再調(diào)用Context.stopService
    Service的onDestory方法不會(huì)立刻執(zhí)行,因?yàn)橛幸粋€(gè)與Service綁定的Activity,但是在Activity退出的時(shí)候,會(huì)執(zhí)行onDestory,如果要立刻執(zhí)行stopService,就得先解除綁定 
     
    要注意合理中斷Service中的線程,最好設(shè)置變量檢測(cè)中斷(先挖個(gè)坑)。

  • onStartCommand返回值
    START_STICKY:如果service進(jìn)程被kill掉,保留service的狀態(tài)為開始狀態(tài),但不保留遞送的intent對(duì)象。隨后系統(tǒng)會(huì)嘗試重新創(chuàng)建service,由于服務(wù)狀態(tài)為開始狀態(tài),所以創(chuàng)建服務(wù)后一定會(huì)調(diào)用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動(dòng)命令被傳遞到service,那么參數(shù)Intent將為null。
    START_NOT_STICKY:“非粘性的”。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)
    START_REDELIVER_INTENT:重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。
    START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務(wù)被kill后一定能重啟。

  • **bindService參數(shù) **
    BIND_AUTO_CREATE:一般為這個(gè),代表Service不存在時(shí)自動(dòng)創(chuàng)建該Service。

二、Service與Activity通信

  • 采用onBind與接口方式雙向通信
public interface BinderInterface {    
      int getI();    
      void setI(int a);
}          
            
class MyBinder extends Binder implements BinderInterface{    
      @Override    
      public int getI() {        
      return i;    
      }    
      @Override    
      public void setI(int a) {        
      i = a;        
      mtThread.interrupt();    
      }
}
   
public MyBinder mBinder = new MyBinder();    
public IBinder onBind(Intent intent) { 
      return mBinder;    
}

利用obBind()將一個(gè)Binder對(duì)象傳遞給Activity。

public TestService.MyBinder myBinder;
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{     
      @Override    
      public void onServiceConnected(ComponentName name, IBinder service) {        
            myBinder = (TestService.MyBinder)service;    
      }    
      @Override    
      public void onServiceDisconnected(ComponentName name) {

      }
}

轉(zhuǎn)化為MyBinder對(duì)象之后就可以使用MyBinder中的方法來相互通信了。

myBinder.setI(1000);
int i = myBinder.getI();
  • 使用Intent通信
    使用Intetnt在Activity啟動(dòng)Service時(shí),將數(shù)據(jù)放入Intent之中,之后在Service中的onStartCommand(Intent intent, int flags, int startId)方法中獲取到Intetnt并提取出數(shù)據(jù)。
Activity中:
Intent intent = new Intent(MainActivity.this,TestService.class)
intent.putExtra("name","li");
startService(intent);
    
Service中
public int onStartCommand(Intent intent, int flags, int startId) {    
      String name  = (intent.getExtras()).getString("name");        
      return START_STICKY;
}

三、前臺(tái)服務(wù)

  • 提升為前臺(tái)服務(wù)
    什么是前臺(tái)服務(wù)

A foreground service(前臺(tái)服務(wù)) is a service that's considered to be(被用戶所認(rèn)可的) something the
user is actively aware of and thus not a candidate for(而不是一個(gè)候選的,可以在內(nèi)存不足時(shí),被系統(tǒng)殺死
的) the system to kill when low on memory. A foreground service must provide a notification for the status
bar(前臺(tái)服務(wù)必須提供一個(gè)顯示通知), which is placed under the "Ongoing" heading(它是不可以忽略的), >which means that the notification cannot be dismissed unless the service is either stopped or removed from >the foreground.(意思是通知信息不能被忽略,除非服務(wù)停止或主動(dòng)移除,否則將一直顯示)

前臺(tái)服務(wù)是那些被認(rèn)為用戶知道(用戶認(rèn)可所認(rèn)可)且在系統(tǒng)內(nèi)存不足的時(shí)候不允許系統(tǒng)殺死的服務(wù)。 前臺(tái)服務(wù)必須給狀態(tài)欄提供一個(gè)通知,它被放到正在運(yùn)行(Ongoing)標(biāo)題之下——這就意味著通知只有在這個(gè)服務(wù)被終止或從前臺(tái)主動(dòng)移除通知后才能被解除。
如果我們希望Service可以一直保持運(yùn)行狀態(tài)且不會(huì)在內(nèi)存不足的情況下被回收時(shí),可以選擇將需要保持運(yùn)行的Service設(shè)置為前臺(tái)服務(wù)
   
創(chuàng)建Notifition

private void bulidNotifition() {    
      notificationBuilder = new Notification.Builder(this);    
      Intent intent = new Intent(this,MainActivity.class);    
      notification = notificationBuilder.setContentIntent(PendingIntent.getActivity(this,0,intent,0))
              .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher))
              .setContentTitle("前臺(tái)Serviece")            
              .setContentText("內(nèi)容")           
              .setWhen(System.currentTimeMillis()).build();
}

在onStartCommand中啟動(dòng)前臺(tái)服務(wù)

public int onStartCommand(Intent intent, int flags, int startId) {    
      bulidNotifition();    
      startForeground(100,notification);    //100表示前臺(tái)服務(wù)的id  當(dāng)使用的通知ID一致時(shí),只會(huì)更新當(dāng)前Notification
      return START_STICKY;
}

停止前臺(tái)服務(wù)

stopForeground(true);

啟動(dòng)服務(wù)之后,就會(huì)看到提示框那里有個(gè)提示欄,說明我們的Service已經(jīng)成為前臺(tái)服務(wù)了。

四、IntentService

開啟一個(gè)線程來處理用戶的intent請(qǐng)求,采用隊(duì)列等待,一個(gè)時(shí)間只有一個(gè)intent請(qǐng)求被執(zhí)行。

主要方法:onHandleIntent(Intent intent)

此方法在具有請(qǐng)求的工作線程上被調(diào)用。 每次只處理一個(gè)Intent,但是處理發(fā)生在獨(dú)立于其他應(yīng)用程序邏輯運(yùn)行的工作線程上。 所以,如果這段代碼需要很長(zhǎng)時(shí)間,它會(huì)阻止對(duì)同一IntentService的其他請(qǐng)求,但它不會(huì)阻止任何其他。 當(dāng)所有請(qǐng)求都被處理后,IntentService停止自己,所以你不應(yīng)該調(diào)用stopSelf()。

button1.setOnClickListener(new View.OnClickListener() {
    @Override    
    public void onClick(View v) {
        Intent intentservice1 = new Intent(MainActivity.this,MyIntentService.class);
        intentservice1.putExtra("action",1);
        startService(intentservice1);
    }
});

button2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intentservice2 = new Intent(MainActivity.this,MyIntentService.class);
        intentservice2.putExtra("action",2);
        startService(intentservice2);
    }
}
);
protected void onHandleIntent(Intent intent) {
    Log.d("intent",intent.getIntExtra("action",0)+"");
    try {
         Log.d("A1sleep","A1sleep");
         Thread.sleep(2000);
         Log.d("sleep down","sleep down");
    } catch (InterruptedException e) {
         e.printStackTrace();
    }
}
依次按下按鈕,intent依次執(zhí)行

五、跨進(jìn)程Service與通信

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容