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

Android 14(API 34)中从Activity设置铃声崩溃的修复请求

修复Android 14+设置默认铃声崩溃问题

问题根源

Android 14(API 34)开始,系统禁止直接修改MediaStore.MediaColumns.DATA字段(该字段变为只读),你的代码中在ContentValues里添加了这个字段,导致插入MediaStore时抛出IllegalArgumentException: Mutation of _data is not allowed。

修复方案

1. 移除DATA字段的设置

删除values.put(MediaStore.MediaColumns.DATA, f.getAbsolutePath());这一行,Android 14+会自动管理媒体文件的存储路径。

2. 简化文件写入流程

不需要先将raw资源写入自己的外部文件目录,直接通过MediaStore返回的Uri写入流,减少冗余操作。

3. 修正其他细节

  • MediaStore.Audio.Media.ARTIST应该传入字符串,而非资源ID(原代码用R.string.app_name,需改为getString(R.string.app_name))。
  • 统一使用try-with-resources管理流资源,避免资源泄漏。

修改后的完整代码

interface Tone {
    String PHONE_RINGTONE = "ringtone";
    String NOTIFICATION_TONE = "notification";
    String ALARM = "alarm";
}

public void setRingtone(String type) {
    ContentResolver mCr = getContentResolver();
    Uri mUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.horse);
    AssetFileDescriptor soundFile;
    try {
        soundFile = mCr.openAssetFileDescriptor(mUri, "r");
    } catch (FileNotFoundException e) {
        Toast.makeText(this, "无法读取音频资源", Toast.LENGTH_SHORT).show();
        return;
    }

    // 构建MediaStore插入参数
    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.TITLE, getString(R.string.app_name));
    values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg");
    values.put(MediaStore.Audio.Media.ARTIST, getString(R.string.app_name));

    if (Objects.equals(type, Tone.NOTIFICATION_TONE)) {
        values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
    } else if (Objects.equals(type, Tone.ALARM)) {
        values.put(MediaStore.Audio.Media.IS_ALARM, true);
    } else {
        values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
    }

    Uri newUri = null;
    try {
        // 插入MediaStore获取Uri
        newUri = mCr.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
        if (newUri == null) {
            Toast.makeText(this, "无法创建媒体条目", Toast.LENGTH_SHORT).show();
            return;
        }

        // 将raw资源写入MediaStore对应的流
        try (InputStream fis = soundFile.createInputStream();
             OutputStream os = mCr.openOutputStream(newUri)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();
        }

        // 设置默认铃声/通知/闹钟
        int ringtoneType;
        String settingsKey;
        String successMsg;

        if (Objects.equals(type, Tone.NOTIFICATION_TONE)) {
            ringtoneType = RingtoneManager.TYPE_NOTIFICATION;
            settingsKey = Settings.System.NOTIFICATION_SOUND;
            successMsg = "通知铃声修改成功";
        } else if (Objects.equals(type, Tone.ALARM)) {
            ringtoneType = RingtoneManager.TYPE_ALARM;
            settingsKey = Settings.System.ALARM_ALERT;
            successMsg = "闹钟铃声修改成功";
        } else {
            ringtoneType = RingtoneManager.TYPE_RINGTONE;
            settingsKey = Settings.System.RINGTONE;
            successMsg = "来电铃声修改成功";
        }

        RingtoneManager.setActualDefaultRingtoneUri(this, ringtoneType, newUri);
        Settings.System.putString(mCr, settingsKey, newUri.toString());
        showMessage("完成", successMsg);

    } catch (IOException e) {
        Toast.makeText(this, "写入音频失败: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
        // 插入失败时删除已创建的MediaStore条目
        if (newUri != null) {
            mCr.delete(newUri, null, null);
        }
    } catch (Throwable t) {
        Toast.makeText(this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
        if (newUri != null) {
            mCr.delete(newUri, null, null);
        }
    }
}

额外说明

  • 权限:Android 13及以下需申请WRITE_EXTERNAL_STORAGE权限,Android 14+写入MediaStore无需该权限,但访问自身外部文件目录仍需适配权限规则。
  • MIME类型:直接指定audio/mpeg比通过getMIMEType解析更可靠,避免路径解析错误。
  • 错误处理:新增Uri为空的判断,插入失败时删除已创建的媒体条目,避免残留无效内容。

内容的提问来源于stack exchange,提问作者Ivan Rancic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:25:54