Service单文件单线程断点下载

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

截图

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;
        }

    }



}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容