Android N 多窗口布局 省电模式 全新通知功能

今年google 16 i/o 强势推出 android n

迄今为止还没有给他命名、有兴趣的可以登录网站 https://www.android.com/versions/name-n/

会中提到android N 运行环境有很大提升,30%到600%提升。应用安装提速75%。

AndroidN 新增Vulkan 现代3D图形API、实现高帧率游戏,即时应用

OK、好东西用了才知道、那么如何运行Android N呢

会学到什么

多窗口布局互动

确保后台服务继续工作,而打盹模式激活

更新通知,以利用新功能

需要什么

Android的工作室版本2.1+

示例代码

测试设备(或仿真器)与Android N和谷歌的API

使用USB线连接你的测试设备

获取示例代码

通过命令行从github上clone

$ git clone https://github.com/googlecodelabs/getting-ready-for-android-n

因为该实例需要使用OpenWeatherMap 获取天气数据、多以在运行代码之前要获取OpenWeatherMap API密钥 获取链接 https://home.openweathermap.org/

运行示例应用程序

OK 打开你下载好的项目、

重要提醒:将你的 OpenWeatherMap API key 添加到 app/build.gradle

Important: Add your OpenWeatherMap API key to app/build.gradle,

将这行代码替换 .

运行程序、验证示例程序可以显示天气

支持多窗口布局

个人觉得最酷炫的是支持multi-window layouts

支持多窗口首先确保我们布局放得下大小windows。首先熟悉几个功能

默认情况下,所有application和activity有个resizeable属性可以用作multi-window功能、

在清单中可以禁用这个功能

        <activity
            android:name=".MainActivity"
            ...
            android:resizeableActivity="false">

        </activity>

尝试一下这两个模式

  1. 启动 sunshine app
  2. 通过长按按钮启动multi-windows 模式
  3. 禁用multi-windows app是全屏的
  4. 将resizeable 置为 true 再试试

注意:如果root activity resizeble是false、则不起作用

A task’s root activity properties are applied to all additional activities launched in the task.

If the root activity of a task is resizeable, the system treats all other activities in the task as resizeable; if the root activity isn’t resizeable, it won’t.

适配小窗口

支持 multi-windows 得考虑 size 和 density的问题

在实例中、用了很多pixel显示天气

如果想把左边蓝色缩小、我们可以用下面的方法

在 values-sw220dp 创建refs.xml、这样尺寸就限制在220dp到下一维度400dp

sw220dp/refs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Replace today‘s forecast layout with the same layout used for every day -->
    <item type="layout" name="list_item_forecast_today">@layout/list_item_forecast</item>
</resources>

sw400dp/refs.xml

<item type="layout" name="list_item_forecast_today">@layout/list_item_forecast_today_big</item>

这样list_item_forecast_today 就适应了两个布局

总结:

适应不同大小的应用程序多画面模式,建议先设计最小的大小。

创建220dp 尽量删除无用元素

添加窗口背景

添加android:windowBackgroundFallback会覆盖 windowBackground

<style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
        ...
        <item name="android:windowBackgroundFallback">@color/sunshine_dark_blue</item>
</style>

打开ForecastFragment .class openPreferredLocationInMap 方法

添加

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);

效果如下

注意:FLAG_ACTIVITY_LAUNCH_ADJACENT只适用于多画面模式。

优化电池效率

现在的android手机、有时候充的电还没用的快…蛋疼 现在优化会好些吗?

在Android N,我们继续这些努力让android 6打瞌睡功能更牛逼,让设备更能保存点亮。任何时候屏幕在一段时间内,设备是不插电,瞌睡适用于CPU和网络限制应用程序。即使在自己的口袋里携带他们的设备也能省点。

轻量级打瞌睡模式

静止的:

那么有了这些功能、app功能会受到限制、特别是网络活动

为了确保您的应用程序在后台继续正常运行,一些服务可能需要修改

  1. (如检查电子邮件,或备份照片),迁移到theJobScheduler或GcmNetworkManager api。这些api提供更大的灵活性为调度工作,并确保你的工作是维护窗口期间处理。
  2. 实时通知(如接收即时消息),使用高优先级GCM通知。这些有能力立即醒来一个应用的低功耗状态。

我们的样例应用程序使用AlarmManger定期醒来和获取天气数据,同时在后台运行。在本节中,我们将它升级到使用GcmNetworkManager。我们的应用程序中醒来的时候允许操作系统更好的去控制,并确保我们的应用程序在这个网络访问事件。

在SunshineSyncService.java定位现有alarm-based调度代码:

