四大組件之:service

一、service是什么

  • service是Android中實(shí)現(xiàn)程序后臺(tái)運(yùn)行的解決方案,他非常適合是去執(zhí)行那些不需要和用戶交互而且還要長期運(yùn)行的任務(wù)。
  • 服務(wù)的運(yùn)行不依賴于任何用戶界面,即使程序被切換到后臺(tái),或者用戶打開了另一個(gè)應(yīng)用程序,服務(wù)仍然能夠保持獨(dú)立運(yùn)行。
  • 服務(wù)并不是運(yùn)行在一個(gè)獨(dú)立的進(jìn)程當(dāng)中,而是依賴于創(chuàng)建服務(wù)時(shí)所在的應(yīng)用程序進(jìn)程。當(dāng)某個(gè)應(yīng)用程序被殺掉時(shí),所有依賴該進(jìn)程的服務(wù)也會(huì)停止運(yùn)行。

二、service的兩種狀態(tài)

啟動(dòng)狀態(tài):

當(dāng)應(yīng)用組件(如 Activity)通過調(diào)用 startService() 啟動(dòng)服務(wù)時(shí),服務(wù)即處于“啟動(dòng)”狀態(tài)。一旦啟動(dòng),服務(wù)即可在后臺(tái)無限期運(yùn)行,即使啟動(dòng)服務(wù)的組件已被銷毀也不受影響,除非手動(dòng)調(diào)用才能停止服務(wù), 已啟動(dòng)的服務(wù)通常是執(zhí)行單一操作,而且不會(huì)將結(jié)果返回給調(diào)用方。

綁定狀態(tài):

當(dāng)應(yīng)用組件通過調(diào)用 bindService() 綁定到服務(wù)時(shí),服務(wù)即處于“綁定”狀態(tài)。綁定服務(wù)提供了一個(gè)客戶端-服務(wù)器接口,允許組件與服務(wù)進(jìn)行交互、發(fā)送請(qǐng)求、獲取結(jié)果,甚至是利用進(jìn)程間通信 (IPC) 跨進(jìn)程執(zhí)行這些操作。 僅當(dāng)與另一個(gè)應(yīng)用組件綁定時(shí),綁定服務(wù)才會(huì)運(yùn)行。 多個(gè)組件可以同時(shí)綁定到該服務(wù),但全部取消綁定后,該服務(wù)即會(huì)被銷毀。

三、啟動(dòng)服務(wù)與綁定服務(wù)的生命周期

image.png

四、創(chuàng)建服務(wù)

4.1、創(chuàng)建 Service 的子類,重寫onStartCommand()、onCreate()、onDestroy()幾個(gè)方法。

public class MainService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
  
  //創(chuàng)建
    @Override
    public void onCreate() {
        super.onCreate();
    }

//  啟動(dòng)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

//銷毀
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

onCreate():

1.如果service沒被創(chuàng)建過,調(diào)用startService()后會(huì)執(zhí)行onCreate()回調(diào);
2.如果service已處于運(yùn)行中,調(diào)用startService()不會(huì)執(zhí)行onCreate()方法。
onCreate()只會(huì)在第一次創(chuàng)建service時(shí)候調(diào)用,多次執(zhí)行startService()不會(huì)重復(fù)調(diào)用onCreate(),此方法適合完成一些初始化工作。

onStartCommand():

如果多次執(zhí)行了Context的startService()方法,那么Service的onStartCommand()方法也會(huì)相應(yīng)的多次調(diào)用。onStartCommand()方法很重要,我們?cè)谠摲椒ㄖ懈鶕?jù)傳入的Intent參數(shù)進(jìn)行實(shí)際的操作,比如會(huì)在此處創(chuàng)建一個(gè)線程用于下載數(shù)據(jù)或播放音樂等。

onBind():

Service中的onBind()方法是抽象方法,Service類本身就是抽象類,所以onBind()方法是必須重寫的,即使我們用不到。

onDestory() :

在銷毀的時(shí)候會(huì)執(zhí)行Service該方法。

4.2、啟動(dòng)和關(guān)閉服務(wù)

在Activity 或Fragment 的點(diǎn)擊事件 或者生命周期中

啟動(dòng)服務(wù)

 Intent start = new Intent(this,myservice.class);
  startService(start);

停止服務(wù)

   Intent stop = new Intent(this,myservice.class);
   stopService(stop);

