淺談Android Service

Service 服務(wù)

什么是服務(wù):

A service is not a separate process and A service is not thread; A Service is an application component that can perform long-running opreations in the background and doesnot provider a userinterface.

  • 服務(wù)是一個無界面化的應(yīng)用程序組件
  • 服務(wù)一般用于后臺進行耗時操作

Service的生命周期:

![Upload service_lifecycle.png failed. Please try again.]

startService方式開啟服務(wù):

  • startService(Intent service),通過intent值來指定啟動哪個Service,可以直接指定目標(biāo)Service的名,也可以通過Intent的action屬性來啟動設(shè)置了相應(yīng)action屬性的Service,使用這種方式啟動的Service,當(dāng)啟動它的Activity被銷毀時,是不會影響到它的運行的,這時它仍然繼續(xù)在后臺運行它的工作。直至調(diào)用StopService(Intent service)方法時或者是當(dāng)系統(tǒng)資源非常緊缺時,這個服務(wù)才會調(diào)用onDestory()方法停止運行。所以這種Service一般可以用做,處理一些耗時的工作。
  • 四大組件默認(rèn)都是和activity運行在同一個主線程中的,那就是說activity通過startservice方法啟動一個服務(wù)后,被啟動的服務(wù)和activity都是在同一個線程中的。所以當(dāng)我主動銷毀了這個activity,但是他所在的線程還是存在的,只不過是這個activity他所占用的資源被釋放掉了,這個activity所在的主線程只有當(dāng)android內(nèi)存不足才會被殺死掉,否則一般的情況下這個activity所在的應(yīng)用程序的線程始終存在,也就是這個activity所啟動的服務(wù)也會一直運行下去。
Service

    public class LifeService extends Service {
        private static final String TAG = "LifeService";

        @Override
        public void onCreate() {
            Log.d(TAG, "服務(wù)------onCreate");
            super.onCreate();
    
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "服務(wù)------onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
        @Override
        public void onDestroy() {
            Log.d(TAG, "服務(wù)------onDestroy");
            super.onDestroy();
        }
    }
Activity

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void startService(View view) {
            Intent intent = new Intent(this, LifeService.class);
            startService(intent);
        }
    
        public void stopService(View view) {
    
            Intent intent = new Intent(this, LifeService.class);
            stopService(intent);
        }
    }
運行結(jié)果:

![Upload start_service_lifecycle.png failed. Please try again.]

Service 可以被開啟多次,但是只會創(chuàng)建一次.

bindService方式開啟服務(wù)

  • bindService開啟的服務(wù),可以調(diào)用到服務(wù)中的方法.
  • 啟動的LifeService是和MainActivity在同一個進程里的,因為在注冊服務(wù)時,沒有配置它的android:process = "xxxx" 屬性。
Service

    public class LifeService extends Service {
        private static final String TAG = "LifeService";

        @Override
        public void onCreate() {
            Log.d(TAG, "服務(wù)------onCreate");
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "服務(wù)------onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "服務(wù)------onDestroy");
            super.onDestroy();
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.d(TAG, "服務(wù)------onUnbind");
            return super.onUnbind(intent);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG, "服務(wù)------onBind");
            return new Mybind();
        }
    
        public class Mybind extends Binder {
    
            public void callMethodInService() {
                methodInService();
            }
    
        }
        
        public void methodInService() {
            Toast.makeText(this, "服務(wù)里的方法被調(diào)用了", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "服務(wù)里的方法被調(diào)用了");
        }   
    }
Activity

    public class MainActivity extends AppCompatActivity {
    
        private ServiceConnection conn;
        private LifeService.Mybind mBinder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        
        //綁定服務(wù)
        public void bindService(View view) {
            Intent intent = new Intent(this, LifeService.class);
            conn = new MyServiceConnection();
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
    
        private class MyServiceConnection implements ServiceConnection {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinder = (LifeService.Mybind) service;
    
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        }
    
        //解綁服務(wù)
        public void unbindService(View view) {
            unbindService(conn);
        }
        //調(diào)用服務(wù)里的方法
        public void callMethodInService(View view) {
            mBinder.callMethodInService();
        }
    }
運行結(jié)果

![Upload bind_service_1.png failed. Please try again.]

出現(xiàn)一個有意思的現(xiàn)象: 當(dāng)解綁服務(wù)后,service已經(jīng)onDestroy(),但是還是能調(diào)用服務(wù)中的方法.運行圖如下:

![Upload bind_service_2.png failed. Please try again.]

服務(wù)雖然是onDestroy了,但是MainActivity中還保留LifeService.Binder的引用,服務(wù)中的方法也保留了Service自身的引用,所以即便是Service onDestroy()了,但是還是可以調(diào)用到服務(wù)中的方法.

混合方式開啟服務(wù)

  • startService開啟服務(wù): 服務(wù)能在后臺長期運行,不能調(diào)用服務(wù)中方法.
  • bindService開啟服務(wù): 能調(diào)用服務(wù)中的方法,但是不能在后臺長期運行.
  • 混合方式開啟服務(wù): 保證服務(wù)后臺長期運行, 還能調(diào)用服務(wù)中的方法.

![Upload service_binding_tree_lifecycle.png failed. Please try again.]

Service

    public class LifeService extends Service {
        private static final String TAG = "LifeService";
    
    
        @Override
        public void onCreate() {
            Log.d(TAG, "服務(wù)------onCreate");
            super.onCreate();
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "服務(wù)------onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "服務(wù)------onDestroy");
            super.onDestroy();
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.d(TAG, "服務(wù)------onUnbind");
            return super.onUnbind(intent);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG, "服務(wù)------onBind");
            return new Mybind();
        }
    
        public class Mybind extends Binder {
    
            public void callMethodInService() {
                methodInService();
            }
    
        }
    
    
        public void methodInService() {
            Toast.makeText(this, "服務(wù)里的方法被調(diào)用了", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "服務(wù)里的方法被調(diào)用了");
        }
    
    }
