返回顶部
首页 > 资讯 > 移动开发 >Android实现断点续传功能
  • 269
分享到

Android实现断点续传功能

2024-04-02 19:04:59 269人浏览 薄情痞子
摘要

本文实例为大家分享了Android实现断点续传的具体代码,供大家参考,具体内容如下 断点续传功能,在文件上传中断时,下次上传同一文件时,能在上次的断点处继续上传,可节省时间和流量 总

本文实例为大家分享了Android实现断点续传的具体代码,供大家参考,具体内容如下

断点续传功能,在文件上传中断时,下次上传同一文件时,能在上次的断点处继续上传,可节省时间和流量

总结规划步骤:

1.给大文件分片,每一个大文件发送前,相对应的创建一个文件夹存放所有分片

2.上传接口,每一个分片上传完成就删掉,直到所有分片上传完成,再删掉存放分片的文件夹,服务器把分片合成完整的文件。

先看分片功能,传入的3个参数分别为源文件地址,分片大小,存放分片的文件夹地址。返回的是分片个数。


    public static int splitFile(String sourceFilePath, int partFileLength, String splitPath) throws Exception {
        File sourceFile = null;
        File targetFile = null;
        InputStream ips = null;
        OutputStream ops = null;
        OutputStream confiGops = null;//该文件流用于存储文件分割后的相关信息,包括分割后的每个子文件的编号和路径,以及未分割前文件名
        Properties partInfo = null;//properties用于存储文件分割的信息
        byte[] buffer = null;
        int partNumber = 1;
        sourceFile = new File(sourceFilePath);//待分割文件
        ips = new FileInputStream(sourceFile);//找到读取源文件并获取输入流
        //创建一个存放分片的文件夹
        File tempFile = new File(splitPath);
        if (!tempFile.exists()) {
            tempFile.mkdirs();
        }
        configOps = new FileOutputStream(new File(tempFile.getAbsolutePath() + File.separator + "config.properties"));
        buffer = new byte[partFileLength];//开辟缓存空间
        int tempLength = 0;
        partInfo = new Properties();//key:1开始自动编号 value:文件路径
 
        int sliceCount = 0;
        while ((tempLength = ips.read(buffer, 0, partFileLength)) != -1) {
            String targetFilePath = tempFile.getAbsolutePath() + File.separator + "part_" + (partNumber);//分割后的文件路径+文件名
            sliceCount = partNumber;
            partInfo.setProperty((partNumber++) + "", targetFilePath);//将相关信息存储进properties
            targetFile = new File(targetFilePath);
            ops = new FileOutputStream(targetFile);//分割后文件
            ops.write(buffer, 0, tempLength);//将信息写入碎片文件
 
            ops.close();//关闭碎片文件
        }
        partInfo.setProperty("name", sourceFile.getName());//存储源文件名
        partInfo.setProperty("sliceCount", sliceCount + "");//存储分片个数
        partInfo.store(configOps, "ConfigFile");//将properties存储进实体文件中
        ips.close();//关闭源文件流
 
        return sliceCount;
    }

接下来,和服务器协商接口,一共2个接口

1.uploadLargeFilePre,传入参数除了常规上传文件参数之外加了分片个数sliceCount和fileHashcode。这一步是给服务器开辟存放分片的控件的,不执行上传操作,文件哈希值作为识别分片归属的唯一标准。返回int类型rCode,根据rCode结果判断是否执行第2步上传动作

2.uploadLargeFile,传入参数除了常规上传文件参数之外加了分片path,分片index,isFinished。isFinished是最后一片的依据。客户端就在上传接口的response里继续上传下一个分片,直到最后一片上传完成,服务器才会返给这个大文件的url。

看代码

protected void addFileMsg(String path) {
        forceLogin();
 
        if (path == null) {
            return;
        }
        File file = new File(path);
        if (file.exists()) {
            ImMsg msg = new ImMsg();
            msg.setType(ImMsg.MSG_TYPE_FILE);
            msg.setTime(System.currentTimeMillis());
            msg.setMsgReaded();
            msg.setReceiveTime(System.currentTimeMillis());
            AccountInfo accountInfo = IMApp.instance().getAccountInfo();
            msg.setUserId(accountInfo.getUserId());
            msg.setSex(accountInfo.getSex());
            msg.setUserName(accountInfo.mNickName);
            msg.setHeadUrl(accountInfo.mHead);
            msg.mMasterId = mMasterId;
            msg.setMsg(new File(path).getName());
            msg.setPicPath(path);
            msg.setState(ImMsg.STATE_SEND_UPLOADING);
            String ext = null;
            if (path.endsWith("doc") || path.endsWith("docx")) {
                ext = "doc";
            } else if (path.endsWith("xls") || path.endsWith("xlsx")) {
                ext = "xls";
            } else if (path.endsWith("ppt") || path.endsWith("pptx")) {
                ext = "ppt";
            } else if (path.endsWith("pdf")) {
                ext = "pdf";
            }
            msg.setMsg_extend3(ext);
 
            msg.mFileSize = (int) new File(path).length();
            msg.setHasAtt(hasAtt());
            addMsgToDB(msg);
 
            isFileListSingle = fileList.size() == 1;
            SPHelper spHelper = SPHelper.build();
            int lastSlices = spHelper.get(slice_old, 0);
            String aesPath = spHelper.get(slice_aesEncPath, "");
            String lastPath = spHelper.get(slice_picPath, "");
            int tempTotalCount = spHelper.get(CommonUtils.FaiLED_TEMP_SEND_TOTAL_COUNT, 0);//实际发送总个数
            if (lastSlices == 1 && tempTotalCount > 1) {
                
                isFileListSingle = false;
            }
            //根据文件大小,判断是否用分片上传 modify hexiaokang 2019年11月5日11点01分
            if (new File(path).length() < Global.FILE_SPILT_LENGTH) {//文件小于5M,常规上传方式
                upLoadFile(msg);
            } else {
 
                File sourceFile = new File(path);
                //分片所在文件夹,以未做AES加密的源文件名作为 分片文件夹名字
                String sliceDir = sourceFile.getParent() + File.separator + sourceFile.getName() + "_split";
 
                if (lastSlices == 1
                        && path.equals(lastPath)
                        && new File(sliceDir).exists()
                        && !aesPath.equals("")
                        && new File(aesPath).exists()) {//发送上次的旧文件中断的分片
                    //只走一次
                    spHelper.put(slice_old, 0);
                    sliceIndex = spHelper.get(slice_sliceIndex, 0);
                    int count = spHelper.get(slice_sliceCount, 0);
                    LogUtil2.i(TAG + "&onUploadComplete", "sendOldFiles sliceIndex = " + sliceIndex + ", sliceCount = " + count);
                    largeFilePre = true;
                    upLoadLargeFilePre(msg, count, sliceDir, aesPath);
                } else {//发送大文件正常流程
                    //给文件分片
                    int partFileLength = Global.FILE_SPILT_LENGTH;//指定分割的子文件大小为5M
                    //先对文件做AES加密,再进行分片,这里很重要
                    String aesEncPath = EncryptMgr.encFile(path, accountInfo.getEncTime(), accountInfo.getEncKey());
                    File f = new File(aesEncPath);
                    LogUtil2.i(TAG + "&onUploadComplete", "ChatMsgActivity.addFileMsg: big file enc path=" + path);
 
                    try {
                        sliceCount = FileSliceUtil.splitFile(aesEncPath, partFileLength, sliceDir);//将文件分割
                    } catch (Exception e) {
                        LogUtil2.e(TAG, "split.e:" + e.getMessage());
                        e.printStackTrace();
                    }
//                  LogUtil2.e(TAG+"&onUploadComplete", "ChatMsgActivity.addFileMsg: sliceCount:" + sliceCount);
 
                    //分片上传
                    largeFilePre = false;
                    upLoadLargeFilePre(msg, sliceCount, sliceDir, aesEncPath);
 
                }
            }
        }
    }

上面这一块代码,除了小文件常规上传,就是大文件上传方式了。大文件上传这里分了2种情况,

1.发送上次中断的大文件分片,这里就不用分片了,直接从sp拿到上次中断的分片count、index等信息直接上传

2.从分片到发送的全部流程,因为我这里对文件做了AES加密,所以是加密之后再分片

接下来就是上传过程

public void upLoadLargeFilePre(final ImMsg msg, final int sliceCount, final String sliceDir, final String aesEncPath) {
        if (msg.getState() != ImMsg.STATE_SEND_WAITING) {
            msg.setState(ImMsg.STATE_SEND_UPLOADING);
            mListAdapter.notifyDataSetChanged();
        }
        AccountInfo accountInfo = IMApp.instance().getAccountInfo();
        UploadFileHelper helper = new UploadFileHelper(accountInfo.getEncTime(), accountInfo.getEncKey(),
                new UploadFileCallback() {
 
                    @Override
                    public void onError(Call call, Exception e) {
                        e.printStackTrace();
                        LogUtil2.e("onUploadComplete", "ChatMsgActivity.onError: error(split_upload):" + e.toString()+", call = "+call);
                        failCount++;
//                            if (msg.getPicPath() != null && msg.getPicPath().contains(SDCardUtil.getSDcardPathEx())) {
//                                new File(msg.getPicPath()).delete();
//                            }
                        btn_other_sendfile.setClickable(true);
                        CommonUtils.isSendBtnClickable = true;
                        Intent comIntent = new Intent();
                        comIntent.setAction(CommonUtils.USBFILE_COMPLETE_SEND);
                        comIntent.putExtra("fail_count", failCount);
                        sendBroadcast(comIntent);
 
                        tempProgress = 0;
                        largeFilePre = false;
                        //todo 上传失败,上传任务终止 (需要保存失败msg的信息,以及分片信息)
                        String picPath = msg.getPicPath();
                        // 保存picPath, sliceIndex, sliceCount, aesEncPath
                        SPHelper spHelper = SPHelper.build();
                        spHelper.put(slice_picPath, picPath);
                        spHelper.put(slice_sliceIndex, sliceIndex);
                        spHelper.put(slice_sliceCount, sliceCount);
                        spHelper.put(slice_aesEncPath, aesEncPath);
                        spHelper.put(slice_old, 1);//标记,1表示有上次失败的碎片,处理完上次失败的碎片之后设置为0
                        return;
                    }
 
                    @Override
                    public void onResponse(UploadFileAckPacket uploadFileAckPacket) {
                        LogUtil2.i("onUploadComplete", "ChatMsgActivity.onResponse: pre upload ack packet code="+uploadFileAckPacket.getRetCode()+", desc="+uploadFileAckPacket.getRetDesc());
                        if (getMsgFromDB(msg.getId()) == null) {
                            msg.setState(ImMsg.STATE_SEND_FAILED);
                            LogUtil2.i("onUploadComplete", "msg not exist d = (split_upload)" + msg.getId());
                            updateMsgToDB(msg);
                            mListAdapter.notifyDataSetChanged();
 
                            failCount++;
                            btn_other_sendfile.setClickable(true);
                            CommonUtils.isSendBtnClickable = true;
                            Intent comIntent = new Intent();
                            comIntent.setAction(CommonUtils.USBFILE_COMPLETE_SEND);
                            sendBroadcast(comIntent);
 
                            tempProgress = 0;
                            return;
                        }
                        if (uploadFileAckPacket != null && uploadFileAckPacket.isSuccess()) {
                            LogUtil2.i("onUploadComplete", "msg exist and sucess(uploadFileAckPacket.sliceIndex(split_upload)):" + uploadFileAckPacket.sliceIndex+", sliceCount="+sliceCount+", url="+uploadFileAckPacket.mUrl);
                            if (sliceIndex < sliceCount && TextUtils.isEmpty(uploadFileAckPacket.mUrl)) {
                                //更新进度条
                                if (isFileListSingle) {//单个大文件
                                    int pro = 100 * sliceIndex / sliceCount;
 
                                    Intent uploadIntent = new Intent();
                                    uploadIntent.setAction(CommonUtils.USBFILE_PROGRESS_SEND);
                                    uploadIntent.putExtra("sentCount", -1);//-1 代表发送的是单个文件
                                    uploadIntent.putExtra("sentPro", pro);
                                    sendBroadcast(uploadIntent);
                                } else {//一次发送多个文件,包括大文件
 
                                }
                                //删除掉上传成功的分片
                                String slicePath = sliceDir + File.separator + "part_" + (sliceIndex);
                                new File(slicePath).delete();
                                sliceIndex++;
                                //还有待上传的分片
                                upLoadLargeFilePre(msg, sliceCount, sliceDir, aesEncPath);
                            } else {
                                //所有分片上传完成
                                largeFilePre = false;
                                LogUtil2.i("onUploadComplete", "ChatMsgActivity.onResponse: 所有分片上传完成 largeFilePre="+largeFilePre);
                                msg.updateImageUpLoadProgress(100);
                                msg.setPicBigUrl(uploadFileAckPacket.mUrl);
 
                                //这里删除原文件
 
                                if (msg.getPicPath() != null && msg.getPicPath().contains(SDCardUtil.getSDcardPathEx())) {
                                    File file = new File(msg.getPicPath());
                                    //删除分片所在的文件夹
                                    FileUtil.deleteFolderFile(sliceDir, true);
                                    //删除文件
                                    file.delete();
//                                    EventBus.getDefault().post(new EncFileEvent(EncFileEvent.COM_FILE_DELETE, msg.getPicPath(), 0));
                                    msg.setPicPath("");
                                }
                                if (msg.getType() == ImMsg.MSG_TYPE_IMAGE) {
                                    msg.setPicSmallUrl(uploadFileAckPacket.mThumbnail);
                                    msg.mThumbWidth = this.mThumbWidth;
                                    msg.mThumbHeight = this.mThumbHeight;
                                }
 
 
                                LogUtil2.i("onUploadComplete", "msg exist and sucess(msg.getPicBigUrl()(split_upload)):" + msg.getPicBigUrl());
                                sendMsg(msg);
                                sentCount++;
                                sliceIndex = 1;
 
                                if (isFileListSingle) {//单个文件不用处理
 
                                } else {
                                    //传递上传进度
                                    Intent uploadIntent = new Intent();
                                    uploadIntent.setAction(CommonUtils.USBFILE_PROGRESS_SEND);
                                    uploadIntent.putExtra("sentCount", sentCount);
                                    sendBroadcast(uploadIntent);
                                }
 
                                //继续上传下一个文件
                                if (sentCount < fileList.size()) {
                                    addFileMsg(fileList.get(sentCount).getAbsolutePath());
                                } else {
                                    //所有文件上传完成
                                    btn_other_sendfile.setClickable(true);
                                    CommonUtils.isSendBtnClickable = true;
                                    Intent comIntent = new Intent();
                                    comIntent.setAction(CommonUtils.USBFILE_COMPLETE_SEND);
                                    sendBroadcast(comIntent);
 
                                    tempProgress = 0;
                                }
                            }
                        } else {
                            LogUtil2.e("onUploadComplete", "rCode(split_upload)):" + uploadFileAckPacket.getRetCode()+", sliceIndex="+uploadFileAckPacket.sliceIndex);
                            if(uploadFileAckPacket.getRetCode()==1343688774){
                                LogUtil2.e("onUploadComplete", "ChatMsgActivity.onResponse: 缺片了!");
                            }
                            msg.setState(ImMsg.STATE_SEND_FAILED);
                            updateMsgToDB(msg);
                            if (!IMMsgMgr.notifyActivity(IMMsgMgr.IM_CMD_IMP2PMSG_ACK, msg.getUserId(), msg.hasAtt(), false, msg)) {
                                
                            }
                            mListAdapter.notifyDataSetChanged();
                        }
                    }
 
                    @Override
                    public void inProgress(float progress) {
                        super.inProgress(progress);
//                        LogUtil2.i("onUploadProgress", "inProgress " + progress+", path="+msg.getPicPath()+", sliceDir="+sliceDir);
                        LogUtil2.i("onUploadProgress", "ChatMsgActivity.inProgress: sliceCount="+sliceCount+", sliceIndex="+sliceIndex+", sentCount="+sentCount+", list.size="+fileList.size()+", progress="+progress+", tempProgress="+tempProgress);
                        int pro = (int) (progress * 100);
                        if (new File(msg.getPicPath()).length() < Global.FILE_SPILT_LENGTH) {
//
                        }else{
                            int allPro= (int)(100*(progress+(sliceIndex-1))/sliceCount);
                            if (isFileListSingle && allPro - tempProgress >= 1) {
                                //todo 分片上传,进度条重新计算,
                                //多个文件上传不用考虑,这里重新计算单个文件的上传问题
                                
                                LogUtil2.i("onUploadProgress", "ChatMsgActivity.inProgress: big file allPro="+allPro);
                                Intent uploadIntent = new Intent();
                                uploadIntent.setAction(CommonUtils.USBFILE_PROGRESS_SEND);
                                uploadIntent.putExtra("sentCount", -1);//-1代表发送的是单个文件,这里是针对用户感知而言的代码逻辑
                                uploadIntent.putExtra("sentPro", allPro);
                                tempProgress = allPro;
                                sendBroadcast(uploadIntent);
                            }
                        }
                        // 更新
                        mListAdapter.notifyDataSetChanged();
                    }
                }, msg);
        LogUtil2.i("onUploadComplete", "ChatMsgActivity.upLoadLargeFilePre: largeFilePre="+largeFilePre);
        if (largeFilePre) {//todo 是否有过预处理
            String slicePath = sliceDir + File.separator + "part_" + (sliceIndex);
            int isFinished = sliceIndex == sliceCount ? 1 : 0;
            helper.upLoadLargeFile(aesEncPath, slicePath, sliceIndex, isFinished);
        } else {
            //上传大文件 预处理
            int rCode = helper.upLoadLargeFilePre(aesEncPath, sliceCount);
            if (rCode == 0) {//预处理成功,可以执行上传任务
                largeFilePre = true;
                String slicePath = sliceDir + File.separator + "part_" + (sliceIndex);
                int isFinished = sliceIndex == sliceCount ? 1 : 0;
                helper.upLoadLargeFile(aesEncPath, slicePath, sliceIndex, isFinished);
            } else {
                //预处理失败,不执行上传任务
                LogUtil2.i("onUploadComplete", "someWordsrCode:" + rCode+", before plus faileCount="+failCount);
 
                msg.setState(ImMsg.STATE_SEND_FAILED);
                updateMsgToDB(msg);
                mListAdapter.notifyDataSetChanged();
                failCount++;
                btn_other_sendfile.setClickable(true);
                CommonUtils.isSendBtnClickable = true;
                Intent comIntent = new Intent();
                comIntent.putExtra("upload_error", 0);
                comIntent.putExtra("fail_count",failCount);
                comIntent.setAction(CommonUtils.USBFILE_COMPLETE_SEND);
                LogUtil.LogShow("onUploadComplete", "ChatMsgActivity.upLoadLargeFilePre: before sendIntent failCount="+failCount);
                sendBroadcast(comIntent);
 
                failCount=0;
                tempProgress = 0;
            }
        }
    }

上面这一块就是上传过程

int rCode = helper.upLoadLargeFilePre(aesEncPath, sliceCount); 这一句为第一个接口预处理,根据结果决定是否执行上传。

helper.upLoadLargeFile(aesEncPath, slicePath, sliceIndex, isFinished); 这一句执行上传,在onResponse里处理上传结果,我这里有多个文件连续上传,所以结果处理看起来有点凌乱。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: Android实现断点续传功能

本文链接: https://lsjlt.com/news/165332.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android实现断点续传功能
    本文实例为大家分享了Android实现断点续传的具体代码,供大家参考,具体内容如下 断点续传功能,在文件上传中断时,下次上传同一文件时,能在上次的断点处继续上传,可节省时间和流量 总...
    99+
    2024-04-02
  • Golang实现断点续传功能
    本文实例为大家分享了Golang实现断点续传的具体代码,供大家参考,具体内容如下 1、将文件pic_src.jpg复制到pic_des.jpg文件; 2、读写过程中断时,读写的中断位...
    99+
    2024-04-02
  • android怎么实现多线程断点续传功能
    这篇文章主要介绍了android怎么实现多线程断点续传功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下布局:<xml version="...
    99+
    2023-05-30
    android 多线程
  • android原生实现多线程断点续传功能
    本文实例为大家分享了android实现多线程断点续传功能的具体代码,供大家参考,具体内容如下 需求描述: 输入一个下载地址,和要启动的线程数量,点击下载 利用多线程将文件下载到手机端...
    99+
    2024-04-02
  • Android入门之利用OKHttp实现断点续传功能
    目录简介课程目标断点下载的原理自定义Android里的ProgressBar的样式项目结构前端代码后端代码DbOpeerateHelper.javaDBService.javaDow...
    99+
    2023-01-09
    Android OKHttp断点续传功能 Android OKHttp断点续传 Android 断点续传 Android OKHttp
  • C#中怎么实现断点续传功能
    本篇文章为大家展示了C#中怎么实现断点续传功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。以下是一个请求报文与相应的回复报文的例子:GET /image/index_r4_c1.jpg&...
    99+
    2023-06-17
  • Java中怎么实现断点续传功能
    这篇文章给大家介绍Java中怎么实现断点续传功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。(一)断点续传的原理   其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。   打个比方,浏览器请...
    99+
    2023-06-03
  • Android实现网络多线程断点续传下载功能
    我们编写的是Andorid的HTTP协议多线程断点下载应用程序。直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。那么,多线程断点需要什么功能? 1.多线程下载 2...
    99+
    2022-06-06
    多线程 断点续传 断点 线程 Android
  • Android多线程断点续传下载功能实现代码
    原理 其实断点续传的原理很简单,从字面上理解,所谓断点续传就是从停止的地方重新下载。 断点:线程停止的位置。 续传:从停止的位置重新下载。 用代码解析就是: 断点:当...
    99+
    2022-06-06
    android多线程 断点续传 断点 线程 Android
  • HTML5如何实现文件断点续传功能
    这篇文章主要为大家展示了“HTML5如何实现文件断点续传功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“HTML5如何实现文件断点续传功能”这篇文章吧。HTM...
    99+
    2024-04-02
  • 通过Java实现文件断点续传功能
    目录什么是断点续传解决方案效果演示参考代码前端后端什么是断点续传 用户上传大文件,网络差点的需要历时数小时,万一线路中断,不具备断点续传的服务器就只能从头重传,而断点续传就是,允许用...
    99+
    2024-04-02
  • Android实现多线程断点续传
    本文实例为大家分享了Android实现多线程断点续传的具体代码,供大家参考,具体内容如下 多线程下载涉及到的知识点: 1、Service的使用:我们在Service中去下载文件;2、...
    99+
    2024-04-02
  • Java实现断点续传功能的示例代码
    目录一、题目描述二、解题思路三、代码详解一、题目描述 题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节...
    99+
    2022-11-13
    Java实现断点续传 Java断点续传
  • Android(Java)下载断点续传的实现
    Android(Java)下载断点续传的实现一、要注意的地方1. 追加文件2. 跳过输入流3.range header坑点1.坑点2坑点3.二、...
    99+
    2022-06-06
    JAVA 断点续传 断点 Android
  • Android 断点续传原理以及实现
    Android 断点续传原理以及实现 0.  前言 在Android开发中,断点续传听起来挺容易,在下载一个文件时点击暂停任务暂停,点击开始会继续下载文件。但是真正实...
    99+
    2022-06-06
    断点续传 断点 Android
  • Node.js实现断点续传
    目录方案分析 切片 断点续传 具体解决流程 逻辑分析 前端 服务端 小结 方案分析 切片 就是对上传视频进行切分,具体操作为: File.slice(start...
    99+
    2024-04-02
  • Android如何实现简单断点续传和下载到本地功能
    这篇文章主要介绍了Android如何实现简单断点续传和下载到本地功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下效果展示导入依赖与权限依赖compile&nbs...
    99+
    2023-05-30
    android
  • 怎么通过Java实现文件断点续传功能
    这篇文章主要介绍“怎么通过Java实现文件断点续传功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么通过Java实现文件断点续传功能”文章能帮助大家解决问题。什么是断点续传用户上传大文件,网络差...
    99+
    2023-06-30
  • Android中怎么利用FTP实现多线程断点续传下载上传功能
    Android中怎么利用FTP实现多线程断点续传下载上传功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。FTP下载原理FTP单线程断点续传FTP和传统的HTT...
    99+
    2023-05-30
    android
  • 怎么在Android中实现一个多线程断点续传下载功能
    本篇文章给大家分享的是有关怎么在Android中实现一个多线程断点续传下载功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、布局实现具体布局内容如下:<LinearL...
    99+
    2023-05-30
    android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作