Service

本文copy自全面簡潔Service講解,僅僅用于個人加深印象

Service是Android程序中四大基礎組件之一,它和Activity一樣都是Context的子類,只不過它沒有UI界面,是在后臺運行的組件。
Service是Android中實現(xiàn)程序后臺運行的解決方案,它非常適用于去執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務。
Service默認并不會運行在子線程中,它也不運行在一個獨立的進程中,它同樣執(zhí)行在UI線程中,因此,不要在Service中執(zhí)行耗時的操作,除非你在Service中創(chuàng)建了子線程來完成耗時操作。


生命周期

  • 官方說明圖


  • 生命周期方法具體介紹
    主要介紹內部調用方法 & 外部調用方法的關系。



    4個手動調用的方法
    startService() 啟動服務
    stopService() 關閉服務
    bindService() 綁定服務
    unbindService() 解綁服務
    5個自動調用的方法
    onCreat() 創(chuàng)建服務
    onStartCommand() 開始服務
    onDestroy() 銷毀服務
    onBind() 綁定服務
    onUnbind() 解綁服務

  • 常見的生命周期使用


類型

按照運行地點分類

  • 本地服務
    特點:運行在主線程,主進程被終止后,服務也會終止
    優(yōu)點:節(jié)約資源,通信方便,由于在同一進程因此不需要IPC和AIDL
    缺點:限制性大,主進程被終止后,服務也會終止
    應用:需要依附某個進程的服務,最常用的服務類型,如音樂播放
  • 遠程服務
    特點:運行在獨立進程,服務常駐在后臺,不受其他Activity影響
    優(yōu)點:靈活,服務常駐在后臺,不受其他Activity影響
    缺點:消耗資源,單獨進程,使用AIDL進程IPC復雜
    應用:系統(tǒng)級別服務

按照運行類型分類

  • 前臺服務
    特點:在通知欄顯示通知,用戶能看到。
    應用:服務使用時需讓用戶知道并進行相關操作等,如音樂播放器,服務被終止時,通知欄的通知也會消失
  • 后臺服務
    特點:處于后臺的服務,用戶無法看到
    應用:服務使用時不需要用戶知道或進行相關操作,如天氣更新,日期同步。服務被終止時,用戶無法知道

按照功能分類

  • 不可通信的后臺服務
    特點:用startService()啟動,調用者退出后Service仍然存在
    應用:服務不需要與Activity&Service通信
  • 可通信的后臺服務
    1)
    特點:用bindService() 啟動,調用者退出后,隨著調用者銷毀。
    應用:服務需要與Activity&Service通信,需控制服務開始時刻。
    2)
    特點:使用startService(),bindService()啟動,調用者退出后,隨著調用者銷毀。
    應用:服務需要與Activity&Service通信,不需要控制服務開始時刻。(服務一開始就運行)

使用講解

本地Service

這是最普通、最常用的后臺服務Service。

  • 步驟1:新建子類繼承Service類
    需重寫父類的onCreate()、onStartCommand()、onDestroy()和onBind()方法
public class MyService extends Service {
//啟動Service之后,就可以在onCreate()或onStartCommand()方法里去執(zhí)行一些具體的邏輯
//由于這里作Demo用,所以只打印一些語句
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("執(zhí)行了onCreat()");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("執(zhí)行了onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("執(zhí)行了onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  • 步驟2:構建用于啟動Service的Intent對象
  • 步驟3:調用startService()啟動Service、調用stopService()停止服務
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startService;
    private Button stopService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = (Button) findViewById(R.id.startService);
        stopService = (Button) findViewById(R.id.stopService);
        startService.setOnClickListener(this);
        startService.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            //點擊啟動Service Button
            case R.id.startService:
                //構建啟動服務的Intent對象
                Intent startIntent = new Intent(this, MyService.class);
                //調用startService()方法-傳入Intent對象,以此啟動服務
                startService(startIntent);
            //點擊停止Service Button
            case R.id.stopService:
                //構建停止服務的Intent對象
                Intent stopIntent = new Intent(this, MyService.class);
                //調用stopService()方法-傳入Intent對象,以此停止服務
                stopService(stopIntent);
        }
    }
}
  • 步驟4:在AndroidManifest.xml里注冊Service
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="scut.carson_ho.demo_service">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        //注冊Service服務
        <service android:name=".MyService">
        </service>
    </application>
</manifest>

Androidmanifest里Service的常見屬性說明

屬性                      說明                                        備注
android:name              Service的類名    
android:label             Service的名字                               若不設置,默認為Service類名
android:icon              Service的圖標    
android:permission        申明此Service的權限                          有提供了該權限的應用才能控制或連接此服務
android:process           表示該服務是否在另一個進程中運行(遠程服務)     不設置默認為本地服務;remote則設置成遠程服務
android:enabled           系統(tǒng)默認啟動                                 true:Service 將會默認被系統(tǒng)啟動;不設置則默認為false
android:exported          該服務是否能夠被其他應用程序所控制或連接        不設置默認此項為 false
可通信的服務Service

上面介紹的Service是最基礎的,但只能單機使用,即無法與Activity通信
接下來將在上面的基礎用法上,增設“與Activity通信”的功能,即使用綁定Service服務(Binder類、bindService()、onBind()、unbindService()、onUnbind())

  • 步驟1:在新建子類繼承Service類,并新建一個子類繼承自Binder類、寫入與Activity關聯(lián)需要的方法、創(chuàng)建實例
public class MyService extends Service {

