Android 6.0 低电耗模式 和 待机(休眠)模式

    因为公司项目在做VOIP网络电话功能, 所以就涉及到后台常驻服务: 驻留一个服务, 等待有网络电话打进来. 探索了多种后台常驻技术手段...

在使用了现阶段能用的后台常驻服务手段后(用户感知比较强烈那种), 最后遇到了另一个难题: Android 6.0 后新增的 低电耗模式 和 待机休眠模式

查阅文档, 这两个模式会导致, 后台常驻服务在息屏状态下无法接受网络请求!

低电耗模式

低电耗模式通过在设备长时间处于闲置状态时推迟应用的后台 CPU 和网络 Activity 来减少电池消耗. 应用待机模式可推迟用户近期未与之交互的应用的后台网络 Activity.

设备未插接电源、处于静止状态一段时间且屏幕关闭, 设备会进入低电耗模式. 在低电耗模式下, 系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量. 这还可以阻止应用访问网络并推迟其作业、同步和标准闹铃.

系统会定期退出低电耗模式一会儿, 好让应用完成其已推迟的 Activity. 在此维护时段内, 系统会运行所有待定同步、作业和闹铃并允许应用访问网络.

在每个维护时段结束后, 系统会再次进入低电耗模式, 暂停网络访问并推迟作业、同步和闹铃. 随着时间的推移, 系统安排维护时段的次数越来越少, 这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低电池消耗.

一旦用户通过移动设备、打开屏幕或连接到充电器唤醒设备, 系统就会立即退出低电耗模式, 并且所有应用都将返回到正常 Activity.

在低电耗模式下, 应用会受到以下限制:

  • 暂停访问网络.
  • 忽略 wake locks.
  • 标准 AlarmManager 闹铃(包括 setExact() 和 setWindow())推迟到下一维护时段.
    • 如果需要在低电耗模式下设置闹铃, 请使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle().
    • 一般情况下, 使用 setAlarmClock() 设置的闹铃将继续触发, —但系统会在这些闹铃触发之前不久退出低电耗模式.
  • 不执行 Wi-Fi 扫描.
  • 不允许运行同步适配器.
  • 不允许运行 JobScheduler.
PS:

即使这两种方法, 每个App每15分钟唤醒次数也不能超过一次. 休眠模式, 会影响后台服务, 比如 推送, google 建议是用 GCM( Google Cloud Messaging)解决, 但这个只适合国外的. 而国内, 解决办法是目前使用华为推送和小米推送等手机厂家自身提供的推送SDK, 但是这个工作量很大(无论是APP端还是服务端). 要么就期望"统一推送联盟"尽早推出统一推送SDK吧.

应用待机模式

用户有一段时间未触摸应用时, 系统便会作出此判定: 应用处于待机模式

以下情况例外:

  • 用户显式启动应用
  • 应用当前有一个进程位于前台(表现为 Activity 或前台服务形式, 或被另一 Activity 或前台服务占用)
  • 应用生成用户可在锁屏或通知托盘中看到的通知
    设备插入电源时, 系统将从待机状态释放应用, 之后应用可以自由访问网络并执行任何待定作业和同步. 而如果设备长时间处于空闲状态, 系统将按每天大约一次的频率允许空闲应用访问网络.

    在低电耗模式和应用待机模式期间, 加入白名单的应用可以使用网络并保留部分 wake locks. 应用可以使用方法 isIgnoringBatteryOptimizations() 检查自身当前是否位于豁免白名单中, 代码如下:
/**
 * 是否加入了休眠模式白名单
 * @param context 上下文
 * @return true: 已加入
 */
public static boolean isJoinDozeModeWhiteList(Context context) {
    PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        String packName = getPackageName(context);
        return manager.isIgnoringBatteryOptimizations(packName);
    } else {
        return false;
    }
}

/**
 * 获取应用程序版本包名
 *
 * @param context 上下文
 * @return 当前应用的applicationID (即包名)
 */
public static String getPackageName(Context context) {
    try {
        PackageManager manager = context.getPackageManager();
        PackageInfo info = manager.getPackageInfo(
                context.getPackageName(), 0);
        return info.packageName;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
设置低电耗模式白名单

    用户可以在 Settings > Battery > Battery Optimization 中手动配置该白名单.

    或者, 系统会为应用提供请求用户将应用加入白名单的方式:
方法1:

private int REQUEST_IGNORE_BATTERY_CODE = 1;

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

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == REQUEST_IGNORE_BATTERY_CODE) {
            //TODO something
        }
    } else if (resultCode == RESULT_CANCELED) {
        if (requestCode == REQUEST_IGNORE_BATTERY_CODE) {
            Toast.makeText(this, "请开启忽略电池优化", Toast.LENGTH_SHORT).show();
        }
    }
}

/**
 * 判断并弹窗: 加入休眠模式白名单对话框
 *
 * @param context 上下文
 */
public void joinDozeModeWhiteList(Context context) {
    PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        String packName = getPackageName();
        Intent intent = new Intent();
        //请求弹窗设置休眠模式白名单
        intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packName));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivityForResult(intent, REQUEST_IGNORE_BATTERY_CODE);
    }
}
方法2:
这种方法是跳转到系统低电耗模式白名单界面, 让用户自己手动设置(没有第一种好) 需要在AndroidMainFest中配置权限:
<!--休眠模式弹窗权限-->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

代码:

/**
 * 跳转到低电耗模式白名单设置界面
 *
 * @param context 上下文
 */
public void jumpToDozeModeWhiteListActivity(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent intent = new Intent();
        //跳转界面设置休眠模式白名单
        intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
}

用户可以根据需要手动从白名单中移除应用.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值