本文講解內(nèi)容:
- Service的簡單使用
- 普通Service
- IntentService
- Service的綁定操作
- Service的生命周期
- 前臺Service的使用
- Android通知欄的使用
1.Service的簡單使用
1.1普通Service的簡單使用
后臺服務的優(yōu)先級是很低的,當系統(tǒng)內(nèi)存不足的時候就會被回收.
- 創(chuàng)建Service
- 重寫相應的方法
- 啟動/關閉服務
1.1.1 創(chuàng)建服務
創(chuàng)建服務的方法就不寫了,這里主要說 明一下AndroidManifest中的屬性
- android:name Service的類名稱
- android:label Service的名字
- android:icon Service的圖標
- android:enabled 是否可以被系統(tǒng)實例化,默認是true 因為父標簽也有enable屬性,所以必須兩個都為true的情況下服務才能被激活,否則不會被激活.
- android:exported 代表是否能被其他應用隱式調(diào)用,由inter-filter決定,如果為false的情況下,即便你匹配了inter-filter也無法隱式調(diào)用
- android:process 是否需要在單獨的進程中運行,當設置為android:process = ":remote"時,代表Service在單獨的進程中運行.這里注意":"很重要,它的意思是要在當前進程名稱前面附加上當前的包名,所以"remote"和":remote"不是同一個意思,前者的進程名稱為:remote,而后者的進程名稱為: App-packageName:remote.
- android:permission 是權限聲明
- android:isolatedProcess 設置true意味著服務會在一個特殊的進程下運行,這個進程與系統(tǒng)其他進程分開且沒有自己的權限.與其通信的唯一途徑就是通過服務的API(bind and start)
1.1.2重寫相應的方法
public class GeneralService extends Service {
private String TAG = GeneralService.class.getSimpleName();
public GeneralService() {
}
@Override
public IBinder onBind(Intent intent) {
/*這個是綁定Binder的相應的方法,
*這個服務中先不去考慮
*/
return null;
}
@Override
public void onCreate() {
super.onCreate();
/*
* 創(chuàng)建服務的時候調(diào)的回調(diào)
* 這個方法只有在創(chuàng)建Service的時候執(zhí)行一次
*/
Log.e(TAG, "服務創(chuàng)建了");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*
* 具體執(zhí)行邏輯的時候的方法
* 1.這里有一點問題說明一下,有的時候你創(chuàng)建相應的服務了,但是由于后臺資源不足,服務被銷毀了
* 這個時候,在執(zhí)行的時候就會存在相應intent為空的情況,當你遇到這個情況的時候,只要返回相應的標識就可以了
* return Service.START_REDELIVER_INTENT;就能保證服務再次啟動的時候intent不為空了
* 2.這個方法每次調(diào)用相應的startService都會去執(zhí)行
*/
Log.e(TAG, "服務正在執(zhí)行");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
/*
* 銷毀服務的回調(diào)
* 這個方法只有在銷毀Service的時候執(zhí)行一次
*/
Log.e(TAG, "服務銷毀了");
}
}
1.1.3啟動/關閉服務
- 開啟服務
Intent intent = new Intent(this, GeneralService.class); startService(intent);
- 關閉服務
Intent intent = new Intent(this, GeneralService.class); stopService(intent);
1.1.4這里著重介紹一下相應得方法
- onCreate 服務創(chuàng)建的時候回調(diào)的方法
- onBind 綁定服務的時候調(diào)用的方法,后面將服務綁定的時候講解
- onStartCommand 執(zhí)行邏輯的方法
- onDestory 服務關閉時候的回調(diào)方法
相應的執(zhí)行邏輯:
- 正常的生命周期邏輯(第一次啟動)
構造方法()->onCreate()->onStartCommand()->onDestory(); - 當Service存在的情況下再次啟動
onStartCommand()
也就是說如果多次點擊啟動,onCreate()不會多次執(zhí)行,只有Service銷毀的時候再次啟動的時候才會執(zhí)行相應的onCreat()方法,簡單理解就是onCreat()方法只有在創(chuàng)建的時候執(zhí)行一次!
1.2IntentService的簡單使用
使用上和上面的內(nèi)容沒有什么出入,只是繼承的方法和內(nèi)部相應的實現(xiàn)有點變化,但是變化不是很大,這里就貼一下相應的內(nèi)容,不去做相應的具體講解了,只要記住這個Service能自己調(diào)用相應的onDestory()就可以了.
public class IntentService extends android.app.IntentService {
private String TAG = IntentService.class.getSimpleName();
public IntentService() {
super("IntentService");
/*調(diào)用父類的構造方法,這里面?zhèn)魅氲拿质枪ぷ骶€程的名稱,所以這個名稱你可以隨便傳*/
Log.e(TAG, "服務有名字了");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "服務創(chuàng)建了");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
/*
* 在我的理解,這個工作線程只會有一個,因為里面維護了一個相應的Handler
* 每次的耗時操作都會以相應的隊列的方式在IntentService中一次執(zhí)行
* 每次開啟服務的時候都會走這個方法,但是我調(diào)用相應的Stop無法停止相應的服務
* 這個還有待于研究,因為子停止,或許不需要停止的相應的方法吧(反正相應的停止的方法是不好使的)
*/
for (int i = 0; i < 100; i++) {
Log.e(TAG, "服務正在執(zhí)行" + i);
}
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
/*這個方法實在o'nHandleIntent之前進行執(zhí)行
*所以這里可以初始化一些相應的內(nèi)容
*/
Log.e(TAG, "onStartCommand: 執(zhí)行了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
/*這個方法會在相應的onHandleIntent執(zhí)行完成的時候回調(diào)*/
Log.e(TAG, "服務銷毀了");
}
}
相應的啟動方法類似.
但是這里要注意幾個問題:
- 當你startService的時候,即使你調(diào)用相應的stopService也不會讓Service停止下來
- 這個服務不存在相應的stopService的方法了
剩下的基本上注釋都有.
2.綁定服務的方法
- 簡單的介紹一下為什么要綁定服務
你可能會發(fā)現(xiàn),上面的方法只是啟動了服務,但是其實Service和Activity其實根本沒有什么關聯(lián),在Activity也沒有辦法去控制Service里面的執(zhí)行內(nèi)容,也就是Service脫離了相應的Activity,只是通過Activity啟動而已,這個不是我們想看到的,所以才有相應的綁定方法來控制Service.
2.1 綁定服務的寫法
上面在開啟服務的時候,不知道大家有沒有注意到一個細節(jié)在onBind()方法中我們返回的是空,為什么這里返回的是空呢???其實這個就是綁定服務所要必須的內(nèi)容.下面我們開始實現(xiàn)簡單的內(nèi)容吧!
2.1.1創(chuàng)建相應的Binder對象
class MyBinder extends Binder {
public void startBinder() {
Log.e(TAG, "startBinder: ");
}
public void stopBinder() {
Log.e(TAG, "stopBinder: ");
}
}
這里面的方法你可以隨便的寫,想要什么寫什么!!!
2.1.2在相應的Service中創(chuàng)建相應的對象,并在Binder()中返回
private MyBinder mMyBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mMyBinder;
}
2.1.3啟動相應的Service
這個也是這里的重點問題,涉及到一個ServiceConnection
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
/*這個方法會在相應的創(chuàng)建的時候進行調(diào)用*/
Log.e(TAG, "onServiceConnected: 連接創(chuàng)建的時候調(diào)用");
//向下轉型從而調(diào)用相應的方法
BindService.MyBinder binder = (BindService.MyBinder) service;
binder.bindService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
/*這個方法是在Service丟失的情況下才被調(diào)用
* 或者在Service被殺死的視乎調(diào)用*/
}
};
說明一下上面兩個回調(diào)方法:
- onServiceConnected 系統(tǒng)調(diào)用這個方法來傳送在Service的onBind中返回的IBinder
- onServiceDisconnected 在Service的鏈接意外丟失的時候調(diào)用這個方法,比如當Service崩潰了或者被越塔強殺了的時候會調(diào)用這個方法,但是注意當解除綁定的時候不會調(diào)用這個方法.
- 還有一點說明一下:startBinder()這個方法是你自己的方法,也就是說,在這里你就可以控制Service了
//綁定
Intent intent = new Intent(this, BindService.class);
/*參數(shù)三有必要說明下:
*BIND_AUTO_CREATE 這個方法是創(chuàng)建關聯(lián)后自動創(chuàng)建Service,會使得相應Service中的onCreate()方法的到執(zhí)行
* 但相應的onStartCommand()不會被執(zhí)行
*/
bindService(intent, mConnection, BIND_AUTO_CREATE);
//解綁
unbindService(mConnection);
2.1.3BindService的生命周期
構造方法->oncreate()->onBind()->onServiceConnected()
當你再次點擊的時候不會調(diào)用相應的啟動的流程了,除非你調(diào)用unBind()方法進行相應的取消否則不會去創(chuàng)建的,這里只是創(chuàng)建了連接,讓Activity持有了相應的Service可以使用內(nèi)部的相應方法了!
3.Service的聲明周期
- 當你調(diào)用startService()的時候生命周期是這樣的:
onCreate() -> onStartCommand()
這里注意,要是之前你啟動過這個service的話那么onCreate()不會多次調(diào)用,除非你調(diào)用了** stopService(mIntent);**結束了這個Service否則不會在走onCreate();也就是說生命周期中onCreate()只會執(zhí)行一次; - 當你調(diào)用stopService()的時候生命周期是這樣的:
onDestroy() - 當你調(diào)用bindService的時候和上面的生命周期類似,這里只是建立了一個持久連接.別無其他.
- boolean onUnBind(Intent intent) 當該Service上綁定得所有客戶端都斷開連接得時候回調(diào)
這里有一個問題是你需要注意的,如果你想在onStartCommand()想結束Service的話,直接調(diào)用stopSelf()方法就可以了
3.1幾種特殊情況下的生命周期問題
- 當一個Service既被調(diào)用了bindService()又調(diào)用了startService(),這種情況下你如果想要關閉服務的話,必須兩種服務的結束方法都調(diào)用才能結束當前的服務.也就是stopService()和unBindService()方法同時執(zhí)行,這樣Service才會走onDestroy()方法.
4.一些服務的特殊使用方法
開機啟動服務(其實這個思路很簡單,監(jiān)聽開機的廣播,然后啟動你的服務就可以實現(xiàn)了),下面直接上代碼:
- 廣播的代碼:
public class BootBroadcastReceiver extends BroadcastReceiver {
private static final String mBootAction = "android.intent.action.BOOT_COMPLETED";
private static final String mShutDownAction = "android.intent.action.ACTION_SHUTDOWN";
private static final String TAG = BootBroadcastReceiver.class.getSimpleName();
private Intent mServiceIntent;
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) return;
if (intent.getAction().equals(mBootAction)) {
Log.e(TAG, "onReceive: 監(jiān)聽到開機廣播了");
/*這里啟動服務*/
mServiceIntent = new Intent(context, MyService.class);
mServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(mServiceIntent);
} else if (intent.getAction().equals(mShutDownAction)) {
Log.e(TAG, "onReceive: 監(jiān)聽到關機廣播了");
if (mServiceIntent != null) {
/*這里關閉服務*/
context.stopService(mServiceIntent);
}
}
}
}
- 廣播在清單文件中注冊的代碼
<receiver
android:name=".BootBroadcastReceiver"
android:enabled="true"
android:exported="true">
<!--開機廣播-->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<!--關機廣播-->
<intent-filter>
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
其實上面的內(nèi)容加起來就可以啟動相應的廣播了,但是一定要注意一點就是監(jiān)聽開機廣播的時候涉及到權限的問題
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
這個問題千萬別忘了...