Service之断点续传(下载)

涉及知识点:

1.Service
2.intentStart.putExtra(“fileInfo”, fileInfo);//把实体类存入Intent中,fileInfo = (FileInfo) intent.getSerializableExtra(“fileInfo”);//从Intent中取出实体类
3.获得SD卡目录:Environment.getExternalStorageDirectory().getAbsolutePath()
4.发送消息给handler: mHandler.obtainMessage(MSG_INIT, fileInfo).sendToTarget();
5. conn.setRequestProperty(“Range”, “bytes=”+start+”-“+end);//读取这部分内容
6. raf.seek(start);//在读写的时候跳过设置的字节,比如seek(100),跳过100字节,从101开始读写


效果

这里写图片描述

MainActivity

package com.example.day0313;

import com.example.day0313.entity.FileInfo;
import com.example.day0313.service.DownloadService;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Filter;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{

    private String TAG = "MainActivity";
    private TextView mTvFileName;
    private ProgressBar mPbDownload;
    private Button mBtStart;
    private Button mBtStop;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 注册广播
        IntentFilter filter = new IntentFilter();
        filter.addAction(DownloadService.ACTION_UPDATE);
        registerReceiver(receiver, filter);

        initView();

    }

    BroadcastReceiver receiver = new BroadcastReceiver(){

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(DownloadService.ACTION_UPDATE)) {
                int progress = intent.getIntExtra("finished", 0);
                mPbDownload.setProgress(progress);
            }
        }};

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

    private void initView() {
        mTvFileName =  (TextView) findViewById(R.id.tv_name);
        mPbDownload =  (ProgressBar) findViewById(R.id.pb_download);
        mBtStart =  (Button) findViewById(R.id.bt_start);
        mBtStart.setOnClickListener(this);
        mBtStop =  (Button) findViewById(R.id.bt_stop);
        mBtStop.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        FileInfo fileInfo = new FileInfo(1, "http://www.imooc.com/mobile/mukewang.apk", "mukewang.apk", 0, 0);
        switch (v.getId()) {
        case R.id.bt_start:
            Intent intentStart = new Intent(this, DownloadService.class);
            intentStart.putExtra("fileInfo", fileInfo);
            intentStart.setAction(DownloadService.ACTION_START);
            startService(intentStart);
            break;

        case R.id.bt_stop:
            Intent intentStop = new Intent(this, DownloadService.class);
            intentStop.putExtra("fileInfo", fileInfo);
            intentStop.setAction(DownloadService.ACTION_STOP);
            startService(intentStop);
            break;
        }

    }


}


DownloadService

package com.example.day0313.service;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;


import com.example.day0313.entity.FileInfo;

import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

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 int MSG_INIT = 1;
    public static final String DIR_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/AABCdownlaods/";
    private DownlaodTask mDownlaodTask = null;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case MSG_INIT:
                FileInfo fileInfo = (FileInfo) msg.obj;
                //下载
                mDownlaodTask = new DownlaodTask(DownloadService.this, fileInfo);
                mDownlaodTask.download();
                break;
            }
        };
    };

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


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        FileInfo fileInfo = null;
        if (intent.getAction().equals(ACTION_START)) {
            fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
            new DownloadThread(fileInfo).start();
        } else if (intent.getAction().equals(ACTION_STOP)) {
            fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
            if (mDownlaodTask != null) {
                mDownlaodTask.isPause = true;
            }
        }

        return super.onStartCommand(intent, flags, startId);
    }

    class DownloadThread extends Thread {
        private FileInfo fileInfo = null;

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

        @SuppressWarnings("deprecation")
        @Override
        public void run() {
            HttpURLConnection conn = null;
             RandomAccessFile raf = null;
            try {
                //连接网络
                URL url = new URL(fileInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(3000);
                conn.setRequestMethod("GET");
                //访问是否成功
                if (conn.getResponseCode() != 200) {
                    Log.v(TAG, "访问失败");
                    return ;
                }
                //获得文件长度
                int length = -1;
                length = conn.getContentLength();
                //路径是否正确
                if (length <= 0) {
                    Log.v(TAG, "路径错误");
                    return ;
                }
                //创建文件写入
                //判断路径是否存在
                File dir = new File(DIR_PATH);
                Log.v(TAG, dir.exists()+"");
                if (!dir.exists()) {
                    dir.mkdir();//创建文件
                }
                //创建本地文件
                File file = new File(dir, fileInfo.getFileName());
                raf = new RandomAccessFile(file,"rwd");//r-可读,w-可写,d-可删
                raf.setLength(length);
                //发送长度给Handler,打印长度
                fileInfo.setLength(length);
                mHandler.obtainMessage(MSG_INIT, fileInfo).sendToTarget();

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                conn.disconnect();
            }
        }
    }


}

DownLoadTask

