美文网首页Android中高级进阶
关于Service总结知识

关于Service总结知识

作者: Sincerity_ | 来源:发表于2019-03-27 11:31 被阅读2次

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

    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_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一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧.

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

    相关文章

      网友评论

        本文标题:关于Service总结知识

        本文链接:https://www.haomeiwen.com/subject/zbaavqtx.html