美文网首页Android
Android:Service保活

Android:Service保活

作者: 测天测地测空气 | 来源:发表于2018-08-06 18:39 被阅读0次

    1: 开启一个像素的Activity
    系统一般是不会杀死前台进程的。所以要使得进程常驻,我们只需要在锁屏的时候在本进程开启一个Activity,
    为了欺骗用户,让这个Activity的大小是1像素,并且透明无切换动画,
    在开屏幕的时候,把这个Activity关闭掉,所以这个就需要监听系统锁屏广播.

    //权限
        <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/>
    
    //注册
        <service android:name=".ui.service.MainService"
                android:process="1000"/>
    
        <receiver android:name=".ui.broadcastReceiver.ScreenBroadcastListener$ScreenBroadcastReceiver">
            <intent-filter android:priority="90000">
                <action android:name="android.intent.action.USER_PRESENT"/>
            </intent-filter>
        </receiver>
    
        
        
        
        
    //1px Activity  
        public class SinglePixelActivity extends Activity {
    
            public static final String TAG = SinglePixelActivity.class.getSimpleName();
    
            
            
            public static void actionToSinglePixelActivity(Context context) {
                Intent intent = new Intent(context, SinglePixelActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                Log.d(TAG, "onCreate");
                setContentView(R.layout.activity_singlepixel);
                Window window = getWindow();
                //放在左上角
                window.setGravity(Gravity.START | Gravity.TOP);
                WindowManager.LayoutParams attributes = window.getAttributes();
                //宽高设计为1个像素
                attributes.width = 1;
                attributes.height = 1;
                //起始坐标
                attributes.x = 0;
                attributes.y = 0;
                window.setAttributes(attributes);
    
                ScreenManager.getInstance(this).setActivity(this);
            }
    
            @Override
            protected void onDestroy() {
                super.onDestroy();
            }
        }
    
    
        在屏幕关闭的时候把SinglePixelActivity启动起来,
        在开屏的时候把SinglePixelActivity 关闭掉,
        所以要监听系统锁屏广播,以接口的形式通知MainActivity启动或者关闭SinglePixActivity。
        public class ScreenBroadcastListener {
    
            private Context mContext;
    
            private ScreenBroadcastReceiver mScreenReceiver;
    
            private ScreenStateListener mListener;
    
            public ScreenBroadcastListener(Context context) {
                mContext = context.getApplicationContext();
                mScreenReceiver = new ScreenBroadcastReceiver();
            }
    
            interface ScreenStateListener {
    
                void onScreenOn();
    
                void onScreenOff();
            }
    
            /**
             * screen状态广播接收者
             */
            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)) { // 开屏
                        mListener.onScreenOn();
                    } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏
                        mListener.onScreenOff();
                    }
                }
            }
    
            public void registerListener(ScreenStateListener listener) {
                mListener = listener;
                registerListener();
            }
    
            private void registerListener() {
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_SCREEN_ON);
                filter.addAction(Intent.ACTION_SCREEN_OFF);
                mContext.registerReceiver(mScreenReceiver, filter);
            }
        }
    
    
        //1px Activity管理类
        public class ScreenManager {
    
            private Context mContext;
    
            private WeakReference<Activity> mActivityWref;
    
            public static ScreenManager gDefualt;
    
            public static ScreenManager getInstance(Context context) {
                if (gDefualt == null) {
                    gDefualt = new ScreenManager(context.getApplicationContext());
                }
                return gDefualt;
            }
            private ScreenManager(Context context) {
                this.mContext = context;
            }
    
            public void setActivity(Activity pActivity) {
                mActivityWref = new WeakReference<Activity>(pActivity);
            }
    
            public void startActivity() {
                SinglePixelActivity.actionToSinglePixelActivity(mContext);
            }
    
            public void finishActivity() {
                //结束掉SinglePixelActivity
                if (mActivityWref != null) {
                    Activity activity = mActivityWref.get();
                    if (activity != null) {
                        activity.finish();
                    }
                }
            }
        }
        
        现在MainActivity改成如下
        public class MainActivity extends AppCompatActivity {
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                final ScreenManager screenManager = ScreenManager.getInstance(MainActivity.this);
                ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
                 listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
                    @Override
                    public void onScreenOn() {
                        screenManager.finishActivity();
                    }
    
                    @Override
                    public void onScreenOff() {
                        screenManager.startActivity();
                    }
                });
            }
        }
    
        初步的思路是先判断app进程是否存在,如果存在的话,
        就利用startActivities启动MainActivity和DetailActivity。
        为什么还要启动MainActivity而不直接只启动DetailActivity?
        因为有如下情况,进程中的所有Activity都已经退出了,但进程还没有被系统回收,
        这时判断进程是否存在返回true,然后只启动DetailActivity的话,按Back键任务栈就直接到底,返回桌面了。
        而我们要的效果是按Back键返回上一级Activity,也就是MainActivity。
    
        如果app进程已经退出,不存在了,此时就用一个Intent启动应用,
        该Intent中包含一个Bundle, Bundle中存有启动DetailActivity所需的参数,
        这个Intent传入SplashActivity后,再由SplashActivity传给MainActivity,在MainActivity中加入判断,
        如果有该参数,则表示应用是从通知栏启动的,要进行跳转到DetailActivity的操作,否则就是常规启动。
        
        (缺点: 如果没root 在部分机器上会造成广播监听不到)
    

    2
    系统自带的,onStartCommand方法必须具有一个整形的返回值,
    这个整形的返回值用来告诉系统在服务启动完毕后,
    如果被Kill,系统将如何操作,这种方案虽然可以,
    但是在某些情况or某些定制ROM上可能失效,
    认为可以多做一种保保守方案。

    START_STICKY
    如果系统在onStartCommand返回后被销毁,系统将会重新创建服务并依次调用onCreate和onStartCommand(
    注意:根据测试Android2.3.3以下版本只会调用onCreate根本不会调用onStartCommand,
            Android4.0可以办到),这种相当于服务又重新启动恢复到之前的状态了)。
    

    3
    JobSheduler
    JobSheduler是作为进程死后复活的一种手段,
    native进程方式最大缺点是费电,
    Native 进程费电的原因是感知主进程是否存活有两种实现方式,在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,当主进程不存活时进行拉活。
    其次5.0以上系统不支持。
    但是JobSheduler可以替代在Android5.0以上native进程方式,这种方式即使用户强制关闭,也能被拉起来,亲测可行。

    4 进程相互唤醒
      顾名思义,就是指的不同进程,
    不同app之间互相唤醒,如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,
    那么你打开任意一个阿里系的app后,有可能就顺便把其他阿里系的app给唤醒了。

    注:服务保活的前提是:要尽可能减少内存和电量的消耗。
    
    Android 7.0版本以上,目前没有什么真正意义上的保活。
    

    相关文章

      网友评论

        本文标题:Android:Service保活

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