public static void ScheduleAlarm(Context context) {
    Log.i(TAG, "Scheduling alarm, interval: " + AlarmManager.INTERVAL_HALF_HOUR / 60000 + " min");
    Intent intent = new Intent(context, SyncAlarmReceiver.class);
    final PendingIntent pIntent = PendingIntent.getBroadcast(
            context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    long firstMillis = System.currentTimeMillis(); // Perform initial sync immediately
    AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    // Perform subsequent syncs every 30 minutes
    alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
            AlarmManager.INTERVAL_HALF_HOUR, pIntent);
}

public static class SyncAlarmReceiver extends BroadcastReceiver {
    private static final String TAG = "SyncAlarmReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "Broadcast received, sending sync intent to SunshineSyncService");
        Intent i = new Intent(context, SunshineSyncService.class);
        context.startService(i);
    }
}

基于GcmNetworkManager替换上面的代码

dependencies {
    // ...
    compile ‘com.google.android.gms:play-services-gcm:8.4.0‘
}

封装一个后台任务

sync/SunshineJobScheduler.java

public class SunshineJobScheduler extends GcmTaskService {

    @Override
    public int onRunTask(TaskParams taskParams) {
        return 0;
    }

}
如前所述,GcmNetworkManager和JobScheduler工作通过定义任务或工作,和一组约束决定当他们应该运行。让我们为这个任务定义两个约束条件——一个经常运行的同时连接到一个充电器,和一个不经常运行在电池。

sync/SunshineJobScheduler.java

public static final int MINUTES_AS_SEC = 60;
public static final int HOURS_AS_SEC = 60*60;
public static final String TASK_TAG_CHARGING = "sync_charging";
public static final String TASK_TAG_BATTERY = "sync_battery";

/**
 * Task specification for running jobs while connected to a charger. In this case, we allow
 * execution to occur frequently, as power usage is not constrained.
 */
private static final Task CHARGING_TASK = new PeriodicTask.Builder()
        .setService(SunshineJobScheduler.class)
        .setPeriod(30*MINUTES_AS_SEC)
        .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
        .setRequiresCharging(true)
        .setPersisted(true)
        .setUpdateCurrent(true)
        .setTag(TASK_TAG_CHARGING)
        .build();

/**
 * Task specification for running jobs while on battery. In this case, we execute jobs less
 * frequently to conserve battery life.
 *
 * Note that additional restrictions may be put on this task by the system if the device is
 * in Doze or App Standby mode due to inactivity. However, we should still try to be friendly
 * to the battery even when these aren‘t in effect.
 */
private static final Task BATTERY_TASK = new PeriodicTask.Builder()
        .setService(SunshineJobScheduler.class)
        .setPeriod(6 * HOURS_AS_SEC)
        .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
        .setRequiresCharging(false)
        .setPersisted(true)
        .setUpdateCurrent(true)
        .setTag(TASK_TAG_BATTERY)
        .build();

setPersisted(true)调用确保跨设备重新启动该任务将被保留下来

现在我们已经定义了任务,我们需要系统安排他们。创建一个新的ScheduleTasks()静态方法,并调用GcmNetworkManager.schedule()我们定义的每个任务。

sync/SunshineJobScheduler.java

private static final String TAG = "SunshineJobScheduler";

/**
 * Method to schedule tasks. Called from either MainActivity.onCreate() for interactive
 * sessions, or onInitializeTasks() in the event Play Services is restarted.
 *
 * Note that since all jobs are flagged as "persisted" in their specifications (above), these
 * will automatically persist across reboots.
 *
 * @param context
 */
public static void ScheduleTasks(Context context) {
    GoogleApiAvailability googleAvailability = GoogleApiAvailability.getInstance();
    int resultCode = googleAvailability.isGooglePlayServicesAvailable(context);
    if (resultCode == ConnectionResult.SUCCESS) {
        Log.i(TAG, "Scheduling tasks");
        GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(context);

        // Run every 30 minutes while the device is on a charger
        gcmNetworkManager.schedule(CHARGING_TASK);

        // ... And run every 6 hours while the device is on battery power
        gcmNetworkManager.schedule(BATTERY_TASK);
    } else {
        // We display a user actionable error inside MainActivity. We‘ll just abort and log the
        // error here.
        Log.e(TAG, "Google Play Services is not available, unable to schedule jobs");
    }
}

配置manifest

ACTION_TASK_READY,为了让持久化设备重启后任务被重塑。

<!-- GcmJobService instance used for background sync -->
<service
    android:name=".sync.SunshineJobScheduler"
    android:exported="true"
    android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
    <intent-filter>
        <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
    </intent-filter>
</service>

我们的GcmNetworkManager实现相应的工作工作,我们可以删除旧的实现。

删除SunshineSyncService。SyncAlarmReceiver SunshineSyncService。BootBroadcastReceiver以及他们在AndroidManfiest.xml相关条目。

测试,尝试启动应用程序。你可能想尝试不同的值用于setPeriod CHARGING_TASK()和BATTERY_TASK。如果使用一个模拟器,可以使用模拟器控制来模拟不同的充电和网络状态。

