Android进程间的通信 - 耍流氓的方式保活Service

1. Service为什么会被杀死?


在我们开发的过程当中,有几种情况会导致我们的应用会被杀死:
1>:应用正在运行,这个时候由于内存不足会杀死进程进行回收内存;
2>:手机用了系统自带的或者一些第三方的清理软件,比如360、腾讯管家清理进程也会杀死我们应用的进程;
3>:各大Rom厂商,在应用退出的时候也会杀死我们应用的进程;

基本就是以上3种情况,作为开发来讲,其实最主要关心的是第一种情况就可以,下边我们就针对于这3中情况进行逐一的解决。

2. 进程优先级


共有5级,第一个最重要,最后一个是最不重要的,会从最后一个开始回收内存资源,以确保新的进程或者更重要的进程。

可以参照我之前的文章:
Android中的进程保活
或者参照大神的文章:
Android进程间的通信 - 耍流氓的方式保活Service

3. 解决第一种 —— 应用正在运行,这个时候由于内存不足会杀死进程进行回收内存


一般有3种解决方式:

1>:在应用退到后台时候,就需要释放资源,达到降低App内存的占用量,因为在oom_adj相同的时候,会优先干掉内存消耗大的进程;

举例说明:
比如:首页的ViewPager轮播图,在应用切换到其他页面或者返回到桌面时一定要处理,不要让它再去轮播,如果页面都切换到其他页面或者返回到桌面,还让它继续轮播,可能会消耗比较大的内存;

比如:百度地图的使用,必须在onResume()、onStop()、onDestroy()中必须调用mapView.onResume()、mapView.onStop()、mapView.onDestroy()方法,来释放内存;

2>:对于一直在后台运行的Service,我们一定要让它轻量,不能太风骚;

处理方式和第一种差不太多;

3>:提高进程的优先级,其实就是减小进程的 oom_adj,越小越好,越大越容易被回收,比如启动Service调用startForeground()方法,就会让你的应用在状态栏出现,从而提高进程优先级;

比如墨迹天气会一直在我们手机状态栏中存在,就是调用startForeground();

下边举例说明:

比如我从MainActivity启动一个MessageService,然后在MessageService中重写onStartCommand()方法,然后调用 startForeground()方法,就会达到下边的效果,在状态栏会一直出现我们的应用,效果如下:


Android进程间的通信 - 耍流氓的方式保活Service_第1张图片
图片.png
代码如下:
1>:MainActivity代码如下:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:25
 * Version 1.0
 * Params:
 * Description:
*/
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService(new Intent(this , MessageService.class)) ;
    }
}
2>:MessageService代码如下:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:08
 * Version 1.0
 * Params:
 * Description:    QQ聊天通讯  Service代码中一定要轻量
*/

public class MessageService extends Service {


    private int MessageId = 1;

    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Log.e("TAG", "等待接收消息");

                    try {
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }


    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        // 提高进程优先级  参数1:id 参数2:通知
        startForeground(MessageId , new Notification());
        return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
3>:在清单文件中配置:



    
        
            
                

                
            
        

        
    


只要在onStartCommand()方法中调用 startForeground()方法,就可以看到,手机状态栏会出现我们应用的图标,可以手动在状态栏中强行停止上边的ServiceALIveDemo.

2. 解决第二种 —— 用了系统自带的或者一些第三方的清理软件,也会杀死我们应用的进程;


解决方式是:

采用双进程守护,使用两个进程,即就是开启两个服务,让其相互唤醒,可以达到杀死其中一个,另一个会立马唤醒这个让其再重新启动然后建立连接,代码如下:

1>:第一个进程MessageService:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:08
 * Version 1.0
 * Params:
 * Description:    QQ聊天通讯  Service代码中一定要轻量
*/

public class MessageService extends Service {


    private int MessageId = 1;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ProcessConnection.Stub(){} ;
    }


    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Log.e("TAG", "等待接收消息");

                    try {
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }


    /**
     * MainActivity中一启动MessageService之后,就会调用 onStartCommand()方法
     */
    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        // 提高进程优先级 ,就会在通知栏中出现自己的应用,如果不想提高优先级,可以把这个注释
        // 参数1:id 参数2:通知
        startForeground(MessageId , new Notification());

        // 让MessageService绑定 GuardService并建立连接
        bindService(new Intent(this , GuardService.class) , mServiceConnection , Context.BIND_IMPORTANT) ;
        return START_STICKY;
    }


    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 连接上
            Toast.makeText(MessageService.this , "建立连接" , Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 断开连接,需要重新启动,然后重新绑定

            // 重新启动
            startService(new Intent(MessageService.this , GuardService.class)) ;
            // 重新绑定
            bindService(new Intent(MessageService.this , GuardService.class) , mServiceConnection , Context.BIND_IMPORTANT) ;
        }
    } ;
}
2>:第二个进程GuardService:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:32
 * Version 1.0
 * Params:
 * Description:    守护进程,双进程通讯,需要使用aidl(进程间通讯)
 *                 两个进程之间相互监听,相互唤醒