最后記得 Android 的四大組件 都要在 AndroidManifest.xml 注冊(cè):

   <service android:name=".MainService"/>

啟動(dòng)流程:第一次啟動(dòng)服務(wù) ->第二次啟動(dòng)服務(wù) ->第三次啟動(dòng)服務(wù) ->銷毀服務(wù)


image.png

在我們第一次啟動(dòng)服務(wù)的時(shí)候,會(huì)執(zhí)行service中的 oncreate 還有 onStartCommand(前提是服務(wù)在之前還沒有進(jìn)行啟動(dòng)) 否則 他只會(huì)單獨(dú)調(diào)用 onStartCommand方法 ,使用 stopservice() 就能夠?qū)崿F(xiàn)中斷服務(wù)的啟動(dòng)。

五、service綁定服務(wù)

  • 當(dāng)其他組件(如 Activity)綁定到服務(wù)時(shí),Activity可以向Service發(fā)送請(qǐng)求,或者調(diào)用Service)的方法,此時(shí)被綁定的Service會(huì)接收信息并響應(yīng)。

  • 與啟動(dòng)服務(wù)不同的是,綁定服務(wù)的生命周期通常只在為其他應(yīng)用組件(如Activity)服務(wù)時(shí)處于活動(dòng)狀態(tài),不會(huì)無限期在后臺(tái)運(yùn)行,也就是說宿主(如Activity)解除綁定后,綁定服務(wù)就會(huì)被銷毀。

三種方法
擴(kuò)展 Binder 類
在service類中進(jìn)行添加一個(gè)binder內(nèi)部類,我們通過前臺(tái)進(jìn)行綁定后,當(dāng)綁定后成功后,客戶端收到binder 后,可利用他直接訪問 Binder 實(shí)現(xiàn)中以及Service 中可用的公共方法。如果我們的服務(wù)只是自有應(yīng)用的后臺(tái)工作線程,則優(yōu)先采用這種方法。前提:service服務(wù)端與客戶端相同的進(jìn)程中運(yùn)行。

使用 Messenger
這是執(zhí)行進(jìn)程間通信 (IPC) 的最簡(jiǎn)單方法,因?yàn)?Messenger 會(huì)在單一線程中創(chuàng)建包含所有請(qǐng)求的隊(duì)列,也就是說Messenger是以串行的方式處理客戶端發(fā)來的消息,這樣我們就不必對(duì)服務(wù)進(jìn)行線程安全設(shè)計(jì)了。

使用 AIDL
,如果我們想讓服務(wù)同時(shí)處理多個(gè)請(qǐng)求,則應(yīng)該使用 AIDL。 在此情況下,服務(wù)必須具備多線程處理能力,并采用線程安全式設(shè)計(jì)。使用AIDL必須創(chuàng)建一個(gè)定義編程接口的 .aidl 文件。Android SDK 工具利用該文件生成一個(gè)實(shí)現(xiàn)接口并處理 IPC 的抽象類,隨后可在服務(wù)內(nèi)對(duì)其進(jìn)行擴(kuò)展。

5.1、擴(kuò)展 Binder 類,實(shí)現(xiàn)組件與Service交互
流程如下:
1、在服務(wù)中:創(chuàng)建 binder子類,讓組件能夠通過 binder 類實(shí)現(xiàn)對(duì) service 的調(diào)用,service 中的 onbinder方法返回 binder 實(shí)例。
2、組件中:創(chuàng)建一個(gè)ServiceConnection 的匿名類。
3、通過點(diǎn)擊事件或者其他綁定或解綁服務(wù)

5.1.1、創(chuàng)建 binder子類、onbinder方法返回 binder 實(shí)例

public class MainService extends Service {
    private static final String TAG = "MainService";
    private LocalBinder mBinder=new LocalBinder();
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
      ....
    public class LocalBinder extends Binder {
        public void start(){
            Log.e(TAG, "start:" );
        }
        public void end(){
            Log.e(TAG, "end:" );
        }
    }
}

5.1.2、創(chuàng)建ServiceConnection 匿名類

public class MainActivity extends AppCompatActivity {
private MyService.LocalBinder loadBinder;//獲取服務(wù)中定義的LocalBinder;
....
 private ServiceConnection connection =new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
       //綁定成功
       //調(diào)用LocalBinder 里面的任何public方法
              loadBinder=(MyService.LocalBinder ) service;
              loadBinder.start();
              loadBinder.end();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
  //斷開綁定

        }
    };
}

