Android-Service系列之断点续传下载

来源:互联网 发布:巨杉数据库作用 编辑:程序博客网 时间:2024/05/22 03:43

PS:本文代码来自慕课网同名课程Android-Service系列之断点续传下载,这里只是为了Mark下来方便自己以后使用。

首先是布局文件,因为只是demo,所以使用图形化工具生成。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    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.tk.download.MainActivity" >    <TextView        android:id="@+id/tv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />    <ProgressBar        android:id="@+id/pb_progress"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_below="@+id/tv"        android:layout_marginTop="36dp"        android:layout_toRightOf="@+id/tv" />    <Button        android:id="@+id/btn_start"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@+id/pb_progress"        android:layout_marginTop="31dp"        android:layout_alignParentLeft="true"               android:text="start" />    <Button        android:id="@+id/btn_stop"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/btn_start"        android:layout_alignBottom="@+id/btn_start"        android:layout_alignParentRight="true"        android:text="stop" /></RelativeLayout>
MainActivity.java

public class MainActivity extends Activity implements OnClickListener{    private TextView mTvFileName;    private ProgressBar mProgressBar;    private Button btnStart;    private Button btnStop;    private final FileInfo fileInfo = new FileInfo(0,"http://down.qingkan.net/32/32033.txt","翡翠之塔.txt",0,0);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();            }        private void init(){    mTvFileName = (TextView) findViewById(R.id.tv);        mProgressBar = (ProgressBar) findViewById(R.id.pb_progress);    btnStart = (Button) findViewById(R.id.btn_start);    btnStop = (Button) findViewById(R.id.btn_stop);    mProgressBar.setMax(100);        btnStart.setOnClickListener(this);        btnStop.setOnClickListener(this);                IntentFilter filter = new IntentFilter();        filter.addAction(DownloadService.ACTION_UPDATE);        registerReceiver(mReceiver,filter);    }        @Override    protected void onDestroy(){    super.onDestroy();    unregisterReceiver(mReceiver);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }    /**     * 更新ui的广播接收器     */    BroadcastReceiver mReceiver = new BroadcastReceiver(){@Overridepublic void onReceive(Context context, Intent intent) {if(DownloadService.ACTION_UPDATE.equals(intent.getAction())){int finished = intent.getIntExtra("finished",0);mProgressBar.setProgress(finished);}}        };@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.btn_start:Intent intent = new Intent(MainActivity.this, DownloadService.class);intent.setAction( DownloadService.ACTION_START);intent.putExtra("fileInfo", fileInfo);startService(intent);break;case R.id.btn_stop:Intent mIntent = new Intent(MainActivity.this, DownloadService.class);mIntent.setAction( DownloadService.ACTION_STOP);mIntent.putExtra("fileInfo", fileInfo);startService(mIntent);break;}}}
数据库相关代码

DBHelper.java

/** * 创建数据库语句 *  * */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);// TODO Auto-generated constructor stub}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(SQL_CREATE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL(SQL_DROP);db.execSQL(SQL_CREATE);}}
DAO相关

public interface ThreadDAO {/** * 插入线程信息 *  * @param threadInfo */public void insertThread(ThreadInfo threadInfo);/** * 删除线程 *  * @param url * @param threadId */public void deleteThread(String url, int threadId);/** * 更新线程 *  * @param url * @param threadId */public void updateThread(String url, int threadId,int finished);/** * 查找线程 *  * @param url * @return */public List<ThreadInfo> getThreads(String url);/** * 线程消息是否存在 * @param url * @param threadId * @return */public boolean isExtists(String url,int threadId);}
public class ThreadDAOImpl implements ThreadDAO{private DBHelper mHelper = null;public ThreadDAOImpl(Context context){mHelper = new DBHelper(context);}@Overridepublic void insertThread(ThreadInfo threadInfo) {SQLiteDatabase db = mHelper.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.getEnd()});db.close();}@Overridepublic void deleteThread(String url, int threadId) {SQLiteDatabase db = mHelper.getWritableDatabase();db.execSQL("delete from thread_info where url=? and thread_id=?",new Object[]{url,threadId});db.close();}@Overridepublic void updateThread(String url, int threadId,int finished) {SQLiteDatabase db = mHelper.getWritableDatabase();db.execSQL("update thread_info set finished=? where url=? and thread_id=?",new Object[]{finished,url,threadId});db.close();}@Overridepublic List<ThreadInfo> getThreads(String url) {List<ThreadInfo> list = new ArrayList<ThreadInfo>();SQLiteDatabase db = mHelper.getWritableDatabase();Cursor cursor = db.rawQuery("select * from thread_info where url=?", new String[]{url});while(cursor.moveToNext()){ThreadInfo thread = new ThreadInfo();thread.setId(cursor.getInt(cursor.getColumnIndex("thread_id")));thread.setUrl(cursor.getString(cursor.getColumnIndex("url")));thread.setStart(cursor.getInt(cursor.getColumnIndex("start")));thread.setEnd(cursor.getInt(cursor.getColumnIndex("end")));thread.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));    list.add(thread);}cursor.close();db.close();return list;}@Overridepublic boolean isExtists(String url, int threadId) {SQLiteDatabase db = mHelper.getWritableDatabase();Cursor cursor = db.rawQuery("select * from thread_info where url=? and thread_id=?", new String[]{url,threadId+""});boolean extists = cursor.moveToNext();cursor.close();db.close();return extists;}}
实体类两个