Activity

    public class MainActivity extends AppCompatActivity {
        private ServiceConnection conn;
        private LifeService.Mybind mBinder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        //開啟服務(wù)
        public void startService(View view) {
            Intent intent = new Intent(this, LifeService.class);
            startService(intent);
        }
        //停止服務(wù)
        public void stopService(View view) {
            Intent intent = new Intent(this, LifeService.class);
            stopService(intent);
        }
    
        //綁定服務(wù)
        public void bindService(View view) {
            Intent intent = new Intent(this, LifeService.class);
            conn = new MyServiceConnection();
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
        //解綁服務(wù)
        public void unbindService(View view) {
            unbindService(conn);
        }
    
        private class MyServiceConnection implements ServiceConnection {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinder = (LifeService.Mybind) service;
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        }
        //調(diào)用服務(wù)中的方法
        public void callMethodInService(View view) {
            mBinder.callMethodInService();
        }
    }
運行結(jié)果

![Upload mix_start_service.png failed. Please try again.]

注意幾點:

  • 以startService方式開啟的服務(wù), 解綁服務(wù),并不能使服務(wù)onDestroy
  • IBinder: the communication channel to the service,may return null if clients not connect to services.
  • unlike other application components, calls on to the IBinder interface returned here may not happen on the main thread of the process

接口

利用接口屏蔽方法內(nèi)部實現(xiàn)的細(xì)節(jié), 只暴露需要暴露的方法.

IService

    public interface IService {
        void callMethodInService();
    }
Service

    private class Mybind extends Binder implements IService {
        public void callMethodInService() {
                methodInService();
        }
    
    }
Activity

    private class MyServiceConnection implements ServiceConnection {
    
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
            //轉(zhuǎn)化Iservice對象
             mIService = (IService) service;
         }
          @Override
          public void onServiceDisconnected(ComponentName name) {
    
          }
     }

IntentService 類

Service 的子類,它使用工作線程逐一處理所有啟動請求。如果您不要求服務(wù)同時處理多個請求,這是最好的選擇。 您只需實現(xiàn) onHandleIntent() 方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執(zhí)行后臺工作。由于大多數(shù)啟動服務(wù)都不必同時處理多個請求(實際上,這種多線程情況可能很危險),因此使用 IntentService 類實現(xiàn)服務(wù)也許是最好的選擇。

IntentService 執(zhí)行以下操作:

  • 創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給 onStartCommand() 的所有 Intent。
  • 創(chuàng)建工作隊列,用于將 Intent 逐一傳遞給 onHandleIntent() 實現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問題。
  • 在處理完所有啟動請求后停止服務(wù),因此您永遠(yuǎn)不必調(diào)用 stopSelf()。
  • 提供 onBind() 的默認(rèn)實現(xiàn)(返回 null)。
  • 提供 onStartCommand() 的默認(rèn)實現(xiàn),可將 Intent 依次發(fā)送到工作隊列和 onHandleIntent() 實現(xiàn)。

綜上所述,您只需實現(xiàn) onHandleIntent() 來完成客戶端提供的工作即可。(不過,您還需要為服務(wù)提供小型構(gòu)造函數(shù)。)


    public class HelloIntentService extends IntentService {
    
      /**
       * A constructor is required, and must call the super IntentService(String)
       * constructor with a name for the worker thread.
       */
      public HelloIntentService() {
          super("HelloIntentService");
      }
    
      /**
       * The IntentService calls this method from the default worker thread with
       * the intent that started the service. When this method returns, IntentService
       * stops the service, as appropriate.
       */
      @Override
      protected void onHandleIntent(Intent intent) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
      }
    }

您只需要一個構(gòu)造函數(shù)和一個 onHandleIntent() 實現(xiàn)即可。如果您決定還重寫其他回調(diào)方法(如 onCreate()、onStartCommand() 或 onDestroy()),請確保調(diào)用超類實現(xiàn),以便 IntentService 能夠妥善處理工作線程的生命周期。

執(zhí)行多線程耗時操作Service

