Android模拟文件上传---------------找不到错误

本文对比分析了两个Android上传文件的请求类,其中一个类在实际使用中遇到问题,而另一个可以正常工作。主要探讨了multipart/form-data编码方式下,如何正确设置请求头及构建请求体,包括处理数据字符串、图片文件及token验证信息。

上传文件的时候,出现问题,却找不到错误,之前测试的是可以的,但就是有问题。

后来把测试类粘贴过来就可以了,但我实在是找不到二者间有什么区别,暂且放在这里,待以后再来分析。

出问题的类文件:

package com.md.util.request;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.md.entity.ImageForm;
import com.md.entity.TokenValidate;
import com.md.util.net.UrlString;
import com.md_c_test.MyApplication;
import com.md_c_test.R;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * Created by SECONDHEAVEN on 2015/12/10.
 */
public class UploadBodyAndImageRequest extends PostRequest {
    private static final String BOUNDARY = "---------------------------7d931c5d043e";
    private static final String ENTRY_BOUNDARY = "--" + BOUNDARY;
    private static final String END_BOUNDARY = ENTRY_BOUNDARY + "--\r\n";

    private List<ImageForm> imageList;
    private String dataBeanStr;

    public UploadBodyAndImageRequest(String url, String dataBeanStr, List<ImageForm> imageList, ResponseListener listener) {
        super(url, null, listener);
        this.imageList = imageList;
        this.dataBeanStr = dataBeanStr;
        Log.e("tokenINFO",dataBeanStr);
    }

    @Override
    public String getBodyContentType() {
        return "multipart/form-data;boundary=" + BOUNDARY;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
//        if (imageList == null || imageList.size() == 0) {
//            return null;
//        }
        int N = imageList.size();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageForm imageForm;
        try {

            StringBuffer sb = new StringBuffer();
            //表单格式
            //ENTRY_BOUNDARY
            //\r\n
            //Content-Disposition:form-data;name="upload"
            //\r\n
            //\r\n
            //content
            //\r\n

            //传输message内容
            sb.append(ENTRY_BOUNDARY);
            sb.append("\r\n");
            sb.append("Content-Disposition:form-data;name=\"");
            sb.append(UrlString.uploadDataTag);
            sb.append("\"");
            sb.append("\r\n");
            sb.append("\r\n");
            bos.write(sb.toString().getBytes(getParamsEncoding()));
            bos.write(dataBeanStr.getBytes(getParamsEncoding()));
            bos.write("\r\n".getBytes(getParamsEncoding()));


            //读取token信息
            SharedPreferences sharedPreferences = MyApplication.getContext()
                    .getSharedPreferences(MyApplication.getContext()
                            .getString(R.string.sharedPreferences_tokenInfo), Context.MODE_PRIVATE);

            int userId = sharedPreferences.getInt(MyApplication.getContext()
                    .getString(R.string.sharedPreference_tokenInfo_userId), -1);
            String token = sharedPreferences.getString(MyApplication.getContext()
                    .getString(R.string.sharedPreference_tokenInfo_token), "");

            TokenValidate tokenValidate = new TokenValidate(userId, token);
            //String tokenInfo = JsonConverter.toJson(tokenValidate);
            String tokenInfo ="{\"token\":\"1453604610717\",\"userId\":23}";
            Toast.makeText(MyApplication.getContext(),"123" + tokenInfo, Toast.LENGTH_LONG).show();
            Log.e("tokenINFO",tokenInfo);

            //传输token验证信息
            /*StringBuffer sbToken = new StringBuffer();
            sbToken.append(ENTRY_BOUNDARY);
            sbToken.append("\r\n");
            sbToken.append("Content-Disposition:form-data;name=\"");
            sbToken.append(MyApplication.getContext()
                    .getString(R.string.RequestParam_UserValidate_token));
            sbToken.append("\"");
            sbToken.append("\r\n");
            sbToken.append("\r\n");
            bos.write(sbToken.toString().getBytes(getParamsEncoding()));
            bos.write(tokenInfo.getBytes(getParamsEncoding()));
            bos.write("\r\n".getBytes(getParamsEncoding()));
*/
            StringBuffer sbToken = new StringBuffer();
            sbToken.append(ENTRY_BOUNDARY);
            sbToken.append("\r\n");
            sbToken.append("Content-Disposition:form-data;name=\"");
            sbToken.append("token");
            sbToken.append("\"");
            sbToken.append("\r\n");
            sbToken.append("\r\n");
            bos.write(sbToken.toString().getBytes(getParamsEncoding()));
            bos.write(tokenInfo.getBytes(getParamsEncoding()));
            bos.write("\r\n".getBytes(getParamsEncoding()));
            //传输message图片文件
            for (int i = 0; i < N; i++) {
                imageForm = imageList.get(i);
                StringBuffer sb1 = new StringBuffer();
                sb1.append(ENTRY_BOUNDARY);
                sb1.append("\r\n");
                sb1.append("Content-Disposition:form-data;name=\"");
                sb1.append(imageForm.getName());
                sb1.append("\";filename=\"" + imageForm.getPath());
                sb1.append("\"\r\nContent-Type:");
                sb1.append(imageForm.getMimeType());
                sb1.append("\r\n\r\n");
                bos.write(sb1.toString().getBytes(getParamsEncoding()));
                bos.write(imageForm.getValue());
                bos.write("\r\n".getBytes(getParamsEncoding()));

            }

            bos.write(END_BOUNDARY.getBytes(getParamsEncoding()));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bos.toByteArray();
    }
}



可以正常运行的类

package com.md.util.request;

import android.content.Context;
import android.content.SharedPreferences;

import com.android.volley.AuthFailureError;
import com.md.entity.ImageForm;
import com.md.entity.TokenValidate;
import com.md.util.net.JsonConverter;
import com.md.util.net.UrlString;
import com.md_c_test.MyApplication;
import com.md_c_test.R;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;



/**
 * Created by SECONDHEAVEN on 2015/12/10.
 */
public class UploadBodyAndImageRequest extends PostRequest {
    private static final String BOUNDARY = "---------------------------7d931c5d043e";
    private static final String ENTRY_BOUNDARY = "--" + BOUNDARY;
    private static final String END_BOUNDARY = ENTRY_BOUNDARY + "--\r\n";

