Service是一个后台服务,专门用来处理常驻后台工作的组件。
即时通讯:service来做常驻后台的心跳传输。
核心服务尽可能轻,很多人喜欢把所有的后台操作放在一个service里面,这是不太好的,因为“树大招风”。应该核心服务专门做一个进程,跟其他所有后台操作隔离。
进程的重要性优先级(从高到低):
1. 前台进程:
- 用户正在交互的Activity;
- 当某个Service绑定正在交互的Activity;
- 被主动调用为前台的Service(startForegroud());
- 组件正在执行声明周期的回调
- 广播接收者(BroadcastReceiver)正在执行onResume
2. 可见进程
- Activity处于onPause()(没有进入onStop())
- 绑定到前台Activity的Service
3.服务进程
简单的startService()启动
4. 后台进程
对用户没有直接影响的进程,比如Activity处于onStop()的时候
5. 空进程
不含有任何活动的组件。安卓设计的,为了第二次启动更快,采取的权衡。。当我们退出一个app后,其实这个进程还是存在的,这是系统这么设计的。
如何提升进程的优先级
提高进程优先级,尽量做到不轻易被系统杀死。
1.QQ采取在锁屏的时候启动一个1像素的Activity(注意:锁屏界面在上面),当用户解锁(或者是开屏)以后,要将这个Activity结束,顺便把自己的核心服务再开启。
背景:当手机锁屏的时候什么都干死了,为了省电。
下面我们就简单实现一个例子。
//屏幕广播接收以及状态回调的类
public class ScreenListener {
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private ScreenStateListener mScreenStateListener;
public ScreenListener(Context context) {
mContext = context;
mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
*广播接收
*/
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { //开屏
mScreenStateListener.onScreenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏
mScreenStateListener.onScreenOff();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁
mScreenStateListener.onUserPresent();
}
}
}
/**
* 初始化
*
* @param listener
*/
public void begin(ScreenStateListener listener) {
mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
*获取屏幕状态
*/
private void getScreenState() {
PowerManager manager = (PowerManager) mContext
.getSystemService(Context.POWER_SERVICE);
if (manager.isScreenOn()) {
if (mScreenStateListener != null) {
mScreenStateListener.onScreenOn();
}
} else {
if (mScreenStateListener != null) {
mScreenStateListener.onScreenOff();
}
}
}
public void unregisterListener() {
mContext.unregisterReceiver(mScreenReceiver);
}
/**
* 注册广播接收
*/
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiver(mScreenReceiver, filter);
}
//屏幕状态监听
public interface ScreenStateListener {
public void onScreenOn();
public void onScreenOff();
public void onUserPresent();
}
}
//控制1像素的activity显示和消失的Service
public class KeepService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
ScreenListener listener=new ScreenListener(this);
listener.begin(new ScreenListener.ScreenStateListener() {
@Override
public void onScreenOn() {
//开屏
KeepLiveActivityManager.getInstance(KeepService.this).finishKeepLiveActivity();
}
@Override
public void onScreenOff() {
//锁屏
KeepLiveActivityManager.getInstance(KeepService.this).startKeepLiveActivity();
}
@Override
public void onUserPresent() {
//解锁后
}
});
}
/**
* 补充:
* 锁屏-->回调onScreenOff
* 按键后屏幕亮--->onScreenOn
* 不解锁,再锁屏-->onScreenOff
* 按键后屏幕亮--->onScreenOn
* 解锁-->onUserPresent
*/
}
//1个像素的activity
public class KeepLiveActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.width=1;
params.height=1;
params.x=0;
params.y=0;
window.setGravity(Gravity.LEFT|Gravity.TOP);
window.setAttributes(params);
KeepLiveActivityManager.getInstance(this).setKeepLiveActivity(this);
System.out.println("-----KeepLiveActivity:onCreate-----");
}
@Override
protected void onDestroy() {
super.onDestroy();
System.out.println("-----KeepLiveActivity:onDestroy-----");
}
}
//activity的管理类
public class KeepLiveActivityManager {
private static KeepLiveActivityManager instance;
private Context context;
private WeakReference<Activity> activityInstance;
public static KeepLiveActivityManager getInstance(Context context) {
if(instance==null){
instance = new KeepLiveActivityManager(context.getApplicationContext());
}
return instance;
}
private KeepLiveActivityManager(Context context) {
this.context = context;
}
public void setKeepLiveActivity(Activity activity){
activityInstance = new WeakReference<Activity>(activity);
}
public void startKeepLiveActivity() {
Intent intent = new Intent(context, KeepLiveActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
public void finishKeepLiveActivity() {
if(activityInstance!=null&&activityInstance.get()!=null){
Activity activity = activityInstance.get();
activity.finish();
}
}
}
<style name="KeepLiveStyle">
<!--背景透明-->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowNoDisplay">false</item>
</style>
//清单文件注册activity
<activity android:name=".KeepLiveActivity"
android:theme="@style/KeepLiveStyle"/>
<service android:name=".keep.KeepService"/>
当然了千万不要忘了启动Service
Intent intent=new Intent(MainActivity.this, KeepService.class);
2.app运营商和手机厂商合作,加入白名单。
3.双进程守护
一个进程被杀死,另一个进程又把它启动,相互监听启动。本质是和杀进程时间赛跑。
利用双进程守护可以保证在停止单个服务(应用管理->正在运行)后又启动服务或者第三方清理软件清理失败。
下面是两个不同进程的Service,相互监听,不同进程间通信用到了AIDL。
public class LocalService extends Service {
public static final String TAG = "gxh";
private MyBind binder;
private MyServiceConnection conn;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
if (binder == null) {
binder = new MyBind();
}
conn = new MyServiceConnection();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//绑定
LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class),
conn, Context.BIND_IMPORTANT);
// Notification notification=new Notification(R.mipmap.ic_launcher,"哈哈哈哈",System.currentTimeMillis());
// notification.contentIntent= PendingIntent.getService(this,0,intent,0);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setTicker("hahaha")
.setSmallIcon(R.mipmap.ic_launcher)//设置小图标
.setContentTitle("LocalService")
.setContentIntent(pendingIntent)
.setAutoCancel(true)//点击后消失
.setContentText("ContentText")
.setWhen(System.currentTimeMillis());
Notification notification=builder.build();
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0, notification);//显示通知
//设置为前台,尽量避免被系统杀死
startForeground(startId, notification);
return START_STICKY;
}
class MyBind extends face.gxh.cn.imeitext.aidl.RemoteConnection.Stub {
@Override
public String getProcessName() throws RemoteException {
return "LocalService";
}
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "local--onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "local--onServiceDisconnected");
Global.showToast("RemoteService断开了");
//RemoteService断开了,所以要重新启动这个服务
LocalService.this.startService(new Intent(LocalService.this,RemoteService.class));
LocalService.this.bindService(new Intent(LocalService.this,RemoteService.class),
conn, Context.BIND_IMPORTANT);
}
}
}
public class RemoteService extends Service {
public static final String TAG="gxh";
private MyBind binder;
private MyServiceConnection conn;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
if(binder==null){
binder=new MyBind();
}
conn=new MyServiceConnection();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//绑定
RemoteService.this.bindService(new Intent(RemoteService.this, LocalService.class),
conn, Context.BIND_IMPORTANT);
// Notification notification=new Notification(R.mipmap.ic_launcher,"哈哈哈哈",System.currentTimeMillis());
// notification.contentIntent= PendingIntent.getService(this,0,intent,0);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setTicker("hahaha")
.setContentTitle("RemoteService")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setContentText("ContentText")
.setWhen(System.currentTimeMillis());
Notification notification=builder.build();
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(1, notification);//显示通知
//设置为前台,尽量避免被系统杀死
startForeground(startId, notification);
return START_STICKY;
}
class MyBind extends face.gxh.cn.imeitext.aidl.RemoteConnection.Stub{
@Override
public String getProcessName() throws RemoteException {
return "LocalService";
}
}
class MyServiceConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG,"remote--onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG,"remote--onServiceDisconnected");
Global.showToast("LocalService断开了");
//LocalService断开了
RemoteService.this.startService(new Intent(RemoteService.this,LocalService.class));
RemoteService.this.bindService(new Intent(RemoteService.this,LocalService.class),
conn, Context.BIND_IMPORTANT);
}
}
}
AIDL的创建:
创建aidl文件夹,右键new->AIDL->AIDL FILE->修改文件名->Finish->在生成的aidl文件中写你的方法->重新编译一下。
注意生成的对应的java文件在app->build->generated->source->aidl
// RemoteConnection.aidl
package face.gxh.cn.imeitext.aidl;
// Declare any non-default types here with import statements
interface RemoteConnection {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);
String getProcessName();
}
注册:
<service android:name=".doubl.LocalService"/>
<service android:name=".doubl.RemoteService"
android:process=":remoteprogress"/>
启动:
startService(new Intent(MainActivity.this, LocalService.class));
startService(new Intent(MainActivity.this, RemoteService.class));
4.JobScheduler
详见下一篇文章吧。