涉及知识点:
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"/>