Service单文件单线程断点下载

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

Service单文件单线程断点下载_第1张图片
截图

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 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 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  getThreads(String url){
        List 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 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单文件单线程断点下载)