一像素Activity保护后台进程熄屏状态下不被杀死
Android进程保活分为如下两种情况:
1. 提供进程优先级,降低进程被杀死的概率
2. 在进程被杀死后,进行拉活
进程的优先级分为5级:
论Service为什么会被杀死
Service被强一般通常是三个方面,第一种现象是当手机内存不足,你的应用或者Service在后台这个时候你精力或者营养更不上可能就被强了;第二种现象是用了第三方的一些管理软件比如流氓360,腾讯管家去清理进程他们也会对你下手;第三种现象就是各大Rom厂商,在你退出应用的时候会做一些清理工作。
2.1 进程的优先级:
google的官网给进程划分了等级,并且明确告诉你哥们我不会乱来,回收进程的时候有自己套路。担心有些哥们不想翻墙这里我就Copy一下。
Android 系统将尽量长时间地保持应用进程,但为了新建进程或运行更重要的进程,最终需要移除旧进程来回收内存。 为了确定保留或终止哪些进程,系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。 必要时,系统会首先消除重要性最低的进程,然后是重要性略逊的进程,依此类推,以回收系统资源。
重要性层次结构一共有 5 级。以下列表按照重要程度列出了各类进程(第一个进程最重要,将是最后一个被终止的进程):
1.前台进程
用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:
- 托管用户正在交互的Activity已调用Activity的onResume()方法
- 托管某个Service,后者绑定到用户正在交互的 Activity
- 托管正在“前台”运行的Service服务已调用startForeground()
- 托管正执行一个生命周期回调的Service (onCreate() 、onStart()或onDestroy())
- 托管正执行其onReceive()方法的BroadcastReceiver
通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。
2.可见进程
- 没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
- 托管不在前台、但仍对用户可见的Activity已调用其onPause()方法。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
- 托管绑定到可见(或前台)Activity 的Service。
- 可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
3.服务进程
正在运行已使用startService()方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
4.后台进程
包含目前对用户不可见的 Activity 的进程已调用 Activity 的onStop()方法。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。 有关保存和恢复状态的信息,请参阅Activity文档。
5.空进程
不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最高级别。例如,如果某进程托管着服务和可见 Activity,则会将此进程评定为可见进程,而不是服务进程。
此外,一个进程的级别可能会因其他进程对它的依赖而有所提高,即服务于另一进程的进程其级别永远不会低于其所服务的进程。 例如,如果进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者如果进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为至少与进程 B 同样重要。
监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。
注意该 Activity 需设计成用户无感知。通过该方案,可以使进程的优先级在屏幕锁屏时间由4提升为最高优先级1。
本方案主要解决第三方应用及系统管理工具在检测到锁屏事件后一段时间(一般为5分钟以内)内会杀死后台进程,以达到省电的目的问题。
一:创建一个一像素的继承fragmentActivity的活动
public class OnePixelActivity extends FragmentActivity {
//注册广播接受者 当屏幕开启结果成功结束一像素的activity
BroadcastReceiver br;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设定一像素的activity
Window window = getWindow();
window.setGravity(Gravity.LEFT | Gravity.TOP);
WindowManager.LayoutParams params = window.getAttributes();
params.x = 0;
params.y = 0;
params.height = 1;
params.width = 1;
window.setAttributes(params);
//在一像素activity里注册广播接受者 接受到广播结束掉一像素
br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "--------OnePixelActivity finish");
finish();
}
};
registerReceiver(br, new IntentFilter("finish activity"));
checkScreenOn("onCreate");
}
@Override
protected void onDestroy() {
Log.d("TAG", "--------OnePixelActivity onDestroy");
unregisterReceiver(br);
super.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
checkScreenOn("onResume");
}
/**
* 检查锁屏/解屏的方法
* isScreenOn为true 则表示屏幕"亮"了,否则屏幕"暗"了,亮着就结束1像素
*/
private void checkScreenOn(String methodName) {
Log.d("TAG", "-------from call method: " + methodName);
PowerManager pm = (PowerManager) OnePixelActivity.this.getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
Log.d("TAG", "-------isScreenOn: " + isScreenOn);
if (isScreenOn) {
finish();
}
}
}
二:创建广播接受者
public class OnepxReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { //屏幕关闭的时候接受到广播
Intent it = new Intent(context, OnePixelActivity.class);
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(it);
Log.d("TAG", "-------screen off");
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { //屏幕打开的时候发送广播 结束一像素
context.sendBroadcast(new Intent("finish activity"));
Log.d("TAG", "------screen on");
Intent home=new Intent(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTION_CLEAR_TOP);
home.addCateGory(Intent.CATEGORY_HOME);
context.startActivity(home);
}
}
}
三:在main里注册接受锁屏 解锁的的广播接受者
public class MainActivity extends AppCompatActivity {
private OnepxReceiver mOnepxReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 注册广播接受者 接受屏幕的
*/
//注册一像素的receiver
mOnepxReceiver=new OnepxReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.USER_PRESENT");
registerReceiver(mOnepxReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mOnepxReceiver);
}
}
四:清单文件一像素activity设置:
<resources>
<!-- 套路一 开启一个像素的Activity 4/4:清单文件一像素activity设置为透明无actionBar -->
<!-- 也可以是@null
<item name="android:windowBackground">@null</item>
-->
<style name="OnePixelActivity" 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:windowIsTranslucent">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>
</style>
</resources>
<!--从 AndroidManifest 中通过如下属性,排除 Activity 在 RecentTask 中的显示:-->
<activity
android:name=".onepix.OnePixelActivity"
android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
android:excludeFromRecents="true"
android:exported="false"
android:finishOnTaskLaunch="false"
android:launchMode="singleInstance"
android:process=":live"
android:theme="@style/OnePixelActivity" />
<service android:name=".servicekeeplivce.KeepLiveService" />
<receiver android:name=".onepix.OnepxReceiver" />