    private List<ImageForm> imageList;
    private String dataBeanStr;

    public UploadBodyAndImageRequest(String url, String dataBeanStr, List<ImageForm> imageList, ResponseListener listener) {
        super(url, null, listener);
        this.imageList = imageList;
        this.dataBeanStr = dataBeanStr;
    }

    @Override
    public String getBodyContentType() {
        return "multipart/form-data;boundary=" + BOUNDARY;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
//        if (imageList == null || imageList.size() == 0) {
//            return null;
//        }
        int N = imageList.size();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageForm imageForm;
        try {

            StringBuffer sb = new StringBuffer();
            //表单格式
            //ENTRY_BOUNDARY
            //\r\n
            //Content-Disposition:form-data;name="upload"
            //\r\n
            //\r\n
            //content
            //\r\n

            //传输message内容
            sb.append(ENTRY_BOUNDARY);
            sb.append("\r\n");
            sb.append("Content-Disposition:form-data;name=\"");
            sb.append(UrlString.uploadDataTag);
            sb.append("\"");
            sb.append("\r\n");
            sb.append("\r\n");
            bos.write(sb.toString().getBytes(getParamsEncoding()));
            bos.write(dataBeanStr.getBytes(getParamsEncoding()));
            bos.write("\r\n".getBytes(getParamsEncoding()));


//读取token信息
            SharedPreferences sharedPreferences = MyApplication.getContext()
                    .getSharedPreferences(MyApplication.getContext()
                            .getString(R.string.sharedPreferences_tokenInfo), Context.MODE_PRIVATE);

            int userId = sharedPreferences.getInt(MyApplication.getContext()
                    .getString(R.string.sharedPreference_tokenInfo_userId), -1);
            String token = sharedPreferences.getString(MyApplication.getContext()
                    .getString(R.string.sharedPreference_tokenInfo_token), "");

            TokenValidate tokenValidate = new TokenValidate(userId, token);
            String tokenInfo = JsonConverter.toJson(tokenValidate);






            //传输token验证信息
            StringBuffer sbToken = new StringBuffer();
            sbToken.append(ENTRY_BOUNDARY);
            sbToken.append("\r\n");
            sbToken.append("Content-Disposition:form-data;name=\"");
            sbToken.append(MyApplication.getContext()
                    .getString(R.string.RequestParam_UserValidate_token));
            sbToken.append("\"");
            sbToken.append("\r\n");
            sbToken.append("\r\n");
            bos.write(sbToken.toString().getBytes(getParamsEncoding()));
            bos.write(tokenInfo.getBytes(getParamsEncoding()));
            bos.write("\r\n".getBytes(getParamsEncoding()));


            //传输message图片文件
            for (int i = 0; i < N; i++) {
                imageForm = imageList.get(i);
                StringBuffer sb1 = new StringBuffer();
                sb1.append(ENTRY_BOUNDARY);
                sb1.append("\r\n");
                sb1.append("Content-Disposition:form-data;name=\"");
                sb1.append(imageForm.getName());
                sb1.append("\";filename=\"" + imageForm.getPath());
                sb1.append("\"\r\nContent-Type:");
                sb1.append(imageForm.getMimeType());
                sb1.append("\r\n\r\n");
                bos.write(sb1.toString().getBytes(getParamsEncoding()));
                bos.write(imageForm.getValue());
                bos.write("\r\n".getBytes(getParamsEncoding()));

            }

            bos.write(END_BOUNDARY.getBytes(getParamsEncoding()));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bos.toByteArray();
    }
}


### 已知问题分析 `uni-file-picker` 是 UniApp 提供的一个用于文件选择和上传的组件。然而,在某些场景下,可能会遇到 **进度条不动** 的问题。这通常是由以下几个原因引起的: 1. **自定义上传未正确配置**:当使用 `customUpload=true` 参数时,开发者需要自行处理文件上传逻辑以及更新进度条的状态[^1]。 2. **事件回调缺失**:如果在调用 `uni.uploadFile` 或其他上传接口时,未正确监听上传过程中的进度变化,则无法动态更新进度条[^4]。 3. **跨平台兼容性问题**:不同平台(如 H5、小程序、APP)可能对上传机制有不同的实现方式,可能导致部分平台上进度条无法正常工作[^3]。 --- ### 解决方案 #### 方法一:确保自定义上传逻辑正确 如果启用了 `customUpload=true`,则需要手动实现上传逻辑,并通过 `setProgressByCustomUplaod` 更新进度条状态。以下是具体实现代码示例: ```javascript methods: { customUpload(file) { const that = this; uni.uploadFile({ url: 'https://your-server-url/upload', // 替换为实际服务器地址 filePath: file.url, name: 'file', formData: {}, // 可选参数 success(res) { console.log('上传成功:', res); that.$emit('success'); // 上报成功事件 }, fail(err) { console.error('上传失败:', err); that.$emit('fail'); // 上报失败事件 }, complete() { that.setProgressByCustomUplaod(file.uuid, 100); // 设置完成状态 } }); // 动态更新进度条 let intervalId = setInterval(() => { if (that.currentProgress >= 100) { clearInterval(intervalId); return; } // 假设每秒增加10%进度 that.currentProgress += Math.min(10, 100 - that.currentProgress); that.setProgressByCustomUplaod(file.uuid, that.currentProgress); }, 1000); }, setProgressByCustomUplaod(uuid, progress) { const currentFile = this.files.find(item => item.uuid === uuid); if (currentFile) { currentFile.progress = progress; } } } ``` 此方法的关键在于: - 调用 `uni.uploadFile` 并在其过程中实时更新进度[^1]。 - 使用定时器模拟进度变化,或者直接利用 `onProgressUpdate` 回调函数来获取真实进度。 --- #### 方法二:启用默认上传模式 如果不涉及复杂的业务需求,建议关闭 `customUpload` 属性,让 `uni-file-picker` 组件按照默认逻辑执行上传操作。此时无需额外编写上传代码,只需确保网络环境良好即可。 ```html <uni-file-picker v-model="files" :limit="3" /> ``` 在这种情况下,进度条由框架内部管理,一般不会出现问题[^2]。 --- #### 方法三:检查跨平台差异 对于不同的运行环境(H5、微信小程序、安卓/iOS APP),可能存在特定的行为差异。可以通过以下方式进行排查和优化: 1. **H5 平台** 如果是在浏览器中运行应用,需确认服务器是否允许 CORS 请求,并验证 `uni.uploadFile` 是否返回正确的响应数据[^4]。 2. **小程序平台** 小程序环境下推荐优先使用 `wx.cloud.uploadFile` 接口替代原生 API,以减少潜在错误[^2]。 3. **移动端 App** 对于 Android 和 iOS 应用,注意测试弱网条件下的表现,必要时可引入断点续传功能。 --- ### 注意事项 - 确保服务器端能够接收分片传输请求,并及时反馈当前已完成的比例给客户端[^4]。 - 配合调试工具观察整个流程是否有中断现象发生;例如查看 Network Panel 下是否存在超时或异常终止的情况。 --- ### 总结 针对 `uni-file-picker` 进度条不动的问题,可以从调整上传策略(开启/禁用自定义)、完善进度监控机制以及适配各终端特性这三个方面入手加以改进。最终目标是让用户直观感受到文件上传的过程进展状况。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值