美文网首页
Service单文件单线程断点下载

Service单文件单线程断点下载

作者: Skypew | 来源:发表于2017-05-24 16:39 被阅读35次

    总体思路 是这样 还有很多需要优化的地方

    截图

    Activity

    
    //一个文件  单线程 断点 下载
    
    public class DownLoadDemoActivity extends AppCompatActivity {
        private TextView mTvFileName ;
        private ProgressBar  mPbProgress;
        private Button  btnStop;
        private  Button btnStart;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_down_load_demo);
    
            mTvFileName = (TextView) findViewById(R.id.tvFileName);
            mPbProgress = (ProgressBar) findViewById(R.id.pbProgress);
            btnStart = (Button) findViewById(R.id.btnStart);
            btnStop  = (Button) findViewById(R.id.btnStop);
    
            mPbProgress.setMax(100);
    
            //创建文件信息      这里使用 知乎的作参考
             final FileInfo fileInfo = new FileInfo(0,"http://zhstatic.zhihu.com/pkg/store/zhihu/futureve-mobile-zhihu-release-4.51.1(488).apk","知乎apk",0,0);
    
    
            mTvFileName.setText(fileInfo.getFileName());
    
            btnStart.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent i = new Intent(DownLoadDemoActivity.this,DownLoadService.class);
                    i.setAction(DownLoadService.ACTION_START);
                    i.putExtra("fileInfo",fileInfo);//传递文件
                    startService(i);
                }
            });
    
    
            btnStop.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    // 通过Intent传递参数给Service
                    Intent intent = new Intent(DownLoadDemoActivity.this, DownLoadService.class);
                    intent.setAction(DownLoadService.ACTION_STOP);
                    intent.putExtra("fileInfo", fileInfo);
                    startService(intent);
                }
            });
    
            // 注册广播接收器
            IntentFilter filter = new IntentFilter();
            filter.addAction(DownLoadService.ACTION_UPDATE);
            registerReceiver(mReceiver, filter);
    
    
    
        }
    
        /**
         * 更新UI的广播接收器
         */
        BroadcastReceiver mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (DownLoadService.ACTION_UPDATE.equals(intent.getAction())) {
    
                    int finised = intent.getIntExtra("finished", 0);
                    mPbProgress.setProgress(finised);
    
                    Logger.show("接收到的比例",finised+"%");
    
                }
            }
        };
    
    
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(mReceiver);
        }
    
    }
    
    

    下载的Service

    /**
     * 下载  service
     */
    public class DownLoadService extends Service {
    
        public static final String ACTION_START = "ACTION_START";
        public static final String ACTION_STOP = "ACTION_STOP";
        public static final String ACTION_UPDATE = "ACTION_UPDATE"; //更新进度
    
        public static final String TAG ="DownLoadService";
    
        public static final String DOWNLOAD_PAHT = Environment.getExternalStorageDirectory().getAbsolutePath()+
                "/downloads/";
    
        public static final int MSG_INIT =0;
    
        private DownloadTask downloadTask =null;
    
    
    
        // 初始化线程(获取文件长度 后  会接受到message)
        Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case MSG_INIT:
    
                        FileInfo fileInfo = (FileInfo) msg.obj;
                        //启动下载 任务线程
                        downloadTask = new DownloadTask(DownLoadService.this, fileInfo);
                        downloadTask.downLoad();
                        break;
    
                    default:
                        break;
    
                }
    
            }
        };
    
    
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
    
            if (ACTION_START.equals(intent.getAction())){
           FileInfo  fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
                Log.e(TAG,"开始:"+fileInfo.toString());
                //启动 初始化 线程
                new InitThread(fileInfo).start();
    
            } else if(ACTION_STOP.equals(intent.getAction())){
                FileInfo  fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
                if (downloadTask != null) {
                    downloadTask.isPause = true;
                }
                Log.e(TAG,"暂停:"+fileInfo.toString());
            }
    
            return super.onStartCommand(intent, flags, startId);
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
          return null;
        }
    
    
       class InitThread extends Thread{
    
           private FileInfo fileInfo =null;
    
           public InitThread(FileInfo fileInfo) {
               this.fileInfo = fileInfo;
           }
    
           @Override
           public void run() {
               HttpURLConnection conn = null;
               RandomAccessFile raf = null;
               URL url = null;
               try {
                   //连接当前 网络
                   url = new URL(fileInfo.getUrl());
                   conn = (HttpURLConnection) url.openConnection();
                   conn.setConnectTimeout(3000);
                   conn.setRequestMethod("GET"); //这里 用Get进行下载
                   int length = -1;
    
                   if (conn.getResponseCode() == 200){
                       //获取 文件长度
                       length =  conn.getContentLength();
                   }
    
                   Logger.show("下载长度",""+length+"结果码"+conn.getResponseCode());
    
                   if (length<=0){
                       return;
                   }
    
                   // todo 创建本地 下载路径
                   File  dir = new File(DOWNLOAD_PAHT);
                   if (!dir.exists()){
                       dir.mkdir();
                   }
    
                   File  file = new File(dir,fileInfo.getFileName());
                   //在文件的任意一个位置 进行 断点操作   rw 表示读写模式可读可写 可删除
                   raf = new RandomAccessFile(file, "rwd");
                   raf.setLength(length); //长度为文件的长度
                   fileInfo.setLength(length);
                   //发送 message
                   mHandler.obtainMessage(MSG_INIT,fileInfo).sendToTarget();
    
               } catch (Exception e) {
                   e.printStackTrace();
               }finally {
                   try {
                       conn.disconnect();
                       raf.close();       //关闭流
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
    
    
               }
    
    
           }
       }
    
    }
    
    

    下载任务类 DownloadTask

    /**
     * Created by dc on 2017/5/23.
     * 下载 任务类
     */
    
    public class DownloadTask {
    
        private Context mContext = null;
        private FileInfo mFileInfo = null;
    
        private int mFinised = 0; //默认结束位置
    
        private ThreadDaoImpl mDao = null;
        public boolean isPause = false;
    
    
        public DownloadTask(Context mContext, FileInfo mFileInfo) {
            this.mContext = mContext;
            this.mFileInfo = mFileInfo;
            mDao = new ThreadDaoImpl();
        }
    
        /**
         * 开始下载
         */
        public void downLoad() {
    
    
            // 读取数据库的线程信息
            List<ThreadInfo> threads = mDao.getThreads(mFileInfo.getUrl());
    
            ThreadInfo threadInfo = null;
    
            if (0 == threads.size()) {//数据库中无数据
    
                // 初始化线程信息对象
                threadInfo = new ThreadInfo(mFileInfo.getId(), mFileInfo.getUrl(),
                        0, mFileInfo.getLength(), 0);
    
                Logger.show("数据库中无数据 ","数据库中无数据");
    
            } else {//数据库 中有数据
                threadInfo = threads.get(0);
                Logger.show("数据库中有 "+threads.size(),threadInfo.toString());
            }
            // 创建子线程进行下载
            new DownloadThread(threadInfo).start();
        }
    
    
    
        /**
         * 下载 线程
         */
        private class DownloadThread extends Thread {
    
            private ThreadInfo mThreadInfo = null;
            /**
             * @param mInfo
             */
            public DownloadThread(ThreadInfo mInfo) {
                this.mThreadInfo = mInfo;
            }
    
            @Override
            public void run() {
    
                //数据库 中 不存在    插入线程信息
                if (!mDao.isExists(mThreadInfo.getUrl(), mThreadInfo.getThread_id())) {
                    mDao.insertThread(mThreadInfo);
                    Logger.show("插入数据库 ","插入数据库");
                }
    
                HttpURLConnection conn = null;
                RandomAccessFile raf = null;
                InputStream inputStream = null;
                try {
                    URL url = new URL(mThreadInfo.getUrl());
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(5000);
                    conn.setRequestMethod("GET");
                    // 设置下载位置
                    int start = mThreadInfo.getStart() + mThreadInfo.getFinished();
                    //设置 范围 开始到结束
                    conn.setRequestProperty("Range",
                            "bytes=" + start + "-" + mThreadInfo.getEnd());
    
                    // 设置文件写入位置
                    File file = new File(DownLoadService.DOWNLOAD_PAHT,
                            mFileInfo.getFileName());
                    raf = new RandomAccessFile(file, "rwd");
                    //读写的时候 跳过的字节
                    raf.seek(start);
    
                    //todo 开始下载  读取数据  写入文件   发广播 给Activity
    
                    //发送进度
                    Intent intent = new Intent();
                    intent.setAction(DownLoadService.ACTION_UPDATE);
                    mFinised += mThreadInfo.getFinished(); //下载进度
    
                    // 网络正常 时
                    if (conn.getResponseCode() == 206) {
                        // 读取数据
                        inputStream = conn.getInputStream();
                        byte[] buf = new byte[1024 * 4];
                        int len = -1;
    
                        long time = System.currentTimeMillis();
    
                        while ((len = inputStream.read(buf)) != -1) {
                            // 写入文件
                            raf.write(buf, 0, len);
                            // 把下载进度发送广播给Activity
    
                            mFinised += len;
    
                            //进度 发送activity  todo  防止数组越界  int类型最大值超标
                            if (System.currentTimeMillis() - time > 500) { //间隔半秒发送一次
                                time = System.currentTimeMillis();
    
                                float precent =  ((float)mFinised )* 100 / (float) mThreadInfo.getEnd();
    
                                intent.putExtra("finished",(int)precent );//%形式
                                mContext.sendBroadcast(intent);
                            }
    
                            // 在下载暂停时,保存下载进度 到数据库
                            if (isPause) {
                                Logger.show("更新数据库 ","更新数据库");
                                mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getThread_id(), mFinised);
                                return;
                            }
    
                            float precent = ((float)mFinised )* 100 / (float) mThreadInfo.getEnd();
    
                            Logger.show("当前总进度"+mThreadInfo.getEnd(),"已下载:"+mFinised+"百分比"+(int)precent+"%");
    
                        }
    
                        //  下载完成后       删除线程信息
                        mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getThread_id());
                        Logger.show("DownloadTask", "下载完毕");
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                } finally { //关闭所有流
    
                    try {
    
                        if (conn != null) {
                            conn.disconnect();
                        }
    
                        if (raf != null) {
                            raf.close();
                        }
    
                        if (inputStream != null) {
                            inputStream.close();
                        }
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                }
            }
        }
    
    
    }
    
    

    文件信息类

    /**
     *文件信息
     */
    
    public class FileInfo implements Serializable{
        private int id;
        private String url;
        private String fileName;
        private int length;
        private int finished;
    
    
        public FileInfo() {
        }
    
        /**
         * @param id
         * @param url
         * @param fileName
         * @param length   长度
         * @param finished  下载进度
         */
        public FileInfo(int id, String url, String fileName, int length, int finished) {
            this.id = id;
            this.url = url;
            this.fileName = fileName;
            this.length = length;
            this.finished = finished;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getFileName() {
            return fileName;
        }
    
        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    
        public int getLength() {
            return length;
        }
    
        public void setLength(int length) {
            this.length = length;
        }
    
        public int getFinished() {
            return finished;
        }
    
        public void setFinished(int finished) {
            this.finished = finished;
        }
    
    
        @Override
        public String toString() {
            return "FileInfo{" +
                    "id=" + id +
                    ", url='" + url + '\'' +
                    ", fileName='" + fileName + '\'' +
                    ", length=" + length +
                    ", finished=" + finished +
                    '}';
        }
    
    }
    
    

    线程任务类

    /**
     * 线程  数据表 
     * Created by dc on 2017/5/23.
     * 
     */
    public class ThreadInfo extends DataSupport {
        private int id;
        private int thread_id;
        private String url;
        private int start;
        private int  end;
        private int finished;
    
    
        public ThreadInfo() {
        }
    
        /**
         * @param thread_id
         * @param url
         * @param start
         * @param end
         * @param finished 当前完成 进度
         */
        public ThreadInfo(int thread_id, String url, int start, int end, int finished) {
            this.thread_id = thread_id;
            this.url = url;
            this.start = start;
            this.end = end;
            this.finished = finished;
        }
    
    
        public int getThread_id() {
            return thread_id;
        }
    
        public void setThread_id(int thread_id) {
            this.thread_id = thread_id;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public int getStart() {
            return start;
        }
    
        public void setStart(int start) {
            this.start = start;
        }
    
        public int getEnd() {
            return end;
        }
    
        public void setEnd(int end) {
            this.end = end;
        }
    
        public int getFinished() {
            return finished;
        }
    
        public void setFinished(int finished) {
            this.finished = finished;
        }
    
        @Override
        public String toString() {
            return "ThreadInfo{" +
                    "id=" + id +
                    ", thread_id=" + thread_id +
                    ", url='" + url + '\'' +
                    ", start=" + start +
                    ", end=" + end +
                    ", finished=" + finished +
                    '}';
        }
    }
    
    
    

    数据库 帮助类

    /**
     * Created by dc on 2017/5/23.
     * 数据库 帮助类  实现 增删 改查
     *
     */
    
    public class ThreadDaoImpl {
    
        public ThreadDaoImpl() {
            SQLiteDatabase db = LitePal.getDatabase(); //获取 实例
        }
    
    
        public void  insertThread(ThreadInfo threadInfo){
            threadInfo.save();
        }
    
    
        public void  deleteThread(String url ,int thread_id){
    
            String s = String.valueOf(thread_id);
    
            List<ThreadInfo> list = DataSupport.where("url = ? and thread_id = ?",url,s).find(ThreadInfo.class);
    
            if (list.size()>0){
                DataSupport.delete(ThreadInfo.class,list.get(0).getId());
            }
        }
    
        public void  updateThread(String url, int thread_id,int finshed){
    
            String id = String.valueOf(thread_id);
    
            ThreadInfo  threadInfo = new ThreadInfo();
            threadInfo.setFinished(finshed);
            threadInfo.updateAll("url = ? and thread_id = ?", url,id);
    
        }
    
    
        public  List<ThreadInfo>  getThreads(String url){
            List<ThreadInfo> list = DataSupport.where("url = ? ",url).find(ThreadInfo.class);
            return list;
        }
    
    
        public boolean isExists(String url, int thread_id) {
    
            String s = String.valueOf(thread_id);
    
            List<ThreadInfo> list = DataSupport.where("url = ? and thread_id = ?",url,s).find(ThreadInfo.class);
    
            if (list.size()>0){
    
                Logger.show("数据库中存在的数量","查询存在 "+list.size());
    
                return true;
            }else {
                Logger.show("数据库中不存在该记录","数据库中不存在该记录 "+list.size());
    
                return false;
            }
    
        }
    
    
    
    }
    
    

    相关文章

      网友评论

          本文标题:Service单文件单线程断点下载

          本文链接:https://www.haomeiwen.com/subject/dyzwxxtx.html