5.1.3、綁定或解綁服務(wù)
綁定服務(wù):

Intent intent=new Intent(this,MyService.class);
  bindService(intent,connection,BIND_AUTO_CREATE);

解綁服務(wù)

unbindService(connection );

六、啟動(dòng)服務(wù)與綁定服務(wù)之間的問題

  • 先綁定服務(wù)后啟動(dòng)服務(wù)
    如果當(dāng)前Service實(shí)例先以綁定狀態(tài)運(yùn)行,然后再以啟動(dòng)狀態(tài)運(yùn)行,那么綁定服務(wù)將會(huì)轉(zhuǎn)為啟動(dòng)服務(wù)運(yùn)行,這時(shí)如果之前綁定的宿主(Activity)被銷毀了,也不會(huì)影響服務(wù)的運(yùn)行,服務(wù)還是會(huì)一直運(yùn)行下去,指定收到調(diào)用停止服務(wù)或者內(nèi)存不足時(shí)才會(huì)銷毀該服務(wù)。

  • 先啟動(dòng)服務(wù)后綁定服務(wù)
    如果當(dāng)前Service實(shí)例先以啟動(dòng)狀態(tài)運(yùn)行,然后再以綁定狀態(tài)運(yùn)行,當(dāng)前啟動(dòng)服務(wù)并不會(huì)轉(zhuǎn)為綁定服務(wù),但是還是會(huì)與宿主綁定,只是即使宿主解除綁定后,服務(wù)依然按啟動(dòng)服務(wù)的生命周期在后臺(tái)運(yùn)行,直到有Context調(diào)用了stopService()或是服務(wù)本身調(diào)用了stopSelf()方法抑或內(nèi)存不足時(shí)才會(huì)銷毀服務(wù)。

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

  • 后臺(tái)服務(wù)的系統(tǒng)優(yōu)先級(jí)還是比較低的,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足的情況時(shí),就有可能會(huì)回收正在后臺(tái)運(yùn)行的服 務(wù)。
  • 如果你希望可以一直保持運(yùn)行狀態(tài),而不會(huì)由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥?,就可以考慮使用前臺(tái)服 務(wù)。
  • 前臺(tái)服務(wù)和普通服務(wù)最大的區(qū)別就在于,他會(huì)一直有一個(gè)正在運(yùn)行的圖標(biāo)在系統(tǒng)的狀態(tài)欄顯示,下拉狀 態(tài)欄后可以看到更加詳細(xì)的信息,非常類似于通知的效果。

具體實(shí)例:在服務(wù)(service)的onCreate()方法中啟動(dòng)通知

   @Override
    public void onCreate() {
        Log.d(TAG, "onCreate: ");
        super.onCreate();
        Notification notification=new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentText("服務(wù)啟動(dòng)")
                .setContentTitle("服務(wù)").build();

        startForeground(1,notification);
    }

重新運(yùn)行啟動(dòng)服務(wù):


image.png

八、IntentService

Android 專門提供了一個(gè)IntentService類,是 Service 的子類,這是一個(gè)異步的、會(huì)自動(dòng)停止的服務(wù)。

使用步驟:

  • 第一步:新建類并繼承IntentService,在這里需要提供一個(gè)無參的構(gòu)造函數(shù)且必須在其內(nèi)部調(diào)用父類的有參構(gòu)造函數(shù),然后具體實(shí)現(xiàn) onHandleIntent()方法,在里可以去處理一些耗時(shí)操作而不用擔(dān)心 ANR的問題,因?yàn)檫@個(gè)方法已經(jīng)是在子線程中運(yùn)行的了。
  • 第二步:在配置文件中進(jìn)行注冊(cè)。
  • 第三步:在活動(dòng)中利用Intent實(shí)現(xiàn)IntentService的啟動(dòng),和Service用的方法是完全一樣的。
    新建一個(gè)newMainService類 繼承IntentService:
public class NewMainService extends IntentService {
    private static final String TAG = "NewMainService";

    public NewMainService() {
        super("NewMainService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent: "+Thread.currentThread().getName());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }
}

記得在配置文件中配置

        <service android:name=".NewMainService"/>

跟普通Service 一樣啟動(dòng)它:

       Intent intent=new Intent(this,NewMainService.class);
        startService(intent);

結(jié)果:


image.png

參考文章: https://blog.csdn.net/weixin_39460667/article/details/82770164

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容