导读

增强的Doze模式

后台优化

Data Saver

一.增强的Doze模式

Android N对Android M引进的Doze模式进行了进一步的增强,变化体现在两个方面.一方面是降低了进入Doze模式的条件,Android M中的条件是不插电,屏幕熄灭且静置一段时间,在Android N中去掉了静置的条件,这个改变大大增加了设备进入Doze模式的机会,因而使得Doze对应用程序的影响大大增加.另一方面,Doze模式被分成了两个阶段,当设备切断电源,熄灭屏幕一段时间,会进入到第一阶段,切断网络连接,推迟任务和同步.如果设备在第一阶段的基础上再静置一段时间,就会进入第二阶段,在第一阶段的基础上增加对维持唤醒(PowerManager.WakeLock),定时任务(AlarmManager alarms),GPS和Wi-Fi扫描的限制,如下图所示:

First level

Second level

 

应对方案:

方案一:在Android 6.0中AlarmManager中增加了两个方法setAndAllowWhileIdle() and setExactAndAllowWhileIdle(),通过使用这两个方法可以让alarm在Doze模式下运行.

需要注意的是官方文档指出,使用这两个方法时,每个应用每9分钟只能唤醒一次alarm.

Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.

以一个定时任务为例进行测试,核心代码如下:

Service:

在Service的onStartCommand()方法中,获取一个AlarmManager的实例,设置任务执行的时间是10s后,处理定时任务的广播接收器是AlarmReceiver.

public class LongRunningService extends Service {

public static final String TAG = "LongRunningService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"executed at " + new Date().toString());
            }
        }).start();

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int offset= 10 * 1000;//间隔时间10s
        long triggerAtTime = SystemClock.elapsedRealtime() + offset;
        Intent i = new Intent(this, AlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);

manager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
//        manager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);

return super.onStartCommand(intent, flags, startId);
    }
}

BroadcastReceiver:

重写onReceive()方法,创建一个Intent,启动LongRunningService.这样一来,就形成了一个每隔10s执行一次的定时任务.

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, LongRunningService.class);
        context.startService(i);
    }
}

 

测试结果:

I/LongRunningService: executed at Thu Apr 14 22:32:58 GMT+08:00 2016

I/LongRunningService: executed at Thu Apr 14 22:33:08 GMT+08:00 2016

I/LongRunningService: executed at Thu Apr 14 22:33:18 GMT+08:00 2016

I/LongRunningService: executed at Thu Apr 14 22:42:18 GMT+08:00 2016

I/LongRunningService: executed at Thu Apr 14 22:51:18 GMT+08:00 2016

从测试结果可以看出,设备在正常使用的情况下(前三行),每隔10s运行一次,进入到Doze模式后(后三行),每隔9分钟执行一次.

为方便操作,这里介绍一下测试步骤:

Step1.运行应用程序

Step2.关闭设备的屏幕

Step3.使用如下命令强制系统进入Doze模式

$ adb shell dumpsys battery unplug

$ adb shell dumpsys deviceidle step

需要多次运行第二条命令,直到设备进入到空闲状态.

 

方案二:在应用程序运行时,引导用户将该应用添加到白名单中.

实现方式1(不推荐):使用ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS使用户跳转到电池优化设置页,手动将该应用添加到白名单中.

核心代码如下:

Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
startActivity(intent);

该方法可行,但存在一个缺点:跳转到电池优化页后,用户需要在”所有应用”列表里(应用安装后会默认设置为”优化”)找到该应用进行设置,而且系统提示会引导用户选择优化,如图所示:

实现方式2(推荐):给应用添加权限REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,并使用ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,系统会弹出设置窗口,用户可以直接将该应用添加到白名单中,如下图所示:

核心代码:

在清单文件中添加权限:

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

使用ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS作为参数创建一个Intent,并以"package:com.example.xxx.xxx"的Uri形式将包名传入.

Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:com.example.janiszhang.dozedemo3"));
startActivity(intent);

方案三:使用GCM(Google Cloud Messaging ),该方法不可行,不再赘述.

二.后台优化

优化点1.针对预览版,应用不再接收静态注册的CONNECTIVITY_ACTION广播.但是应用在前台时仍然能够监听到动态注册的CONNECTIVITY_CHANGE广播.

