前言
写着一篇文章的原因,主要是因为在面试中,服务这个关键词的出现频率非常高。很多时候,面试官会问你,Service中能否进行耗时操作? 我们稍后就会揭晓那么这个答案。
生命周期
由图中可以直观的看出几点。
使用方法
Service
方法需要在AndroidManifest.xml
中进行注册
// 第一步:在AndroidManifest.xml中进行注册
<service android:name=".LocalService"/>
// 第二步:启动
① startService(Intent);
② bindService(Intent, ServiceConnection, Int);
// 第三步:解绑(使用方法② 启动时操作)
unBindService(ServiceConnection);
// 第四步:暂停
stopService(Intent);
Activity和Service的通信
Activity
和Service
的通信其实就是基于IBinder
来进行实现的。但是IBinder
其实是一个接口,对我们而言一般使用他的实现类Binder
并通过强制转换来完成操作。
/**
* 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()
。
在上文的使用方法中已经提到了bindService()
使用到的参数,Intent
、ServiceConnection
、Int
。
ServiceConnection
/**
* 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;
}
};
Int
BIND_AUTO_CREATE
:收到绑定需求,如果Service尚未创建,则立即创建。BIND_DEBUG_UNBIND
:用于测试使用,对unbind调用不匹配的调试帮助。BIND_NOT_FOREGROUND
:不允许此绑定将目标服务的进程提升到前台调度优先级这是一个已经存在于Service
类中的值,这里并不全部例举,一般来说都是使用BIND_AUTO_CREATE
。
Q1:为什么我们一定要调用这个方法,如果我们不解绑会出现什么样的问题?
经过测试,Logcat中爆出了这样的错误Activity has leaked ServiceConnection that was originally bound here
。也就是说ServiceConnection
内存泄漏了。这也是为什么我们一直说需要解绑的原因。
IntentService
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)
。那我们也和之前一样做一个源码导读好了。
IntentService源码导读
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()
。
onCreate()
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
,也就说明服务在内部处理。
onStartCommand()
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId); // 1 -->
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; // 2 -->
}
这里出现了两个部分:(1)onStart()方法(2)mRedelivery变量,下面将着重介绍。
onStart()
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
其他都是和Handler
一致的,整体流程也就是Message的数据装载
,再通过Handler
进行一个发送。
mRedelivery
这个变量是干什么的?
/**
* 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
的介绍了,使用方法上来说应该也是比较简单了。
Thread和Service的区别
总结
Service
的响应时长不能超过20s,其实也可以比较直观的看出,Service
其实并不能进行所谓耗时操作。但是如果加上了Thread
进行异步处理,那么其实他还是可以进行耗时操作的。(具体看你怎么进行回答,主要还是一个知识点,Service
运行在主线程)Service
存在的原因是Activity
是一个频繁会被创建、销毁的组件,虽然我们同样可以通过Thread
进行异步操作,但是当Activity
实例被销毁时,相应的捆绑在Activity
生命周期内的Thread
实例我们也没有能力再去寻找了,且如果耗时过长可能会引发内存泄漏。