android前台服务需要解绑,Android必知必会的四大组件 -- Service篇

前言

写着一篇文章的原因,主要是因为在面试中,服务这个关键词的出现频率非常高。很多时候,面试官会问你,Service中能否进行耗时操作? 我们稍后就会揭晓那么这个答案。

思维导图

00a859ffe578f0c452037419a45da629.png

生命周期

5dc1cc4e00d1fb1c4b755cc38b92e401.png

由图中可以直观的看出几点。

启动方式

存在方式

startService()

独立于Activity运行,自行结束或被叫停

bindService()

绑定于Activity运行,Activity结束时,会被叫停

涉及方法

用途

onCreate()

onDestroy()

onStartCommand()

用于计数,服务被调用的次数

onBind()

与Activity组件绑定

onUnbind()

与Activity组件解绑

使用方法

Service方法需要在AndroidManifest.xml中进行注册

// 第一步:在AndroidManifest.xml中进行注册

// 第二步:启动

① 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。

必须要调用的unbindService(ServiceConnection)

为什么我们一定要调用这个方法,如果我们不解绑会出现什么样的问题?

经过测试,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 --> } 复制代码

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.

*

*

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级的水平呢,哈哈哈哈!!

就不折磨你们了,直接做出一个解释吧。

START_NOT_STICKY:默认模式,这是一个容许被杀的模式,随时允许被叫停

START_REDELIVER_INTENT:告诉系统在崩溃后重新启动服务,并重新传递在崩溃时存在的意图

好了,以上基本就是整个IntentService的介绍了。

总结

在ANR机制中,Service的响应时长不能超过20s,其实也可以比较直观的看出,Service其实并不能进行所谓耗时操作。但是如果加上了Thread进行异步处理,那么其实他还是可以进行耗时操作的。(具体看你怎么进行回答,主要还是一个知识点,Service运行在主线程)

Service存在的原因是Activity是一个经常会被销毁的组件,虽然我们同样可以通过Thread进行异步操作,但是当Activity实例被销毁时,相应的捆绑在Activity生命周期内的Thread实例我们也没有能力再去寻找了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值