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

Android录制更新Notification时触发TransactionTooLargeException求助

解决RemoteView更新Notification触发TransactionTooLargeException的问题

我太懂你这个困扰了——明明已经把要更新的数据压到最小,用CountDownTimer更新录制时长的Notification还是触发了TransactionTooLargeException。其实问题核心不是你传递的文本数据,而是每次更新都重新构建整个Notification对象,导致Binder传输的序列化数据累积过载,尤其是频繁调用notify()的时候。

下面结合你的代码,给几个针对性的解决方案:

1. 复用已构建的Notification,避免重复序列化全量数据

你现在每次调用mNotificationManager.notify()时,都通过mBuilder.build()重新生成全新的Notification,这会把所有PendingIntent、布局资源等都重新序列化一遍,哪怕你只改了时间文本。

修改步骤:

  • 先新增一个成员变量保存已构建的Notification:
private Notification mNotification; // 新增成员变量
  • 在showNotificationRecording()中构建并保存这个对象:
public void showNotificationRecording() {
    // ... 原有逻辑代码 ...
    mNotification = mBuilder.build(); // 保存构建好的Notification
    startForeground(NOTIFICATION_ID, mNotification);
}
  • 在showTimeRecording()里,只更新RemoteView内容,直接复用已有的Notification:
private void showTimeRecording(int convertToSecond) {
    int hours = convertToSecond / 3600;
    int minutes = (convertToSecond % 3600) / 60;
    int seconds = convertToSecond % 60;
    mRecordTime = String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds);
    mRecordTimeNotification = mRecordTime;
    mRemoteViews.setTextViewText(R.id.tv_notify_time, mRecordTimeNotification);
    
    // 只有状态真的变化时才更新,减少不必要的RemoteView操作
    String targetState = mContext.getString(R.string.recording_state);
    if (!mState.equals(targetState)) {
        mState = targetState;
        mRemoteViews.setTextViewText(R.id.tv_notify_status, mState);
    }
    
    // 直接复用已有的mNotification,无需重新build
    mNotificationManager.notify(NOTIFICATION_ID, mNotification);
}

2. 提前创建PendingIntent,避免重复生成

你现在每次调用showNotificationRecording()都会重新创建多个PendingIntent,这些Intent的序列化数据会增加Notification的体积。可以把PendingIntent的创建移到Service初始化阶段,复用同一个实例:

private PendingIntent mMainPendingIntent;
private PendingIntent mPauseAndResumePending;
private PendingIntent mSavePendingIntent;
private PendingIntent mDeletePendingIntent;

@Override
public void onCreate() {
    super.onCreate();
    // 提前创建所有需要的PendingIntent
    Intent notificationIntent = new Intent(this, MainActivity.class);
    mMainPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
    Intent pauseIntent = new Intent(this, RecordAudioService.class);
    pauseIntent.setAction(ACTION_PAUSE_AND_RESUME);
    mPauseAndResumePending = PendingIntent.getService(this, 0, pauseIntent, 0);
    
    Intent saveIntent = new Intent(this, RecordAudioService.class);
    saveIntent.setAction(ACTION_STOP_RECORD);
    mSavePendingIntent = PendingIntent.getService(this, 0, saveIntent, 0);
    
    Intent deleteIntent = new Intent(this, RecordAudioService.class);
    deleteIntent.setAction(ACTION_NOTIFICATION_DISCARD);
    mDeletePendingIntent = PendingIntent.getService(this, 0, deleteIntent, 0);
}

之后在showNotificationRecording()里直接使用这些提前创建好的PendingIntent即可。

3. 调整CountDownTimer间隔,减少更新频率

你的CountDownTimer设置250ms触发一次onTick,但实际每4次(也就是1秒)才更新一次时间。完全可以把间隔改成1000ms,减少不必要的回调和notify()调用:

public CountDownTimer countDownRecordingTime() {
    return new CountDownTimer(Long.MAX_VALUE, 1000) { // 把250改成1000
        @Override
        public void onTick(long millisUntilFinished) {
            mTime++; // 直接计数秒数,简化逻辑
            mHandler.post(() -> showTimeRecording(mTime));
            
            // 检查定时结束条件
            if (mTimerToEnd != 0 && mTimerToEnd == mTime) {
                onStopRecording();
            }
        }

        @Override
        public void onFinish() {}
    };
}

4. 优化RemoteView创建逻辑,避免重复实例化

在showNotificationRecording()的分支中,你多次重新创建mRemoteViews,可以优化成只创建一次,再根据模式调整内容:

public void showNotificationRecording() {
    isSecretModeEnable = mSharePreferencesSettings.getBoolean(RecordSettings.SECRET_MODE, false);
    Log.d(TAG, "isSecretModeEnable " + isSecretModeEnable);
    
    // 根据模式选择布局,只创建一次RemoteView
    int layoutId = isSecretModeEnable ? R.layout.notify_secret_mode_layout : R.layout.notify_recording_layout;
    mRemoteViews = new RemoteViews(getPackageName(), layoutId);
    
    mBuilder = new NotificationCompat.Builder(mContext);
    if (isSecretModeEnable) {
        mBuilder.setPriority(Notification.PRIORITY_MIN)
                .setSmallIcon(R.drawable.ic_notify_secret)
                .setContent(mRemoteViews);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_notify_save, mSavePendingIntent);
    } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
        }
        mBuilder.setSmallIcon(R.drawable.record_circle)
                .setPriority(Notification.PRIORITY_MAX)
                .setDefaults(Notification.DEFAULT_LIGHTS)
                .setContent(mRemoteViews)
                .setContentIntent(mMainPendingIntent);
        
        mRemoteViews.setTextViewText(R.id.tv_notify_time, mRecordTimeNotification);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_notify_pause_and_resume, mPauseAndResumePending);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_notify_save, mSavePendingIntent);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_notify_closed, mDeletePendingIntent);
        
        if (isRecording) {
            mRemoteViews.setImageViewResource(R.id.iv_notify_pause_and_resume, R.drawable.ic_notify_pause);
            mState = mContext.getString(R.string.recording_state);
        } else {
            mRemoteViews.setImageViewResource(R.id.iv_notify_pause_and_resume, R.drawable.ic_notify_record);
            mState = mContext.getString(R.string.pause_state);
        }
        mRemoteViews.setTextViewText(R.id.tv_notify_status, mState);
    }
    isShowNotification = true;
    mNotificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
    mNotification = mBuilder.build();
    startForeground(NOTIFICATION_ID, mNotification);
}

这些优化结合起来,能大幅减少每次Notification更新时传输的数据量,彻底避免触发TransactionTooLargeException。

内容的提问来源于stack exchange,提问作者Công Hải

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:28:00