Android O 迁移(适配Android 8.0)

Android O Migrating

小伙伴们现在装载android 8.0 的手机已经在市面销售那么作为程序员的我们是否已经完成面向Android O的迁移了呢?


现在我们介绍下 Android O新的改动:

通知

在 Android 8.0 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的方式。这些变更包括:

  • Android 8.0 中的通知长按菜单。
    通知渠道:Android 8.0 引入了通知渠道,其允许您为要显示的每种通知类型创建用户可自定义的渠道。用户界面将通知渠道称之为通知类别。要了解如何实现通知渠道的信息,请参阅通知渠道指南。

    • 通知标志:Android 8.0 引入了对在应用启动器图标上显示通知标志的支持。通知标志可反映某个应用是否存在与其关联、并且用户尚未予以清除也未对其采取行动的通知。通知标志也称为通知点。要了解如何调整通知标志,请参阅通知标志指南。

    • 休眠:用户可以将通知置于休眠状态,以便稍后重新显示它。重新显示时通知的重要程度与首次显示时相同。应用可以移除或更新已休眠的通知,但更新休眠的通知并不会使其重新显示。

    • 通知超时:现在,使用 setTimeoutAfter() 创建通知时您可以设置超时。您可以使用此函数指定一个持续时间,超过该持续时间后,通知应取消。如果需要,您可以在指定的超时持续时间之前取消通知。

    • 通知设置:当您使用 Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCESIntent 从通知创建指向应用通知设置的链接时,您可以调用 setSettingsText() 来设置要显示的文本。此系统可以提供以下 Extra 数据和 Intent,用于过滤应用必须向用户显示的设置:EXTRA_CHANNEL_ID、NOTIFICATION_TAG 和 NOTIFICATION_ID。
    • 通知清除:系统现在可区分通知是由用户清除,还是由应用移除。要查看清除通知的方式,您应实现 NotificationListenerService 类的新 onNotificationRemoved() 函数。
    • 背景颜色:您现在可以设置和启用通知的背景颜色。只能在用户必须一眼就能看到的持续任务的通知中使用此功能。例如,您可以为与驾车路线或正在进行的通话有关的通知设置背景颜色。您还可以使用 Notification.Builder.setColor() 设置所需的背景颜色。这样做将允许您使用 Notification.Builder.setColorized() 启用通知的背景颜色设置。
    • 消息样式:现在,使用 MessagingStyle 类的通知可在其折叠形式中显示更多内容。对于与消息有关的通知,您应使用 MessagingStyle 类。您还可以使用新的 addHistoricMessage() 函数,通过向与消息相关的通知添加历史消息为会话提供上下文。

自动填充框架

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。)

API 变更

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() 函数。

自动调整 TextView 的大小

Android 8.0 允许您根据 TextView 的大小自动设置文本展开或收缩的大小。这意味着,在不同屏幕上优化文本大小或者优化包含动态内容的文本大小比以往简单多了。如需了解有关如何在 Android 8.0 中自动调整 TextView 的大小的详细信息,请参阅自动调整 TextView 的大小。

自适应图标

Android 8.0 引入自适应启动器图标。自适应图标支持视觉效果,可在不同设备型号上显示为各种不同的形状。要了解如何创建自适应图标,请参阅自适应图标预览功能指南。

更多请参阅Android 8.0 功能和 API


通知功能适配

1:Create a new class and name it NotificationUtils, extending ContextWrapper.
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作为参数。

Importance Levels

从Android O开始,各个通知不推荐使用优先级。 而是在创建通知渠道时设置重要性级别,范围从NotificationManager.IMPORTANCE_NONE到NotificationManager.IMPORTANCE_HIGH。 我们将Android频道设置为IMPORTANCE_DEFAULT,而iOS频道的频道为IMPORTANCE_HIGH。

可用的重要选项的完整列表是:

  • IMPORTANCE_MAX:未使用
  • IMPORTANCE_HIGH:到处显示,造成噪音和偷看
  • IMPORTANCE_DEFAULT:处处显示,产生噪音,但不会在视觉上侵入
  • IMPORTANCE_LOW:处处显示,但不侵入
  • IMPORTANCE_MIN:仅在折叠下的阴影中显示
  • IMPORTANCE_NONE:通知无关紧要; 不在阴凉处显示
    所有通道的通知将被赋予相同的重要性级别。
Create Notifications and Post to Channels

指定应该将哪个通知发送到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方法。

Create the XML Layout

现在我们已经创建并发布到通知渠道,我们创建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"/>


        
Post Notifications to Channels

发布到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());
            }
        }
    });
}

再次运行应用程序并输入标题和作者,然后单击发送按钮立即接收通知。

Notification Channel Settings

再次运行应用程序并输入标题和作者,然后单击发送按钮立即接收通知。在撰写本文时,不能以编程方式更改特定通知通道设置的配置。 相反,唯一可用的选项是让用户在设备设置中转到应用程序的通知设置屏幕。 从那里,用户可以访问应用程序通知设置来修改设置,如振动,声音等。用户可以通过以下任一方式导航到应用程序通知设置:

  • 长按通知抽屉上的通知。
  • 设置>应用程序和通知>通知>然后选择应用程序

您也可以将用户从您的应用程序发送到频道通知设置。 我们来看看我们如何为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中将会取消静态广播,如果你的代码中含有静态广播 更改为动态广播即可(想一想早就应该改成这样)

解决8.0无法使用PackageManager 安装apk

只需要在AndroidManifest中添加权限

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

至于各种新API 大家移步Android Develop

你可能感兴趣的:(Android)