一、常见保活方案

  • 1、监听广播:监听全局的静态广播,比如时间更新的广播、开机广播、解锁屏、网络状态、解锁加锁亮屏暗屏(3.1版本),高版本需要应用开机后运行一次才能监听这些系统广播,目前此方案失效。可以更换思路,做APP启动后的保活(监听广播启动保活的前台服务)

  • 2、定时器、JobScheduler:假如应用被系统杀死,那么定时器则失效,此方案失效。JobService在5.0,5.1,6.0作用很大,7.0时候有一定影响(可以在电源管理中给APP授权)

  • 3、双进程(NDK方式Fork子进程)、双Service守护:高版本已失效,5.0起系统回收策略改成进程组。双Service方案也改成了应用被杀,任何后台Service无法正常状态运行

  • 4、提高Service优先级:只能一定程度上缓解Service被立马回收


二、保活

  • 1、AIDL方式单进程、双进程方式保活Service
  • 2、降低oom_adj的值:常驻通知栏(可通过启动另外一个服务关闭Notification,不对oom_adj值有影响)、使用”1像素“的Activity覆盖在getWindow()的view上、循环播放无声音频(黑科技,7.0下杀不掉)
  • 3、监听锁屏广播:使Activity始终保持前台
  • 4、使用自定义锁屏界面:覆盖了系统锁屏界面。
  • 5、通过android:process属性来为Service创建一个进程
  • 6、跳转到系统白名单界面让用户自己添加app进入白名单

三、复活

  • 1、JobScheduler:原理类似定时器,5.0,5.1,6.0作用很大,7.0时候有一定影响(可以在电源管理中给APP授权)
  • 2、推送互相唤醒复活:极光、友盟、以及各大厂商的推送
  • 3、同派系APP广播互相唤醒:比如今日头条系、阿里系

方案实现效果统计

