`
wx1569567608
  • 浏览: 63907 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Android 文件断点下载

 
阅读更多

第一步我们先来创建一张表用来保存我们的下载信息

public class DbHelper extends SQLiteOpenHelper {

    public static String TABLE = "file";//表名

    public DbHelper(Context context) {
        super(context, "download.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //文件名,下载地址,下载文件的总长度,当前下载完成长度
        db.execSQL("create table file(fileName varchar,url varchar,length integer,finished integer)");
    }
}
  •  

:第二步同时既然是对数据库的操作,那我们在DbHelper.class中来写好几个公用方法

    /**
     * 插入一条下载信息
     */
    public void insertData(SQLiteDatabase db, FileInfo info) {
        ContentValues values = new ContentValues();
        values.put("fileName", info.getFileName());
        values.put("url", info.getUrl());
        values.put("length", info.getLength());
        values.put("finished", info.getFinished());
        db.insert(TABLE, null, values);
    }

    /**
     * 是否已经插入这条数据
     */
    public boolean isExist(SQLiteDatabase db, FileInfo info) {
        Cursor cursor = db.query(TABLE, null, "url = ?", new String[]{info.getUrl()}, null, null, null, null);
        boolean exist = cursor.moveToNext();
        cursor.close();
        return exist;
    }

    /**
     * 查询已经存在的一条信息
     */
    public FileInfo queryData(SQLiteDatabase db, String url) {
        Cursor cursor = db.query(TABLE, null, "url = ?", new String[]{url}, null, null, null, null);
        FileInfo info = new FileInfo();
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String fileName = cursor.getString(cursor.getColumnIndex("fileName"));
                int length = cursor.getInt(cursor.getColumnIndex("length"));
                int finished = cursor.getInt(cursor.getColumnIndex("finished"));
                info.setStop(false);
                info.setFileName(fileName);
                info.setUrl(url);
                info.setLength(length);
                info.setFinished(finished);
            }
            cursor.close();
        }
        return info;
    }


    /**
     * 恢复一条下载信息
     */
    public void resetData(SQLiteDatabase db, String url) {
        ContentValues values = new ContentValues();
        values.put("finished", 0);
        values.put("length", 0);
        db.update(TABLE, values, "url = ?", new String[]{url});
    }

3.从上面方法中可以看出来还有一个FileInfo对象,没错这是自己创建的一个下载任务实体类一起来看看吧

//保存下载任务信息
public class FileInfo {
    private String fileName;//文件名
    private String url;//下载地址
    private int length;//文件大小
    private int finished;//下载以已完成进度
    private boolean isStop = false;//是否暂停下载
    private boolean isDownLoading = false;//是否正在下载
    //......
    //剩下的都是对应的get and set 方法就不贴出来了,自动生成就好了

四:第三步我们创建一个类DownLoaderManger来管理我们的下载任务包括、添加下载任务、开始下载、暂停下载、重新下载

public class DownLoaderManger {

    public static String FILE_PATH = Environment.getExternalStorageDirectory() + "/azhong";//文件下载保存路径
    private DbHelper helper;//数据库帮助类
    private SQLiteDatabase db;
    private OnProgressListener listener;//进度回调监听
    private Map<String, FileInfo> map = new HashMap<>();//保存正在下载的任务信息
    private static DownLoaderManger manger;

    private DownLoaderManger(DbHelper helper, OnProgressListener listener) {
        this.helper = helper;
        this.listener = listener;
        db = helper.getReadableDatabase();
    }

    /**
     * 单例模式
     *
     * @param helper   数据库帮助类
     * @param listener 下载进度回调接口
     * @return
     */
    public static synchronized DownLoaderManger getInstance(DbHelper helper, OnProgressListener listener) {
        if (manger == null) {
            synchronized (DownLoaderManger.class) {
                if (manger == null) {
                    manger = new DownLoaderManger(helper, listener);
                }
            }
        }
        return manger;
    }

    /**
     * 开始下载任务
     */
    public void start(String url) {
        db = helper.getReadableDatabase();
        FileInfo info = helper.queryData(db, url);
        map.put(url, info);
        //开始任务下载
        new DownLoadTask(map.get(url), helper, listener).start();
    }

    /**
     * 停止下载任务
     */
    public void stop(String url) {
        map.get(url).setStop(true);
    }

    /**
     * 重新下载任务
     */
    public void restart(String url) {
        stop(url);
        try {
            File file = new File(FILE_PATH, map.get(url).getFileName());
            if (file.exists()) {
                file.delete();
            }
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        db = helper.getWritableDatabase();
        helper.resetData(db, url);
        start(url);
    }

    /**
     * 获取当前任务状态
     */
    public boolean getCurrentState(String url) {
        return map.get(url).isDownLoading();
    }

    /**
     * 添加下载任务
     *
     * @param info 下载文件信息
     */
    public void addTask(FileInfo info) {
        //判断数据库是否已经存在这条下载信息
        if (!helper.isExist(db, info)) {
            db = helper.getWritableDatabase();
            helper.insertData(db, info);
            map.put(info.getUrl(), info);
        } else {
            //从数据库获取最新的下载信息
            db = helper.getReadableDatabase();
            FileInfo o = helper.queryData(db, info.getUrl());
            if (!map.containsKey(info.getUrl())) {
                map.put(info.getUrl(), o);
            }
        }
    }
}

五:上面代码中OnProgressListener接口,当然还有一个最最重要的DownLoadTask了这里面就是实现了如何断点下载的,下面来一起看下里面的实现逻辑吧。。。

//下载进度接口
public interface OnProgressListener {

    void updateProgress(int max, int progress);
}

六:重点–下载线程

/**
 * 下载文件线程
 * 从服务器获取需要下载的文件大小
 */
public class DownLoadTask extends Thread {
    private FileInfo info;
    private SQLiteDatabase db;
    private DbHelper helper;//数据库帮助类
    private int finished = 0;//当前已下载完成的进度
    private OnProgressListener listener;//进度回调监听

    public DownLoadTask(FileInfo info, DbHelper helper, OnProgressListener listener) {
        this.info = info;
        this.helper = helper;
        this.db = helper.getReadableDatabase();
        this.listener = listener;
        info.setDownLoading(true);
    }

    @Override
    public void run() {
        getLength();
        HttpURLConnection connection = null;
        RandomAccessFile rwd = null;
        try {
            URL url = new URL(info.getUrl());
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(3000);
            //从上次下载完成的地方下载
            int start = info.getFinished();
            //设置下载位置(从服务器上取要下载文件的某一段)
            connection.setRequestProperty("Range", "bytes=" + start + "-" + info.getLength());//设置下载范围
            //设置文件写入位置
            File file = new File(DownLoaderManger.FILE_PATH, info.getFileName());
            rwd = new RandomAccessFile(file, "rwd");
            //从文件的某一位置开始写入
            rwd.seek(start);
            finished += info.getFinished();
            if (connection.getResponseCode() == 206) {//文件部分下载,返回码为206
                InputStream is = connection.getInputStream();
                byte[] buffer = new byte[1024 * 4];
                int len;
                while ((len = is.read(buffer)) != -1) {
                    //写入文件
                    rwd.write(buffer, 0, len);
                    finished += len;
                    info.setFinished(finished);
                    //更新界面显示
                    Message msg = new Message();
                    msg.what = 0x123;
                    msg.arg1 = info.getLength();
                    msg.arg2 = info.getFinished();
                    handler.sendMessage(msg);
                    //停止下载
                    if (info.isStop()) {
                        info.setDownLoading(false);
                        //保存此次下载的进度
                        helper.updateData(db, info);
                        db.close();
                        return;
                    }
                }
                //下载完成
                info.setDownLoading(false);
                helper.updateData(db, info);
                db.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            try {
                if (rwd != null) {
                    rwd.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 首先开启一个线程去获取要下载文件的大小(长度)
     */
    private void getLength() {
        HttpURLConnection connection = null;
        try {
            //连接网络
            URL url = new URL(info.getUrl());
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(3000);
            int length = -1;
            if (connection.getResponseCode() == 200) {//网络连接成功
                //获得文件长度
                length = connection.getContentLength();
            }
            if (length <= 0) {
                //连接失败
                return;
            }
            //创建文件保存路径
            File dir = new File(DownLoaderManger.FILE_PATH);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            info.setLength(length);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            try {
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 更新进度
     */
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0x123:
                    if (listener != null) {
                        listener.updateProgress(msg.arg1, msg.arg2);
                    }
                    break;
            }
        }
    };
}

七:下载流程—>首先获取要下载文件的总长度—>然后指定从上次结束的位置开始下载文件。客官阅读需仔细哦,精华都在注释里面哦!个人认为重点部分如下两个:

//设置下载位置(从服务器上取要下载文件的某一段)
connection.setRequestProperty("Range", "bytes=" + start + "-" + info.getLength());//设置下载范围

RandomAccessFile rwd = new RandomAccessFile(file, "rwd");
//从文件的某一位置开始写入
rwd.seek(start);

八:上面做了一系列准备工作之后,就可以正式开始下载了让我们一起来瞧瞧

1.给主布局界面放两个按钮,来开始/暂停/重新下载

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.azhong.downloader.MainActivity">

    <com.azhong.downloader.view.NumberProgressBar
        android:id="@+id/pb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="开始下载" />

    <Button
        android:id="@+id/restart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="重新下载" />
</LinearLayout>
  •  

2.关于NumberProgressBar的使用可以移驾至这里 
3.记得在清单文件中加入 网络访问和内存读写权限哦! 
4.既然我们封装了那么久,那肯定用起来就会很简单了

public class MainActivity extends AppCompatActivity implements OnProgressListener {

    private NumberProgressBar pb;//进度条
    private DownLoaderManger downLoader = null;
    private FileInfo info;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb = (NumberProgressBar) findViewById(R.id.pb);
        final Button start = (Button) findViewById(R.id.start);//开始下载
        final Button restart = (Button) findViewById(R.id.restart);//重新下载
        final DbHelper helper = new DbHelper(this);
        downLoader = DownLoaderManger.getInstance(helper, this);
        info = new FileInfo("Kuaiya482.apk", "http://downloadz.dewmobile.net/Official/Kuaiya482.apk");
        downLoader.addTask(info);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (downLoader.getCurrentState(info.getUrl())) {
                    downLoader.stop(info.getUrl());
                    start.setText("开始下载");
                } else {
                    downLoader.start(info.getUrl());
                    start.setText("暂停下载");
                }
            }
        });
        restart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                downLoader.restart(info.getUrl());
                start.setText("暂停下载");
            }
        });
    }

    @Override
    public void updateProgress(final int max, final int progress) {
        pb.setMax(max);
        pb.setProgress(progress);
    }
}

转载于:https://my.oschina.net/u/3407628/blog/1562965

分享到:
评论

相关推荐

    Android文件断点下载

    在Android平台上,文件断点下载是一项重要的功能,尤其对于大文件的下载,它允许用户在任意时间暂停并恢复下载过程,而不会丢失已下载的数据。本文将深入探讨如何使用HttpURLConnection实现这一功能。 首先,理解...

    Android文件下载(实现断点续传)

    综上所述,实现Android文件的断点续传下载主要依赖于Java的RandomAccessFile类和多线程技术,通过精确控制文件的读写位置和下载范围,确保下载的连续性和可靠性。这种技术不仅提高了用户的下载体验,也在一定程度上...

    Android文件断点下载案例

    在Android开发中,断点下载是一项重要的功能,它允许用户在中断网络连接后从上次停止的位置继续下载大文件,如应用程序、音乐或视频。本文将深入探讨如何在Android平台上实现断点下载,包括其原理、步骤以及核心代码...

    Android OkHttp断点下载

    在Android开发中,OkHttp和RxJava的结合可以实现高效的网络请求处理,其中包括断点下载功能。断点下载是指在用户暂停下载后,可以从上次停止的位置继续下载,避免了重新开始下载大文件的不便。本篇文章将深入探讨...

    android文件下载(实现断点续传)

    在Android平台上,文件下载是一项常见的任务,特别是在处理大型文件或多媒体资源时,为了提升用户体验,开发者通常会采用多线程下载并实现断点续传功能。断点续传允许用户在下载过程中暂停、恢复,避免因网络问题或...

    android AsyncTask 断点下载实例

    本实例将探讨如何利用AsyncTask实现断点下载功能,这是一种允许用户在暂停后继续下载大文件的技术,极大地提高了用户体验。 首先,我们需要了解AsyncTask的结构。AsyncTask包含三个泛型参数:Params, Progress, ...

    Android 断点下载文件通知栏提示

    在Android开发中,断点下载是一项重要的功能,它允许用户在网络连接不稳定或者设备电量不足时暂停下载,并在后续时间继续从上次停止的地方开始,而无需重新下载整个文件。结合通知栏提示,可以提供用户友好的体验,...

    android 多线程文件断点下载

    在Android开发中,多线程文件断点下载是一项重要的技术,尤其对于大文件的下载,它能显著提高下载效率并提供更好的用户体验。断点下载允许用户在任何时间暂停下载,并在之后从停止的地方继续,而不会丢失已下载的...

    Android断点下载示例

    这个示例中提供的“断点续传”文件可能包含了实现上述步骤的源代码,包括网络请求、文件写入、进度更新等模块,是深入理解Android断点下载机制的好素材。通过分析和实践这些代码,开发者可以进一步掌握Android网络...

    Android断点下载.zip

    总的来说,Android断点下载是一个涉及网络通信、文件操作和状态管理的复杂过程。开发者需要对HTTP协议有深入理解,并熟练掌握Android的文件系统和网络库。通过分析提供的源码,可以进一步学习和理解这一机制的具体...

    android通知栏,断点下载

    总之,Android断点下载涉及的关键技术包括:后台任务处理(如`AsyncTask`或`IntentService`)、`DownloadManager`API、文件状态的持久化存储以及通知栏的实时更新。通过研究和实践"yinglovezhuzhu/AndroidDownloader...

    Android多线程断点续传下载

    Android提供了一个系统级别的`DownloadManager`服务,它可以处理文件的断点续传,但可能不如自定义实现的多线程下载灵活。 6. **文件读写操作** 在下载过程中,需要使用`RandomAccessFile`进行文件的追加写入,...

    android多线程断点下载

    在Android开发中,多线程断点下载是一项重要的技术,特别是在处理大文件或者网络环境不稳定的情况下,能够提高下载效率并确保下载的连续性。本文将详细介绍如何在Android中实现多线程断点下载,以及如何封装一个易于...

    Android高级应用源码-Android断点下载.zip

    在Android平台上,断点下载是一项重要的功能,它允许用户在中断网络连接后,从上次停止的地方继续下载大文件,而不必重新开始。本资源“Android高级应用源码-Android断点下载.zip”提供了实现这一功能的详细源代码,...

    Android断点下载-IT计算机-毕业设计.zip

    在Android平台上进行断点下载是一项常见的技术需求,尤其对于大文件下载或网络不稳定的情况,它允许用户暂停、恢复下载过程,提高用户体验。本项目是一个基于Android应用的源码开发示例,适合毕业设计学习,涵盖了...

    Android单个文件,断点下载

    在Android开发中,实现“单个文件的断点下载”是一项常见的需求,它涉及到多个关键技术和组件的协同工作。下面将详细阐述这个过程中的主要知识点。 首先,我们要理解什么是“断点下载”。断点下载允许用户在下载...

    Android 文件断点续传源码

    Android 文件断点续传源码可以下在直接用的

    android Http实现文件多线程断点下载

    在Android平台上,实现文件的多线程断点下载是一项常见的任务,这有助于提高下载速度并允许用户在中断后继续未完成的下载。以下是一个详细解释这个过程的关键知识点: 1. **HTTP请求与响应**: - HTTP是互联网上...

    Android网络通信之文件断点下载事例代码

    以上就是Android网络通信中实现文件断点下载的主要步骤。在NetMulThreadDownload这个示例中,你应该能找到具体的实现细节,包括如何配置XML资源(如string.xml中的net_path属性),以及如何组织和协调多线程下载。...

    Android 文件断点续传实例

    总结,Android文件断点续传涉及网络请求、文件操作、数据存储等多个技术领域,通过合理的策略和适当的工具,可以为用户提供高效、可靠的文件传输体验。在实际开发中,还需要考虑到各种异常情况的处理,确保服务的...

Global site tag (gtag.js) - Google Analytics