public class ThreadInfo implements Serializable{private int id;private String url;private int start;private int end;//文件长度private int finished;//任务中断时的进度public ThreadInfo() {super();}public ThreadInfo(int id, String url, int start, int end, int finished) {super();this.id = id;this.url = url;this.start = start;this.end = end;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 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;}@Overridepublic String toString() {return "ThreadInfo [id=" + id + ", url=" + url + ", start=" + start+ ", end=" + end + ", finished=" + finished + "]";}}
public class FileInfo implements Serializable{private int id;private String url;private String fileName;private int length;private int finished;public FileInfo() {}public FileInfo(int id, String url, String fileName, int length,int finished) {super();this.id = id;this.url = url;this.fileName = fileName;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 getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}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;}@Overridepublic String toString() {return "FileInfo [id=" + id + ", url=" + url + ", fileName=" + fileName+ ", length=" + length + ", finished=" + finished + "]";}}
下载核心类

public class DownloadService extends Service {    private final String tag = getClass().getName();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 DOWNLOAD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/mDownLoads/";public static final int MSG_INIT = 0;private DownloadTask task = null;@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {//获得Activity传来的参数if(ACTION_START.equals(intent.getAction())){FileInfo fileInfo = (FileInfo)intent.getSerializableExtra("fileInfo");Log.i(tag,"Start+"+fileInfo.toString());new InitThread(fileInfo).start();}else if(ACTION_STOP.equals(intent.getAction())){FileInfo fileInfo = (FileInfo)intent.getSerializableExtra("fileInfo");Log.i(tag,"Stop+"+fileInfo.toString());if(task!=null){task.setPause(true);}}return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}Handler mHandler = new Handler(){public void handleMessage(Message msg){switch(msg.what){case MSG_INIT:FileInfo fileInfo = (FileInfo)msg.obj;Log.i(tag,"INIT"+fileInfo.toString());//启动下载任务task = new DownloadTask(DownloadService.this,fileInfo);task.download();break;}}};    /**     * 初始化子线程     */class InitThread extends Thread{private FileInfo fileInfo;public InitThread(FileInfo fileInfo) {super();this.fileInfo = fileInfo;}public void run(){HttpURLConnection coon = null;    RandomAccessFile raf = null;try{//连接网络文件URL url = new URL(fileInfo.getUrl());coon = (HttpURLConnection)url.openConnection();coon.setConnectTimeout(3000);coon.setRequestMethod("GET");int length = -1;if (coon.getResponseCode()==HttpStatus.SC_OK){//获取文件长度length = coon.getContentLength();}if (length<0){return;}File dir = new File(DOWNLOAD_PATH);if(!dir.exists()){dir.mkdir();}//本地创建文件    File file = new File(dir,fileInfo.getFileName());    raf = new  RandomAccessFile(file,"rwd");    //设置文件长度    raf.setLength(length);    fileInfo.setLength(length);    //利用handler将信息从线程中回传给service    mHandler.obtainMessage(MSG_INIT,fileInfo).sendToTarget();}catch(Exception e){e.printStackTrace();}finally{try {coon.disconnect();raf.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}

public class DownloadTask {private Context mContext = null;private FileInfo mFileInfo = null;private ThreadDAO mDao = null;private int mFinished = 0;private boolean isPause = false;public DownloadTask(Context mContext, FileInfo mFileInfo) {super();this.mContext = mContext;this.mFileInfo = mFileInfo;mDao = new ThreadDAOImpl(mContext);}public void setPause(boolean isPause) {this.isPause = isPause;}public void download(){//读取数据库线程信息List<ThreadInfo> threadInfos = mDao.getThreads(mFileInfo.getUrl());ThreadInfo threadInfo = null;if(threadInfos.size()==0){//初始化线程信息对象threadInfo = new ThreadInfo(0,mFileInfo.getUrl(),0,mFileInfo.getLength(),0);}else{threadInfo = threadInfos.get(0);}//创建子线程下载new DownloadThread(threadInfo).start();}class DownloadThread extends Thread{private ThreadInfo mThreadInfo = null;    public DownloadThread(ThreadInfo mThreadInfo) {super();this.mThreadInfo = mThreadInfo;}public void run(){//数据库插入线程信息if(!mDao.isExtists(mThreadInfo.getUrl(),mThreadInfo.getId())){mDao.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();conn.setRequestProperty("Range", "bytes="+start+"-"+mThreadInfo.getEnd());   //写入位置File file = new File(DownloadService.DOWNLOAD_PATH,mFileInfo.getFileName());raf = new RandomAccessFile(file,"rwd");raf.seek(start);Intent intent = new Intent(DownloadService.ACTION_UPDATE);mFinished+=mThreadInfo.getFinished();//开始下载,返回值206if(conn.getResponseCode()==HttpStatus.SC_PARTIAL_CONTENT){//读取数据input = conn.getInputStream();byte[] bytes = new byte[1024];int len = -1;long time = System.currentTimeMillis();//减慢进度条刷新时间,减少ui负载while((len = input.read(bytes))!=-1){    //写入文件raf.write(bytes,0,len);//把下载进度发送广播给ActivitymFinished += len;if(System.currentTimeMillis()-time>500){time = System.currentTimeMillis();intent.putExtra("finished", mFinished*100/mFileInfo.getLength());mContext.sendBroadcast(intent);}//下载暂停时,保存下载进度if(isPause){mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinished);    return;}}//删除数据库中的线程信息mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId());}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {conn.disconnect();    input.close();raf.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}


0 0
原创粉丝点击