如何使用图片URL作为通知素材,替代drawable目录下的本地图片资源?
问题原因说明
BitmapFactory.decodeResource只能加载本地drawable资源,无法直接处理网络URL,且Android禁止在主线程发起网络请求,所以直接填写URL会触发报错。
注意:通知的setSmallIcon方法是Android系统硬性要求,必须使用本地drawable资源,无法替换为网络图片
实现步骤
1. 添加必要权限
在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
如果适配Android 13及以上版本,还需要添加通知权限:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
2. 选择加载方案
方案1:使用Glide(推荐,自动处理子线程、缓存、异常)
首先在app模块的build.gradle中添加依赖:
dependencies { implementation 'com.github.bumptech.glide:glide:4.16.0' kapt 'com.github.bumptech.glide:compiler:4.16.0' }
修改通知发送代码如下:
private fun sendNotification(title: String, message: String, productImageUrl: String, logoUrl: String) { val intent: Intent = Intent(this, SplashActivity::class.java).apply { flags=Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } // Android 12及以上PendingIntent必须显式指定FLAG_IMMUTABLE或FLAG_MUTABLE val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_IMMUTABLE) // 子线程异步加载网络图片 CoroutineScope(Dispatchers.IO).launch { // 加载通知大图 val productBitmap = Glide.with(applicationContext) .asBitmap() .load(productImageUrl) .submit() .get() // 加载通知大图标 val logoBitmap = Glide.with(applicationContext) .asBitmap() .load(logoUrl) .submit() .get() // 切回主线程构建发送通知 withContext(Dispatchers.Main) { val builder = NotificationCompat.Builder(this@YourActivityClassName, CHANNEL_ID) .setSmallIcon(R.drawable.product_image) // 必须保留本地资源作为小图标 .setContentTitle(title) .setContentText(message) .setLargeIcon(logoBitmap) .setStyle(NotificationCompat.BigPictureStyle().bigPicture(productBitmap)) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_DEFAULT) with(NotificationManagerCompat.from(this@YourActivityClassName)) { if (ActivityCompat.checkSelfPermission( this@YourActivityClassName, Manifest.permission.POST_NOTIFICATIONS ) != PackageManager.PERMISSION_GRANTED ) { // 无通知权限时可在此处申请权限后再发送 return@withContext } notify(notificationId, builder.build()) } } } }
将代码中的YourActivityClassName替换为你当前Activity的类名即可。
方案2:原生代码实现(无需第三方库)
如果不想引入额外依赖,可以自己实现网络下载Bitmap的方法,必须在子线程调用:
private fun getBitmapFromUrl(imageUrl: String): Bitmap? { return try { val url = URL(imageUrl) val connection = url.openConnection() as HttpURLConnection connection.doInput = true connection.connect() val inputStream = connection.inputStream BitmapFactory.decodeStream(inputStream) } catch (e: Exception) { e.printStackTrace() // 加载失败返回默认本地图片兜底 BitmapFactory.decodeResource(resources, R.drawable.default_error_image) } }
后续调用逻辑和方案1一致,在IO协程中调用该方法获取两张Bitmap后,切回主线程发送通知即可。
注意事项
- 所有网络图片加载操作必须在子线程执行,禁止主线程直接发起网络请求
- 如果你的Firebase Storage文件没有设置公共读权限,要确保使用的是Firebase SDK生成的带鉴权参数的有效下载URL,否则会加载失败
- 建议添加加载失败的兜底图片,避免网络异常时通知显示异常
内容的提问来源于stack exchange,提问作者Codist
相关产品推荐
相关产品推荐