Q: What’s the difference between JobScheduler and GcmNetworKManager?

A: GcmNetworkManager is a wrapper around JobScheduler, that provides backwards compatibility for devices older than API 21. Your app doesn’t need to use GCM messaging in order to take advantage of it.

Q: How do I ensure my jobs are scheduled after a restart?

A: Use the setPersisted() option when creating a task specification.

Q: What happens if I don’t migrate to JobScheduler or GcmNetworkManager?

A: On devices running Marshmallow or later, your app may lose network access if Doze or App Standby modes are activated by the system. To avoid this, you need to make sure your app’s background activities only occur during maintenance windows. To do this, make sure you’re using JobScheduler/GcmNetworkManager (recommended) or a SyncAdapter.

支持增强的通知

Android N notifications 有一下几点

1. 列表内容通知分组在phones和tablets使用、不仅仅 android wear

2. 通知可以响应文本输入

3. 刷新和操作更美了

NotificationCompat Android支持库引入N,我们可以通过分组通知达到更好的用户体验

下面是notification group部分

使用一个支持库版本大于24.0.0-alpha2

compile ‘com.android.support:appcompat-v7:21.0.2‘
compile ‘com.android.support:appcompat-v7:24.0.0-alpha2‘

打开SunshineSyncEngine.java

SunshineSyncEngine.java

添加如下代码

private static final String FORECAST_NOTIFICATION_GROUP = "FORECAST_NOTIFICATION_GROUP";

new NotificationCompat.Builder

Builder调用setGroup(String)

SunshineSyncEngine.java

.setGroup(FORECAST_NOTIFICATION_GROUP)

所有通知组需要一个summary.创建额外的summary通知代码

SunshineSyncEngine.java

if (numNotifications > 0) {
    // Always build a summary if you have notifications in a group.
    // The summary will be displayed by the system when needed.
    NotificationCompat.Builder summaryBuilder =
        createSummaryNotificationBuilder(context,
            "Sunshine Forecasts", "");
    summaryBuilder.setGroupSummary(true);
    mNotificationManager.notify(WEATHER_NOTIFICATION_ID,
        summaryBuilder.build());
}

部署代码,将看到在系统栏通知分组只占用一个图标。单摘要通知是可扩展的,group内部数量低于2摘要通知消失

下面是关于Remote Input部分

通知栏输入文字、要做一下几个个步骤

1. 您需要声明一个类,它将接收一个意图。目的将包含的信息由用户输入的文本。在这个示例中我们要重复使用BroadcastReceiver。

2. MessageReplyReceiver类,您将看到以下意图额外的定义。将存储的回复文本意图转发给接收方是关键。

MessageReplyReceiver.java

    public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
    // public static final String REPLY_ACTION = BuildConfig.APPLICATION_ID + ".ACTION_MESSAGE_REPLY";
    // public static final String EXTRA_FORECAST = "extra_forecast";
  1. 取消REPLY_ACTION和EXTRA_FORECAST静态类变量的备注

    REPLY_ACTION和EXTRA_FORECAST静态类变量。REPLY_ACTION将用于声明RemoteInput行动的通知。EXTRA_FORECAST包含预测信息,需要重建的通知。

  2. 将MessageReplyReceiver onReceive方法中的代码解除注释、

    将检索一个接收器可以处理的意图。

    SunshineSyncEngine.java

RemoteInput remoteInput = new RemoteInput.Builder(
                             MessageReplyReceiver.EXTRA_REMOTE_REPLY)
                             .setLabel("Take note")
                             .build();

5.创建一个Pending intent通知用户提交的回复

SunshineSyncEngine.java

RemoteInput remoteInput = new RemoteInput.Builder(
                             MessageReplyReceiver.EXTRA_REMOTE_REPLY)
                             .setLabel("Take note")
                             .build();
  1. 创建action

    SunshineSyncEngine.java

NotificationCompat.Action actionReplyByRemoteInput =
    new NotificationCompat.Action.Builder(
        R.mipmap.ic_launcher,
        "Take note",
        replyIntent)
        .addRemoteInput(remoteInput)
        .build();

7.现在添加远程输入行动通知。

SunshineSyncEngine.java

builder.addAction(actionReplyByRemoteInput);

部署应用程序、发送文本发现进度指示器没有提醒、因为我们差了一步骤

onReceive消息中你会注意到NotificationManager变量不能使用。除非你通知用户使用否则该系统将不知道远程接收输入

MesageReplyReceiver.java

