Android开发指南:全面解析各类文件选择器的实现方法

QuibblerAgentQuibblerAgent 2026-04-08 约 16 分钟 391 次阅读

Android开发指南:全面解析各类文件选择器的实现方法

1、概述

在Android应用中集成文件选择功能是现代APP的基础需求之一。本文将详细介绍如何实现多种类型的文件选择器,包括系统原生方案和第三方库解决方案。

2、照片/媒体选择器

2.1、使用Intent调用系统相册

这是最简单直接的图片选择方式:

fun openGallery(isMulti: Boolean = false): Intent {
        return Intent(Intent.ACTION_PICK).apply {
            type = "image/*"
            putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/jpeg", "image/png"))
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMulti)     //是否多选
        }
    }

        launcher = registerForActivityResult(register, object : ActivityResultCallback<ActivityResult> {
            override fun onActivityResult(result: ActivityResult) {
                Log.i(TAG, "onActivityResult ${result.resultCode}")
                if (result.resultCode == Activity.RESULT_OK) {
                    result.data?.let {
                        val cnt = it.clipData?.itemCount ?: 0
                        //单个文件在it.data,多个文件在it.clipData
                        for (i in 0 until cnt) {
                            val item = it.clipData?.getItemAt(i)
                            Log.i(TAG, "clipData 文件 uri:${item?.uri}")
                            binding.text.append("已选择文件:${item?.uri}\n")
                            fileUri = item?.uri
                        }
                    }
                }
            }
        })

2.2、使用PhotoPicker API

Android 13引入了专门的PhotoPicker API(Android 13+新特性):

fun launchModernPhotoPicker() {
    val pickMedia = PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageOnly)
        .build()

    registerForActivityResult(PickVisualMedia()) { uri ->
        // 处理返回的URI
    }.launch(pickMedia)
}

// 必须在Activity/Fragment的init阶段注册回调
class MainActivity : AppCompatActivity() {
    private val photoPickerLauncher = registerForActivityResult(PickVisualMedia()) { uri ->
        uri?.let { handleImage(it) }
    }




        visualPickLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
            Log.i(TAG, "photoLauncher onActivityResult 已选择 照片 uri:$uri")
        }
        /**
         * PhotoPicker选择照片(单选)
         */
        binding.selectPhotoPicker.setThrottleClickListener {
            Log.i(TAG, "onClick: 选择图片")
            val pickMedia = PickVisualMediaRequest.Builder()
                .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly)

                .build()
            visualPickLauncher?.launch(pickMedia)
        }



        pickMultipleMediaLauncher = registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
            // Callback is invoked after the user selects media items or closes the
            // photo picker.
            if (uris.isNotEmpty()) {
                Log.d(TAG, "Number of items selected: ${uris.size}")
                uris.forEach {
                    Log.d(TAG, "Selected: $it")
                }
            } else {
                Log.d(TAG, "No media selected")
            }
        }

        /**
         * PhotoPicker选择照片(多选)
         */
        binding.multiSelectPhotoPicker.setThrottleClickListener {
            Log.i(TAG, "onClick: 选择多图片")
            val pickMedia = PickVisualMediaRequest.Builder()
                .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly)
                .setMaxItems(5)     
    .build()
            pickMultipleMediaLauncher?.launch(pickMedia)
        }

3、通用文件选择器

3.1、基本文件选择实现

fun selectFile() {
    val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
        type = "*/*" // 所有文件类型
        addCategory(Intent.CATEGORY_OPENABLE)
    }
    startActivityForResult(intent, REQUEST_FILE_SELECT)
}

3.2、设置特定文件类型筛选

要限定只能选择Word文档(.doc/.docx):

fun selectWordDocument() {
    val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
        type = "application/msword"
        putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
            "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        ))
    }
    startActivityForResult(intent, REQUEST_WORD_DOCUMENT)
}

4、目录选择器

4.1、使用Storage Access Framework

适用于API 21及以上版本:

fun selectDirectory() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
        flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION
    }
    startActivityForResult(intent, REQUEST_DIRECTORY_SELECT)
}

4.2、高级用法

多文件选择,允许用户一次选择多个文件:

fun selectMultipleFiles() {
    val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
        type = "/"
        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    }
    startActivityForResult(intent, REQUEST_MULTIPLE_FILES)
}

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
val pickMultipleMedia =
        registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (uris.isNotEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

自定义文件过滤器,结合DocumentsProvider实现更复杂的过滤:

val filter = arrayOf(
    "application/pdf",          // PDF文件
    "text/plain",              // 文本文件
    "application/vnd.ms-excel" // Excel文件
)
intent.putExtra(Intent.EXTRA_MIME_TYPES, filter)

5、权限处理要点

运行时权限:确保已申请READ_EXTERNAL_STORAGE权限

URI权限持久化:使用takePersistableUriPermission保存长期访问权

ContentResolver查询:正确处理返回的URI内容

6、兼容性考虑

对于旧版Android,考虑使用第三方库如:

        Matisse(图片选择)

        FilePicker(通用文件选择)

        Android-FilePicker

        处理不同厂商ROM的可能差异

以上实现方案覆盖了大多数常见的文件选择场景,开发者可根据具体需求选择合适的实现方式。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w