昨天练习了一个从网络上下载一个apk,然后自动安装的demo,具体使用了服务、广播、数据库、文件,由于demo支持断点下载,后面有源码
附上截图
一、下面介绍下demo的创建过程
1、总体思路
通过网络请求首先获取 到资源的大小,然后根据资源的大小创建一个与之相对应的文件准备,然后通过线程下载资源,并将下载资源的线程的信息存储在数据库中,当点击暂停按钮之后, 更新数据库中下载线程的信息,将已经下载的资源位置作标记,继续下载的时候将会从,暂停的地方开始下载,这样就实现的了资源的断点下载,当文件下载完毕之后,通过文件的路径, 打开apk跳到安装界面,点击可以安装
2、首先要完成资源的下载,要个资源设计一个实体类,里面存储的都是文件的信息
3、既然要用线程进行下载,并实现断点下载功能,那就需要将下载的线程也存储起来,线程也需要一个实体类,存储下载文件的起始位置,终止位置,完成情况
4、线程信息需要存储在数据库中,所以我们使用SQLite来存储线程的信息
5、下载的进度的更新,我们使用的是广播,每0.5s发送一条更新进度条的广播,实现进度条的实时更新
以上几个是比较重要的地方和大致思路
二、下面介绍一下几个必要重要的类
1、SQLite数据库方面就不再介绍,上面有一篇博文有SQlite数据库的详细介绍,下面附上几个主要的接口和实现方法
public interface ThreadDao {
public void insertThread(ThreadIfo threadIfo);
public void deleteThread(String url,int thread_id );
public void updateThread(String url,int thread_id,int finished );
public List<ThreadIfo> getThread(String url);
public boolean isexists(String url,int thread_id);
}
下面是接口的实现
public class ThreadDaoImpl implements ThreadDao {
private DBhelper dBhelper;
public ThreadDaoImpl(Context context) {
super();
dBhelper = new DBhelper(context);
}
//插入线程
@Override
public void insertThread(ThreadIfo threadIfo) {
// TODO Auto-generated method stub
SQLiteDatabase db=dBhelper.getWritableDatabase();
db.execSQL("insert into thread_info(thread_id,url,start,end,finished) values(?,?,?,?,?)",
new Object[]{threadIfo.getId(),threadIfo.getUrl(),threadIfo.getStart(),threadIfo.getStop(),threadIfo.getFinished()});
db.close();
}
//删除线程
@Override
public void deleteThread(String url, int thread_id) {
// TODO Auto-generated method stub
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) {
// TODO Auto-generated method stub
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<ThreadIfo> getThread(String url) {
// TODO Auto-generated method stub
SQLiteDatabase db=dBhelper.getWritableDatabase();
Cursor cursor=db.rawQuery("select * from thread_info where url=? ",new String[]{url});
List<ThreadIfo> list=new ArrayList<ThreadIfo>();
while (cursor.moveToNext()) {
ThreadIfo threadIfo=new ThreadIfo(cursor.getInt(cursor.getColumnIndex("thread_id")),
cursor.getString(cursor.getColumnIndex("url")),
cursor.getInt(cursor.getColumnIndex("start")),
cursor.getInt(cursor.getColumnIndex("end")),
cursor.getInt(cursor.getColumnIndex("finished")));
list.add(threadIfo);
}
cursor.close();
db.close();
return list;
}
//判断线程是否存在
@Override
public boolean isexists(String url, int thread_id) {
SQLiteDatabase db=dBhelper.getWritableDatabase();
Cursor cursor=db.rawQuery("select * from thread_info where url=? and thread_id=?",new String[]{url,thread_id+""});
if(cursor.moveToNext()) {
return true;
}
cursor.close();
db.close();
return false;
}
}
2、下面写一下最主要的地方也就是文件的下载
首先通过url获取到下载资源,得到资源的大小,根据资源的大小,在本地创建一个相对应的文件
public class DownloadService extends Service {
private DownloadTask task=null;
public static final int initmsg = 0;
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() + "/downloads/";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
if (ACTION_START.equals(intent.getAction())) {
FileIfo fileIfo = (FileIfo) intent.getSerializableExtra("fileifo");
System.out.println("文件信息已经开始" + fileIfo.toString());
//启动初始化线程
new InitThread(fileIfo).start();
} else if (ACTION_STOP.equals(intent.getAction())) {
FileIfo fileIfo = (FileIfo) intent.getSerializableExtra("fileifo");
System.out.println("文件信息已经停止" + fileIfo.toString());
if (task!=null) {
task.ispause=true;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
//在<span style="font-family: Arial, Helvetica, sans-serif;">Handler中启动下载的任务</span><span style="font-family: Arial, Helvetica, sans-serif;">DownloadTask</span><span style="font-family: Arial, Helvetica, sans-serif;">
</span>
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case initmsg:
FileIfo fileIfo=(FileIfo) msg.obj;
System.out.println("handler中的fileIfo"+fileIfo.toString());
task=new DownloadTask(getApplicationContext(), fileIfo);
task.download();
break;
default:
break;
}
};
};
/*
* 初始化子线程
*/
class InitThread extends Thread {
private FileIfo fileIfo = null;
public InitThread(FileIfo fileIfo) {
super();
this.fileIfo = fileIfo;
}
@Override
public void run() {
HttpURLConnection conn = null;
RandomAccessFile raf= null;
try {
// 连接网络文件
URL url = new URL(fileIfo.getFileurl());
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setRequestMethod("GET");
int length = -1;
if (conn.getResponseCode() == 200) {
// 获得文件长度
length = conn.getContentLength();
System.out.println("这是文件的长度"+length);
}
if (length <= 0) {
return;
}
File dir = new File(DOWNLOAD_PATH);
//如果路径不存在,就进行重新创建
if (!dir.exists()) {
dir.mkdir();
}
// 在本地创建文件
File file = new File(dir, fileIfo.getFilename());
raf = new RandomAccessFile(file, "rwd");
// 设置文件长度
raf.setLength(length);
fileIfo.setFilelength(length);
handler.obtainMessage(initmsg,fileIfo).sendToTarget();
raf.close();
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3、下载任务放在DownloadTask中,使用url获取到网络资源,然后通过文件的写入将文件下载下来
public class DownloadTask {
private Context mContext = null;
private FileIfo fileIfo = null;
private ThreadDao threadDao = null;
private int mfinished = 0;
public boolean ispause = false;
public DownloadTask(Context mContext, FileIfo fileIfo) {
super();
this.mContext = mContext;
this.fileIfo = fileIfo;
threadDao = new ThreadDaoImpl(mContext);
}
public void download() {
// 读取数据库的线程信息
List<ThreadIfo> mlist = threadDao.getThread(fileIfo.getFileurl());
ThreadIfo threadIfo = null;
if (mlist.size() == 0) {
threadIfo = new ThreadIfo(0, fileIfo.getFileurl(), 0,
fileIfo.getFilelength(), 0);
} else {
threadIfo = mlist.get(0);
}
// 创建子线程进行下载
new Downloadthread(threadIfo).start();
}
class Downloadthread extends Thread {
private ThreadIfo threadIfo = null;
public Downloadthread(ThreadIfo threadIfo) {
super();
this.threadIfo = threadIfo;
}
@Override
public void run() {
// 向数据库插入线程信息
if (!threadDao.isexists(threadIfo.getUrl(), threadIfo.getId())) {
threadDao.insertThread(threadIfo);
}
// 设置下载位置
URL url = null;
HttpURLConnection conn = null;
RandomAccessFile raf = null;
InputStream is = null;
try {
url = new URL(threadIfo.getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setRequestMethod("GET");
int start = threadIfo.getStart() + threadIfo.getFinished();
conn.setRequestProperty("Range", "bytes=" + start + "-"
+ threadIfo.getStop());
// 设置文件的写入位置
File file = new File(DownloadService.DOWNLOAD_PATH,
fileIfo.getFilename());
raf = new RandomAccessFile(file, "rwd");
raf.seek(start);
Intent intent = new Intent(DownloadService.ACTION_UPDATE);
mfinished += threadIfo.getFinished();
// 开始下载
if (conn.getResponseCode() == 206) {
// 读取数据
is = conn.getInputStream();
byte[] buffer = new byte[1024 * 4];
int len = -1;
long time = System.currentTimeMillis();
while ((len = is.read(buffer)) != -1) {
// 写入文件
raf.write(buffer, 0, len);
mfinished += len;
// 把下载进度发送广播给activity
if (System.currentTimeMillis() - time > 500) {
intent.putExtra("finished", mfinished * 100
/ fileIfo.getFilelength());
mContext.sendBroadcast(intent);
time = System.currentTimeMillis();
}
// 在下载暂停时保存下载进度
if (ispause) {
threadDao.updateThread(threadIfo.getUrl(),
threadIfo.getId(), mfinished);
return;
}
}
//下载完成后,实现文件的自动安装
Intent intent2 = new Intent();
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent2.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/downloads/imooc.apk")); // 这里是APK路径
intent2.setDataAndType(uri,
"application/vnd.android.package-archive");
mContext.startActivity(intent2);
//下载完成后删除数据库中下载线程的相关信息
threadDao.deleteThread(threadIfo.getUrl(),
threadIfo.getId());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
conn.disconnect();
try {
raf.close();
is.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
4、MainActivity中的主要作用是:创建文件对象、启动服务,接收广播更新进度、广播的注销
public class MainActivity extends ActionBarActivity {
private Button start;
private Button stop;
private TextView name;
private ProgressBar pBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction(DownloadService.ACTION_UPDATE);
registerReceiver(broadcastReceiver, intentFilter);
// 创建文件信息对象
final FileIfo fileIfo = new FileIfo(
0,
"imooc.apk",
"http://www.imooc.com/mobile/imooc.apk",
0, 0);
name.setText(fileIfo.getFilename());
start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent=new Intent(MainActivity.this,DownloadService.class);
intent.setAction("ACTION_START");
intent.putExtra("fileifo", fileIfo);
startService(intent);
}
});
stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent=new Intent(MainActivity.this,DownloadService.class);
intent.setAction("ACTION_STOP");
intent.putExtra("fileifo", fileIfo);
startService(intent);
}
});
}
private void initView() {
// TODO Auto-generated method stub
start = (Button) findViewById(R.id.download_bt);
stop = (Button) findViewById(R.id.stop_bt);
name = (TextView) findViewById(R.id.name_tv);
pBar = (ProgressBar) findViewById(R.id.myprogressBar);
pBar.setMax(100);
}
BroadcastReceiver broadcastReceiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (DownloadService.ACTION_UPDATE.equals(intent.getAction())) {
pBar.setProgress(intent.getIntExtra("finished", 0));
}
}
};
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
};
}
下面将会附上demo下载地址: http://download.csdn.net/download/jl_stone/9182601