You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android后台/关闭状态下FCM通知无法显示可展开图片求助

解决FCM后台/关闭状态下可展开通知图片不显示的问题

首先,你的问题核心在于后台Service中异步加载Bitmap的可靠性不足,以及Glide在Service上下文下的配置问题。当应用处于后台或关闭状态时,MyFirebaseMessagingService的生命周期很短,你用的AsyncTask可能还没完成图片加载,Service就被系统回收了,导致onPostExecute根本没机会执行,自然无法显示带图片的通知。另外,Glide在Service中直接使用当前上下文也可能存在上下文回收的风险。

下面是具体的修复方案:

方案1:优化Glide加载逻辑,替换AsyncTask为回调方式

放弃AsyncTask,改用Glide的listener回调来获取Bitmap,同时使用Application Context确保上下文稳定:

public void backGroundNotification() {
    Intent intent = new Intent(this, MainActivity.class);
    intent.putExtra("title", title);
    intent.putExtra("text", body);
    intent.putExtra("imageUrl", imageUrl);
    intent.putExtra("type", type);
    intent.putExtra("id", id);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    pendingIntentPromo = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);

    // 用Application Context初始化Glide,避免Service上下文被回收
    Glide.with(getApplicationContext())
         .asBitmap()
         .load(imageUrl)
         .override(100, 100)
         .listener(new RequestListener<Bitmap>() {
             @Override
             public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                 e.printStackTrace();
                 Log.e("noti exp", "图片加载失败: " + e.getMessage());
                 // 加载失败时显示普通通知兜底
                 showBasicNotification();
                 return false;
             }

             @Override
             public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                 // 图片加载完成后构建带大图的通知
                 showBigPictureNotification(resource);
                 return false;
             }
         })
         .submit();
}

// 显示普通通知(图片加载失败时使用)
private void showBasicNotification() {
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.app_icon)
            .setContentTitle(title)
            .setContentText(body)
            .setAutoCancel(true)
            .setTicker("DealDio")
            .setSound(sound)
            .setVibrate(vibration)
            .setContentIntent(pendingIntentPromo);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, notificationBuilder.build());
}

// 显示带大图的通知
private void showBigPictureNotification(Bitmap bitmap) {
    NotificationCompat.BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle()
            .bigPicture(bitmap)
            .bigLargeIcon(null)
            .setSummaryText(body);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.app_icon)
            .setContentTitle(title)
            .setContentText(body)
            .setAutoCancel(true)
            .setTicker("DealDio")
            .setSound(sound)
            .setVibrate(vibration)
            .setContentIntent(pendingIntentPromo)
            .setStyle(bigPictureStyle);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, notificationBuilder.build());
}

方案2:使用WorkManager确保任务稳定执行

如果后台Service被系统回收的概率很高,推荐用WorkManager来处理图片加载和通知构建,它是Android官方推荐的后台任务组件,能在系统限制下保证任务完成:

1. 添加WorkManager依赖

在build.gradle中添加:

implementation "androidx.work:work-runtime:2.8.1"

2. 创建WorkManager任务类

public class NotificationWorker extends Worker {
    private static final String KEY_TITLE = "title";
    private static final String KEY_BODY = "body";
    private static final String KEY_IMAGE_URL = "imageUrl";
    private static final String KEY_TYPE = "type";
    private static final String KEY_ID = "id";

    public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 获取传递的参数
        String title = getInputData().getString(KEY_TITLE);
        String body = getInputData().getString(KEY_BODY);
        String imageUrl = getInputData().getString(KEY_IMAGE_URL);
        String type = getInputData().getString(KEY_TYPE);
        String id = getInputData().getString(KEY_ID);

        // 同步加载Bitmap(doWork本身在后台线程,可安全使用同步方法)
        Bitmap bitmap = null;
        try {
            bitmap = Glide.with(getApplicationContext())
                    .asBitmap()
                    .load(imageUrl)
                    .override(100, 100)
                    .submit()
                    .get();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("noti exp", "图片加载失败: " + e.getMessage());
        }

        // 构建跳转Intent
        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        intent.putExtra("title", title);
        intent.putExtra("text", body);
        intent.putExtra("imageUrl", imageUrl);
        intent.putExtra("type", type);
        intent.putExtra("id", id);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);

        // 构建通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext())
                .setSmallIcon(R.drawable.app_icon)
                .setContentTitle(title)
                .setContentText(body)
                .setAutoCancel(true)
                .setTicker("DealDio")
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setVibrate(new long[]{1000, 1000})
                .setContentIntent(pendingIntent);

        // 如果图片加载成功,添加大图样式
        if (bitmap != null) {
            NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle()
                    .bigPicture(bitmap)
                    .bigLargeIcon(null)
                    .setSummaryText(body);
            builder.setStyle(style);
        }

        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, builder.build());

        return Result.success();
    }

    // 对外提供启动任务的方法
    public static void startNotificationWork(Context context, String title, String body, String imageUrl, String type, String id) {
        Data inputData = new Data.Builder()
                .putString(KEY_TITLE, title)
                .putString(KEY_BODY, body)
                .putString(KEY_IMAGE_URL, imageUrl)
                .putString(KEY_TYPE, type)
                .putString(KEY_ID, id)
                .build();

        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class)
                .setInputData(inputData)
                .build();

        WorkManager.getInstance(context).enqueue(workRequest);
    }
}

3. 在MyFirebaseMessagingService中调用WorkManager

public void backGroundNotification() {
    // 直接启动WorkManager任务,无需自己处理线程和生命周期
    NotificationWorker.startNotificationWork(this, title, body, imageUrl, type, id);
}

关键原因解释

  1. AsyncTask的不可靠性:后台Service的生命周期不受开发者完全控制,AsyncTask依赖Service存活,一旦Service被系统回收,AsyncTask会被终止,onPostExecute无法执行。
  2. Glide上下文问题:使用Service的this作为Glide上下文,当Service销毁时,Glide的加载任务会被取消;改用Application Context能避免这个风险。
  3. WorkManager的优势:它会根据系统状态自动调度任务,即使应用被关闭,也能在合适的时机完成任务,是处理后台通知这类需求的最优解。

内容的提问来源于stack exchange,提问作者Rahul Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:01:32