标签:
麻雀虽小五脏俱全,本文我是从慕课网学习的感谢慕课提供了那么免费优秀的资源
这里巧妙的把Android的四大主键紧密的联系了起来
Activity—Service—Broadcast Receiver—-SQLite
不多啰嗦 直接上代码
注释很详细
慢慢参透
public class MainActivity extends Activity {
private ListView mListView;
private List<FileInfo> mFileList;
private ListViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initList();
mListView = (ListView) findViewById(R.id.lv_listView);
mAdapter = new ListViewAdapter(MainActivity.this, mFileList);
mListView.setAdapter(mAdapter);
IntentFilter filter = new IntentFilter();
filter.addAction(DownloadService.ACTION_FINISHED);
filter.addAction(DownloadService.ACTION_UPDATE);
registerReceiver(receiver, filter);
}
private void initList() {
mFileList = new ArrayList<FileInfo>();
FileInfo mFileInfo = new FileInfo("mukewang0.apk", 0, 0,
"http://www.imooc.com/mobile/mukewang.apk", 0);
FileInfo mFileInfo1 = new FileInfo(
"知乎.apk",
0,
1,
"http://zhstatic.zhihu.com/pkg/store/zhihu/zhihu-android-app-zhihu-release-2.4.4-244.apk",
0);
FileInfo mFileInfo2 = new FileInfo(
"知乎日报.apk",
0,
2,
"http://zhstatic.zhihu.com/pkg/store/daily/zhihu-daily-zhihu-2.5.3(390).apk",
0);
mFileList.add(mFileInfo);
mFileList.add(mFileInfo1);
mFileList.add(mFileInfo2);
}
BroadcastReceiver receiver = new BroadcastReceiver() {
long time = System.currentTimeMillis();
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
FileInfo mFileInfo = (FileInfo) intent
.getSerializableExtra("fileInfo");
if (DownloadService.ACTION_UPDATE.equals(action)) {
// 更新UI
int finished = intent.getIntExtra("finished", -1);
int fileId = intent.getIntExtra("fileId", -1);
// 调用Adpter中的更新UI方法;
if ((System.currentTimeMillis() - time) > 1000) {
time = System.currentTimeMillis();
mAdapter.updateProgress(fileId, finished);
}
} else if (DownloadService.ACTION_FINISHED.equals(action)) {
// 下载结束后重置,并弹出Toast提示
FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
mAdapter.updateProgress(fileInfo.getId(), fileInfo.getLength());
Toast.makeText(MainActivity.this,
mFileInfo.getFileName() + " 下载完成!", Toast.LENGTH_SHORT)
.show();
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}
public class ListViewAdapter extends BaseAdapter {
private Context mContext;
private List<FileInfo> fileList;
public ListViewAdapter(Context mContext, List<FileInfo> fileList) {
this.mContext = mContext;
this.fileList = fileList;
}
@Override
public int getCount() {
return fileList.size();
}
@Override
public Object getItem(int position) {
return fileList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final FileInfo mFileInfo = fileList.get(position);
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(
R.layout.list_item, null);
holder.tv_fileName = (TextView) convertView
.findViewById(R.id.tv_fileName);
holder.btn_start = (Button) convertView
.findViewById(R.id.btn_start);
holder.btn_stop = (Button) convertView.findViewById(R.id.btn_stop);
holder.pb_download = (ProgressBar) convertView
.findViewById(R.id.pb_download);
holder.tv_fileName.setText(mFileInfo.getFileName());
holder.btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, DownloadService.class);
intent.setAction(DownloadService.ACTION_START);
intent.putExtra("fileInfo", mFileInfo);
mContext.startService(intent);
}
});
holder.btn_stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, DownloadService.class);
intent.setAction(DownloadService.ACTION_STOP);
intent.putExtra("fileInfo", mFileInfo);
mContext.startService(intent);
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.pb_download.setProgress(mFileInfo.getFinished());
return convertView;
}
/**
* 更新进度条
*
* @param id
* @param progress
*/
public void updateProgress(int fileId, int finished) {
FileInfo fileInfo = fileList.get(fileId);
fileInfo.setFinished(finished);
notifyDataSetChanged();// 调用此方法后系统会重新调用getView方法,完成刷新UI的操作
}
static class ViewHolder {
TextView tv_fileName;
Button btn_start, btn_stop;
ProgressBar pb_download;
}
}
/**
* 文件信息
*
* @author Lang Junping
*
*/
public class FileInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String fileName; // 文件名
private int length; // 文件长度
private int id; // 文件ID
private String url; // 文件在网络上的url
private int finished; // 文件进度
public FileInfo() {
super();
}
public FileInfo(String fileName, int length, int id, String url,
int finished) {
super();
this.fileName = fileName;
this.length = length;
this.id = id;
this.url = url;
this.finished = finished;
}
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 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 getFinished() {
return finished;
}
public void setFinished(int finished) {
this.finished = finished;
}
@Override
public String toString() {
return "FileInfo [fileName=" + fileName + ", length=" + length
+ ", id=" + id + ", url=" + url + ", finished=" + finished
+ "]";
}
}
/**
* 线程信息
*
* @author Lang Junping
*
*/
public class ThreadInfo {
private int id;
private String url;
private int start; // 开始下载的位置
private int stop; // 停止下载的位置
private int finished; // 下载进度
public ThreadInfo() {
super();
}
public ThreadInfo(int id, String url, int start, int stop, int finished) {
super();
this.id = id;
this.url = url;
this.start = start;
this.stop = stop;
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 getStop() {
return stop;
}
public void setStop(int stop) {
this.stop = stop;
}
public int getFinished() {
return finished;
}
public void setFinished(int finished) {
this.finished = finished;
}
@Override
public String toString() {
return "TheadInfo [id=" + id + ", url=" + url + ", start=" + start
+ ", stop=" + stop + ", finished=" + finished + "]";
}
}
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 ACTION_FINISHED = "ACTION_FINISHED";
public static final String DOWNLOAD_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/downloads/";
public static final int THREAD_COUNT = 3; //下载线程数
public static final int MSG_INIT = 0x001;
private InitThread mInitThread = null;
private Map<Integer,DownloadTask> mTasks = new LinkedHashMap<Integer,DownloadTask>();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
if (ACTION_START.equals(intent.getAction())) {
//启动下载
mInitThread = new InitThread(fileInfo);
DownloadTask.sExecutorService.execute(mInitThread);
} else if (ACTION_STOP.equals(intent.getAction())) {
//暂停下载
int id = fileInfo.getId();
if(mTasks!=null){
DownloadTask mTask = mTasks.get(id);
mTask.setPause(true);
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_INIT:
FileInfo mFileInfo = (FileInfo) msg.obj;
//启动下载
DownloadTask mTask= new DownloadTask(DownloadService.this, mFileInfo,THREAD_COUNT);
mTask.download();
mTasks.put(mFileInfo.getId(), mTask);
break;
}
}
};
/**
* 初始化线程子类
*
* @author Lang Junping
*
*/
class InitThread extends Thread {
private FileInfo mFileInfo;
public InitThread(FileInfo mFileInfo) {
this.mFileInfo = mFileInfo;
}
@Override
public void run() {
// 开启网络,查询长度,创建文件,返回信息
HttpURLConnection conn = null;
RandomAccessFile raf = null;
try {
// 开启网络
URL url = new URL(mFileInfo.getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
// 获取文件长度
int length = -1;
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
length = conn.getContentLength();
}
if (length <= 0) {
return;
}
// 创建文件夹
File dir = new File(DOWNLOAD_PATH);
if (!dir.exists()) {
dir.mkdir();
}
// 创建文件
File mFile = new File(dir, mFileInfo.getFileName());
// 创建RAF文件
raf = new RandomAccessFile(mFile, "rwd");
raf.setLength(length);
// 设置文件长度,并通知主线程
mFileInfo.setLength(length);
mHandler.obtainMessage(MSG_INIT, mFileInfo).sendToTarget();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
conn.disconnect();
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 下载任务类
*
*/
public class DownloadTask {
private Context mContext;
private FileInfo mFileInfo;
private ThreadDAO mThreadDAO;
private boolean isPause = false;
private int threadsCount = 1;
private List mThreadList;
private long mFinished = 0;
//线程池
public static ExecutorService sExecutorService = Executors.newCachedThreadPool();
public DownloadTask(Context mContext, FileInfo mFileInfo, int threadsCount) {
this.mContext = mContext;
this.mFileInfo = mFileInfo;
this.threadsCount = threadsCount;
mThreadDAO = new ThreadDAOimpl(mContext);
}
public boolean isPause() {
return isPause;
}
public void setPause(boolean isPause) {
this.isPause = isPause;
}
/**
* 下载方法
*/
public void download() {
// 读取数据库的线程信息
List<ThreadInfo> threads = mThreadDAO.getThread(mFileInfo.getUrl());
// 判断线程信息是否为空
if (threads.size() == 0) {
// 如果为空,则创建线程信息
// 先计算文件分段长度
int length = mFileInfo.getLength() / threadsCount;
for (int i = 0; i < threadsCount; i++) {
ThreadInfo mThreadInfo = new ThreadInfo(i, mFileInfo.getUrl(),
i * length, (i + 1) * length - 1, 0);
// 不能整除的情况
if (i == threadsCount - 1) {
mThreadInfo.setStop(mFileInfo.getLength());
}
threads.add(mThreadInfo);
// 向数据库插入线程信息
mThreadDAO.insert(mThreadInfo);
}
}
// 启动线程,开始下载
mThreadList = new ArrayList<DownloadThread>();
for (ThreadInfo info : threads) {
DownloadThread dt = new DownloadThread(info);
// 启动线程
// new Thread(dt).start();
//用线程池启动线程
DownloadTask.sExecutorService.execute(dt);
// 将线程添加到集合中,方便管理
mThreadList.add(dt);
}
}
/**
* 下载线程
*
*/
class DownloadThread implements Runnable {
public boolean isThreadFinished = false;
private ThreadInfo mThreadInfo;
public DownloadThread(ThreadInfo mThreadInfo) {
this.mThreadInfo = mThreadInfo;
}
@Override
public void run() {
HttpURLConnection conn = null;
RandomAccessFile raf = null;
InputStream input = null;
try {
// 开启网络
URL url = new URL(mThreadInfo.getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(3000);
conn.setRequestMethod("GET");
// 设置下载位置
int start = mThreadInfo.getStart() + mThreadInfo.getFinished();
// 下载范围
String range = "bytes=" + start + "-" + mThreadInfo.getStop();
conn.setRequestProperty("Range", range);
// 设置写入位置
File file = new File(DownloadService.DOWNLOAD_PATH,
mFileInfo.getFileName());
raf = new RandomAccessFile(file, "rwd");
raf.seek(start);
// 累加完成进度
mFinished += mThreadInfo.getFinished();
// 开始下载
if (conn.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) {
// 读取数据
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(mThreadInfo.getFinished() + len);
int progress = (int) (mFinished * 100 / mFileInfo
.getLength());
// 发送更新UI广播
Intent intent = new Intent(
DownloadService.ACTION_UPDATE);
intent.putExtra("finished", progress);
intent.putExtra("fileId", mFileInfo.getId());
mContext.sendBroadcast(intent);
// 下载暂停时保存线程下载进度
if (isPause()) {
mThreadDAO.updateThread(mThreadInfo.getUrl(),
mThreadInfo.getId(),
mThreadInfo.getFinished());
return;
}
}
isThreadFinished = true;
// 判断所有的线程是否下载完毕
checkAllThreadIsFinished();
} else {
Toast.makeText(mContext, "网络请求失败", Toast.LENGTH_SHORT)
.show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.disconnect();
raf.close();
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private synchronized void checkAllThreadIsFinished() {
boolean allFinished = true;
// 遍历集合
for (DownloadThread dt : mThreadList) {
if (!dt.isThreadFinished) {
allFinished = false;
return;
}
}
if (allFinished) {
Intent intent = new Intent(DownloadService.ACTION_FINISHED);
intent.putExtra("fileInfo", mFileInfo);
mContext.sendBroadcast(intent);
mThreadDAO.delete(mFileInfo.getUrl());
}
}
}
}
public class DBHelper extends SQLiteOpenHelper {
public static DBHelper sHelper = null;
public static final String DB_NAME = "download.db";
public static final int VERSION = 1;
// 创建数据库的SQL语法
public static final String SQL_CREATE = "create table if not exists thread_info(_id integer primary key autoincrement,"
+ "thread_id integer,url text,start integer,stop integer,finished integer)";
// 删除数据库的语法
public static final String SQL_DROP = "drop table if exists thread_info";
private DBHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
/**
* 单例模式
*/
public static DBHelper getInstance(Context context){
if(sHelper==null){
sHelper = new DBHelper(context);
}
return sHelper;
}
@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);
}
}
/**
* 数据库访问接口
* @author Lang Junping
*
*/
public interface ThreadDAO {
/**
* 插入线程信息
* @param threadInfo
*/
public void insert(ThreadInfo threadInfo);
/**
* 删除线程信息
* @param url filepath
* @param thread_id threadId
*/
public void delete(String url);
/**
* 更新线程下载进度
* @param url
* @param thread_id
*/
public void updateThread(String url,int thread_id,long finished);
/**
* 查询线程的文件信息
* @param url
* @return 返回一个含有线程信息的List
*/
public List getThread(String url);
/**
* 判断线程信息是否
* @param url
* @param thread_id
* @return
*/
public boolean isExists(String url,int thread_id);
}
public class ThreadDAOimpl implements ThreadDAO {
private DBHelper mHelper = null;
public ThreadDAOimpl(Context context) {
mHelper = DBHelper.getInstance(context);
}
@Override
public synchronized void insert(ThreadInfo threadInfo) {
// 创建数据库
SQLiteDatabase db = mHelper.getWritableDatabase();
db.execSQL(
"insert into thread_info(thread_id,url,start,stop,finished) values(?,?,?,?,?)",
new Object[] { threadInfo.getId(), threadInfo.getUrl(),
threadInfo.getStart(), threadInfo.getStop(),
threadInfo.getFinished() });
db.close();
}
@Override
public synchronized void delete(String url) {
SQLiteDatabase db = mHelper.getWritableDatabase();
db.execSQL("delete from thread_info where url=?", new Object[] { url });
db.close();
}
@Override
public synchronized void updateThread(String url, int thread_id,
long finished) {
SQLiteDatabase db = mHelper.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> getThread(String url) {
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery("select * from thread_info where url=?",
new String[] { url });
List<ThreadInfo> list = new ArrayList<ThreadInfo>();
ThreadInfo mThread = null;
while (cur.moveToNext()) {
mThread = new ThreadInfo();
mThread.setId(cur.getInt(cur.getColumnIndex("thread_id")));
mThread.setStart(cur.getInt(cur.getColumnIndex("start")));
mThread.setStop(cur.getInt(cur.getColumnIndex("stop")));
mThread.setFinished(cur.getInt(cur.getColumnIndex("finished")));
mThread.setUrl(cur.getString(cur.getColumnIndex("url")));
list.add(mThread);
}
cur.close();
db.close();
return list;
}
@Override
public boolean isExists(String url, int thread_id) {
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery(
"select * from thread_info where url=? and thread_id=?",
new String[] { url, thread_id + "" });
boolean exists = cur.moveToNext();
cur.close();
db.close();
return exists;
}
}
也许大伙把代码搬完了,然而程序并没有达到预期的效果
老鸟应该都知道,既然有网络访问,网络权限是必须要加的
《uses-permission android:name=”android.permission.INTERNET”/》
这里还涉及到文件的读写权限
《uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/》
这里要启动Service,Service一定要在配置文件中注册了才能使用
《service android:name=”包名.DownloadService”/》
万恶的编辑器会吃代码
标签:
原文地址:http://blog.csdn.net/qq_23976141/article/details/51383940