package com.example.day0313.service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import com.example.day0313.db.ThreadDaoImpl;
import com.example.day0313.entity.FileInfo;
import com.example.day0313.entity.ThreadInfo;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class DownlaodTask {

    private String TAG = "DownlaodTask";
    private Context mContext;
    private FileInfo mFileInfo;
    private ThreadDaoImpl mDaoImpl;
    private int mFinished = 0;
    public boolean isPause = false;

    public DownlaodTask(Context context, FileInfo fileInfo) {
        this.mContext = context;
        this.mFileInfo = fileInfo;
        mDaoImpl = new ThreadDaoImpl(context);
    }

    public void download() {
        // 读取信息集合
        List<ThreadInfo> list = mDaoImpl.queryThreads(mFileInfo.getUrl());
        ThreadInfo threadInfo = null;
        if (list.size() == 0) {
            threadInfo = new ThreadInfo(0, mFileInfo.getUrl(), 0, mFileInfo.getLength(), 0);
        } else  {
            threadInfo = list.get(0);
        }

        //开始下载
        new DownloadThread(threadInfo).start();
    }

    public class DownloadThread extends Thread {

        private ThreadInfo mThreadInfo;


        public DownloadThread(ThreadInfo mThreadInfo) {
            this.mThreadInfo = mThreadInfo;
        }


        @Override
        public void run() {
            //先往数据库插入线程信息
            if (!mDaoImpl.isExist(mThreadInfo.getUrl(), mThreadInfo.getId())) {
                mDaoImpl.insertThread(mThreadInfo);
            }
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            InputStream input = null;
            try {
                URL url = new URL(mThreadInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(3000);
                conn.setRequestMethod("GET");
                //设置下载的位置
                int start = mThreadInfo.getStart()+mThreadInfo.getFinished();
                int end = mThreadInfo.getEnd();
                conn.setRequestProperty("Range", "bytes="+start+"-"+end);
                //设置文件写入的位置
                File file = new File(DownloadService.DIR_PATH, mFileInfo.getFileName());
                raf = new RandomAccessFile(file, "rwd");
                raf.seek(start);//在读写的时候跳过设置的字节,比如seek(100),跳过100字节,从101开始读写
                Intent intent = new Intent(DownloadService.ACTION_UPDATE);
                mFinished += mThreadInfo.getFinished();
                //开始下载
                if (conn.getResponseCode() == 206) {
                    //读取数据
                    input = conn.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int len = -1;
                    while ((len = input.read(buffer)) != -1) {
                        //写入文件
                        raf.write(buffer,0,len);
                        mFinished += len;
                        mThreadInfo.setFinished(mFinished);
                        //把下载进度发送广播给activty
                        intent.putExtra("finished", mFinished * 100 / mFileInfo.getLength());
                        mContext.sendBroadcast(intent);
                        //在下载暂停时,保持进度到数据库
                        if (isPause) {
                            mDaoImpl.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mThreadInfo.getFinished());
                            return ; 
                        }
                    }

                    //删除线程信息
                    mDaoImpl.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId());
                }


            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    input.close();
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                conn.disconnect();
            }

        }
    }




}

DBHelper

package com.example.day0313.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "download.db";
    private static final int VERSION = 1;
    private static final String SQL_CREATE = "create table thread_info (_id integer primary key autoincrement, " +
            "thread_id integer, url text, start integer, end integer, finished integer)";
    private static final String SQL_DROP = "drop table if exists thread_info";


    public DBHelper(Context context) {
        super(context, DB_NAME, null, VERSION);
    }

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

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(SQL_DROP);
        db.execSQL(SQL_CREATE);
    }

}

ThreadDao(接口)

package com.example.day0313.db;

import java.util.List;

import com.example.day0313.entity.ThreadInfo;

/**
 *  数据访问接口
 */
public interface ThreadDao {

    /**
     *  插入线程信息
     * @param threadInfo
     */
    public void insertThread(ThreadInfo threadInfo);

    /**
     * 删除线性信息
     * @param url
     * @param thread_id
     */
    public void deleteThread(String url, int thread_id);

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

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

    /**
     * 判断这个线程是否在数据库中存在
     * @param url
     * @param thread_id
     * @return
     */
    public boolean isExist(String url, int thread_id);



}

ThreadDaoImpl(实现)

package com.example.day0313.db;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.example.day0313.entity.ThreadInfo;

public class ThreadDaoImpl implements ThreadDao{

    private DBHelper dbHelper = null;

    public ThreadDaoImpl(Context context) {
        dbHelper = new DBHelper(context);
    }


    @Override
    public void insertThread(ThreadInfo threadInfo) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.execSQL("insert into thread_info (thread_id, url, start, end, finished) values (?,?,?,?,?)",
                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 = dbHelper.getWritableDatabase();
        db.execSQL("delete from thread_info where url = ? and thread_id = ?",
                new Object[]{url, thread_id});
        db.close();
    }

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

    @Override
    public List<ThreadInfo> queryThreads(String url) {
        List<ThreadInfo> list = new ArrayList<ThreadInfo>();
        ThreadInfo threadInfo = null;
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Cursor c = db.rawQuery("select * from thread_info where url = ?",
                new String[]{url});
        while (c.moveToNext()) {
            threadInfo = new ThreadInfo();
            threadInfo.setId(c.getInt(c.getColumnIndex("thread_id")));
            threadInfo.setUrl(c.getString(c.getColumnIndex("url")));
            threadInfo.setStart(c.getInt(c.getColumnIndex("start")));
            threadInfo.setEnd(c.getInt(c.getColumnIndex("end")));
            threadInfo.setFinished(c.getInt(c.getColumnIndex("finished")));
            list.add(threadInfo);
        }
        c.close();
        db.close();
        return list;
    }

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

}

FileInfo(实体类)

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

权限

 <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

转载于:http://www.imooc.com/learn/363

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值