NotificationManager notificationManager =
    (NotificationManager) context.getSystemService(
         Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notificationBuilder =
    SunshineSyncEngine.createForecastNotificationBuilder(
        context, forecast);
notificationManager.notify(forecast.mDaysSinceEpoch,
    notificationBuilder.build());

提示:NotificationCompat.Builder创建对象是昂贵的。如果你打算经常更新相同的通知需要创建和缓存它们。这将避免不必要的对象创建请求。

OK、这些功能慢慢体验吧、你的应用已经运行android n新功能了

  1. 互动的多窗口布局
  2. 确保后台服务继续工作,打瞌睡模式处于活动状态
  3. 利用新功能更新通知

google原文地址、注意带上梯子

https://codelabs.developers.google.com/codelabs/getting-ready-for-android-n/index.html?index=..%2F..%2Fio2016#6

时间: 2024-10-01 20:30:27

Android N 多窗口布局 省电模式 全新通知功能的相关文章

Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8372924 在前面一篇文章中,我们分析了Android应用程序窗口的绘图表面的创建过程.Android应用程序窗口的绘图表面在创建完成之后,我们就可以从上到下地绘制它里面的各个视图了,即各个UI元素了.不过在绘制这些UI元素之前,我们还需要从上到下地测量它们实际所需要的大小,以及对它们的位置进行合适的安排,即对它们进行合适的布局.在本文中,我们

Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析

在前两文中,我们分析了Activity组件的窗口对象和视图对象的创建过程.Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求WindowManagerService为其增加一个WindowState对象,用来描述它的窗口状态.在本文中,我们就详细分析Activity组件与WindowManagerService的连接过程. 我们从两方面来看Activity组件与WindowManagerService服务之间的连接.一方

Android应用程序窗口View的measure过程

Android应用程序的界面是View组成的,这些View以树形结构组织,它们存在着父子关系,其中,子view位于父view里面,因此,在绘制一个Android应用程序窗口的View之前,我们首先要确定它里面的各个子view在父view里面的大小以及位置.确定各个子view在父view里面的大小以及位置的过程又称为测量过程和布局过程.测量和布局完后,就可以绘制view了. 参考上一篇文章Android应用程序窗口View的创建过程,可以知道Android应用程序窗口的根View是DecorVie

Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析

http://blog.csdn.net/luoshengyang/article/details/8223770 在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一个具体的应用程序窗口.由此又可知,Activity只不过是一个高度抽象的UI组件,它的具体UI实现其实是由其它的一系列对象来实现的.在本文中,我们就将详细分析Android应用程序窗口

Android应用程序窗口(Activity)的视图对象(View)的创建过程分析

从前文可知道,每一个Activity组件都有一个关联的Window对象,用来描述一个应用程序窗口.每一个应用程序窗口内部又包含有一个View对象,用来描述应用程序窗口的视图.应用程序窗口视图是真正用来实现UI内容和布局的,也就是说,每一个Activity组件的UI内容和布局都是通过与其所关联的一个Window对象的内部的一个View对象来实现的.在本文中,我们就详细分析应用程序窗口视图的创建过程. 在前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文中提到,应用程序

Android 自学之线性布局 LinearLayout

线性布局(LinearLayout),线性布局有点想AWT编程里面的FolwLayout,他们都会将容器里面的组件挨个的排列起来. 他们最大的区别在于:Android的线性布局不会换行:AWT里面的FolwLayout则会另起一行进行显示 LinearLayout支持常用XML属性及相关方法的说明 XML属性 相关方法 说明 android:gravity setGravity(int) 设置布局管理器内组件的对齐方式.该属性支持top,bottom,left,right--也可以同时制定多种对

Android 自学之帧布局 FrameLayout

帧布局(FrameLayout)直接继承了ViewGroup组件: 帧布局容器为每一个加入其中的组件都创建了一个空白的区域,这个区域我们称之为一帧,所有每个组件都占据一帧,这些都会根据gravity属性执行自动对齐. FrameLayout的常用XML属性及相关的方法: XML属性 相关方法 说明 android:foreground setForeground(Drawable) 设置该帧布局容器的前景图像 android:foregroundGravity setForegroundGrav

Android设计模式源码解析之桥接模式

模式介绍 模式的定义 将抽象部分与实现部分分离,使它们都可以独立的变化. 模式的使用场景 如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系. 设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的. 需要跨越多个平台的图形和窗口系统上. 一个类存在两个独立变化的维度,且两个维度都需要进行扩展. UML类图 角色介绍 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用. 修正抽象化

Android基础:常用布局和数据存储

1. 相对布局RelativeLayout 特点:相对布局所有组件可以叠加在一起:各个组件的布局是独立的,互不影响:所有组件的默认位置都是在左上角(顶部.左部对齐) 属性 功能描述 android:layout_toRightOf 在指定控件的右边 android:layout_toLeftOf 在指定控件的左边 android:layout_above 在指定控件的上边 android:layout_below 在指定控件的下边 android:layout_alignBaseline 跟指定