美文网首页
断点下载

断点下载

作者: _成长ing_ | 来源:发表于2018-10-04 15:05 被阅读0次

效果图


效果图.gif

断点下载的过程


过程图.png

这里是简单的一个下载,下一篇介绍列表的断点下载
1.绘制UI图,并初始化控件
2.创建实体类:文件类、线程类
文件类:

public class FileInfo implements Serializable {
    private int id;
    private String url;
    private String flieName;
    private int length;
    private int finished;


    public FileInfo() {
    }

    public FileInfo(int id, String url, String flieName, int length, int finished) {
        this.id = id;
        this.url = url;
        this.flieName = flieName;
        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 getFlieName() {
        return flieName;
    }

    public void setFlieName(String flieName) {
        this.flieName = flieName;
    }

    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 + '\'' +
                ", flieName='" + flieName + '\'' +
                ", length=" + length +
                ", finished=" + finished +
                '}';
    }
}

线程类

public class ThreadInfo {
    private int id;
    private String url;
    private int start;
    private int end;
    private int finished;

    @Override
    public String toString() {
        return "ThreadInfo{" +
                "id=" + id +
                ", url='" + url + '\'' +
                ", start=" + start +
                ", end=" + end +
                ", finished=" + finished +
                '}';
    }

    public ThreadInfo(int id, String url, int start, int end, int finished) {
        this.id = id;
        this.url = url;
        this.start = start;
        this.end = end;
        this.finished = finished;
    }

    public ThreadInfo() {
    }

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

DownloadService(记得在AndroidManifest.xml文件中注册)

public class DownloadService extends Service {
    //下载的路径
    public static final String DOWNLOAD_PATH =
            Environment.getExternalStorageDirectory().getAbsolutePath() + "/download/";
    //开始下载
    public static final String ACTION_START = "ACTION_START";
    //暂停下载
    public static final String ACTION_STOP = "ACTION_STOP";
    //更新下载
    public static final String ACTION_UPDATE_PROGRESS = "ACTION_UPDATE";
    //获取下载信息
    public static final String FILE_INFO = "fileInfo";
    public static final int MSG_INIT = 0;
    //下载任务
    private DownloadTask task = null;


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (ACTION_START.equals(intent.getAction())) {
            FileInfo fileInfo = (FileInfo) intent.getSerializableExtra(FILE_INFO);
            Log.e("test", "start:" + fileInfo.toString());
            //启动线程--获取文件长度
            new InitThread(fileInfo).start();
        } else if (ACTION_STOP.equals(intent.getAction())) {
            FileInfo fileInfo = (FileInfo) intent.getSerializableExtra(FILE_INFO);
            Log.e("test", "stop:" + fileInfo.toString());
            //点击暂停下载
            if (task != null) {
                task.isPause = true;
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

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

    //初始化信息完毕,开始下载
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_INIT:
                    FileInfo fileInfo = (FileInfo) msg.obj;
                    Log.e("test", "Thread:" + fileInfo.toString());
                    task = new DownloadTask(DownloadService.this, fileInfo);
                    task.download();
                    break;
            }
        }
    };

    //获取文件长度
    class InitThread extends Thread {
        private FileInfo fileInfo;

        public InitThread(FileInfo fileInfo) {
            this.fileInfo = fileInfo;
        }

