关于Service总结知识

本文介绍Android进程保活的多种方法,包括开启1像素Activity、前台服务保活、相互唤醒、JobScheduler、粘性服务和系统捆绑服务等。还探讨了不同类型的进程及其重要性,并提供了一些实用的代码示例。
摘要由CSDN通过智能技术生成

  • 前言,这些天一直在看一些以前学过的知识,突然发现好多以前的旧知识都忘记了,特此记录下来,此篇会一直更新下去.

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

进程划分(重要性从高到底)

前台进程

  正在使用的程序,一般系统不会杀死,除非用户强制停止或者系统内存不足等极端情况下会杀死

  1. 某个进程持有正在与用户交互的Activity并且该Activity正处于resume状态
  2. 某个进程持有一个Service,并且该Service正在与用户交互的Activity绑定
  3. 某个进程持有一个Service,并且该Service调用setForeground方法使自己位于前台
  4. 某个进程持有一个Service,并且该Service正在执行它的某个生命周期回调方法
  5. 某个进程持有一个broadcastReceiver,并且broadcastreceiver正在执行onReceiver方法
可见进程

用户正在使用,看得到,没有覆盖到整个屏幕,只有屏幕的一部分可见进程不包含任何前台进程,一般系统也是不会杀死

  1. 拥有不在前台,但仍对用户可见的Activity(一调用onPause)
  2. 拥有绑定到可见Activity的Service
服务进程
  1. 某个进程中运行着一个Service且改Service是通过StartService启动,与用户看见的界面没有直接关联
后台进程
  1. 用户按了"back"或者"Home"后,程序本身看不到了,但是其实还在运行的程序,不如Activity调用了Onpause方法
空进程
  1. 某个进程不包含任何活跃的组件时,该进程就会被设置为空进程,完全没用,杀了他只有好处没有坏处

进程保活方法

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_ADJ16预留的最低级别,一般对于缓存的进程才有可能设置成这个级别
CACHED_APP_MAX_ADJ15缓存进程,空进程,在内存不足的情况下就会优先被kill
CACHED_APP_MIN_ADJ9缓存进程,也就是空进程
SERVICE_B_ADJ8不活跃的进程
PREVIOUS_APP_ADJ7切换进程
HOME_APP_ADJ6与Home交互的进程
SERVICE_ADJ5有Service的进程
VY_WEIGHT_APP_ADJ4高权重进程
BACKUP_APP_ADJ3正在备份的进程
PERCEPTIBLE_APP_ADJ2可感知的进程,比如那种播放音乐
VISIBLE_APP_ADJ1可见进程
FOREGROUND_APP_ADJ0前台进程
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一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧.

  • 所以,进程保活的根本方案终究还是回到了性能优化上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值