如下代码监听开机广播,启动一个Service
package com.android.demo.service;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;import com.android.demo.util.ShellUtils;import java.util.ArrayList;
import java.util.List;public class AppService extends Service {private final static String TAG = "AppService";private boolean isServiceStarted = false;private Intent startIntent = null;@Overridepublic IBinder onBind(Intent arg0) {return null;}@Overridepublic void onCreate() {super.onCreate();Log.e(TAG, "AppService onCreate");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e(TAG, "AppService onStartCommand");//onStart(intent, startId);//return super.onStartCommand(intent, flags, startId);//START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。//随后系统会尝试重新创建service,由于服务状态为开始状态,//所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。//如果在此期间没有任何启动命令被传递到service,那么参数Intent将为nullreturn START_STICKY;}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubstartIntent = intent;Log.e(TAG, "AppService, onStart");if (!isServiceStarted) {isServiceStarted = true;}}@Overridepublic void onDestroy() {// TODO Auto-generated method stubLog.e(TAG, "AppService, onDestroy");isServiceStarted = false;//在销毁的时候,重新开启if (startIntent != null) {startService(startIntent);}}
}
package com.android.demo.broadcast;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;import com.android.demo.service.AppService;public class BootBroadcastReceiver extends BroadcastReceiver {private static final String TAG = "BootBroadcastReceiver";private static Context mContext;@Overridepublic void onReceive(Context context, Intent intent) {mContext = context;String action = intent.getAction();Log.e(TAG, "BootBroadcastReceiver action = " + action);if (action == null) {return;}if (action.equals("android.intent.action.BOOT_COMPLETED")) {Log.i(TAG, "BOOT_COMPLETED");Intent i = new Intent(context, AppService.class);i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startService(i);}}}
Service是Android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。
Service的启动有两种方式:context.startService() 和 context.bindService()
context.startService() 启动流程:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
onstart()方法是在android2.0一下的版本中使用。而在android2.0以上则使用onstartCommand()方法。
如果Service还没有运行,则android先调用onCreate(),然后调用onStart();
如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行,该Service的调用者在启动起来后可以通过stopService关闭Service。
所以调用startService的生命周期为:onCreate --> onStart (可多次调用) --> onDestroy
context.bindService()启动流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
Service的生命周期并不像Activity那么复杂,它只继承了onCreate()、onStart()、onDestroy()三个方法
当我们第一次启动Service时,先后调用了onCreate()、onStart()这两个方法;当停止Service时,则执行onDestroy()方法。
这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。
它可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己,只要调用一次stopService()方法便可以停止服务,无论调用了多少次的启动服务方法。
添加android:persistent=“true"到AndroidManifest.xml,
Google文档描述如下:Whether or not the application should remain running at all times-true” if it should, and "false"if not. The default value is “false”. Applications should not normally set this flag; persistence mode is intended only for certain system applications.可见这个属性不能随便用,到目前为止,我所发现使用该属性的应用只有Phone,而且使用是要求权限的,所以这个属性对第三方应用来说意义不是很大;常驻内存属性对第三方app无效
设置onStartCommand()的返回值 。
@Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY;
}
简单介绍下这个方法,在Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理。然后我们注意到这个函数有一个int的返回值,这篇文章就是简单地讲讲int返回值的作用。
从Android官方文档中,我们知道onStartCommand有4种返回值:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
一般来说,这样做是可以的。但是如果这样----》设置–>下载–>强制停止。则不会执行ondestory方法,或者通过别人应用,如360直接kill掉我的应用时,也是不会调用Service的ondestory方法的。onDestroy方法里重启serviceservice +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
//这个就是自定义的action
在onDestroy时:
@Override
public void onDestroy() { stopForeground(true); Intent intent = new Intent("com.dbjtech.waiqin.destroy"); sendBroadcast(intent); super.onDestroy();
}
在BootReceiver里
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) { //在这里写重新启动service的相关操作 startUploadService(context); } }
}
也可以直接在onDestroy()里startService
@Override
public void onDestroy() { Intent sevice = new Intent(this, MainService.class); this.startService(sevice); super.onDestroy();
}
【结论】当在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证.
如果在加入了此部分代码,表示该程序运行在system进程组中,system进程组是没有权限访问sd卡的,而且service是不会自动重启的。
不管你service的优先级别有多高,用户都是可以手动杀死的.
提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
1.前台进程( FOREGROUND_APP)
2.可视进程(VISIBLE_APP )
3.次要服务进程(SECONDARY_SERVER )
4.后台进程 (HIDDEN_APP)
5.内容供应节点(CONTENT_PROVIDER)
6.空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
在onStartCommand方法内添加如下代码:
Notification notification = new Notification(R.drawable.ic_launcher,
getString(R.string.app_name), System.currentTimeMillis());
PendingIntent pendingintent = PendingIntent.getActivity(this, 0,
new Intent(this, AppMain.class), 0);
notification.setLatestEventInfo(this, "uploadservice", "请保持程序在后台运行",
pendingintent);
startForeground(0x111, notification);
注意在onDestroy里还需要stopForeground(true),运行时在下拉列表会看到自己的APP
启动、网络切换、耳机插入、锁屏,亮屏等系统广播,系统每隔一段时间发送这个广播,当service被杀死的时候,隔一段时间通过广播启动,动态注册android.intent.action.TIME_TICK监听
判断service是否启动
public boolean isServiceRunning(String serviceName)
{ ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); for (RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE)) { if(serviceName.equals(service.service.getClassName())) { return true; } } return false;
}
接受到广播后判断是否启动该service 若没有启动就启动它
if(intent.getAction().equals(Intent.ACTION_TIME_TICK))
{ if (!isServiceRunning(name)){ Intent mIntent = new Intent(context, MyService.class); context.startService(mIntent); }
}
联系厂商,加入白名单,有童鞋验证把demo工程的包名改成手机QQ的,编译运行在华为的机子上,发现进程杀不死,退到后台oom_adj的值同样不发生变化,而恢复原来的包名就不行了,可见很多大型软件,尤其聊天类的都会和厂商合作,将相关应用加入白名单。
Android之Service全面解析,关于Service你所需要知道的一切
Android Service完全解析,关于服务你所需知道的一切(上)
Android Service完全解析,关于服务你所需知道的一切(下)
务必知道的Android service的完全详解
Android之Service设置android:process作用