断点续传

来源:互联网 发布:js utf 8编码转换器 编辑:程序博客网 时间:2024/06/06 01:15

今天还是看着慕课网,把昨天的断点续传代码做了一些修改,用列表的形式,可以自定义下载一个文件需要的线程数,但是可能是由于线程的创建和销毁,还有多个线程同时操作数据库,所以感觉体验不是很好,虽然对方法声明了同步,也安排对数据库的操作在线程之外,同时也利用了线程池,来尽量减少对资源的消耗,,但是觉得不是很流畅,,,还有万恶的进度条,,,,

同样先是我的代码目录结构

这里写图片描述

adapter很简洁

List<FileInfos> list;    Context mContext;    LayoutInflater inflater;    public MyAdapter(List<FileInfos> list, Context mContext) {        this.list = list;        this.mContext = mContext;        inflater=LayoutInflater.from(mContext);    }    @Override    public int getCount() {        return list.size();    }    @Override    public Object getItem(int position) {        return list.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(final int position, View view, ViewGroup parent) {        MyViewHolder holder=null;        if (view==null)        {            view = inflater.inflate(R.layout.item_layout, parent, false);            holder = new MyViewHolder();            holder.textView= (TextView) view.findViewById(R.id.textView);            holder.start_bt= (Button) view.findViewById(R.id.start_bt);            holder.pause_bt= (Button) view.findViewById(R.id.pause_bt);            holder.progressBar= (ProgressBar) view.findViewById(R.id.progressBar);            view.setTag(holder);        }        else        {            holder= (MyViewHolder) view.getTag();        }        final MyViewHolder holderBuff=holder;        holder.start_bt.setTag(position);        holder.pause_bt.setTag(position);        //设置视图中的控件        final FileInfos fileInfos = list.get(position);        holder.textView.setText(fileInfos.getFileName());        holder.progressBar.setMax(100);        holder.progressBar.setProgress(fileInfos.getFinished());        holderBuff.start_bt.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (position==(int)holderBuff.start_bt.getTag())                {                    //通知service开始下载                    Intent intentStart = new Intent(mContext, DownloadService.class);                    intentStart.setAction(DownloadService.ACTION_START);                    intentStart.putExtra("fileInfo",fileInfos);                    mContext.startService(intentStart);                }            }        });        holderBuff.pause_bt.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (position==(int)holderBuff.pause_bt.getTag())                {                    //通知server暂停下载                    Intent intentStop = new Intent(mContext, DownloadService.class);                    intentStop.setAction(DownloadService.ACTION_STOP);                    intentStop.putExtra("fileInfo",fileInfos);                    mContext.startService(intentStop);                }            }        });        return view;    }    static class MyViewHolder{        TextView textView;        Button start_bt,pause_bt;        ProgressBar progressBar;    }public class FileInfos implements Serializable{    private int id;    private String url;    private String fileName;    private int length;    private int finished;}public class ThreadInfos implements Serializable{    private int id;    private String url;    private int start;    private int end;    private int finished;}public class DBHelper extends SQLiteOpenHelper{    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 synchronized 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 synchronized 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 synchronized void deleteThread(String url) {        SQLiteDatabase db = helper.getReadableDatabase();        db.execSQL("delete from thread_info where url= ? ",                new Object[]{url});        db.close();    }    @Override    public synchronized 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 synchronized 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 synchronized 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;    //下载一个文件需要的线程个数    private int threadCount;    private List<DownloadThread> downloadThreadList=new ArrayList<>();    //带缓存数量的线程池    public static ExecutorService executorService= Executors.newCachedThreadPool();    public DownloadTask(Context context, FileInfos fileInfos,int threadCount) {        this.context = context;        this.fileInfos = fileInfos;        this.threadCount=threadCount;        threadDaoImp=new ThreadDaoImp(context);    }    public void download()    {        //读取数据库的线程信息        List<ThreadInfos> list = threadDaoImp.getThreads(fileInfos.getUrl());        ThreadInfos threadInfos=null;        if (list.size()==0)        {            //获得每个线程需要下载的长度            int length = fileInfos.getLength() / threadCount;            for (int i = 0; i < threadCount; i++) {                //初始化线程信息对象                threadInfos = new ThreadInfos(i,fileInfos.getUrl(),length*i,(i+1)*length-1,0);                if (i==threadCount-1)                {                    threadInfos.setEnd(fileInfos.getLength());                }                list.add(threadInfos);                //先数据库插入线程信息                /*if (!threadDaoImp.isExists(threadInfos.getUrl(),threadInfos.getId()))                {                    threadDaoImp.insertThread(threadInfos);                }*/                threadDaoImp.insertThread(threadInfos);            }        }        //启动多个线程进行下载        for (int i = 0; i < list.size(); i++) {            threadInfos=list.get(i);            DownloadThread downloadThread = new DownloadThread(threadInfos);            //downloadThread.start();            //通过线程池启动线程            executorService.execute(downloadThread);            downloadThreadList.add(downloadThread);        }    }    //判断是否所有线程都执行完毕    public synchronized void checkAllThreadsFinished()    {        boolean allFinished=true;        for (DownloadThread downloadThread:downloadThreadList)        {            if (!downloadThread.isFinished)            {                allFinished=false;                break;            }        }        //下载完毕时,通知页面更新,并传递当前文件信息        if (allFinished)        {            threadDaoImp.deleteThread(fileInfos.getUrl());            Intent intent = new Intent();            intent.setAction(DownloadService.ACTION_FINISH);            intent.putExtra("fileInfo",fileInfos);            intent.putExtra("finish",0);            context.sendBroadcast(intent);        }    }    //下载线程    class DownloadThread extends Thread{        private ThreadInfos threadInfos;        //标志是否完成        public boolean isFinished=false;        public DownloadThread(ThreadInfos threadInfos) {            this.threadInfos = threadInfos;        }        @Override        public void run() {            super.run();            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;                        //设置每个线程的完成进度                        threadInfos.setFinished(threadInfos.getFinished()+length);                        if (mFinished>=fileInfos.getLength())                        {                            mFinished=fileInfos.getLength();                        }                        if (System.currentTimeMillis()-time>1000)                        {                            time=System.currentTimeMillis();                            intent.putExtra("progress",mFinished*100/fileInfos.getLength());                            intent.putExtra("position",fileInfos.getId());                            context.sendBroadcast(intent);                        }                        //在下载暂停时,保存下载进度                        if (isPaused)                        {                            threadDaoImp.updateThread(threadInfos.getUrl(),threadInfos.getId(),threadInfos.getFinished()+length);                            return;                        }                    }                    //当前线程下载完毕                    isFinished=true;                    //检查下载任务是否执行完毕                    checkAllThreadsFinished();                    //下载完成后,删除线程信息                    //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();                }            }        }    }}public interface ThreadDao {    //插入线程信息    public void insertThread(ThreadInfos threadInfos);    //删除线程    public void deleteThread(String url, int thredId);    //删除线程    public void deleteThread(String url);    //更新线程下载进度    public void updateThread(String url, int threadId, int finished);    //查询线程信息    public List<ThreadInfos> getThreads(String url);    //线程信息是否存在    public boolean isExists(String url, int threadId);}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_FINISH="ACTION_FINISH";    public static final String ACTION_UPDATE="ACTION_UPDATE";    public static final int MSG_INIT=0;    DownloadTask downloadTask;    //下载任务的集合    private Map<Integer,DownloadTask> mTasks=new LinkedHashMap<>();    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,1);                    downloadTask.download();                    mTasks.put(fileInfos.getId(),downloadTask);                    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());            InitThread initThread = new InitThread(fileInfo);            //通过线程池启动线程            DownloadTask.executorService.execute(initThread);        }        else if (ACTION_STOP.equals(intent.getAction()))        {            FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");            Log.d("==stop====","======"+fileInfo.toString());            //从集合中取出下载任务            downloadTask=mTasks.get(fileInfo.getId());            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 {    ListView listView;    List<FileInfos> list=new ArrayList<>();    MyAdapter adapter;    MyBroadCastReceiver receiver;    String urlKoWo="http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk";    String urlWangYiYun="http://wap.sogou.com/app/redir.jsp?appdown=1&u=b-5xxbPWjTJoeTuIzmwjONmoKoIYNgdlPOVy7fun_559rBQsnOOI53wn2loT2DsynmZKhKgICw9cvo3pwsuRdnnjD1ytUFis2XKdOfrva1NqaQuikpu3jJQKXph_jOiUllzWmh1shCpefgbQw2K0EZJD7JV3Lhf7&docid=-7472260854952176859&sourceid=-8776534065371990068&w=1906&stamp=20170720";    String urlQqYinYue="http://wap.sogou.com/app/redir.jsp?appdown=1&u=0Gd8piB6093-W-QPHXpNcQJvLH6U5CYdhuq4q4hqPTzLhN43WuAaT3n4Y-s0ktNHy6rGmVCuxuQ.&docid=-4411786374463855878&sourceid=-232956208690215432&w=1906&stamp=20170720";    String urlWangYiXinWen="http://wap.sogou.com/app/redir.jsp?appdown=1&u=b-5xxbPWjTJoeTuIzmwjONmoKoIYNgdlkJxIVeG_E-J5MlgzcFdg_6OaWQcQGiJV0ZeNYiLRI5ox-6Vb9Ht3p3njD1ytUFis2XKdOfrva1OAw54MZ2sYE4mD7zyni3p_HmD2WrN3oRsz6M6Y2evgE5cXC2PaxNpfD-pdxvmeHec.&docid=1984396447247278048&sourceid=4426688076946271253&w=1906&stamp=20170720";    String urlAiQiYi="http://wap.sogou.com/app/redir.jsp?appdown=1&u=0Gd8piB6093-W-QPHXpNcQJvLH6U5CYd5Zr5JWfuiTzw3lCzNhGrNbDfVRQLpRJX&docid=2339797260441192979&sourceid=7064725457117163301&w=1906&stamp=20170720";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        listView= (ListView) findViewById(R.id.listView);        FileInfos fileInfos = new FileInfos(0, urlKoWo, "kuwo.apk", 0, 0);        FileInfos fileInfos1 = new FileInfos(1, urlWangYiYun, "wangyiyun.apk", 0, 0);        FileInfos fileInfos2 = new FileInfos(2, urlQqYinYue, "qq.apk", 0, 0);        FileInfos fileInfos3 = new FileInfos(3, urlWangYiXinWen, "wangyixinwen.apk", 0, 0);        FileInfos fileInfos4 = new FileInfos(4, urlAiQiYi, "aiqiyi.apk", 0, 0);        list.add(fileInfos);        list.add(fileInfos1);        list.add(fileInfos2);        list.add(fileInfos3);        list.add(fileInfos4);        adapter=new MyAdapter(list,this);        listView.setAdapter(adapter);        //注册广播        receiver = new MyBroadCastReceiver();        IntentFilter intentFilter = new IntentFilter();        intentFilter.addAction(DownloadService.ACTION_UPDATE);        intentFilter.addAction(DownloadService.ACTION_FINISH);        registerReceiver(receiver,intentFilter);    }    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);                int position = intent.getIntExtra("position", -1);                if (-1!=progress)                {                    list.get(position).setFinished(progress);                    adapter.notifyDataSetChanged();                }            }            else if (DownloadService.ACTION_FINISH.equals(intent.getAction()))            {                FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");                list.get(fileInfo.getId()).setFinished(0);                adapter.notifyDataSetChanged();                Toast.makeText(MainActivity.this,fileInfo.getFileName()+"下载完成",Toast.LENGTH_SHORT).show();            }        }    }}我这么贴代码是为了方便我自己以后用的,,如果你们感兴趣还是自己敲一遍吧,有什么其他的优化方法记得和我说一声!