1、双进程守护方案(基于onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:原生任务栏滑动清理app,Service会被杀掉,然后被拉起,接着一直存活
  • 2、金立F100(5.1):一键清理直接杀掉整个app,包括双守护进程。不手动清理情况下,经测试能锁屏存活至少40分钟
  • 3、华为畅享5x(6.0):一键清理直接杀掉整个app,包括双守护进程。不手动清理下,锁屏只存活10s。结论:双进程守护方案失效。
  • 4、美图m8s(7.1.1):一键清理直接杀掉整个app,包括双守护进程。不清理情况下,锁屏会有被杀过程(9分钟左右被杀),之后重新复活,之后不断被干掉然后又重新复活。结论:双守护进程可在后台不断拉起Service。
  • 5、原生7.0:任务栏清除APP后,Service存活。使用此方案后Service照样存活。
  • 6、LG V30+(7.1.2):不加双进程守护的时候,一键清理无法杀掉服务。加了此方案之后也不能杀掉服务,锁屏存活(测试观察大于50分钟)
  • 7、小米8(8.1):一键清理直接干掉app并且包括双守护进程。不清理情况下,不加守护进程方案与加守护进程方案Service会一直存活,12分钟左右closed。结论:此方案没有起作用

结论:除了华为此方案无效以及未更改底层的厂商不起作用外(START_STICKY字段就可以保持Service不被杀)。此方案可以与其他方案混合使用

2、监听锁屏广播打开1像素Activity(基于onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:锁屏后3s服务被干掉然后重启(START_STICKY字段起作用)
  • 2、华为畅享5x(6.0):锁屏只存活4s。结论:方案失效。
  • 3、美图m8s(7.1.1):同原生5.0
  • 4、原生7.0:同美图m8s。
  • 5、LG V30+(7.1.2):锁屏后情况跟不加情况一致,服务一致保持运行,结论:此方案不起作用
  • 6、小米8(8.1):关屏过2s之后app全部被干掉。结论:此方案没有起作用

结论此方案无效果

3、故意在后台播放无声的音乐(基于onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:锁屏后3s服务被干掉然后重启(START_STICKY字段起作用)
  • 2、华为畅享5x(6.0):一键清理后服务依然存活,需要单独清理才可杀掉服务,锁屏8分钟后依然存活。结论:此方案适用
  • 3、美图m8s(7.1.1):同5.0
  • 4、原生7.0:任务管理器中关闭APP后服务被干掉,大概过3s会重新复活(同仅START_STICKY字段模式)。结论:看不出此方案有没有其作用
  • 5、LG V30+(7.1.2):使用此方案前后效果一致。结论:此方案不起作用
  • 6、小米8(8.1):一键清理可以杀掉服务。锁屏后保活超过20分钟

结论:成功对华为手机保活。小米8下也成功突破20分钟

4、使用JobScheduler唤醒Service(基于onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:任务管理器中干掉APP,服务会在周期时间后重新启动。结论:此方案起作用
  • 2、华为畅享5x(6.0):一键清理直接杀掉APP,过12s左右会自动重启服务,JobScheduler起作用
  • 3、美图m8s(7.1.1):一键清理直接杀掉APP,无法自动重启
  • 4、原生7.0:同美图m8s(7.1.1)
  • 5、小米8(8.1):同美图m8s(7.1.1)

结论:只对5.0,5.1、6.0起作用

5、混合使用的效果,并且在通知栏弹出通知

  • 1、原生5.0、5.1:任务管理器中干掉APP,服务会在周期时间后重新启动。锁屏超过11分钟存活
  • 2、华为畅享5x(6.0):一键清理后服务依然存活,需要单独清理才可杀掉服务。结论:方案适用。
  • 3、美图m8s(7.1.1):一键清理APP会被杀掉。正常情况下锁屏后服务依然存活。
  • 4、原生7.0:任务管理器中关闭APP后服务被干掉,过2s会重新复活
  • 5、小米8(8.1):一键清理可以杀掉服务,锁屏下后台保活时间超过38分钟
  • 6、荣耀10(8.0):一键清理杀掉服务,锁屏下后台保活时间超过23分钟

结论:高版本情况下可以使用弹出通知栏、双进程、无声音乐提高后台服务的保活概率


实现具体过程

一、双进程实现方案
使用AIDL绑定方式新建2个Service优先级(防止服务同时被系统杀死)不一样的守护进程互相拉起对方,并在每一个守护进程的```ServiceConnection```的绑定回调里判断保活Service是否需要重新拉起和对守护线程进行重新绑定。
  • 1、新建一个AIDL文件KeepAliveConnection
interface KeepAliveConnection  {
}
  • 2、新建一个服务类StepServiceonBind()方法返回new KeepAliveConnection.Stub()对象,并在ServiceConnection的绑定回调中对守护进程服务类GuardService的启动和绑定。
/*** 主进程 双进程通讯** @author LiGuangMin* @time Created by 2018/8/17 11:26*/
public class StepService extends Service {private final static String TAG = StepService.class.getSimpleName();private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {Logger.d(TAG, "StepService:建立链接");boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();if (!isServiceRunning) {Intent i = new Intent(StepService.this, DownloadService.class);startService(i);}}@Overridepublic void onServiceDisconnected(ComponentName componentName) {// 断开链接startService(new Intent(StepService.this, GuardService.class));// 重新绑定bindService(new Intent(StepService.this, GuardService.class), mServiceConnection, Context.BIND_IMPORTANT);}};@Nullable@Overridepublic IBinder onBind(Intent intent) {return new KeepAliveConnection.Stub() {};}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {startForeground(1, new Notification());// 绑定建立链接bindService(new Intent(this, GuardService.class), mServiceConnection, Context.BIND_IMPORTANT);return START_STICKY;}}
  • 3、对守护进程GuardService进行和2一样的处理
/*** 守护进程 双进程通讯** @author LiGuangMin* @time Created by 2018/8/17 11:27*/
public class GuardService extends Service {private final static String TAG = GuardService.class.getSimpleName();private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {Logger.d(TAG, "GuardService:建立链接");boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();if (!isServiceRunning) {Intent i = new Intent(GuardService.this, DownloadService.class);startService(i);}}@Overridepublic void onServiceDisconnected(ComponentName componentName) {// 断开链接startService(new Intent(GuardService.this, StepService.class));// 重新绑定bindService(new Intent(GuardService.this, StepService.class), mServiceConnection, Context.BIND_IMPORTANT);}};@Nullable@Overridepublic IBinder onBind(Intent intent) {return new KeepAliveConnection.Stub() {};}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {startForeground(1, new Notification());// 绑定建立链接bindService(new Intent(this, StepService.class), mServiceConnection, Context.BIND_IMPORTANT);return START_STICKY;}}
  • 4、在Activity中在启动需要保活的DownloadService服务后然后启动保活的双进程
public class MainActivity extends AppCompatActivity {private TextView mShowTimeTv;private DownloadService.DownloadBinder mDownloadBinder;private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mDownloadBinder = (DownloadService.DownloadBinder) service;mDownloadBinder.setOnTimeChangeListener(new DownloadService.OnTimeChangeListener() {@Overridepublic void showTime(final String time) {runOnUiThread(new Runnable() {@Overridepublic void run() {mShowTimeTv.setText(time);}});}});}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, DownloadService.class);startService(intent);bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);//双守护线程,优先级不一样startAllServices();}@Overridepublic void onContentChanged() {super.onContentChanged();mShowTimeTv = findViewById(R.id.tv_show_time);}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(mServiceConnection);}/*** 开启所有守护Service*/private void startAllServices() {startService(new Intent(this, StepService.class));startService(new Intent(this, GuardService.class));}
}

二、监听到锁屏广播后使用“1”像素Activity提升优先级
  • 1、该Activity的View只要设置为1像素然后设置在Window对象上即可。在Activity的onDestroy周期中进行保活服务的存活判断从而唤醒服务。"1像素"Activity如下
public class SinglePixelActivity extends AppCompatActivity {private static final String TAG = SinglePixelActivity.class.getSimpleName();@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);Window mWindow = getWindow();mWindow.setGravity(Gravity.LEFT | Gravity.TOP);WindowManager.LayoutParams attrParams = mWindow.getAttributes();attrParams.x = 0;attrParams.y = 0;attrParams.height = 1;attrParams.width = 1;mWindow.setAttributes(attrParams);ScreenManager.getInstance(this).setSingleActivity(this);}@Overrideprotected void onDestroy() {if (!SystemUtils.isAppAlive(this, Constant.PACKAGE_NAME)) {Intent intentAlive = new Intent(this, DownloadService.class);startService(intentAlive);}super.onDestroy();}
}
  • 2、对广播进行监听,封装为一个ScreenReceiverUtil类,进行锁屏解锁的广播动态注册监听
public class ScreenReceiverUtil {private Context mContext;private SreenBroadcastReceiver mScreenReceiver;private SreenStateListener mStateReceiverListener;public ScreenReceiverUtil(Context mContext) {this.mContext = mContext;}public void setScreenReceiverListener(SreenStateListener mStateReceiverListener) {this.mStateReceiverListener = mStateReceiverListener;// 动态启动广播接收器this.mScreenReceiver = new SreenBroadcastReceiver();IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_SCREEN_ON);filter.addAction(Intent.ACTION_SCREEN_OFF);filter.addAction(Intent.ACTION_USER_PRESENT);mContext.registerReceiver(mScreenReceiver, filter);}public void stopScreenReceiverListener() {mContext.unregisterReceiver(mScreenReceiver);}/*** 监听sreen状态对外回调接口*/public interface SreenStateListener {void onSreenOn();void onSreenOff();void onUserPresent();}public class SreenBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (mStateReceiverListener == null) {return;}if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏mStateReceiverListener.onSreenOn();} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏mStateReceiverListener.onSreenOff();} else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁mStateReceiverListener.onUserPresent();}}}
}
  • 3、对1像素Activity进行防止内存泄露的处理,新建一个ScreenManager
public class ScreenManager {private static final String TAG = ScreenManager.class.getSimpleName();private static ScreenManager sInstance;private Context mContext;private WeakReference<Activity> mActivity;private ScreenManager(Context mContext) {this.mContext = mContext;}public static ScreenManager getInstance(Context context) {if (sInstance == null) {sInstance = new ScreenManager(context);}return sInstance;}/** 获得SinglePixelActivity的引用* @param activity*/public void setSingleActivity(Activity activity) {mActivity = new WeakReference<>(activity);}/*** 启动SinglePixelActivity*/public void startActivity() {Intent intent = new Intent(mContext, SinglePixelActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivity(intent);}/*** 结束SinglePixelActivity*/public void finishActivity() {if (mActivity != null) {Activity activity = mActivity.get();if (activity != null) {activity.finish();}}}
}
  • 4、对1像素的Style进行特殊处理,在style文件中新建一个SingleActivityStyle
<style name="SingleActivityStyle" parent="android:Theme.Holo.Light.NoActionBar"><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowFrame">@null</item><item name="android:windowNoTitle">true</item><item name="android:windowIsFloating">true</item><item name="android:windowContentOverlay">@null</item><item name="android:backgroundDimEnabled">false</item><item name="android:windowAnimationStyle">@null</item><item name="android:windowDisablePreview">true</item><item name="android:windowNoDisplay">false</item>
  • 5、让SinglePixelActivity使用singleInstance启动模式,在manifest文件中
 <activityandroid:name=".activity.SinglePixelActivity"android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"android:excludeFromRecents="true"android:finishOnTaskLaunch="false"android:launchMode="singleInstance"android:theme="@style/SingleActivityStyle" />
  • 6、在保活服务类DownloadService中对监听的广播进行注册和对SinglePixelActivity进行控制。
public class DownloadService extends Service {public static final int NOTICE_ID = 100;private static final String TAG = DownloadService.class.getSimpleName();private DownloadBinder mDownloadBinder;private NotificationCompat.Builder mBuilderProgress;private NotificationManager mNotificationManager;private ScreenReceiverUtil mScreenListener;private ScreenManager mScreenManager;private Timer mRunTimer;private int mTimeSec;private int mTimeMin;private int mTimeHour;private ScreenReceiverUtil.SreenStateListener mScreenListenerer = new ScreenReceiverUtil.SreenStateListener() {@Overridepublic void onSreenOn() {mScreenManager.finishActivity();Logger.d(TAG, "关闭了1像素Activity");}@Overridepublic void onSreenOff() {mScreenManager.startActivity();Logger.d(TAG, "打开了1像素Activity");}@Overridepublic void onUserPresent() {}};private OnTimeChangeListener mOnTimeChangeListener;@Overridepublic void onCreate() {super.onCreate();//        注册锁屏广播监听器mScreenListener = new ScreenReceiverUtil(this);mScreenManager = ScreenManager.getInstance(this);mScreenListener.setScreenReceiverListener(mScreenListenerer);mDownloadBinder = new DownloadBinder();mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Logger.d(TAG, "onStartCommand");startRunTimer();return START_STICKY;}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mDownloadBinder;}@Overridepublic boolean onUnbind(Intent intent) {Logger.d(TAG, "onUnbind");return super.onUnbind(intent);}@Overridepublic void onDestroy() {super.onDestroy();NotificationManager mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);if (mManager == null) {return;}mManager.cancel(NOTICE_ID);stopRunTimer();
//        mScreenListener.stopScreenReceiverListener();}private void startRunTimer() {TimerTask mTask = new TimerTask() {@Overridepublic void run() {mTimeSec++;if (mTimeSec == 60) {mTimeSec = 0;mTimeMin++;}if (mTimeMin == 60) {mTimeMin = 0;mTimeHour++;}if (mTimeHour == 24) {mTimeSec = 0;mTimeMin = 0;mTimeHour = 0;}String time = "时间为:" + mTimeHour + " : " + mTimeMin + " : " + mTimeSec;if (mOnTimeChangeListener != null) {mOnTimeChangeListener.showTime(time);}Logger.d(TAG, time);}};mRunTimer = new Timer();// 每隔1s更新一下时间mRunTimer.schedule(mTask, 1000, 1000);}private void stopRunTimer() {if (mRunTimer != null) {mRunTimer.cancel();mRunTimer = null;}mTimeSec = 0;mTimeMin = 0;mTimeHour = 0;Logger.d(TAG, "时间为:" + mTimeHour + " : " + mTimeMin + " : " + mTimeSec);}public interface OnTimeChangeListener {void showTime(String time);}public class DownloadBinder extends Binder {public void setOnTimeChangeListener(OnTimeChangeListener onTimeChangeListener) {mOnTimeChangeListener = onTimeChangeListener;}}
}---
3、在后台播放音乐
  • 1、准备一段无声的音频,新建一个播放音乐的Service类,将播放模式改为无限循环播放。在其onDestroy方法中对自己重新启动。
public class PlayerMusicService extends Service {private final static String TAG = PlayerMusicService.class.getSimpleName();private MediaPlayer mMediaPlayer;@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();Logger.d(TAG, TAG + "---->onCreate,启动服务");mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.silent);mMediaPlayer.setLooping(true);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {startPlayMusic();}}).start();return START_STICKY;}private void startPlayMusic() {if (mMediaPlayer != null) {Logger.d(TAG, "启动后台播放音乐");mMediaPlayer.start();}}private void stopPlayMusic() {if (mMediaPlayer != null) {Logger.d(TAG, "关闭后台播放音乐");mMediaPlayer.stop();}}@Overridepublic void onDestroy() {super.onDestroy();stopPlayMusic();Logger.d(TAG, TAG + "---->onCreate,停止服务");// 重启自己Intent intent = new Intent(getApplicationContext(), PlayerMusicService.class);startService(intent);}
}
  • 2、 在保活的DownloadServie服务类的onCreate方法中对PlayerMusicService进行启动
 Intent intent = new Intent(this, PlayerMusicService.class);startService(intent);
  • 3、在Manifest文件中进行注册
  <serviceandroid:name=".service.PlayerMusicService"android:enabled="true"android:exported="true"android:process=":music_service" />

4、使用JobScheduler唤醒Service
  • 1、新建一个继承自JobService的ScheduleService类,在其onStartJob回调中对DownloadService进行存活的判断来重启。
public class ScheduleService extends JobService {private static final String TAG = ScheduleService.class.getSimpleName();@Overridepublic boolean onStartJob(JobParameters params) {boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();if (!isServiceRunning) {Intent i = new Intent(this, DownloadService.class);startService(i);Logger.d(TAG, "ScheduleService启动了DownloadService");}jobFinished(params, false);return false;}@Overridepublic boolean onStopJob(JobParameters params) {return false;}
}

2、 在DownloadService服务类中进行JobScheduler的注册和使用

 /*** 使用JobScheduler进行保活*/private void useJobServiceForKeepAlive() {JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);if (jobScheduler == null) {return;}jobScheduler.cancelAll();JobInfo.Builder builder =new JobInfo.Builder(1024, new ComponentName(getPackageName(), ScheduleService.class.getName()));//周期设置为了2sbuilder.setPeriodic(1000 * 2);builder.setPersisted(true);builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);int schedule = jobScheduler.schedule(builder.build());if (schedule <= 0) {Logger.w(TAG, "schedule error!");}}
  • 3、在manifest文件中进行权限设置
 <serviceandroid:name=".service.ScheduleService"android:enabled="true"android:exported="true"android:permission="android.permission.BIND_JOB_SERVICE" />

关于推送类拉活

根据华为官方文档集成HUAWEI Push

  • 1、华为畅玩5X(6.0):APP全部进程被杀死时可以被拉起。
  • 2、华为nove 3e(8.0):APP全部进程被杀死时无法被拉起,能收到推送。
  • 3、华为荣耀10(8.1):同2

结论:理论情况下,华为推送应该可以拉起华为机器才对,感觉是我没花钱的原因

补充:ServiceAliveUtils 类如下
public class ServiceAliveUtils {public static boolean isServiceAlice() {boolean isServiceRunning = false;ActivityManager manager =(ActivityManager) MyApplication.getMyApplication().getSystemService(Context.ACTIVITY_SERVICE);if (manager == null) {return true;}for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {if ("demo.lgm.com.keepalivedemo.service.DownloadService".equals(service.service.getClassName())) {isServiceRunning = true;}}return isServiceRunning;}
}

2018年Android的保活方案效果统计相关推荐

  1. Android的保活方案效果统计

    点击上方的终端研发部,右上角选择"设为星标" 每日早9点半,技术文章准时送上 公众号后台回复"学习",获取作者独家秘制精品资料 往期文章 一波Flutter酷炫 ...

  2. 全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

    全面盘点当前Android后台保活方案的真实运行效果(截止2019年前) 本文原作者"minminaya",作者网站:minminaya.cn,为了提升文章品质,即时通讯网对内容作 ...

  3. 2018年最新Android的保活方案及效果统计

    热文导读 | 点击标题阅读 金九银十跳槽季如何进阶找到合适满意的工作? 要么干,要么辞职,千万别混 重磅:Android 技能图谱学习路线 作者:minminaya https://www.jians ...

  4. Android 进程保活方案

    前言 Android 系统为了保持系统运行流畅,在内存吃紧的情况下,会将一些进程给杀掉,以释放一部分内存.然而,对于一些(如:QQ.微信等)比较重要的.我们希望能及时收到消息的App,需要保持进程持续 ...

  5. Android进程保活方案

    自己曾经也在这个问题上伤过脑经,前几日刚好有一个北京的哥们在QQ说在做IM类的项目,问我进程保活如何处理比较恰当,决定去总结一下,网上搜索一下进程常驻的方案好多好多,但是很多的方案都是不靠谱的或者不是 ...

  6. Android进程保活方案的几种方案

    自己曾经也在这个问题上伤过脑经,前几日刚好有一个北京的哥们在QQ说在做IM类的项目,问我进程保活如何处理比较恰当,决定去总结一下,网上搜索一下进程常驻的方案好多好多,但是很多的方案都是不靠谱的或者不是 ...

  7. 盘点im即时通讯开发中Android后台保活方案

    对于IM应用和消息推送服务的开发者来说,在Android机型上的后台保活是个相当头疼的问题. 老板一句:"为什么微信.QQ能收到消息,而你写的APP却不行?",直接让人崩溃,话说老 ...

  8. Android进程保活--我也想乖,傻C产品就要这样

    方案 推送,保活. Netty长链接很成熟. 双service保活.(7.0已失效,阿里大神) 标题 重点内容 探讨Android6.0及以上系统APP常驻内存(保活)实现-复活篇 探讨Android ...

  9. Android进程保活(常驻内存)

    Android将进程分为6个等级,它们按优先级顺序由高到低依次是:  1.前台进程( FOREGROUND_APP):  2.可视进程(VISIBLE_APP ):  3. 次要服务进程(SECOND ...

最新文章

  1. C++编程进阶5(内联函数、如何降低编译成本、处理继承体系中同名不同参的成员函数、私有虚函数)
  2. 使用qmeu-img创建虚拟机[创建虚拟机,虚拟机快照]
  3. 最简单的贝叶斯分类器MATLAB实现
  4. 佳能g3800故障灯说明书_热水器维修电话|史密斯燃气热水器出现16故障码
  5. C#深入解析数据类型
  6. python存文件代码_Python文件读写保存操作的示例代码
  7. Vue的条件渲染和对象渲染
  8. c语言编写在线考试系统,c语言作业在线考试系统实现
  9. android后台获取当前屏幕截图(screencap.cpp修改)
  10. js实现轮播图背景色随之渐变的效果(小程序版)
  11. c语言求解一元二次方程的两相等实根,C语言 求解一元二次方程
  12. DTD(文档类型定义)介绍
  13. 在线的MySQL数据库表结构对比工具
  14. 02335网络操作系统
  15. python怎么去掉换行符_在Python中,如何去除行末的换行符?
  16. 开机一直黑屏后,扣电池,No bootable device or remote image found
  17. 华为OJ——参数解析
  18. 1.hybird、VLAN基本概念
  19. Swoft 定时任务
  20. 四极定子外充、测试夹具的设计

热门文章

  1. 用python画小猪票佩琪
  2. 基于Vue实现表格拖拽排序——sortablejs
  3. vue3去除字符串前后空格
  4. 2019 第十届蓝桥杯 Java B组 赛后总结
  5. 计算机网络——p2p
  6. 用IP代理保护隐私 结局也许难如你愿
  7. 苹果悬浮球_iPhone:手机的悬浮球功能这么强大,你却不会用?太浪费了
  8. 【递归实现】c语言 十进制转二进制(固定八位显示)
  9. ARMv8内存属性与类型(Memory types and attributes)简介
  10. qt android播放器代码,Qt on android 播放视频的实现