双服务+时间广播和屏幕广播实现Android App保活

来源:互联网 发布:ubuntu 12.04 源 编辑:程序博客网 时间:2024/05/02 08:23

双服务+时间广播和屏幕广播实现Android App保活

最近做项目的时候,需要app保持常在的状态来接受服务器的推送消息,所以实现了app的保活。虽然实现了程序的保活,实际上是用户是可以手动杀死的,如果用户没有手动杀死app,那么系统在内存紧张的时候可以保证app存活在手机当中,既有效的保护了APP的正常运行,也能够让用户可控。
实现的原理是开启两个服务来相互拉取,保证app正常存活。通过监听系统的时间变化广播来和屏幕关闭以及解锁的广播来动态检查服务是不是存活,如果没有存活就拉起服务。
首先我们需要开启两个服务MyServiceOne和MyServiceTwo。代码如下:

MyServiceOne

public class MyServiceOne extends Service {    public final static String TAG = "myservice1";    public MyServiceOne() {    }    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG, "onStartCommand");        startServiceTwo();        //如果这个Service被系统Kill了或者app被Kill了,Service还能自动重启。        return START_REDELIVER_INTENT;    }    @Override    public void onCreate() {        super.onCreate();        Log.e(TAG, "服务创建了");       startServiceTwo();    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e(TAG, "服务销毁了");        startServiceTwo();    }    private void startServiceTwo() {    //myservice2是MyServiceTwo的名字,我们会在manifest中定义,这里必须和manifest中定义的一样        boolean b = ServiceMangerUtils.isServiceWorked(MyServiceOne.this, "myservice2");        if(!b) {            Intent service = new Intent(MyServiceOne.this, MyServiceTwo.class);            startService(service);            Log.e(TAG, "Start ServiceTwo");        }    }}

MyServiceTwo

public class MyServiceTwo extends Service {    public final static String TAG = "myservice2";    public MyServiceTwo() {    }    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG, "onStartCommand");        startServiceOne();        //如果这个Service被系统Kill了或者app被Kill了,Service还能自动重启。        return START_REDELIVER_INTENT;    }    @Override    public void onCreate() {        super.onCreate();        Log.e(TAG, "服务创建了");        startServiceOne();    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e(TAG, "服务销毁了");        startServiceOne();    }    /**     * 检查服务是否存在,不存在唤起     */    private void startServiceOne() {        boolean b = ServiceMangerUtils.isServiceWorked(MyServiceTwo.this, "myservice1");        if (!b) {            Intent service = new Intent(MyServiceTwo.this, MyServiceOne.class);            startService(service);            Log.e(TAG, "start ServiceOne");        }    }}

我们需要在manifest清单文件中注册我们的服务:

 <service            android:name=".service.MyServiceOne"            android:persistent="true"            android:process=":remote">            <!--intent-filter android:priority="1000"           将服务的优先级设置为最高1000           -->            <intent-filter android:priority="1000">                <!--这里定义服务的名字-->                <action android:name="myservice1" />            </intent-filter>        </service>        <service            android:name=".service.MyServiceTwo"            android:persistent="true"            android:process=":remote">            <intent-filter android:priority="1000">                <action android:name="myservice2" />            </intent-filter>        </service>

创建接收系统时间广播和屏幕广播的接收广播,时间广播在屏幕关闭以后可能不会再接收到,所以需要在屏幕解锁时检查服务的状态,保证APP在屏幕解锁时就能启动。

package liuxiaozhu.com.appkeepalive.brodcast;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;import liuxiaozhu.com.appkeepalive.MainActivity;import liuxiaozhu.com.appkeepalive.MyAppliction;import liuxiaozhu.com.appkeepalive.ServiceMangerUtils;import liuxiaozhu.com.appkeepalive.service.MyServiceOne;/** * Created by liuxiaozhu on 2017/5/11. * All Rights Reserved by * 用来监听手机时间广播(在appliytion里开启广播),每一分钟系统会发送一次 * 该广播只需要拉起service1 */public class MyBroadcast extends BroadcastReceiver {    private boolean isServiceRunning = false;    @Override    public void onReceive(Context context, Intent intent) {        if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {//如果广播是每分钟发送一次的时间广播            Log.e("timeBroad", "时间变化了");            isServiceRunning = ServiceMangerUtils.isServiceWorked(MyAppliction.getmContext(), "myservice1");            if (!isServiceRunning) {                Intent i = new Intent(context, MyServiceOne.class);                context.startService(i);            }        }        if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {            Log.e("timeBroad", "屏幕解锁了");            isServiceRunning = ServiceMangerUtils.isServiceWorked(MyAppliction.getmContext(), "myservice1");            if (!isServiceRunning) {                Intent i = new Intent(context, MyServiceOne.class);                context.startService(i);            }        }        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {            Log.e("timeBroad", "屏幕关闭了");            isServiceRunning = ServiceMangerUtils.isServiceWorked(MyAppliction.getmContext(), "myservice1");            if (!isServiceRunning) {                Intent i = new Intent(context, MyServiceOne.class);                context.startService(i);            }        }    }}

自定义MyAppliction继承Appliction,在app启动的时候启动服务,注册广播,时间广播和屏幕广播是系统广播,我们不能在清单里注册只能在代码中注册。

/** * Created by liuxiaozhu on 2017/7/12. * All Rights Reserved by YiZu */public class MyAppliction extends Application {    private static Context mContext;    @Override    public void onCreate() {        super.onCreate();        mContext = getApplicationContext();        //开启系统时间广播(动态注册,不能静态注册)        //部分机型会屏蔽时间广播        IntentFilter intentFilter = new IntentFilter();        intentFilter.addAction(Intent.ACTION_TIME_TICK);//系统时间,每分钟发送一次        intentFilter.addAction(Intent.ACTION_SCREEN_ON);//屏幕打开(解锁),        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);//屏幕关闭        MyBroadcast myBroadcast = new MyBroadcast();        registerReceiver(myBroadcast, intentFilter);        startMyService();    }    public static Context getmContext() {        return mContext;    }    /**     * 开启双服务     */    private void startMyService() {        Intent serviceOne = new Intent();        serviceOne.setClass(this, MyServiceOne.class);        startService(serviceOne);    }}

判断服务是否存货的工具类。

/** * Created by liuxiaozhu on 2017/7/12. * All Rights Reserved by YiZu */public class ServiceMangerUtils {    /**     * 判断服务是否运行     *     * @param context     * @param serviceName     * @return     */    public static boolean isServiceWorked(Context context, String serviceName) {        ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);        //获取当前所有服务        ArrayList<ActivityManager.RunningServiceInfo> runningService =                       (ArrayList<ActivityManager.RunningServiceInfo>) myManager.getRunningServices(Integer.MAX_VALUE);        for (int i = 0; i < runningService.size(); i++) {            if (runningService.get(i).service.getClassName().equals(serviceName)) {                return true;            }        }        return false;    }}

到这里我们的app就可以实现保活了,很好用但是不是太流氓,仅供大家学习,如果没有需要不建议使用。

源码已上传到GitHub,传送门地址