寫着一篇文章的緣由,主要是由於在面試中,服務這個關鍵詞的出現頻率很是高。不少時候,面試官會問你,Service中可否進行耗時操做? 咱們稍後就會揭曉那麼這個答案。java
由圖中能夠直觀的看出幾點。android
啓動方式 | 存在方式 |
---|---|
startService() | 獨立於Activity運行,自行結束或被叫停 |
bindService() | 綁定於Activity運行,Activity結束時,會被叫停 |
涉及方法 | 用途 |
---|---|
onCreate() | |
onDestroy() | |
onStartCommand() | 用於計數,服務被調用的次數 |
onBind() | 與Activity組件綁定 |
onUnbind() | 與Activity組件解綁 |
Service
方法須要在AndroidManifest.xml
中進行註冊面試
// 第一步:在AndroidManifest.xml中進行註冊
<service android:name=".LocalService"/>
// 第二步:啓動
① startService(Intent);
② bindService(Intent, ServiceConnection, Int);
// 第三步:解綁(使用方法② 啓動時操做)
unBindService(ServiceConnection);
// 第四步:暫停
stopService(Intent);
複製代碼
Activity
和Service
的通訊其實就是基於IBinder
來進行實現的。可是IBinder
實際上是一個接口,對咱們而言通常使用他的實現類Binder
並經過強制轉換來完成操做。bash
/** * Service方法繼承 * onBind()是一個抽象方法。 */
public class LocalService extends Service {
private final IBinder binder = new ServiceBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public class ServiceBinder extends Binder {
LocalService getLocalService(){
return LocalService.this;
}
}
}
複製代碼
以上代碼,是一個用於通訊的基礎版本。異步
既然須要通訊,那咱們總須要知道對方是誰,若是使用的是startService()
,上文已經提到他是獨立於Activity
的,因此勢必使用的是bindService()
。ide
在上文的使用方法中已經提到了bindService()
使用到的參數,Intent
、ServiceConnection
、Int
。oop
/** * bindService()方法中的參數之一。 * 用於對service進行操做 */
ServiceConnection connection = new ServiceConnection() {
// Activity和Service綁定時調用
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
// 基於Binder拿到咱們要的Service
service = ((LocalService.ServiceBinder)binder).getLocalService();
// 幹你須要乾的事情
}
// Activity和Service解綁時調用
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
};
複製代碼
BIND_AUTO_CREATE
:收到綁定需求,若是Service還沒有建立,則當即建立。BIND_DEBUG_UNBIND
:用於測試使用,對unbind調用不匹配的調試幫助。BIND_NOT_FOREGROUND
:不容許此綁定將目標服務的進程提高到前臺調度優先級這是一個已經存在於Service
類中的值,這裏並不所有例舉,通常來講都是使用BIND_AUTO_CREATE
。post
爲何咱們必定要調用這個方法,若是咱們不解綁會出現什麼樣的問題?學習
通過測試,Logcat中爆出了這樣的錯誤Activity has leaked ServiceConnection that was originally bound here
。也就是說ServiceConnection
內存泄漏了。這也是爲何咱們一直說須要解綁的緣由。測試
public class LocalIntentService extends IntentService {
/** * Creates an IntentService. Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */
public LocalIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
}
}
複製代碼
先看一段咱們的繼承代碼,和Service
不一樣的地方就是,必須重寫的方法是onHandleIntent(Intent intent)
。 那咱們也和以前同樣作一個源碼導讀好了。
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
}
複製代碼
其實從整個代碼的變量咱們已經能夠作一個猜想了。Looper
+Handler
+Service
的組成成分。那它的處理過程勢必依賴於一個Handler
的通訊機制。另外看到了ServiceHandler
中的stopSelf()
方法,咱們也就清楚了一個問題爲何咱們不須要去控制IntentService
的暫停。
接下來從生命週期的角度來看看這個IntentService
,由於Binder
機制上是一致的,因此分析主線就是onCreate() --> onStartCommand() --> onDestroy()
。
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
複製代碼
建立了一個HandlerThread
,去初始化了Looper
和Handler
,也就說明服務在內部處理。
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId); // 1 -->
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; // 2 -->
}
複製代碼
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
複製代碼
其餘都是和Handler
一致的,總體流程也就是Message
封裝,再經過Handler
進行一個發送。
這個變量是幹什麼的?
/** * Constant to return from {@link #onStartCommand}: if this service's * process is killed while it is started (after returning from * {@link #onStartCommand}), and there are no new start intents to * deliver to it, then take the service out of the started state and * don't recreate until a future explicit call to * {@link Context#startService Context.startService(Intent)}. The * service will not receive a {@link #onStartCommand(Intent, int, int)} * call with a null Intent because it will not be restarted if there * are no pending Intents to deliver. * * <p>This mode makes sense for things that want to do some work as a * result of being started, but can be stopped when under memory pressure * and will explicit start themselves again later to do more work. An * example of such a service would be one that polls for data from * a server: it could schedule an alarm to poll every N minutes by having * the alarm start its service. When its {@link #onStartCommand} is * called from the alarm, it schedules a new alarm for N minutes later, * and spawns a thread to do its networking. If its process is killed * while doing that check, the service will not be restarted until the * alarm goes off. */
public static final int START_NOT_STICKY = 2;
/** * Constant to return from {@link #onStartCommand}: if this service's * process is killed while it is started (after returning from * {@link #onStartCommand}), then it will be scheduled for a restart * and the last delivered Intent re-delivered to it again via * {@link #onStartCommand}. This Intent will remain scheduled for * redelivery until the service calls {@link #stopSelf(int)} with the * start ID provided to {@link #onStartCommand}. The * service will not receive a {@link #onStartCommand(Intent, int, int)} * call with a null Intent because it will only be restarted if * it is not finished processing all Intents sent to it (and any such * pending events will be delivered at the point of restart). */
public static final int START_REDELIVER_INTENT = 3;
複製代碼
一大段冗長的英文很煩,更況且我也就低分飄過6級的水平呢,哈哈哈哈!!
就不折磨大家了,直接作出一個解釋吧。
好了,以上基本就是整個IntentService
的介紹了。
Service
的響應時長不能超過20s,其實也能夠比較直觀的看出,Service
其實並不能進行所謂耗時操做。可是若是加上了Thread
進行異步處理,那麼其實他仍是能夠進行耗時操做的。(具體看你怎麼進行回答,主要仍是一個知識點,Service
運行在主線程)Service
存在的緣由是Activity
是一個常常會被銷燬的組件,雖然咱們一樣能夠經過Thread
進行異步操做,可是當Activity
實例被銷燬時,相應的捆綁在Activity
生命週期內的Thread
實例咱們也沒有能力再去尋找了。以上就是個人學習成果,若是有什麼我沒有思考到的地方或是文章內存在錯誤,歡迎與我分享。
相關文章推薦: