单一文件的断点续传

很久没有更新博客了,最近公司的项目也没那么赶了,就照着慕课网的视频,把断点续传的代码敲了一遍,,调了半天,其中的坑也只有自己敲过才知道.为了今后方便,我现在把所有的代码都粘在下面了.
运行的效果如下:
这里写图片描述
这个才是
这里写图片描述
首先是我的代码目录结构
这里写图片描述

FileInfos主要是记录要下载的文件信息

private int id;
    private String url;
    private String fileName;
    private int length;
    private int finished;

ThreadInfo类是记录线程信息
private int id;
    private String url;
    private int start;
    private int end;
    private int finished;

DBHelper创建我的数据库,单例模式

private static final String DB_NAME="download.db";

    public static DBHelper helper;

    private static String SQL_CREATE="create table if not exists thread_info(_id integer primary key autoincrement,thread_id integer," +
                        "url text,start integer,end integer,finished integer)";
    private static String SQL_DROP="drop table if exists thread_info";

    public static synchronized DBHelper getInstance(Context mContext)
    {
        if (helper==null)
        {
            helper=new DBHelper(mContext,DB_NAME,null,1);
        }
        return helper;
    }

    private DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    } 

**数据访问接口的实现
 * Created by Administrator on 2017/7/19.
 */

public class ThreadDaoImp implements ThreadDao{

    private DBHelper helper;

    public ThreadDaoImp(Context context) {
        helper=DBHelper.getInstance(context);
    }

    @Override
    public void insertThread(ThreadInfos threadInfos) {
        SQLiteDatabase db = helper.getReadableDatabase();
        db.execSQL("insert into thread_info(thread_id,url,start,end,finished) values (?,?,?,?,?)",
                new Object[]{threadInfos.getId(),threadInfos.getUrl(),threadInfos.getStart(),threadInfos.getEnd(),threadInfos.getFinished()});
        db.close();
    }

    @Override
    public void deleteThread(String url, int thredId) {
        SQLiteDatabase db = helper.getReadableDatabase();
        db.execSQL("delete from thread_info where url= ? and thread_id= ?",
                new Object[]{url,thredId});
        db.close();
    }

    @Override
    public void updateThread(String url, int threadId, int finished) {
        SQLiteDatabase db = helper.getReadableDatabase();
        db.execSQL("update thread_info set finished = ? where url= ? and thread_id= ?",
                new Object[]{finished,url,threadId});
        db.close();
    }

    @Override
    public List<ThreadInfos> getThreads(String url) {
        SQLiteDatabase db = helper.getReadableDatabase();
        List<ThreadInfos> list=new ArrayList<>();
        Cursor cursor = db.rawQuery("select * from thread_info where url= ? ",
                new String[]{url});
        while (cursor.moveToNext())
        {
            ThreadInfos threadInfos = new ThreadInfos();
            threadInfos.setId(cursor.getInt(cursor.getColumnIndex("thread_id")));
            threadInfos.setUrl(cursor.getString(cursor.getColumnIndex("url")));
            threadInfos.setStart(cursor.getInt(cursor.getColumnIndex("start")));
            threadInfos.setEnd(cursor.getInt(cursor.getColumnIndex("end")));
            threadInfos.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
            list.add(threadInfos);
        }
        cursor.close();
        db.close();
        return list;
    }

    @Override
    public boolean isExists(String url, int threadId) {
        SQLiteDatabase db = helper.getReadableDatabase();
        Cursor cursor = db.rawQuery("select * from thread_info where url= ? and thread_id= ?",
                new String[]{url,threadId+""});
        boolean exists=cursor.moveToNext();
        cursor.close();
        db.close();
        return exists;
    }
}


/**下载任务类
 * Created by Administrator on 2017/7/19.
 */

public class DownloadTask {

    private Context context;
    private FileInfos fileInfos;
    private ThreadDaoImp threadDaoImp;
    private int mFinished=0;
    public boolean isPaused;

