小伙伴们现在装载android 8.0 的手机已经在市面销售那么作为程序员的我们是否已经完成面向Android O的迁移了呢?
现在我们介绍下 Android O新的改动:
在 Android 8.0 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的方式。这些变更包括:
Android 8.0 中的通知长按菜单。
通知渠道:Android 8.0 引入了通知渠道,其允许您为要显示的每种通知类型创建用户可自定义的渠道。用户界面将通知渠道称之为通知类别。要了解如何实现通知渠道的信息,请参阅通知渠道指南。
通知标志:Android 8.0 引入了对在应用启动器图标上显示通知标志的支持。通知标志可反映某个应用是否存在与其关联、并且用户尚未予以清除也未对其采取行动的通知。通知标志也称为通知点。要了解如何调整通知标志,请参阅通知标志指南。
休眠:用户可以将通知置于休眠状态,以便稍后重新显示它。重新显示时通知的重要程度与首次显示时相同。应用可以移除或更新已休眠的通知,但更新休眠的通知并不会使其重新显示。
通知超时:现在,使用 setTimeoutAfter() 创建通知时您可以设置超时。您可以使用此函数指定一个持续时间,超过该持续时间后,通知应取消。如果需要,您可以在指定的超时持续时间之前取消通知。
Android 8.0 允许以画中画 (PIP) 模式启动操作组件。PIP 是一种特殊的多窗口模式,最常用于视频播放。目前,PIP 模式可用于 Android TV,而 Android 8.0 则让该功能可进一步用于其他 Android 设备。
当某个 Activity 处于 PIP 模式时,它会处于暂停状态,但仍应继续显示内容。因此,您应确保您的应用在 onPause() 处理程序中进行处理时不会暂停播放。相反,您应在 onStop() 中暂停播放视频,并在 onStart() 中继续播放。如需了解详细信息,请参阅多窗口生命周期。
要指定您的 Activity 可以使用 PIP 模式,请在清单中将 android:supportsPictureInPicture 设置为 true。(从 Android 8.0 开始,如果您打算在 Android TV 或其他 Android 设备上支持 PIP 模式,则无需将 android:resizeableActivity 设置为 true;只有在您的 Activity 支持其他多窗口模式时,才需要设置 android:resizeableActivity。)
Android 8.0 引入一种新的对象 PictureInPictureParams,您可以将该对象传递给 PIP 函数来指定某个 Activity 在其处于 PIP 模式时的行为。此对象还指定了各种属性,例如操作组件的首选纵横比。
现在,在添加画中画中介绍的现有 PIP 函数可用于所有 Android 设备,而不仅限于 Android TV。此外,Android 8.0 还提供以下函数来支持 PIP 模式:
Activity.enterPictureInPictureMode(PictureInPictureParams args):将操作组件置于画中画模式。操作组件的纵横比和其他配置设置均由 args 指定。如果 args 中的任何字段为空,系统将使用您上次调用 Activity.setPictureInPictureParams() 时所设置的值。
指定的操作组件被置于屏幕的一角,屏幕剩余部分则被屏幕显示的上一个操作组件填满。进入 PIP 模式的 Activity 将进入暂停状态,但仍保持已启动状态。如果用户点按此 PIP 操作组件,系统将显示一个菜单供用户操作,而在操作组件处于 PIP 状态期间,不会理会任何触摸事件。
Activity.setPictureInPictureParams():更新操作组件的 PIP 配置设置。如果操作组件目前处于 PIP 模式,则会更新此设置;如果操作组件的纵横比发生变化,这非常有用。如果操作组件不处于 PIP 模式,则会使用这些配置设置,而不会考虑您调用的 enterPictureInPictureMode() 函数。
Android 8.0 允许您根据 TextView 的大小自动设置文本展开或收缩的大小。这意味着,在不同屏幕上优化文本大小或者优化包含动态内容的文本大小比以往简单多了。如需了解有关如何在 Android 8.0 中自动调整 TextView 的大小的详细信息,请参阅自动调整 TextView 的大小。
Android 8.0 引入自适应启动器图标。自适应图标支持视觉效果,可在不同设备型号上显示为各种不同的形状。要了解如何创建自适应图标,请参阅自适应图标预览功能指南。
更多请参阅Android 8.0 功能和 API
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Color;
public class NotificationUtils extends ContextWrapper {
private NotificationManager mManager;
public static final String ANDROID_CHANNEL_ID = "com.chikeandroid.tutsplustalerts.ANDROID";
public static final String IOS_CHANNEL_ID = "com.chikeandroid.tutsplustalerts.IOS";
public static final String ANDROID_CHANNEL_NAME = "ANDROID CHANNEL";
public static final String IOS_CHANNEL_NAME = "IOS CHANNEL";
public NotificationUtils(Context base) {
super(base);
createChannels();
}
public void createChannels() {
// create android channel
NotificationChannel androidChannel = new NotificationChannel(ANDROID_CHANNEL_ID,
ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
// Sets whether notifications posted to this channel should display notification lights
androidChannel.enableLights(true);
// Sets whether notification posted to this channel should vibrate.
androidChannel.enableVibration(true);
// Sets the notification light color for notifications posted to this channel
androidChannel.setLightColor(Color.GREEN);
// Sets whether notifications posted to this channel appear on the lockscreen or not
androidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(androidChannel);
// create ios channel
NotificationChannel iosChannel = new NotificationChannel(IOS_CHANNEL_ID,
IOS_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
iosChannel.enableLights(true);
iosChannel.enableVibration(true);
iosChannel.setLightColor(Color.GRAY);
iosChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
getManager().createNotificationChannel(iosChannel);
}
private NotificationManager getManager() {
if (mManager == null) {
mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return mManager;
}
}
在上面的代码中,我们创建了两个NotificationChannel实例,传递一个id(在你的包里必须是唯一的),一个通道名,还有一个重要性级别的构造函数。 对于每个通知频道,我们都会应用声音,灯光,振动和通知等特征来显示在锁定屏幕上。 最后,我们从系统中获得了NotificationManager,然后通过调用createNotificationChannel()方法来注册频道,传递我们创建的频道。
我们可以使用createNotificationChannels()一次创建多个通知通道,并传递Java列表的NotificationChannel实例。 您可以使用getNotificationChannels()获取应用程序的所有通知频道,并使用getNotificationChannel()获取特定频道,只传递频道ID作为参数。
从Android O开始,各个通知不推荐使用优先级。 而是在创建通知渠道时设置重要性级别,范围从NotificationManager.IMPORTANCE_NONE到NotificationManager.IMPORTANCE_HIGH。 我们将Android频道设置为IMPORTANCE_DEFAULT,而iOS频道的频道为IMPORTANCE_HIGH。
可用的重要选项的完整列表是:
指定应该将哪个通知发送到Notification.Builder(Android API 25)构造函数中的通道,我们将通道ID作为第二个参数传递给它。
// ...
public Notification.Builder getAndroidChannelNotification(String title, String body) {
return new Notification.Builder(getApplicationContext(), ANDROID_CHANNEL_ID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(android.R.drawable.stat_notify_more)
.setAutoCancel(true);
}
public Notification.Builder getIosChannelNotification(String title, String body) {
return new Notification.Builder(getApplicationContext(), IOS_CHANNEL_ID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(android.R.drawable.stat_notify_more)
.setAutoCancel(true);
}
//...
请注意,Notification.Builder()也有一个名为setChannel(String channelId)的通知通道id setter方法,因此您可以选择在构造函数中使用通知通道id或使用setter方法。
现在我们已经创建并发布到通知渠道,我们创建XML布局接口,将消息发布到我们的activity_main.xml中。
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="16dp"
tools:context="com.chikeandroid.tutsplusalerts.MainActivity">
"match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
"wrap_content"
android:layout_height="wrap_content"
android:text="Tuts+ Android Channel"
android:layout_gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
"@+id/et_android_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Title"/>
"@+id/et_android_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Author"/>
"match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="20dp">
"wrap_content"
android:layout_height="wrap_content"
android:text="Tuts+ IOS Channel"
android:layout_gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
"@+id/et_ios_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Title"
/>
"@+id/et_ios_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Author"/>
发布到Android频道
在本节中,我们将编辑我们的MainActivity,以便我们可以从EditText组件获取标题和作者,然后将其发送到Android频道。 我们为我们在NotificationUtils中创建的Android频道获取Notification.Builder,然后通知NotificationManager。
import android.app.Notification;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private NotificationUtils mNotificationUtils;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNotificationUtils = new NotificationUtils(this);
final EditText editTextTitleAndroid = (EditText) findViewById(R.id.et_android_title);
final EditText editTextAuthorAndroid = (EditText) findViewById(R.id.et_android_author);
Button buttonAndroid = (Button) findViewById(R.id.btn_send_android);
buttonAndroid.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String title = editTextTitleAndroid.getText().toString();
String author = editTextAuthorAndroid.getText().toString();
if(!TextUtils.isEmpty(title) && !TextUtils.isEmpty(author)) {
Notification.Builder nb = mNotificationUtils.
getAndroidChannelNotification(title, "By " + author);
mNotificationUtils.getManager().notify(101, nb.build());
}
}
});
}
}
此时,运行应用程序并输入标题和作者,然后单击发送按钮以立即接收通知。
在这里,我们将发布到iOS频道。 我们为我们在NotificationUtils中创建的iOS通道获取Notification.Builder,然后在NotificationManager中调用notify()方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
final EditText editTextTitleIos = (EditText) findViewById(R.id.et_ios_title);
final EditText editTextAuthorIos = (EditText) findViewById(R.id.et_ios_author);
Button buttonIos = (Button) findViewById(R.id.btn_send_ios);
buttonIos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String title = editTextTitleIos.getText().toString();
String author = editTextAuthorIos.getText().toString();
if(!TextUtils.isEmpty(title) && !TextUtils.isEmpty(author)) {
Notification.Builder nb = mNotificationUtils
.getIosChannelNotification(title, "By " + author);
mNotificationUtils.getManager().notify(102, nb.build());
}
}
});
}
再次运行应用程序并输入标题和作者,然后单击发送按钮立即接收通知。
再次运行应用程序并输入标题和作者,然后单击发送按钮立即接收通知。在撰写本文时,不能以编程方式更改特定通知通道设置的配置。 相反,唯一可用的选项是让用户在设备设置中转到应用程序的通知设置屏幕。 从那里,用户可以访问应用程序通知设置来修改设置,如振动,声音等。用户可以通过以下任一方式导航到应用程序通知设置:
您也可以将用户从您的应用程序发送到频道通知设置。 我们来看看我们如何为Android频道做到这一点。 建议您在应用设置中执行此操作,以方便用户访问这些通知选项。
编辑XML布局
加入另一个按钮,将用户发送到频道通知设置
在这里,我们创建一个意图,并将其传递给设置操作ACTION_CHANNEL_NOTIFICATION_SETTINGS(API 25),然后添加一些额外的值:应用程序包名称和频道ID。 最后,我们开始设置活动的意图。
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
Button buttonAndroidNotifSettings = (Button) findViewById(R.id.btn_android_notif_settings);
buttonAndroidNotifSettings.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
i.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
i.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationUtils.ANDROID_CHANNEL_ID);
startActivity(i);
}
});
}
//...
运行应用程序,然后单击Android通道的通知设置。
或显示频道的徽章(如果支持)。
如果您想让用户访问您的应用的一般通知设置,也可以使用Intent来完成:
Intent i = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
i.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(i);
对于程序中的广播 在Android O中将会取消静态广播,如果你的代码中含有静态广播 更改为动态广播即可(想一想早就应该改成这样)
只需要在AndroidManifest中添加权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
至于各种新API 大家移步Android Develop