上一篇
安卓加载网络文件数组
- 行业动态
- 2025-04-24
- 3981
安卓通过异步网络请求获取文件流,读取为字节数组或字符串数组,需处理异常及权限
网络请求基础
在安卓中加载网络文件通常需要结合网络请求库(如OkHttp、Retrofit)和文件处理工具,以下是核心步骤:
- 添加依赖(以Retrofit为例):
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
- 定义API接口:
public interface FileApi { @GET Call<ResponseBody> downloadFile(@Url String fileUrl); }
- 创建Retrofit实例:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://example.com/") // 基础URL需匹配实际服务端 .addConverterFactory(GsonConverterFactory.create()) .build(); FileApi api = retrofit.create(FileApi.class);
多文件并发加载
若需加载多个网络文件(如图片数组),可通过线程池或协程实现并发:
Java线程池方案:
ExecutorService executor = Executors.newFixedThreadPool(4); // 限制最大并发数 List<String> urlList = Arrays.asList("url1", "url2", "url3"); List<Future<File>> futures = new ArrayList<>(); for (String url : urlList) { futures.add(executor.submit(() -> { ResponseBody response = api.downloadFile(url).execute().body(); if (response != null) { File file = new File(getCacheDir(), URLEncoder.encode(url, "UTF-8")); try (InputStream is = response.byteStream()) { Files.copy(is, file.toPath()); } return file; } return null; })); }
Kotlin协程方案:
suspend fun downloadFiles(urls: List<String>): List<File> = coroutineScope { urls.map { url -> async(Dispatchers.IO) { try { val response = api.downloadFile(url).execute() response.body()?.let { responseBody -> File(cacheDir, URLEncoder.encode(url, "UTF-8")).apply { responseBody.byteStream().use { input -> outputStream().use { output -> input.copyTo(output) } } } } } catch (e: Exception) { null // 处理异常 } } }.awaitAll().filterNotNull() }
数据结构与解析
文件存储结构
字段 | 类型 | 说明 |
---|---|---|
fileName | String | 原始文件名 |
localPath | String | 本地存储路径 |
size | Long | 文件大小(字节) |
status | Enum | 下载状态(成功/失败/进行中) |
自定义数据类(Kotlin)
data class NetworkFile( val fileName: String, val localPath: String, var size: Long = 0, var status: DownloadStatus = DownloadStatus.PENDING ) enum class DownloadStatus { PENDING, DOWNLOADING, SUCCESS, FAILED }
性能优化策略
优化方向 | 具体措施 |
---|---|
并发控制 | 限制同时下载任务数(如线程池大小设为4),避免内存占用过高 |
缓存复用 | 使用OkHttp 缓存或LruCache 存储已下载文件,减少重复网络请求 |
流量压缩 | 对图片等大文件启用Gzip压缩(需服务端支持) |
断点续传 | 记录已下载字节数,通过Range 请求头实现断点续传(需服务端支持) |
错误处理机制
- 网络异常:捕获
IOException
,提示用户检查网络连接。 - 文件损坏:校验MD5或文件大小,若不一致则重新下载。
- 存储权限:Android 11+需动态申请
MANAGE_EXTERNAL_STORAGE
权限。
相关问题与解答
问题1:如何将下载的网络文件保存到外部存储?
解答:
- 声明存储权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- 动态申请权限(Android 6.0+):
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); }
- 保存路径示例:
File externalDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File file = new File(externalDir, "network_file_" + System.currentTimeMillis());
问题2:如何实现大文件的断点续传?
解答:
- 服务端支持:确保服务端响应
Accept-Ranges: bytes
。 - 记录进度:使用
SQLite
或SharedPreferences
保存已下载字节数。 - Range请求:
Request request = new Request.Builder() .url(url) .addHeader("Range", "bytes=" + downloadedBytes + "-") .build();
- 续传逻辑:
- 检查本地是否存在未完成文件。
- 若存在,读取已下载大小并发起带
Range
头的