Service 是一种程序后台运行的方案,用于不须要用户交互,长期运行的任务,Service 并非在单独进程中运行,也是运行在应用程序进程的主线程中,在执行具体耗时任务过程当中要手动开启子线程,应用程序进程被杀死,全部依赖该进程的服务也会中止运行android
-生命周期安全
-启动方式bash
-Service 通讯服务器
-IntentServiceapp
Service 有两种启动服务的方式,对应的生命周期也不一致异步
onCreate 首次建立服务时,系统将调用此方法。若是服务已在运行,则不会调用此方法,该方法只调用一次ide
onStartCommand 当另外一个组件经过调用 startService()请求启动服务时,系统将调用此方法函数
onDestroy 当服务再也不使用且将被销毁时,系统将调用此方法oop
onBind 当另外一个组件经过调用 bindService()与服务绑定时,系统将调用此方法
onUnbind 当另外一个组件经过调用 unbindService()与服务解绑时,系统将调用此方法
onRebind 当旧的组件与服务解绑后,另外一个新的组件与服务绑定,onUnbind()返回 true 时,系统将调用此方法
经过上面的生命周期咱们可知道,启动 Service 的方式有两种分别是 startService 和 bindService,接下来咱们来分别介绍一下
1.在 AndroidManifest.xml 注册咱们所要写的 Service,咱们这里以 AService 为例
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.madreain"
>
……
<service android:name="com.madreain.AService" >
</service>
</application>
</manifest>
复制代码
2.AService 继承 Service 的相关代码
public class AService extends Service{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
复制代码
咱们还能够在相关的生命周期中打印 Thread.currentThread().getId()及其相关值
3.在 MainActivity 中使用开启服务
Intent intent = new Intent(this, AService.class);
startService(intent);
复制代码
4.屡次调用 Service 来观察生命周期
//启动三个相同服务
Intent intent1 = new Intent(this, AService.class);
startService(intent1);
Intent intent2 = new Intent(this, AService.class);
startService(intent2);
Intent intent3 = new Intent(this, AService.class);
startService(intent3);
//中止服务
Intent intent4 = new Intent(this, AService.class);
stopService(intent4);
//再启动服务
Intent intent5 = new Intent(this, AService.class);
startService(intent5);
复制代码
这时候咱们能够在 Aservice 不一样生命周期中打印生命周期执行函数及其 Thread ID 来分析得出: 1.Thread ID 打印出来是相同的,说明回调方法都在主线程执行的 2.屡次调用 startService,onCreate 方法只被执行一次,每启动一次触发一次 onStartCommand,屡次 startService 不会重复执行 onCreate 回调,但每次都会执行 onStartCommand 回调。
1.建立 BService
public class BService extends Service{
//client 能够经过Binder获取Service实例
public class MyBinder extends Binder {
public BService getService() {
return BService.this;
}
}
//经过binder实现调用者client与Service之间的通讯
private MyBinder binder = new MyBinder();
private final Random generator = new Random();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
return false;
}
@Override
public void onDestroy() {
super.onDestroy();
}
//getRandomNumber是Service暴露出去供client调用的公共方法
public int getRandomNumber() {
return generator.nextInt();
}
}
复制代码
2.在 BActivity 中使用
public class BActivity extends Activity implements Button.OnClickListener {
private BService service = null;
private boolean isBind = false;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBind = true;
BService.MyBinder myBinder = (BService.MyBinder)binder;
service = myBinder.getService();
//int num = service.getRandomNumber();
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBind = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnbindService).setOnClickListener(this);
findViewById(R.id.btnFinish).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.btnBindService){
//单击了“bindService”按钮
Intent intent = new Intent(this, TestTwoService.class);
intent.putExtra("from", "ActivityB");
bindService(intent, conn, BIND_AUTO_CREATE);
}else if(v.getId() == R.id.btnUnbindService){
//单击了“unbindService”按钮
if(isBind){
unbindService(conn);
}
}else if(v.getId() == R.id.btnFinish){
//单击了“Finish”按钮
this.finish();
}
}
@Override
public void onDestroy(){
super.onDestroy();
}
}
复制代码
再建立一个相同的 CActivity 去绑定 Service,而后咱们去动手执行一下操做,而后在对应的生命周期中打印生命周期执行的方法以及 onServiceConnected 方法中打印调用状况 1.BActivity 去 bindService 2.CActivity 去 bindService 3.CActivity 中的 unbindService 按钮 4.BActivity 中的 unbindService 按钮
上面四种状况去操做可发现: 1.再次建立不会调用 onCreate、onBind 方法 2.只有都调用了 unbindService,BService 才会去执行 onUnbind 方法,再执行 onDestroy
补充:系统资源回收
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY | START_STICKY | START_REDELIVER_INTENT;
}
复制代码
START_NOT_STICKY 当系统因回收资源而销毁了 Service,当资源再次充足时再也不自动启动 Service,除非有未处理的 Intent 准备发送。
START_STICKY 当系统因回收资源而销毁了 Service,当资源再次充足时自动启动 Service。并且再次调用 onStartCommand() 方法,可是不会传递最后一次的 Intent,相反系统在回调 onStartCommand() 的时候会传一个空 Intent,除非有未处理的 Intent 准备发送。
START_REDELIVER_INTENT 当系统因回收资源而销毁了 Service,当资源再次充足时自动启动 Service,而且再次调用 onStartCommand() 方法,并会把最后一次 Intent 再次传递给 onStartCommand(),相应的在队列里的 Intent 也会按次序一次传递。此模式适用于下载等服务。
说到这就要说一下保活后台服务的相关方法: 1).提升优先级
<!-- 为防止Service被系统回收,能够尝试经过提升服务的优先级解决,1000是最高优先级,数字越小,优先级越低 -->
android:priority="1000"
复制代码
2).把 service 写成系统服务,将不会被回收:
在 Manifest.xml 文件中设置 persistent 属性为 true,则可以使该服务免受 out-of-memory killer 的影响。可是这种作法必定要谨慎,系统服务太多将严重影响系统的总体运行效率。
3).将服务改为前台服务 foreground service:
重写 onStartCommand 方法,使用 StartForeground(int,Notification)方法来启动 service。
注:通常前台服务会在状态栏显示一个通知,最典型的应用就是音乐播放器,只要在播放状态下,就算休眠也不会被杀,若是不想显示通知,只要把参数里的 int 设为 0 便可。
同时,对于经过 startForeground 启动的 service,onDestory 方法中须要经过 stopForeground(true)来取消前台运行状态。
这个方案将在-ForegroundService细说
4).利用 Android 的系统广播
利用 Android 的系统广播检查 Service 的运行状态,若是被杀掉,就再起来,系统广播是 Intent.ACTION_TIME_TICK,这个广播每分钟发送一次,咱们能够每分钟检查一次 Service 的运行状态,若是已经被结束了,就从新启动 Service。
Activity 与 Service 进行通讯有四种方式
######经过 Intent 传递参数
在 MainActivity 中传递参数
intent = new Intent(MainActivity.this, MyService.class);
intent.putExtra("data", object);
startService(intent);
复制代码
在 MyService 的 onStartCommand 接受参数
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}
复制代码
######Binder 类
MyService 中咱们建立一个 Binder 类,让其实现 android.os.Binder 类,而且定义一个方法 setData,而后咱们经过 onBind()方法将其对象返回 MainActivity。
设置 MyService 中设置参数数据的方法
public class MyService extends Service {
private String data;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
public class Binder extends android.os.Binder{
public void setData(String data){
MyService.this.data = data;
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
复制代码
在 MainActivity 中实现 ServiceConnection 方法,获取到 MyService 中返回的 Binder 对象,接着咱们经过 Binder 对象调用它的方法 setData 向其传递数据
public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
private Intent intent;
private MyService.Binder myBinder = null;//①
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(MainActivity.this, MyService.class);
findViewById(R.id.btySend).setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btySend://想MyService传递数据
if (myBinder != null) {
myBinder.setData("传递能想传递的数据");//③
}
break;
default:
break;
}
}
//一旦绑定成功就会执行该函数
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (MyService.Binder) iBinder;//②
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
复制代码
注意 ①②③ 的顺序
######接口回掉 CallBack 在 MyService 设置 CallBack,可用于 Service 向 activity 传递参数,监听服务中的进程的变化
public class MyService extends Service {
private Boolean myflags = false;
private String data ;
private Callback callback;
private static final String TAG = "MyService";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
public class Binder extends android.os.Binder{
public void setData(String data){
MyService.this.data = data;
}
public MyService getMyService(){
return MyService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
myflags = true;
new Thread(){
@Override
public void run() {
super.run();
int i =1;
while(myflags){
//System.out.println("程序正在运行.....");
try {
String str = i + ":" +data;
Log.d(TAG, str);
if (callback != null){
callback.onDataChange(str);
}
sleep(1000);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
Toast.makeText(MyService.this, "出错了", Toast.LENGTH_SHORT).show();
}
}
Log.d(TAG, "服务器已中止");
}
}.start();
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
myflags = false;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public Callback getCallback() {
return callback;
}
public static interface Callback{
void onDataChange(String data);
}
}
复制代码
在 MainActivity 中咱们能够经过 onServiceConnected 方法中的 iBinder 对象来实现 MyService 中 Callback 的接口,在 Android 中有一个安全机制,辅助线程是不能直接修改主线程中的数据的,所以咱们须要再定义一个 Hander 对象。
public class MainActivity extends AppCompatActivity implements ServiceConnection {
private MyService.Binder myBinder = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//一旦绑定成功就会执行该函数
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (MyService.Binder) iBinder;
myBinder.getMyService().setCallback(new MyService.Callback(){
@Override
public void onDataChange(String data) {
Message msg = new Message();
Bundle b = new Bundle();
b.putString("data",data);
msg.setData(b);
hander.sendMessage(msg);
}
});
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
private Handler hander = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//获取变化的数据 msg.getData().getString("data")
}
};
}
复制代码
######broadcast
经过广播的的形式,可参考BroadcastReciver 详解
IntentService 是继承并处理异步请求的一个类,在 IntentService 内有一个工做线程来处理耗时操做,启动 IntentService 的方式和启动传统的 Service 同样,同时,当任务执行完后,IntentService 会自动中止,而不须要咱们手动去控制或 stopSelf()。另外,能够启动 IntentService 屡次,而每个耗时操做会以工做队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,而且,每次只会执行一个工做线程,执行完第一个再执行第二个,以此类推。
查看 IntentService 类的部分源码
@Override
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);
}
ServiceHandler相关代码
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);
}
}
复制代码
从源码中看,onCreate 中 thread.start()开启工做线程,thread.getLooper()单独的消息队列,经过 handler 中的 handleMessage 方法调用 onHandleIntent 执行处理任务
在实际应用中咱们继承 IntentService,重写 onHandleIntent 方法来执行异步耗时操做
public class MIntentService extends IntentService {
public MIntentService(){
super("MIntentService");
}
/**
* Creates an IntentService. Invoked by your subclass's constructor. * @param name Used to name the worker thread, important only for debugging. */ public MIntentService(String name) { super(name); } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { //TODO耗时操做 实际应用有后台静默上传数据 } @Override public void onDestroy() { super.onDestroy(); } } 复制代码
ForegroundService 前台服务是那些被认为用户知道(用户所承认的)且在系统内存不足的时候不容许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除
应用场景:在通常状况下,Service 几乎都是在后台运行,一直默默地作着辛苦的工做。但这种状况下,后台运行的 Service 系统优先级相对较低,当系统内存不足时,在后台运行的 Service 就有可能被回收。 那么,若是咱们但愿 Service 能够一直保持运行状态且不会在内存不足的状况下被回收时,能够选择将须要保持运行的 Service 设置为前台服务。咱们能够以常见的音乐播放器举例说明
建立音乐服务
public class MusicPlayerService extends Service {
private static final String TAG = MusicPlayerService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind()");
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
复制代码
而后建立 Notification,在 Service 的 onStartCommand 中添加以下代码:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
// 在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; //设置为默认的声音
}
复制代码
在完成 Notification 通知消息的构建后,在 Service 的 onStartCommand 中可使用 startForeground 方法来让 Android 服务运行在前台。
// 参数一:惟一的通知标识;参数二:通知消息。
startForeground(110, notification);// 开始前台服务
复制代码
若是须要中止前台服务,可使用 stopForeground 来中止正在运行的前台服务。
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
stopForeground(true);// 中止前台服务--参数:表示是否移除以前的通知
super.onDestroy();
}
复制代码