    public DownloadTask(Context context, FileInfos fileInfos) {
        this.context = context;
        this.fileInfos = fileInfos;
        threadDaoImp=new ThreadDaoImp(context);
    }

    public void download()
    {
        //读取数据库的线程信息
        List<ThreadInfos> list = threadDaoImp.getThreads(fileInfos.getUrl());
        ThreadInfos threadInfos=null;
        if (list.size()==0)
        {
            //初始化线程信息对象
            threadInfos = new ThreadInfos(0,fileInfos.getUrl(),0,fileInfos.getLength(),0);
            //创建子线程进行下载
            new DownloadThread(threadInfos).start();
        }
        else
        {
            for (int i = 0; i < list.size(); i++) {
                threadInfos=list.get(i);
                new DownloadThread(threadInfos).start();
            }
        }
    }

    //下载线程
    class DownloadThread extends Thread{

        private ThreadInfos threadInfos;

        public DownloadThread(ThreadInfos threadInfos) {
            this.threadInfos = threadInfos;
        }

        @Override
        public void run() {
            super.run();
            //先数据库插入线程信息
            if (!threadDaoImp.isExists(threadInfos.getUrl(),threadInfos.getId()))
            {
                threadDaoImp.insertThread(threadInfos);
            }
            RandomAccessFile raf=null;
            try {
                URL url = new URL(threadInfos.getUrl());
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                //conn.connect();
                int length=-1;
                //设置下载位置
                int start=threadInfos.getStart()+threadInfos.getFinished();
                conn.setRequestProperty("Range","bytes="+start+"-"+threadInfos.getEnd());
                //设置文件写入位置
                File file = new File(DownloadService.DOWNLOAD_PATH,fileInfos.getFileName());
                raf = new RandomAccessFile(file, "rwd");
                raf.seek(start);
                Intent intent = new Intent();
                intent.setAction(DownloadService.ACTION_UPDATE);
                mFinished+=threadInfos.getFinished();
                if (conn.getResponseCode()==206)
                {
                    //开始下载
                    //读取数据
                    InputStream input = conn.getInputStream();
                    byte[] bytes = new byte[1024*4];
                    long time=0;
                    while ((length=input.read(bytes))!=-1)
                    {
                        //写入文件
                        raf.write(bytes,0,length);
                        //把下载进度通过广播发送给activity
                        mFinished+=length;
                        if (mFinished>=fileInfos.getLength())
                        {
                            mFinished=fileInfos.getLength();
                        }
                        if (System.currentTimeMillis()-time>300)
                        {
                            time=System.currentTimeMillis();
                            intent.putExtra("progress",mFinished*100/fileInfos.getLength());
                            context.sendBroadcast(intent);
                        }
                        //在下载暂停时,保存下载进度
                        if (isPaused)
                        {
                            threadDaoImp.updateThread(threadInfos.getUrl(),threadInfos.getId(),mFinished);
                            return;
                        }
                    }
                    //下载完成后,删除线程信息
                    threadDaoImp.deleteThread(threadInfos.getUrl(),threadInfos.getId());
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (raf!=null)
                    {
                        raf.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

/**数据库访问接口
 * Created by Administrator on 2017/7/19.
 */

public interface ThreadDao {

    //插入线程信息
    public void insertThread(ThreadInfos threadInfos);

    //删除线程
    public void deleteThread(String url,int thredId);

    //更新线程下载进度
    public void updateThread(String url,int threadId,int finished);

    //查询线程信息
    public List<ThreadInfos> getThreads(String url);

    //线程信息是否存在
    public boolean isExists(String url,int threadId);
}

/**
 * Created by Administrator on 2017/7/19.
 */

public class DownloadService extends Service{

    public static final String DOWNLOAD_PATH= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
                                                    + File.separator+"demo";
    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 int MSG_INIT=0;

    DownloadTask downloadTask;

    public Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what)
            {
                case 0:
                    FileInfos fileInfos= (FileInfos) msg.obj;
                    Log.d("==handler====","======="+fileInfos.toString());
                    //启动下载任务
                    downloadTask = new DownloadTask(DownloadService.this, fileInfos);
                    downloadTask.download();
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //获取从activity中传递过来的信息
        if (ACTION_START.equals(intent.getAction()))
        {
            FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");
            Log.d("==start====","======"+fileInfo.toString());
            new InitThread(fileInfo).start();
        }
        else if (ACTION_STOP.equals(intent.getAction()))
        {
            FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");
            Log.d("==stop====","======"+fileInfo.toString());
            if (downloadTask!=null)
            {
                downloadTask.isPaused=true;
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    class InitThread extends Thread{
        FileInfos fileInfos;

        public InitThread(FileInfos fileInfos) {
            this.fileInfos = fileInfos;
        }

        @Override
        public void run() {
            super.run();
            RandomAccessFile raf=null;
            try {
                //连接网络文件
                URL url = new URL(fileInfos.getUrl());
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.connect();
                int length=-1;
                if (conn.getResponseCode()==200)
                {
                    //获得文件长度
                    length=conn.getContentLength();
                    if (length<=0)
                    {
                        return;
                    }
                    File dir=new File(DOWNLOAD_PATH);
                    if (!dir.exists())
                    {
                        dir.mkdirs();
                    }
                    //在本地创建文件
                    File file=new File(dir,fileInfos.getFileName());
                    raf = new RandomAccessFile(file, "rwd");
                    //设置文件长度
                    raf.setLength(length);
                }
                fileInfos.setLength(length);
                Message message = handler.obtainMessage();
                message.what=MSG_INIT;
                message.obj=fileInfos;
                handler.sendMessage(message);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (raf!=null)
                    {
                        raf.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    TextView textView;
    ProgressBar progressBar;
    Button start_bt,pause_bt;

    FileInfos fileInfos;

    MyBroadCastReceiver receiver;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView= (TextView) findViewById(R.id.textView);
        progressBar= (ProgressBar) findViewById(R.id.progressBar);
        start_bt= (Button) findViewById(R.id.start_bt);
        pause_bt= (Button) findViewById(R.id.pause_bt);

        initListener();
        initFileInfo();
        initData();
    }

    private void initData() {
        //注册广播
        receiver = new MyBroadCastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(DownloadService.ACTION_UPDATE);
        registerReceiver(receiver,intentFilter);
        progressBar.setMax(50);
        textView.setText(fileInfos.getFileName());
    }

    private void initFileInfo() {

        //http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk
        //http://www.imooc.com/video/7052
        fileInfos = new FileInfos(0, "http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk",
                                            "kuwo.apk", 0, 0);
    }

    private void initListener() {
        start_bt.setOnClickListener(this);
        pause_bt.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId())
        {
            case R.id.start_bt:
                Intent intentStart = new Intent(this, DownloadService.class);
                intentStart.setAction(DownloadService.ACTION_START);
                intentStart.putExtra("fileInfo",fileInfos);
                startService(intentStart);
                break;
            case R.id.pause_bt:
                Intent intentStop = new Intent(this, DownloadService.class);
                intentStop.setAction(DownloadService.ACTION_STOP);
                intentStop.putExtra("fileInfo",fileInfos);
                startService(intentStop);
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

    class MyBroadCastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            if (DownloadService.ACTION_UPDATE.equals(intent.getAction()))
            {
                int progress = intent.getIntExtra("progress", -1);
                if (-1!=progress)
                {
                    progressBar.setProgress(progress);
                }

            }
        }
    }
}

其实还有个bug一直没解决,进度条在文件下载完成后,并没有走满,而且我在公有目录下新建的文件夹的时间显示是2012/00/00/00,,,如果解决了,记得给我留言告我一声啊!
这里写代码片
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值