    private MyBinder mBinder = new MyBinder();
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("執(zhí)行了onCreat()");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("執(zhí)行了onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("執(zhí)行了onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("執(zhí)行了onBind()");
        //返回實例
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("執(zhí)行了onUnbind()");
        return super.onUnbind(intent);
    }
    //新建一個子類繼承自Binder類
    class MyBinder extends Binder {
        public void service_connect_Activity() {
            System.out.println("Service關聯(lián)了Activity,并在Activity執(zhí)行了Service的方法");
        }
    }
}
  • 步驟2:在主布局文件再設置兩個Button分別用于綁定和解綁Service
  • 步驟3:在Activity通過調用MyBinder類中的public方法來實現(xiàn)Activity與Service的聯(lián)系
    即實現(xiàn)了Activity指揮Service干什么Service就去干什么的功能
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startService;
    private Button stopService;
    private Button bindService;
    private Button unbindService;
    private MyService.MyBinder myBinder;

    //創(chuàng)建ServiceConnection的匿名類
    private ServiceConnection connection = new ServiceConnection() {
        //重寫onServiceConnected()方法和onServiceDisconnected()方法
        //在Activity與Service建立關聯(lián)和解除關聯(lián)的時候調用
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
        //在Activity與Service解除關聯(lián)的時候調用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //實例化Service的內部類myBinder
            //通過向下轉型得到了MyBinder的實例
            myBinder = (MyService.MyBinder) service;
            //在Activity調用Service類的方法
            myBinder.service_connect_Activity();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = (Button) findViewById(R.id.startService);
        stopService = (Button) findViewById(R.id.stopService);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        bindService = (Button) findViewById(R.id.bindService);
        unbindService = (Button) findViewById(R.id.unbindService);

        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.startService: //點擊啟動Service
                Intent startIntent = new Intent(this, MyService.class); //構建啟動服務的Intent對象
                startService(startIntent);//調用startService()方法-傳入Intent對象,以此啟動服務
                break;
            case R.id.stopService:   //點擊停止Service
                Intent stopIntent = new Intent(this, MyService.class);  //構建停止服務的Intent對象
                stopService(stopIntent); //調用stopService()方法-傳入Intent對象,以此停止服務
                break;
            case R.id.bindService:   //點擊綁定Service
                Intent bindIntent = new Intent(this, MyService.class);    //構建綁定服務的Intent對象
                bindService(bindIntent,connection,BIND_AUTO_CREATE);  //調用bindService()方法,以此停止服務
                //參數(shù)說明
                //第一個參數(shù):Intent對象
                //第二個參數(shù):上面創(chuàng)建的Serviceconnection實例
                //第三個參數(shù):標志位
                //這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關聯(lián)后自動創(chuàng)建Service
                //這會使得MyService中的onCreate()方法得到執(zhí)行,但onStartCommand()方法不會執(zhí)行
                break;
            case R.id.unbindService: //點擊解綁Service
                unbindService(connection); //調用unbindService()解綁服務,參數(shù)是上面創(chuàng)建的Serviceconnection實例
                break;
                default:
                    break;
        }
    }
}
前臺Service

前臺Service和后臺Service(普通)最大的區(qū)別就在于:

  1. 前臺Service在下拉通知欄有顯示通知(如下圖),但后臺Service沒有;
  2. 前臺Service優(yōu)先級較高,不會由于系統(tǒng)內存不足而被回收;后臺Service優(yōu)先級較低,當系統(tǒng)出現(xiàn)內存不足情況時,很有可能會被回收
    用法很簡單,只需要在原有的Service類對onCreate()方法進行稍微修改即可
@Override
    public void onCreate() {
        super.onCreate();
        System.out.println("執(zhí)行了onCreat()");

        //添加下列代碼將后臺Service變成前臺Service
        //構建"點擊通知后打開MainActivity"的Intent對象
        Intent notificationIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);

        //新建Builer對象
        Notification.Builder builer = new Notification.Builder(this);
        builer.setContentTitle("前臺服務通知的標題");//設置通知的標題
        builer.setContentText("前臺服務通知的內容");//設置通知的內容
        builer.setSmallIcon(R.mipmap.ic_launcher);//設置通知的圖標
        builer.setContentIntent(pendingIntent);//設置點擊通知后的操作

        Notification notification = builer.getNotification();//將Builder對象轉變成普通的notification
        startForeground(1, notification);//讓Service變成前臺Service,并在系統(tǒng)的狀態(tài)欄顯示出來

    }
遠程Service

Android:遠程服務Service(含AIDL & IPC講解)

使用場景

通過上述描述,你應該對Service類型及其使用非常了解;
那么,我們該什么時候用哪種類型的Service呢?
各種Service的使用場景請看下圖:


其他補充

  1. Service 與 Thread的區(qū)別
  • 結論:Service 與 Thread 無任何關系
  • 之所以有不少人會把它們聯(lián)系起來,主要因為Service的后臺概念
    后臺:后臺任務運行完全不依賴UI,即使Activity被銷毀 / 程序被關閉,只要進程還在,后臺任務就可繼續(xù)運行
  • 關于二者的異同


  • 一般會將 Service 和 Thread聯(lián)合著用,即在Service中再創(chuàng)建一個子線程(工作線程)去處理耗時操作邏輯,如下代碼
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
//新建工作線程
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            // 開始執(zhí)行后臺任務  
        }  
    }).start();  
    return super.onStartCommand(intent, flags, startId);  
}  
class MyBinder extends Binder {  
    public void service_connect_Activity() {  
  //新建工作線程
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 執(zhí)行具體的下載任務  
            }  
        }).start();  
    }  
}  
  1. Service和IntentService的區(qū)別
    具體請看文章:Android多線程:IntentService用法&源碼
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容