Skip to content

[ZH] 4.自定义 Notification

jrfeng edited this page Mar 9, 2021 · 9 revisions

可以通过继承以下类来创建一个自定义的 Notification:

其中,PlayerService.NotificationView 是个抽象类,它是通知栏控制器的基类。PlayerService.MediaNotificationView 继承并实现了 PlayerService.NotificationView 类,并提供了一个基于 NotificationCompat.MediaStyle 样式的通知栏控制器。

提示:关于 NotificationCompat.MediaStyle 样式,请参考 Android 官方文档:使用媒体控件创建通知

继承 PlayerService.MediaNotificationView

可以覆盖 PlayerService.MediaNotificationView 的以下方法对其进行自定义:

例:

public class MyMediaNotificationView extends PlayerService.MediaNotificationView {
    ...
    
    @NonNull
    @Override
    protected Bitmap getDefaultIcon() {
        return mMyDefaultIcon;
    }

    @Override
    protected int getSmallIconId() {
        return R.drawable.my_small_icon_id;
    }

    @Override
    protected void onBuildMediaStyle(NotificationCompat.MediaStyle mediaStyle) {
        // 下面这行代码是可选的
        super.onBuildMediaStyle(mediaStyle);

        // 配置 NotificationCompat.MediaStyle
    }

    @Override
    protected void onBuildNotification(androidx.core.app.NotificationCompat.Builder builder) {
        // 下面这行代码是可选的
        super.onBuildNotification(builder);

        // 配置 NotificationCompat.Builder
    }
}

关于 NotificationCompat.MediaStyle 的更多内容,请参考请参考 Android 官方文档:使用媒体控件创建通知

继承 PlayerService.NotificationView

PlayerService.NotificationView 是个抽象类,子类需要实现以下抽象方法:

例:

public class MyCustomNotificationView extends PlayerService.NotificationView {
    // ...

    @Override
    public Notification onCreateNotification() {
        // return a Notification instance
    }

    @Override
    public int getNotificationId() {
        return 1;
    }
}

注意!使用 NotificationCompat.Builder 创建 Notification 对象时,其 channelId 应该设置为 PlayerService.NotificationView.CHANNEL_ID

例:

NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext(), PlayerService.NotificationView.CHANNEL_ID);

添加 Notification 动作

可以使用 buildCustomAction(String actionName, PlayerService.CustomAction customAction) 方法创建一个要与 Notification 动作进行关联的 PendingIntent 对象。

例:

public static class MediaNotificationView extends NotificationView {
    private static final String ACTION_SKIP_TO_PREVIOUS = "SKIP_TO_PREVIOUS";
    private static final String ACTION_PLAY_PAUSE = "PLAY_PAUSE";
    private static final String ACTION_SKIP_TO_NEXT = "SKIP_TO_NEXT";

    private PendingIntent mSkipToPrevious;
    private PendingIntent mPlayPause;
    private PendingIntent mSkipToNext;

    @Override
    protected void onInit(Context context) {
        // 创建 “上一曲” PendingIntent
        mSkipToPrevious = buildCustomAction(ACTION_SKIP_TO_PREVIOUS, new CustomAction() {
                @Override
                public void doAction(@NonNull Player player, @Nullable Bundle extras) {
                    player.skipToPrevious();
                }
            });

        // 创建 “播放/暂停” PendingIntent
        mPlayPause = buildCustomAction(ACTION_PLAY_PAUSE, new CustomAction() {
            @Override
            public void doAction(@NonNull Player player, @Nullable Bundle extras) {
                player.playPause();
            }
        });

        // 创建 “下一曲” PendingIntent
        mSkipToNext = buildCustomAction(ACTION_SKIP_TO_NEXT, new CustomAction() {
            @Override
            public void doAction(@NonNull Player player, @Nullable Bundle extras) {
                player.skipToNext();
            }
        });
    }

    ...

    protected void onBuildNotification(NotificationCompat.Builder builder) {
        // 添加 “上一曲” 动作
        builder.addAction(R.drawable.snow_ic_skip_previous, "skip_to_previous", mSkipToPrevious);

        // 添加 “播放/暂停” 动作
        if (isPlayingState()) {
            builder.addAction(R.drawable.snow_ic_pause, "pause", mPlayPause);
        } else {
            builder.addAction(R.drawable.snow_ic_play, "play", mPlayPause);
        }

        // 添加 “下一曲” 动作
        builder.addAction(R.drawable.snow_ic_skip_next, "skip_to_next", mSkipToNext);
    }
}

应用自定义通知栏控制器

通过覆盖 PlayerServiceonCreateNotificationView() 方法来应用自定义的通知栏控制器。

例:

@PersistenId("MyPlayerService")
public MyPlayerService extends PlayerService {
    ...
    
    @Nullable
    @Override
    protected NotificationView onCreateNotificationView() {
        return new MyCustomNotificationView();
    }
}

加载 Icon

PlayerService.NotificationView 实现了 Icon 加载功能。你可以对其进行配置,或者实现你自己的 Icon 加载逻辑。

可以调用以下方法配置 Icon 加载功能:

可以覆盖 onInit(Context) 方法,并在该方法中完成以上设置。

自定义 Icon 加载

可以覆盖 NotificationViewonCreateBetterIconLoader(Context context) 方法并返回一个自定义的 BetterIconLoader 来自定义 Icon 加载功能。

// 自定义 BetterIconLoader
public class MyBetterIconLoader implements PlayerService.NotificationView.BetterIconLoader {
    @Override
    public void loadIcon(@NonNull MusicItem musicItem, int width, int height, @NonNull AsyncResult<Bitmap> result) {
        // ...加载图片
        // 该方法会在异步线程中执行
        // 当图片加载成功时,应该调用 result 参数的 onSuccess(Bitmap) 方法返回它
        // 当图片加载过程中发生错误,应该调用 result 参数的 onError(Throwable) 方法发出错误通知
    }
}

// 使用自定义的 BetterIconLoader
public class MyNotificationView extends PlayerService.MediaNotificationView {
    ...

    @NonNull
    @Override
    protected BetterIconLoader onCreateBetterIconLoader(@NonNull Context context) {
        return new MyBetterIconLoader();
    }
}

图片加载失败时将使用默认图片。可以使用 setDefaultIcon(Bitmap) 方法设置默认图片。

隐藏通知栏控制器

如果你不需要在通知栏中显示通知栏控制器,可以覆盖 PlayerServiceonCreateNotificationView() 方法并返回 null 即可。

例:

@PersistenId("MyPlayerService")
public class MyPlayerService extends PlayerService{
    ...
    
    @Nullable
    @Override
    public NotificationView onCreateNotificationView() {
        // 返回 null 会隐藏通知栏控制器
        return null;
    }
}

End