优化点2.应用程序不能发送或者接收ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO广播,这个优化会影响到所有应用,不只是针对预览版.

应对方案:

为了应对CONNECTIVITY_ACTION的变化所带来的影响,官方给出了两种缓解方案.

方案一:使用JobScheduler在无计量网络下调度网络任务.

核心代码:

Activity:

在使用JobInfo.Builder()创建JobInfo对象时,调用setRequiredNetworkType()方法,并将

JobInfo.NETWORK_TYPE_UNMETERED作为参数传递进去,这段代码的作用是当设备接入无计量网络时将调起MyJobService.

public static final int MY_BACKGROUND_JOB = 0;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void scheduleJob(Context context) {
    JobScheduler js =
            (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    JobInfo job = new JobInfo.Builder(
            MY_BACKGROUND_JOB,
            new ComponentName(context, MyJobService.class))
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
            .build();
    js.schedule(job);
}

Service:

当条件满足时(在该例中为接入无计量网络),MyJobService中的回调方法onStartJob()将被执行,在实际业务中,可以在这里执行网络任务.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService{

public static final String TAG = "MyJobService";
    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.i(TAG, "on start job: " + jobParameters.getJobId());
        return false;
    }

@Override
    public boolean onStopJob(JobParameters jobParameters) {
        Log.i(TAG, "on stop job: " + jobParameters.getJobId());
        return false;
    }
}

注意:

需要在清单文件中为该Service设置权限:android.permission.BIND_JOB_SERVICE”

<service android:name=".MyJobService"
    android:permission="android.permission.BIND_JOB_SERVICE"/>

方案二:在应用运行时监控网络连接

方式一:动态注册BroadcastReceiver,监听

“android.net.conn.CONNECTIVITY_CHANGE”

BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {

@Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG,"onReceive");
    }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
this.registerReceiver(broadcastReceiver,intentFilter);

方式二:使用ConnectivityManager

首先,使用NetworkRequest.Builder创建一个NetworkRequest对象,然后使用registerNetworkCallback()把这个NetworkRequest对象传递给系统.当网络条件被满足时,应用将收到一个回调去执行定义在ConnectivityManager.MetworkCallback类中的onAvailable()方法.

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkRequest.Builder builder = new NetworkRequest.Builder();

builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);

NetworkRequest networkRequest = builder.build();

ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {

@Override
    public void onAvailable(Network network) {
        super.onAvailable(network);
        Log.i(TAG, "onAvailable");
    }
};
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);

三.Data Saver

 

当用户在计量网络下启用数据节约功能时,系统会封锁后台数据的使用,运行在前台的应用也会尽量少的使用数据流量.用户可以使用白名单允许指定的应用在数据节约模式下使用后台数据.Android N开发者预览版中扩展了ConnectivityManager API的能力,向用户提供了查看和监控数据节约设置的接口.

检测Data Saver首选项的变化

动态注册监听ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED ("android.net.conn.RESTRICT_BACKGROUND_CHANGED")的广播接收者.

核心代码:

BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {

@Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "Data Saver Changed");
    }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.RESTRICT_BACKGROUND_CHANGED");
this.registerReceiver(broadcastReceiver,intentFilter);

注意:必须使用动态注册的方式才能够监听到该广播,不能在清单文件中静态注册.

检查数据节约设置

 

ConnectivityManager的getResrictBackgroundStatus()方法的返回值如下:

RESTRICT_BACKGROUND_STATUS_DISABLED

禁用数据节约

RESTRICT_BACKGROUND_STATUS_ENABLED

启用数据节约

RESTRICT_BACKGROUND_STATUS_WHITELISTED

用户启用了数据节约,但是该应用在白名单中,故不受限制.

下面的示例代码来自官方文档,给出了使用ConnectivityManager.isActiveNetworkMetered()

和ConnectivityManager.getRestrictBackgroundStatus()来判断当前Data Saver设置状态的方法.

注意:这段代码目前还不能使用,RESTRICT_BACKGROUND_STATUS_ENABLED等三个状态值尚不可用.

使用adb命令进行测试

$ adb shell dumpsys netpolicy

