- 前言,这些天一直在看一些以前学过的知识,突然发现好多以前的旧知识都忘记了,特此记录下来,此篇会一直更新下去.
StartService
intent = new Intent(this, MyService.class);
startService(intent); //开启
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent); //停止
}
- 特点: 开启服务后不依赖Activity,即使当前Activity销毁后,service依然在运行,除非调用stopservice或者stopselfe来停止服务
BindService
connection=new MyServiceConnection();
bindService(intent, connection, Service.BIND_AUTO_CREATE);
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(connection!=null);
unbindService(connection);
}
- 绑定服务后,如果当前的Activity销毁,服务也会被销毁,如果Activity销毁时必须要调用unBindService()开取消绑定,
一般进程保活套路
当前业界的Android进程保活手段主要分为** 黑、白、灰 **三种,其大致的实现思路如下:
- 黑色保活:不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
- 白色保活:启动前台Service
- 灰色保活:利用系统的漏洞启动前台Service
进程划分(重要性从高到底)
前台进程
正在使用的程序,一般系统不会杀死,除非用户强制停止或者系统内存不足等极端情况下会杀死
- 某个进程持有正在与用户交互的Activity并且该Activity正处于resume状态
- 某个进程持有一个Service,并且该Service正在与用户交互的Activity绑定
- 某个进程持有一个Service,并且该Service调用setForeground方法使自己位于前台
- 某个进程持有一个Service,并且该Service正在执行它的某个生命周期回调方法
- 某个进程持有一个broadcastReceiver,并且broadcastreceiver正在执行onReceiver方法
可见进程
用户正在使用,看得到,没有覆盖到整个屏幕,只有屏幕的一部分可见进程不包含任何前台进程,一般系统也是不会杀死
- 拥有不在前台,但仍对用户可见的Activity(一调用onPause)
- 拥有绑定到可见Activity的Service
服务进程
- 某个进程中运行着一个Service且改Service是通过StartService启动,与用户看见的界面没有直接关联
后台进程
- 用户按了"back"或者"Home"后,程序本身看不到了,但是其实还在运行的程序,不如Activity调用了Onpause方法
空进程
- 某个进程不包含任何活跃的组件时,该进程就会被设置为空进程,完全没用,杀了他只有好处没有坏处
进程保活方法
1. 开启一个1像素的Activity (前台进程保活)
//二个Activity
/****MainActivity**/
LiveService.toLiveService(this); //开启一个service
/***********ServiceActivity*********/
public class ServiceActivity extends Activity {
//打开自己的方法
public static void actionStartActivity(Context context) {
Intent intent = new Intent(context, ServiceActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
Window window = getWindow();
window.setGravity(Gravity.START | Gravity.TOP);
WindowManager.LayoutParams params = window.getAttributes();
params.height = 1;//设置当前的Activity为1像素
params.width = 1;
params.x = 0;//位置在左上角
params.y = 0;
window.setAttributes(params);
//注册当前Activity用来开启或者关闭当前页面
ScreenManager.getDefault(this).setActivity(this);
}
}
//LiveService页面
public class LiveService extends Service {
//开启service
public static void toLiveService(Context context) {
Intent intent = new Intent(context, LiveService.class);
context.startService(intent);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final ScreenManager aDefault = ScreenManager.getDefault(this);
//注册广播监听锁屏或者解锁
ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
listener.setListener(new ScreenBroadcastListener.BroadcastListener() {
@Override
public void screenOn() {
//解锁
aDefault.finshActivity();
}
@Override
public void screenOff() {
//锁屏
aDefault.startActivity();
}
});
return START_REDELIVER_INTENT;
}
}
//开启广播页面
public class ScreenBroadcastListener {
private BroadcastListener listener;
private Context mContext;
private ScreenBroadcastReceiver broadcastReceiver;
public ScreenBroadcastListener(Context mContext) {
this.mContext = mContext;
broadcastReceiver = new ScreenBroadcastReceiver();
}
public void setListener(BroadcastListener listener) {
this.listener = listener;
registerListener();
}
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(broadcastReceiver, filter);
}
public interface BroadcastListener {
void screenOn();
void screenOff();
}
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)) {
listener.screenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
listener.screenOff();
}
}
}
}
//页面管理器
public class ScreenManager {
private WeakReference<Activity> weakReference; //弱引用
private Context mContext;
private static ScreenManager screenManager;
public static ScreenManager getDefault(Context context) {
if (screenManager == null) {
screenManager = new ScreenManager(context.getApplicationContext());
}
return screenManager;
}
public ScreenManager(Context mContext) {
this.mContext = mContext;
}
public void setActivity(Activity activity) {
weakReference = new WeakReference<Activity>(activity);
}
public void startActivity() {
ServiceActivity.actionStartActivity(mContext);
}
public void finshActivity() {
if (weakReference != null) {
Activity activity = weakReference.get();
if (activity != null)
activity.finish();
}
}
}
//查看当前程序的进程
adb shell //进入设备 exit退出
ps|grep 完整包名 //查看当前程序的进程ID
u0_a79 2997 254 835760 83964 ep_poll f1e34bb9 S com.sincerity.interviewdemo
进程用户 进程ID 进程父ID 进程虚拟内存 实际驻留内存 进程名称
cat /proc/进程ID/oom_adj //查看进程的优先级
adj级别 | 值 | 解释 |
---|---|---|
UNKNOWN_ADJ | 16 | 预留的最低级别,一般对于缓存的进程才有可能设置成这个级别 |
CACHED_APP_MAX_ADJ | 15 | 缓存进程,空进程,在内存不足的情况下就会优先被kill |
CACHED_APP_MIN_ADJ | 9 | 缓存进程,也就是空进程 |
SERVICE_B_ADJ | 8 | 不活跃的进程 |
PREVIOUS_APP_ADJ | 7 | 切换进程 |
HOME_APP_ADJ | 6 | 与Home交互的进程 |
SERVICE_ADJ | 5 | 有Service的进程 |
VY_WEIGHT_APP_ADJ | 4 | 高权重进程 |
BACKUP_APP_ADJ | 3 | 正在备份的进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知的进程,比如那种播放音乐 |
VISIBLE_APP_ADJ | 1 | 可见进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
PERSISTENT_SERVICE_ADJ | -11 | 重要进程 |
PERSISTENT_PROC_ADJ | -12 | 核心进程 |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | 系统起的Native进程 |
不同设备的adj不同 oom_adj越大,占用物理内存越多会被最先kill掉
2. 前台服务保活(服务保活)
public class KeepLiveService extends Service {
public static final int NOTIFICATION_ID = 0x11;
public KeepLiveService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
startForeground(NOTIFICATION_ID, new Notification());
} else {
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(NOTIFICATION_ID, builder.build());
startService(new Intent(this, InnerService.class));
}
}
public static class InnerService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(NOTIFICATION_ID, builder.build());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
stopForeground(true);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
stopSelf();
}
}, 200);
}
}
}
3. 相互唤醒
4. josSchudler
- JobSheduler是作为进程死后复活的一种手段,native进程方式最大缺点是费电, Native 进程费电的原因是感知主进程是否存活有两种实现方式,在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,当主进程不存活时进行拉活。其次5.0以上系统不支持。 但是JobSheduler可以替代在Android5.0以上native进程方式,这种方式即使用户强制关闭,也能被拉起来
public class MyJobService extends JobService {
@Override
public void onCreate() {
super.onCreate();
startScheduler();
}
private void startScheduler() {
JobInfo.Builder builder = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()));
builder.setPeriodic(5);
builder.setPersisted(true);
JobScheduler scheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(builder.build());
}
@Override
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
5. 粘性服务和系统捆绑服务
- onStartCommand方法必须具有一个整形的返回值,这个整形的返回值用来告诉系统在服务启动完毕后,如果被Kill,系统将如何操作,这种方案虽然可以,但是在某些情况or某些定制ROM上可能失效,可以多做一种保保守方案。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_REDELIVER_INTENT;
}
-
START_STICKY :如果系统在onStartCommand返回后被销毁,系统将会重新创建服务并依次调用onCreate和onStartCommand这种相当于服务又重新启动恢复到之前的状态了
-
START_NOT_STICKY:如果系统在onStartCommand返回后被销毁,如果返回该值,则在执行完onStartCommand方法后如果Service被杀掉系统将不会重启该服务。
-
START_REDELIVER_INTENT START_STICKY的兼容版本,不同的是其不保证服务被杀后一定能重启。
-
这里说的系统服务很好理解,比如NotificationListenerService,NotificationListenerService就是一个监听通知的服务,只要手机收到了通知,NotificationListenerService都能监听到,即时用户把进程杀死,也能重启.
public class LiveService extends NotificationListenerService { public LiveService() { //自己的服务去做点事情... } @Override public void onNotificationPosted(StatusBarNotification sbn) { } @Override public void onNotificationRemoved(StatusBarNotification sbn) { } } //记得添加权限 <service android:name=".LiveService" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> <intent-filter> <action android:name="android.service.notification.NotificationListenerService" /> </intent-filter> </service>
6. 双进程守护
-
双进程守护的思想就是,两个进程共同运行,如果有其中一个进程被杀,那么另一个进程就会将被杀的进程重新拉起,相互保护,在一定的意义上,维持进程的不断运行。
双进程守护的两个进程,一个进程用于我们所需的后台操作,且叫它本地进程,另一个进程只负责监听着本地进程的状态,在本地进程被杀的时候拉起,于此同时本地进程也在监听着这个进程,准备在它被杀时拉起,我们将这个进程称为远端进程。
由于在 Android 中,两个进程之间无法直接交互,所以我们这里还要用到 AIDL (Android interface definition Language ),进行两个进程间的交互。/** * Created by Sincerity on 2019/3/27. * 描述:双进程守护 ,service保活手段 */ public class LocalService extends Service { private myServiceName serviceName; @Override public IBinder onBind(Intent intent) { serviceName = new myServiceName(); return serviceName; } public LocalService() { } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "LocalService 已经启动", Toast.LENGTH_LONG).show(); startService(new Intent(LocalService.this, RemoteService.class)); bindService(new Intent(LocalService.this, RemoteService.class), connection, Service.BIND_IMPORTANT); return START_STICKY; } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IMyAidlInterface myAidlInterface = IMyAidlInterface.Stub.asInterface(service); try { Log.i("LocalService", "connected with " + myAidlInterface.getServiceName()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(LocalService.this, "链接断开,重新启动 RemoteService", Toast.LENGTH_SHORT).show(); startService(new Intent(LocalService.this, RemoteService.class)); bindService(new Intent(LocalService.this, RemoteService.class), connection, Context.BIND_IMPORTANT); } }; public class myServiceName extends IMyAidlInterface.Stub { @Override public String getServiceName() throws RemoteException { return LocalService.class.getName(); } } @Override public void onDestroy() { super.onDestroy(); unbindService(connection); } }
/** * Created by Sincerity on 2019/3/27. * 描述:描述:双进程守护 ,service保活手段 */ public class RemoteService extends Service { private myService myService; @Override public IBinder onBind(Intent intent) { myService = new myService(); return myService; } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this,"RemoteService 启动",Toast.LENGTH_LONG).show(); bindService(new Intent(this, LocalService.class), connection , Service.BIND_IMPORTANT); return START_STICKY; } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IMyAidlInterface myAidlInterface = IMyAidlInterface.Stub.asInterface(service); try { Log.i("LocalService", "connected with " + myAidlInterface.getServiceName()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(RemoteService.this, "链接断开,重新启动 LocalService", Toast.LENGTH_LONG).show(); startService(new Intent(RemoteService.this, LocalService.class)); bindService(new Intent(RemoteService.this, LocalService.class), connection, Context.BIND_IMPORTANT); } }; public RemoteService() { } private class myService extends IMyAidlInterface.Stub { @Override public String getServiceName() throws RemoteException { return RemoteService.class.getName(); } } @Override public void onDestroy() { super.onDestroy(); unbindService(connection); } }
//测试 @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_startService: startService(new Intent(this, LocalService.class)); break; case R.id.btn_stopService: stopService(new Intent(this, LocalService.class)); break; case R.id.btn_stop2Service: stopService(new Intent(this, RemoteService.class)); break; case R.id.btn_checkedService: Toast.makeText(this, "服务1的状态" + getServiceIsLife(LocalService.class.getName()) + "服务2的状态" + getServiceIsLife(RemoteService.class.getName()), Toast.LENGTH_SHORT).show(); break; } } /** * * @param ServiceName service.class.getname来获取 * @return 是否存活 */ boolean getServiceIsLife(String ServiceName) { if (TextUtils.isEmpty(ServiceName)) { return false; } ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); ArrayList<ActivityManager.RunningServiceInfo> infoArrayList = (ArrayList<ActivityManager.RunningServiceInfo>) manager.getRunningServices(Integer.MAX_VALUE); for (int i = 0; i < infoArrayList.size(); i++) { if (infoArrayList.get(i).service.getClassName().equals(ServiceName)) { return true; } } return false; }
总结
-
**:有些手机厂商把这些知名的app放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、QQ都在VIVO的白名单中)。如果从白名单中移除,他们终究还是和普通app一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧.
-
所以,进程保活的根本方案终究还是回到了性能优化上