正如上一部分中所述,使用 IntentService 顯著簡化了啟動服務(wù)的實現(xiàn)。但是,若要求服務(wù)執(zhí)行多線程(而不是通過工作隊列處理啟動請求),則可擴展 Service 類來處理每個 Intent。

為了便于比較,以下提供了 Service 類實現(xiàn)的代碼示例,該類執(zhí)行的工作與上述使用 IntentService 的示例完全相同。也就是說,對于每個啟動請求,它均使用工作線程執(zhí)行作業(yè),且每次僅處理一個請求。


    public class HelloService extends Service {
      private Looper mServiceLooper;
      private ServiceHandler mServiceHandler;
    
      // Handler that receives messages from the thread
      private final class ServiceHandler extends Handler {
          public ServiceHandler(Looper looper) {
              super(looper);
          }
          @Override
          public void handleMessage(Message msg) {
              // Normally we would do some work here, like download a file.
              // For our sample, we just sleep for 5 seconds.
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  // Restore interrupt status.
                  Thread.currentThread().interrupt();
              }
              // Stop the service using the startId, so that we don't stop
              // the service in the middle of handling another job
              stopSelf(msg.arg1);
          }
      }
    
      @Override
      public void onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
    
        // Get the HandlerThread's Looper and use it for our Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
      }
    
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    
          // For each start request, send a message to start a job and deliver the
          // start ID so we know which request we're stopping when we finish the job
          Message msg = mServiceHandler.obtainMessage();
          msg.arg1 = startId;
          mServiceHandler.sendMessage(msg);
    
          // If we get killed, after returning from here, restart
          return START_STICKY;
      }
    
      @Override
      public IBinder onBind(Intent intent) {
          // We don't provide binding, so return null
          return null;
      }
    
      @Override
      public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      }
    }

正如您所見,與使用 IntentService 相比,這需要執(zhí)行更多工作。

但是,因為是由您自己處理對 onStartCommand() 的每個調(diào)用,因此可以同時執(zhí)行多個請求。此示例并未這樣做,但如果您希望如此,則可為每個請求創(chuàng)建一個新線程,然后立即運行這些線程(而不是等待上一個請求完成)。

請注意,onStartCommand() 方法必須返回整型數(shù)。整型數(shù)是一個值,用于描述系統(tǒng)應(yīng)該如何在服務(wù)終止的情況下繼續(xù)運行服務(wù)(如上所述,IntentService 的默認(rèn)實現(xiàn)將為您處理這種情況,不過您可以對其進行修改)。從 onStartCommand() 返回的值必須是以下常量之一:

  • START_NOT_STICKY

    如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則除非有掛起 Intent 要傳遞,否則系統(tǒng)不會重建服務(wù)。這是最安全的選項,可以避免在不必要時以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時運行服務(wù)。

  • START_STICKY

    如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會重建服務(wù)并調(diào)用 onStartCommand(),但不會重新傳遞最后一個 Intent。相反,除非有掛起 Intent 要啟動服務(wù)(在這種情況下,將傳遞這些 Intent ),否則系統(tǒng)會通過空 Intent 調(diào)用 onStartCommand()。這適用于不執(zhí)行命令、但無限期運行并等待作業(yè)的媒體播放器(或類似服務(wù))。

  • START_REDELIVER_INTENT

    如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會重建服務(wù),并通過傳遞給服務(wù)的最后一個 Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用于主動執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。

前臺服務(wù)


    public class ForegroundService extends Service {

        @Override
        public void onCreate() {
            super.onCreate();
    
            showNotification();
        }
    
        private void showNotification() {
            
            //創(chuàng)建點擊跳轉(zhuǎn)Intent
            Intent inten = new Intent(this, MainActivity.class);
            //創(chuàng)建任務(wù)棧Builder
            TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
            taskStackBuilder.addParentStack(MainActivity.class);
            taskStackBuilder.addNextIntent(inten);
            PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    
            //創(chuàng)建通知詳細(xì)信息
            Notification notification = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("foreground service")
                    .setContentText("show details news")
                    .setWhen(System.currentTimeMillis())
                    .setContentIntent(pendingIntent)
                    .build();
            
            NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            nm.notify(0, notification);
            startForeground(0,notification);
    
        }
    }

系統(tǒng)服務(wù)

系統(tǒng)服務(wù)提供了很多便捷服務(wù),可以查詢Wifi、網(wǎng)絡(luò)狀態(tài)、查詢電量、查詢音量、查詢包名、查詢Application信息等等等相關(guān)多的服務(wù),具體大家可以自信查詢文檔,這里舉例幾個常見的服務(wù)

  1. 判斷Wifi是否開啟

    
        WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
        boolean enabled = wm.isWifiEnabled();
    
  2. 獲取系統(tǒng)最大音量

```java

    AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
    int max = am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
```
  1. 獲取當(dāng)前音量

    
        AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
        int current = am.getStreamMaxVolume(AudioManager.STREAM_RING);
    
  2. 判斷網(wǎng)絡(luò)是否有連接

    
        ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getActiveNetworkInfo();
        boolean isAvailable = info.isAvailable();
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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