生成一个报告,包括当前的全部后台网络限制的设置,白名单中的包的UID,其他已知包的网络限制.

$ adb shell cmd netpolicy

显示一个完整的网络策略管理命令列表.

$ adb shell cmd netpolicy set restrict-background <boolean>

启用或者禁用数据节约命令

$ adb shell cmd netpolicy add restrict-background-whitelist <UID>

将指定的包的UID加入白名单中

$ adb shell cmd netpolicy remove restrict-background-whitelist <UID>

从白名单中将指定包的UID移除

android 7.0 学习笔记(一)的更多相关文章

  1. DirectX 总结和DirectX 9.0 学习笔记

    转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...

  2. 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移

    不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...

  3. vue2.0学习笔记之路由(二)路由嵌套+动画

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. vue2.0学习笔记之路由(二)路由嵌套

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Android安装器学习笔记(一)

    Android安装器学习笔记(一) 一.Android应用的四种安装方式: 1.通过系统应用PackageInstaller.apk进行安装,安装过程中会让用户确认 2.系统程序安装:在开机的时候自动 ...

  6. hdcms v5.7.0学习笔记

    hdcms v5.7.0学习笔记 https://note.youdao.com/ynoteshare1/index.html?id=c404d63ac910eb15a440452f73d6a6db& ...

  7. dhtmlxgrid v3.0学习笔记

    dhtmlxgrid v3.0学习笔记 分类: dhtmlx JavaScript2012-01-31 15:41 1744人阅读 评论(0) 收藏 举报 stylesheetdatecalendar ...

  8. OAuth 2.0学习笔记

    文章目录 OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动. OAuth在"客户端&quo ...

  9. android cocos2d-x for Android安装和学习笔记(请用adt-bundle21.1或以上导入)

    引用:http://weimingtom.iteye.com/blog/1483566 (20121108)注意:这篇文章用cdt编译ndk工程的内容已过时(现在可以用adt-bundle,避免配置繁 ...

随机推荐

  1. Callbacks vs Events

    前言:本文翻译自Dean Edwards的一篇文章,原文地址:http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/. 文章主要指出了 ...

  2. Cesium应用篇:3控件(3)SelectionIndicator& InfoBox

    假设这样一个场景,用户在Cesium球上加载了一个GeoJson文件(DataSource),里面是全美国所有州的Geometry信息(Entity),叠加到球面后,你自然会有一种冲动,点击某一个州, ...

  3. Asp.Net 使用Npoi导出Excel

    引言 使用Npoi导出Excel 服务器可以不装任何office组件,昨天在做一个导出时用到Npoi导出Excel,而且所导Excel也符合规范,打开时不会有任何文件损坏之类的提示.但是在做导入时还是 ...

  4. label用js,jquery取值赋值,以及怎么在后台取值

    label标签在JS和Jquery中使用不能像其他标签一样用value获取它的值: 可以这样: JS: var label=document.getElementByIdx_x("id&qu ...

  5. VS2013设置护眼背景颜色

    打开VS2013 —> 工具 —> 选项 —> 环境 —> 字体和颜色 —> 选择显示项中的纯文本 —> 项目背景 —> 自定义—> 色调位85.饱和度 ...

  6. 使用c#对windows进行关机、重启或注销

    方法一:调用windows自带的shutdown.exe (缺点:会出现倒计时窗口) System.Diagnostics.Process.Start("shutdown.exe" ...

  7. jQuery+HTML5弹出创意搜索框层

    效果体验:http://hovertree.com/texiao/jquery/26/ 本效果适用于移动设备,可以使用手机等浏览效果. 代码下载:http://hovertree.com/h/bjaf ...

  8. SQL 循环语句 while 介绍 实例

    declare @i int begin insert into test (userid) values(@i) end --------------- while 条件 begin 执行操作 en ...

  9. C#~异步编程再续~await与async引起的w3wp.exe崩溃

    返回目录 最近怪事又开始发生了,IIS的应用程序池无做挂掉,都指向同一个矛头,async,threadPool,Task,还有一个System.NullReferenceException,所以这些都 ...

  10. [C#] .NET4.0中使用4.5中的 async/await 功能实现异

    好东西需要分享 原文出自:http://www.itnose.net/detail/6091186.html 在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framew ...