        @Override
        public void run() {
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            try {
                //链接网络文件,
                URL url = new URL(fileInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(4000);
                conn.setRequestMethod("GET");
                int length = -1;
                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    //获得文件长度
                    length = conn.getContentLength();
                }
                if (length <= 0) {
                    return;
                }
                File dir = new File(DOWNLOAD_PATH);
                if (!dir.exists()) {
                    dir.mkdir();
                }
                //在本地创建文件
                File file = new File(dir, fileInfo.getFlieName());
                raf = new RandomAccessFile(file, "rwd");
                //设置文件长度
                raf.setLength(length);
                fileInfo.setLength(length);
                handler.obtainMessage(MSG_INIT, fileInfo).sendToTarget();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (conn != null) {
                        conn.disconnect();
                    }
                    if (raf != null) {
                        raf.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

暂停下载的时候需要将进度保存下来,需要创建一张表,并对这个表进行操作
表的相关信息

public class ThreadTable {

    public static final String TABLE_NAME = "thread_table";
    public static final String COL_ID = "_id";
    public static final String COL_THREAD_ID = "thread_id";
    public static final String COL_URL = "url";
    public static final String COL_START = "start";
    public static final String COL_END = "end";
    public static final String COL_FINISHED = "finished";

    public static final String CREATE_TABLE = "create table "
            + TABLE_NAME + "("
            + COL_ID + " integer primary key autoincrement,"
            + COL_THREAD_ID + " integer,"
            + COL_URL + " text,"
            + COL_START + " integer,"
            + COL_END + " integer,"
            + COL_FINISHED + " integer);";

    public static final String DROP_TABLE = "drop table if exists " + TABLE_NAME;

}

DBHelp

public class DBHelp extends SQLiteOpenHelper {


    public DBHelp(Context context) {
        super(context, "app_manager", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(ThreadTable.CREATE_TABLE);
        Log.e("sql", "table==" + ThreadTable.CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//        db.execSQL(ThreadTable.DROP_TABLE);
//        db.execSQL(ThreadTable.CREATE_TABLE);
    }
}

ThreadDao

public interface ThreadDao {
    /**
     * 插入线程
     */
    void insertThread(ThreadInfo threadInfo);

    /**
     * 删除线程
     *
     * @param url
     * @param thread_id
     */
    void deleteThread(String url, int thread_id);

    /**
     * 更新线程进度
     *
     * @param url
     * @param thread_id
     * @param finished
     */
    void updateThread(String url, int thread_id, int finished);

    /**
     * 查询文件的线程信息
     *
     * @param url
     * @return
     */
    List<ThreadInfo> getThreads(String url);

    /**
     * 判断线程信息是否存在
     *
     * @param url
     * @param thread_id
     * @return
     */
    boolean isExists(String url, int thread_id);
}

实现类

public class ThreadDaoImpl implements ThreadDao {

    private DBHelp dbHelp = null;

    public ThreadDaoImpl(Context context) {
        dbHelp = new DBHelp(context);
    }

    @Override
    public void insertThread(ThreadInfo threadInfo) {
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        String sql = "insert into " + ThreadTable.TABLE_NAME +
                "(" + ThreadTable.COL_THREAD_ID + "," + ThreadTable.COL_URL + "," + ThreadTable.COL_START + "," + ThreadTable.COL_END + "," + ThreadTable.COL_FINISHED
                + ") values(?,?,?,?,?)";
        Log.e("sql","insert=="+sql);
        db.execSQL(sql, new Object[]{threadInfo.getId(), threadInfo.getUrl(), threadInfo.getStart(), threadInfo.getEnd(), threadInfo.getFinished()});
        db.close();
    }

    @Override
    public void deleteThread(String url, int thread_id) {
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        String sql = "delete from " + ThreadTable.TABLE_NAME + " where " + ThreadTable.COL_URL + " = ? and " + ThreadTable.COL_THREAD_ID + " = ?";
        db.execSQL(sql, new Object[]{url, thread_id});
        db.close();
    }

    @Override
    public void updateThread(String url, int thread_id, int finished) {
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        String sql = "update " + ThreadTable.TABLE_NAME + " set " + ThreadTable.COL_FINISHED + " = ? where " + ThreadTable.COL_URL + " = ? and " + ThreadTable.COL_THREAD_ID + " = ?";
        db.execSQL(sql, new Object[]{finished, url, thread_id});
        db.close();
    }

    @Override
    public List<ThreadInfo> getThreads(String url) {
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        List<ThreadInfo> threadInfoList = new ArrayList<>();
        String sql = "select * from " + ThreadTable.TABLE_NAME + " where " + ThreadTable.COL_URL + " = ?";
        Cursor cursor = db.rawQuery(sql, new String[]{url});
        while (cursor.moveToNext()) {
            ThreadInfo info = new ThreadInfo();
            info.setId(cursor.getInt(cursor.getColumnIndex(ThreadTable.COL_THREAD_ID)));
            info.setUrl(cursor.getString(cursor.getColumnIndex(ThreadTable.COL_URL)));
            info.setStart(cursor.getInt(cursor.getColumnIndex(ThreadTable.COL_START)));
            info.setEnd(cursor.getInt(cursor.getColumnIndex(ThreadTable.COL_END)));
            info.setFinished(cursor.getInt(cursor.getColumnIndex(ThreadTable.COL_FINISHED)));
            threadInfoList.add(info);
        }
        db.close();
        return threadInfoList;
    }

    @Override
    public boolean isExists(String url, int thread_id) {
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        String sql = "select * from " + ThreadTable.TABLE_NAME + " where " + ThreadTable.COL_URL + " = ? and " + ThreadTable.COL_THREAD_ID + " = ?";
        Cursor cursor = db.rawQuery(sql, new String[]{url, thread_id + ""});
        boolean isExist = cursor.moveToNext();
        return isExist;
    }
}

下载的具体实现

public class DownloadTask {
    private Context context;
    private FileInfo fileInfo;
    private ThreadDao mDao;
    public int mFinished = 0;
    public static final String FINISHED = "finished";
    public boolean isPause = false;

    public DownloadTask(Context context, FileInfo fileInfo) {
        this.context = context;
        this.fileInfo = fileInfo;
        mDao = new ThreadDaoImpl(context);
    }

    public void download() {
        //读取数据库的线程信息
        List<ThreadInfo> threads = mDao.getThreads(fileInfo.getUrl());
        ThreadInfo threadInfo = null;
        if (threads == null || threads.size() == 0) {
            threadInfo = new ThreadInfo(0, fileInfo.getUrl(), 0, fileInfo.getLength(), 0);
        } else {
            threadInfo = threads.get(0);
        }
        //创建子线程下载
        new DownLoadThread(threadInfo).start();
    }

    class DownLoadThread extends Thread {
        private ThreadInfo threadInfo;

        public DownLoadThread(ThreadInfo threadInfo) {
            this.threadInfo = threadInfo;
        }

        @Override
        public void run() {
            //向数据库插入线程信息
            if (!mDao.isExists(threadInfo.getUrl(), threadInfo.getId())) {
                mDao.insertThread(threadInfo);
            }
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            InputStream inputStream = null;
            try {
                URL url = new URL(threadInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(4000);
                conn.setRequestMethod("GET");
                //设置下载位置
                int start = threadInfo.getStart() + threadInfo.getFinished();
                conn.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd());
                //设置文件写入位置
                File file = new File(DownloadService.DOWNLOAD_PATH, fileInfo.getFlieName());
                raf = new RandomAccessFile(file, "rwd");
                raf.seek(start);
                mFinished += threadInfo.getFinished();
                Intent intent = new Intent(DownloadService.ACTION_UPDATE_PROGRESS);
                //开始下载
                if (conn.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
                    //读取数据
                    inputStream = conn.getInputStream();
                    byte[] bytes = new byte[1024 * 4];
                    int len = -1;
                    long time = System.currentTimeMillis();
                    while ((len = inputStream.read()) != -1) {
                        //写入文件
                        raf.write(bytes, 0, len);
                        //把下载进度发送广播给activity
                        mFinished += len;
                        if (System.currentTimeMillis() - time > 500) {
                            intent.putExtra(FINISHED, mFinished * 100 / fileInfo.getLength());
                            context.sendBroadcast(intent);
                        }
                        //在下载暂停时,保存下载进度
                        if (isPause) {
                            mDao.updateThread(threadInfo.getUrl(), threadInfo.getId(), mFinished);
                            return;
                        }
                    }
                    //删除线程信息
                    mDao.deleteThread(threadInfo.getUrl(), threadInfo.getId());
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (raf != null) {
                        raf.close();
                    }
                    if (conn != null) {
                        conn.disconnect();
                    }
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Activity接收广播,并更新数据

 BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(DownloadService.ACTION_UPDATE_PROGRESS)) {
                int currentProgress = intent.getIntExtra(DownloadTask.FINISHED, 0);
                progressBar.setProgress(currentProgress);
                tvProgress.setText(currentProgress + "%");
            }
        }
    };

注册广播

 IntentFilter intentFilter = new IntentFilter();
     intentFilter.addAction(DownloadService.ACTION_UPDATE_PROGRESS);
        registerReceiver(receiver, intentFilter);

取消注册

    @Override
    protected void onDestroy() {
        if (receiver != null) {
            unregisterReceiver(receiver);
        }
        super.onDestroy();
    }

项目下载地址:
https://download.csdn.net/download/diudiu666hf/10701030

相关文章

  • 基于Okhttp实现断点下载(续传)和分片下载

    断点下载/续传 断点下载是针对下载大文件需求的一种优化机制,可以从上次下载的断点处继续下载。断点续传原理也相同,只...

  • 断点下载

    效果图 断点下载的过程 这里是简单的一个下载,下一篇介绍列表的断点下载1.绘制UI图,并初始化控件2.创建实体类:...

  • 断点下载

    今天做了断点下载视频或者MP3,具体实现如下 1、主要应用了NSURLSessionDownloadTask和NS...

  • 断点下载

    链接转载;判断当前Service是否是重启的Servciehttp://blog.csdn.net/luyi325...

  • 断点下载

    http://www.jianshu.com/p/f65e32012f07

  • 断点下载

    断点下载重点 利用HTTP请求头的Range属性,就可以实现从指定位置开始下载表示头500个字节:Range: b...

  • 断点下载

    需要遵循NSURLConnectionDataDelegate协议/** 当前的长度/@property (no...

  • 断点下载

  • OC网络:NSURLSession-downloadTask的断

    NSURLSessionDownloadDelegate断点下载说明: 能实现断点下载,即在程序不退出的情况下:暂...

  • Android下载文件(一)下载进度&断点续传

    索引 Android下载文件(一)下载进度&断点续传 Android下载文件(二)多线程并发&断点续传(待续) A...

网友评论

      本文标题:断点下载

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