媒体通知中LargeIcon像素化求助:原图质量良好但显示模糊
媒体通知专辑封面LargeIcon像素化问题解决方法
问题描述
开发媒体通知时,专辑封面作为LargeIcon显示严重像素化,但三星音乐使用同一张封面的通知却保持高清。具体对比:
- 我的通知:像素化封面
- 三星音乐通知:高清封面
- 我的播放器内:封面显示清晰
- 三星音乐播放器内:封面显示清晰
已尝试的无效修复方案:
- 通过MediaMetadata设置LargeIcon:通知无封面
- 手动缩放Bitmap:仅改变封面位置,像素化问题未解决
- 使用drawable目录本地图片作为LargeIcon:显示正常
无论播放歌曲类型、原图分辨率如何,LargeIcon均呈现像素化,需实现与三星音乐一致的高清通知封面效果。
相关代码
private fun buildNotification(song: Song, isPlaying: Boolean): Notification { val playPauseAction = if (isPlaying) { NotificationCompat.Action( R.drawable.ic_pause, "Pause", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PAUSE) ) } else { NotificationCompat.Action( R.drawable.ic_play_arrow, "Play", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY) ) } val style = androidx.media.app.NotificationCompat.MediaStyle() .setShowActionsInCompactView(0) .setMediaSession(mediaSession.sessionToken) // val metadataBuilder = MediaMetadataCompat.Builder() // .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.songName) // .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.songArtist) // .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getBitmapFromUri(song.songCover)) // used as largeIcon // // mediaSession.setMetadata(metadataBuilder.build()) return NotificationCompat.Builder(this, "shufflo_music_channel") .setContentTitle(song.songName) .setContentText(song.songArtist) .setLargeIcon(getBitmapFromUri(song.songCover)) //.setLargeIcon( // BitmapFactory.decodeResource(getResources(), R.drawable.test).scale(128, 128, false)) .setSmallIcon(R.drawable.ic_album_art_placeholder) .addAction(playPauseAction) .setStyle(style) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setPriority(NotificationCompat.PRIORITY_HIGH) .setOnlyAlertOnce(true) .setOngoing(isPlaying) // important for making it non-dismissible .build() } private fun getBitmapFromUri(uri: Uri): Bitmap? { return try { val inputStream = contentResolver.openInputStream(uri) val original = BitmapFactory.decodeStream(inputStream) inputStream?.close() original //original?.scale(128, 128, false) } catch (e: Exception) { e.printStackTrace() null } }
问题根源
直接用BitmapFactory.decodeStream解码Uri得到的Bitmap未适配设备屏幕密度(DPI),通知系统缩放时导致像素化。三星音乐这类应用会根据LargeIcon最优尺寸对原图做采样和缩放,同时匹配屏幕密度,因此显示清晰。
修复方案
1. 获取通知LargeIcon最优尺寸
通知LargeIcon推荐尺寸为192x192dp,可通过系统资源获取对应像素值:
private fun getNotificationLargeIconSize(context: Context): Int { val res = context.resources return res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width) }
2. 优化Bitmap解码流程
修改getBitmapFromUri方法,通过BitmapFactory.Options采样,避免加载过大Bitmap,同时保证缩放清晰度:
private fun getBitmapFromUri(uri: Uri, context: Context): Bitmap? { return try { var inputStream = context.contentResolver.openInputStream(uri) ?: return null // 先获取原图尺寸,不加载到内存 val options = BitmapFactory.Options() options.inJustDecodeBounds = true BitmapFactory.decodeStream(inputStream, null, options) inputStream.close() // 计算采样率,适配目标尺寸 val targetSize = getNotificationLargeIconSize(context) options.inSampleSize = calculateInSampleSize(options, targetSize, targetSize) options.inJustDecodeBounds = false // 开启DPI匹配,保证缩放适配屏幕 options.inScaled = true options.inDensity = options.outWidth options.inTargetDensity = context.resources.displayMetrics.densityDpi inputStream = context.contentResolver.openInputStream(uri) val bitmap = BitmapFactory.decodeStream(inputStream, null, options) inputStream?.close() bitmap } catch (e: Exception) { e.printStackTrace() null } } private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { val height = options.outHeight val width = options.outWidth var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight = height / 2 val halfWidth = width / 2 while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
3. 更新通知构建代码
在buildNotification中调用优化后的方法:
.setLargeIcon(getBitmapFromUri(song.songCover, this))
额外注意事项
- 避免直接使用
Bitmap.scale方法,该方法缩放算法优化不足,解码阶段处理效率更高、清晰度更好。 - 若需通过MediaSession传递封面,确保
METADATA_KEY_ALBUM_ART使用优化后的Bitmap,且MediaSession已正确关联到通知的MediaStyle。
内容的提问来源于stack exchange,提问作者Steve Campos
相关产品推荐
相关产品推荐