*/
public class GuardService extends Service {
    private int GuardId = 1;


    /**
     * 返回 IBinder驱动
     * Stub: 存根
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ProcessConnection.Stub(){} ;
    }


//    private ProcessConnection mBinder = new ProcessConnection.Stub(){} ;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 提高进程优先级 ,就会在通知栏中出现自己的应用,如果不想提高优先级,可以把这个注释
        startForeground(GuardId , new Notification());

        // 让GuardService绑定MessageService 并建立连接
        bindService(new Intent(this , MessageService.class) , mServiceConnection , Context.BIND_IMPORTANT) ;
        return START_STICKY;
    }


    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 连接上
            Toast.makeText(GuardService.this , "建立连接" , Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 断开连接,就需要重新启动,然后重新绑定

            // 重新启动
            startService(new Intent(GuardService.this , MessageService.class)) ;
            // 重新绑定
            bindService(new Intent(GuardService.this , MessageService.class) , mServiceConnection , Context.BIND_IMPORTANT) ;
        }
    } ;
}
3>:在MainActivity中同时启动两个服务:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:25
 * Version 1.0
 * Params:
 * Description:
*/
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService(new Intent(this , MessageService.class)) ;
        startService(new Intent(this , GuardService.class)) ;
    }
}
效果如下:
Android进程间的通信 - 耍流氓的方式保活Service_第2张图片
图片.png
Android进程间的通信 - 耍流氓的方式保活Service_第3张图片
图片.png
由上图可以看到:

点击到手机的 设置 -> 应用管理 -> 正在运行,可以看到有两个一样的进程都正在运行,而且你随便杀死一个,另一个会立马唤醒这个,让它再次重新启动并重新绑定服务;

可以点击应用,然后手动停止应用,或者使用第三方停止应用;
第三方在杀进程的时候,是一个一个杀的。

3. 解决第三个 —— 各大Rom厂商在应用退出的时候会清理杀死进程


电量优化 JobScheduler,处理定时任务,5.0以上才有

1>:JobWakeUpService代码如下:
/**
 * Email: [email protected]
 * Created by JackChen 2018/4/22 10:33
 * Version 1.0
 * Params:
 * Description:   JobService -> 5.0以上才有的
*/


@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class JobWakeUpService extends JobService {


    private final int jobWakeUpId = 1 ;
    /**
     * 开启服务之后,指定一个轮询时间
     */
    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        // 开启一个轮询
        JobInfo.Builder jobBuilder = new JobInfo.Builder(jobWakeUpId , new ComponentName(this , JobWakeUpService.class)) ;
        jobBuilder.setPeriodic(2000) ;  // 2s
        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.schedule(jobBuilder.build()) ;


        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        // 开启一个定时任务,定时轮询 ,  判断MessageService有没有被杀死
        // 如果杀死,就启动,因为这个方法是每隔一段时间进行轮询调用 onStartJob()方法

        // 判断服务有没有被杀死(判断服务有没有正在运行)
        boolean messageServiceALive = serviceAlive(JobWakeUpService.class.getName());
        // 如果服务没有活,就启动 ,这里只需要启动一个服务就ok,不需要启动另一个 GuardService
        if (!messageServiceALive){
            startService(new Intent(JobWakeUpService.this , MessageService.class)) ;
        }

        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }


    /**
     * 判断某个服务是否正在运行的方法
     * @param serviceName
     *            是包名+服务的类名(例如:net.loonggg.testbackstage.TestService)
     * @return true代表正在运行,false代表服务没有正在运行
     */
    private boolean serviceAlive(String serviceName) {
        boolean isWork = false;
        ActivityManager myAM = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        List myList = myAM.getRunningServices(100);
        if (myList.size() <= 0) {
            return false;
        }
        for (int i = 0; i < myList.size(); i++) {
            String mName = myList.get(i).service.getClassName().toString();
            if (mName.equals(serviceName)) {
                isWork = true;
                break;
            }
        }
        return isWork;
    }
}
2>:然后在MainActivity中启动,但是一定要判断是否大于5.0:
/**
 * Email: [email protected]
 * Created by Novate 2018/4/22 9:25
 * Version 1.0
 * Params:
 * Description:
*/
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        startService(new Intent(this , MessageService.class)) ;
        startService(new Intent(this , GuardService.class)) ;

        // 这里必须判断,否则5.0以下手机肯定崩溃
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            startService(new Intent(this , JobWakeUpService.class)) ;
        }
    }
}
3>:最后在清单文件中配置即可:



    // JobService权限
    



    
        
            
                

                
            
        


        

        
        

        
    


代码已上传至github:
https://github.com/shuai999/ServiceALiveDemo.git

注意

不到万不得已就不要这样子写,否则别人可能会卸载你应用。

你可能感兴趣的:(Android进程间的通信 - 耍流氓的方式保活Service)