關于Service你一定要知道的

? ? ? ?Service是Android四大組件之一,主要用于執行需要長時間運行的任務或者處理一些耗時的邏輯。Service可以在程序退出后,在后臺繼續運行。

一、Service的基本用法

啟動Service的方法和啟動Activity很類似,都需要借助Intent來實現,構建出一個Intent對象,調用startService()方法來啟動Service。然后同樣構建出了一個Intent對象,并調用stopService()方法來停Service。當啟動一個Service的時候,會調用該Service中的onCreate()和onStartCommand()方法。

啟動Service:

Intent startIntent =newIntent(this,MyService.class);

startService(startIntent);

關閉service:

Intent pauseIntent =newIntent(this,MyService.class);

stopService(pauseIntent);

? ? ? ?onCreate()方法只會在Service第一次被創建的時候調用,如果當前Service已經被創建過了,不管怎樣調用startService()方法,onCreate()方法都不會再執行,只會執行onStartCommand()方法。啟動Service之后,就可以在onCreate()或onStartCommand()方法里去執行一些具體的邏輯了。

? ? ? ?項目中的每一個Service都必須在AndroidManifest.xml中注冊。

二、Service和Activity通信

? ? ? Service中有一個onBind()方法,這個方法就是用來和Activity通信的。通常會新增了一個類繼承自Binder類,然后在這個類里寫我們的邏輯,再通過onBind()方法將這個類的實例返回到activity中。因此service類應該是這樣的:

public class MyService extends Service {

public static final String?TAG?="MyService";

private MyBinder?mBinder?=new MyBinder();

@Override

public void onCreate()?{

super.onCreate();

Log.i(TAG,"onCreate()?executed");

}

@Override

public int onStartCommand(Intent?intent,int flags,int startId)?{

Log.i(TAG,"onStartCommand()?executed");

return super.onStartCommand(intent,?flags,?startId);

}

@Override

public void onDestroy()?{

super.onDestroy();

Log.i(TAG,"onDestroy()?executed");

}

@Override

publicI Binder?onBind(Intent?intent)?{

return mBinder;

}

class MyBinder extends Binder?{

public void startDownload()?{

Log.i("TAG","startDownload()?executed");

}

}

}

在activity里與service關聯上,首先創建一個ServiceConnection的匿名類,在里面重寫了onServiceConnected()方法和onServiceDisconnected()方法,這兩個方法會在Activity與Service建立關聯和解除關聯的時候調用。在onServiceConnected()方法中,通過向下轉型得到了MyBinder的實例,即我們在service里返回的Binder的子類的實例。在Activity中根據具體的場景來調用Binder的子類中的任何public方法,即Activitys可以指揮Service干什么Service就去干什么。代碼:

private ServiceConnection connection = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

}

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

myBinder = (MyService.MyBinder) service;

myBinder.startDownload();

}

};


Activity和Service的關聯由bindService()方法來完成。構建出一個Intent對象,然后調用bindService()方法將Activity和Service進行關聯。bindService()方法接收三個參數,第一個參數是Intent對象,第二個參數ServiceConnection的實例,第三個參數是一個標志位,這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關聯后自動創建Service,這會使得MyService中的onCreate()方法得到執行,但onStartCommand()方法不會執行。

關聯:

Intent bindIntent =newIntent(this, MyService.class);

bindService(bindIntent,?connection,?BIND_AUTO_CREATE);

解除關聯:

unbindService(connection);

注意,任何一個Service在整個應用程序范圍內都是通用的,即MyService不僅可以和MainActivity建立關聯,還可以和任何一個Activity建立關聯,而且在建立關聯時它們都可以獲取到相同的MyBinder實例。

三、銷毀Service

stopService()只會讓Service停止,unbindService只會讓Service和Activity解除關聯,一個Service必須要在既沒有和任何Activity關聯又處理停止狀態的時候才會被銷毀。

四、Service和Thread的關系

Service和Thread之間沒有任何關系!Thread是用來開啟一個子線程,在Thread里執行一些耗時操作就不會阻塞主線程的運行。實際上,Service是運行在主線程里的。可以這樣檢驗:

在activity里打印當前線程編號:

Log.i("MyService","MainActivity thread id is "+ Thread.currentThread().getId());

在service里打印當前service的線程編號:

Log.i("MyService","MyService thread id is "+ Thread.currentThread().getId());

Android的后臺就是指,它的運行是完全不依賴UI的。即使Activity被銷毀,或者程序被關閉,只要進程還在,Service就可以繼續運行。比如說一些應用程序,始終需要與服務器之間始終保持著心跳連接,就可以使用Service來實現。你可能又會問,前面不是剛剛驗證過Service是運行在主線程里的么?在這里一直執行著心跳連接,難道就不會阻塞主線程的運行嗎?當然會,但是我們可以在Service中再創建一個子線程,然后在這里去處理耗時邏輯就沒問題了。
一個比較標準的Service就可以寫成:

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

new Thread(new Runnable() {

@Override

public void run() {

// 開始執行后臺任務

}

}).start();

return super.onStartCommand(intent, flags, startId);

}

class MyBinder extends Binder {

public void startDownload() {

new Thread(new Runnable() {

@Override

public void run() {

// 執行具體的下載任務

}

}).start();

}

}


五、創建前臺Service

Service幾乎都是在后臺運行的。因為Service的系統優先級是比較低的,當系統出現內存不足時,就有可能會回收掉正在后臺運行的Service。如果希望Service一直保持運行狀態,而不會由于系統內存不足的原因導致被回收,可以考慮使用前臺Service。前臺Service和普通Service最大的區別就在于,它會一直有一個正在運行的圖標在系統的狀態欄顯示,下拉狀態欄后可以看到更加詳細的信息,非常類似于通知的效果。方法就是在service里設置一下:

public class MyService extends Service {

public static final String TAG = "MyService";

private MyBinder mBinder = new MyBinder();

@Override

public void onCreate() {

super.onCreate();

// 在API11之后構建Notification的方式

Notification.Builder builder = new Notification.Builder

(this.getApplicationContext()); //獲取一個Notification構造器

Intent nfIntent = new Intent(this, MainActivity.class);

builder.setContentIntent(PendingIntent.

getActivity(this, 0, nfIntent, 0)) // 設置PendingIntent

.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),

R.mipmap.ic_large)) // 設置下拉列表中的圖標(大圖標)

.setContentTitle("下拉列表中的Title") // 設置下拉列表里的標題

.setSmallIcon(R.mipmap.ic_launcher) // 設置狀態欄內的小圖標

.setContentText("要顯示的內容") // 設置上下文內容

.setWhen(System.currentTimeMillis()); // 設置該通知發生的時間

Notification notification = builder.build(); // 獲取構建好的Notification

notification.defaults = Notification.DEFAULT_SOUND; //設置為默認的聲音

startForeground(1, notification);

Log.d(TAG, "onCreate() executed");

}

.........

}

首先在MyService的onCreate()方法中創建了一個Notification對象,然后調用了它的setLatestEventInfo()方法來為通知初始化布局和數據,并在這里設置了點擊通知后就打開MainActivity。然后調用startForeground()方法就可以讓MyService變成一個前臺Service,并會將通知的圖片顯示出來。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容