Kotlin中Retrofit下载ResponseBody后:自动打开、通知及返回处理问题
文件下载与打开功能问题修复方案
问题1:无对应打开应用时无任何反应
直接启动ACTION_VIEW Intent如果没有匹配的Activity会静默失败,必须先做兼容性校验:
- 调用
packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)判断是否有可处理的Activity - 若返回
null,弹出提示告知用户无可用应用
问题2:无下载完成通知
系统浏览器/邮件的下载通知是通过系统DownloadManager或自定义通知实现的,手动写文件不会自动触发,可通过以下方式实现:
- 创建通知渠道(Android 8.0+强制要求)
- 构建下载完成通知,点击通知可打开文件
- 通知需关联文件的Content URI,确保权限正确
问题3:打开新视图后无法处理返回操作
当前用requireContext().startActivity(intent)启动Activity可能导致返回栈异常,改用requireActivity()启动,确保Activity在当前应用的返回栈中;若需处理返回结果,可使用registerForActivityResult替代直接启动。
修正后的完整代码
override fun onSuccess(result: Response<ResponseBody>) { try { // 用File构造函数拼接路径,避免字符串拼接错误 val fileName = "${idEmail}_${intitule.replace("/", "_")}$extensionFichier" file = File(requireContext().filesDir, fileName) file.writeBytes(result.body()!!.bytes()) // 修正MIME类型错误,补充标准格式 val type = when(extensionFichier.lowercase()) { ".png", ".jpg", ".jpeg", ".gif" -> "image/*" ".pdf" -> "application/pdf" ".xls" -> "application/vnd.ms-excel" ".xlsx" -> "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ".doc" -> "application/msword" ".docx" -> "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ".ppt" -> "application/vnd.ms-powerpoint" ".pptx" -> "application/vnd.openxmlformats-officedocument.presentationml.presentation" ".zip" -> "application/zip" ".rar" -> "application/x-rar-compressed" ".mp3", ".m4a", ".wav" -> "audio/*" ".3gp", ".mpg", ".mpeg", ".mpe", ".mp4", ".avi" -> "video/*" ".txt" -> "text/plain" else -> "*/*" } // 构建打开文件的Intent val uri = FileProvider.getUriForFile( requireContext(), BuildConfig.APPLICATION_ID + ".provider", file ) val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(uri, type) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } // 校验是否有可用应用处理Intent val packageManager = requireContext().packageManager if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { requireActivity().startActivity(intent) // 用Activity启动保证返回栈正常 } else { Toast.makeText(requireContext(), "无可用应用打开此文件", Toast.LENGTH_SHORT).show() } // 发送下载完成通知 sendDownloadCompleteNotification(fileName, uri) } catch (e: Exception) { e.printStackTrace() Toast.makeText(requireContext(), "文件处理失败:${e.message}", Toast.LENGTH_SHORT).show() } } // 发送下载完成通知的方法 private fun sendDownloadCompleteNotification(fileName: String, fileUri: Uri) { val context = requireContext() // Android 8.0+ 创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelId = "download_channel" val channelName = "下载通知" val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT).apply { description = "文件下载完成通知" } val notificationManager = context.getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(channel) } // 构建通知点击Intent val openIntent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(fileUri, context.contentResolver.getType(fileUri)) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } val pendingIntent = PendingIntent.getActivity( context, 0, openIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // 构建通知 val notification = NotificationCompat.Builder(context, "download_channel") .setSmallIcon(R.drawable.ic_download_done) // 替换为你的应用图标资源 .setContentTitle("下载完成") .setContentText(fileName) .setContentIntent(pendingIntent) .setAutoCancel(true) .build() // 发送通知 val notificationManager = context.getSystemService(NotificationManager::class.java) notificationManager.notify(1001, notification) // 1001为自定义通知ID }
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

