android断点续传实现应用程序更新下载

来源:互联网 发布:七天网络查分登录账号 编辑:程序博客网 时间:2024/04/27 15:36

本文内容参考了CSDN博客博主Sodino的文章 地址:http://blog.csdn.net/sodino/archive/2011/06/09/6535278.aspx


这里我对他的工具类NetworkTool进行了一些修改,自己用起来还可以,写下主要为自己以后看的,在此感谢他。

断点续传用到的知识点:
1.使用RandomAccessFile设定文件大小并于指定位置开始读数据[randomAccessFile.seek(position)]。    
2.请求资源链接时指定所请求数据的返回范围。
    httpURLConnection.setRequestProperty("Range", "bytes=" + start + "-" + (contentLength - 1));


直接上代码:NetworkTool类

package com.example.yunmiweather.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;

public class NetWorkTool {


public static final int CONNECTION_TIMEOUT = 1000 * 60 * 5;
public static final int READ_TIMEOUT = 1000 * 60 * 5;
/**
* 开启一个HTTP链接。
*/
public static HttpURLConnection openUrl(Context context, String urlStr) {
URL urlURL = null;
HttpURLConnection httpConn = null;
try {
urlURL = new URL(urlStr);
// 需要android.permission.ACCESS_NETWORK_STATE
// 在没有网络的情况下,返回值为null。
NetworkInfo networkInfo = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE))
.getActiveNetworkInfo();
// 如果是使用的运营商网络
if (networkInfo != null) {
if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
// 获取默认代理主机ip
String host = android.net.Proxy.getDefaultHost();
// 获取端口
int port = android.net.Proxy.getDefaultPort();
if (host != null && port != -1) {
// 封装代理連接主机IP与端口号。
InetSocketAddress inetAddress = new InetSocketAddress(
host, port);
// 根据URL链接获取代理类型,本链接适用于TYPE.HTTP
java.net.Proxy.Type proxyType = java.net.Proxy.Type
.valueOf(urlURL.getProtocol().toUpperCase());
java.net.Proxy javaProxy = new java.net.Proxy(
proxyType, inetAddress);
httpConn = (HttpURLConnection) urlURL
.openConnection(javaProxy);
} else {
httpConn = (HttpURLConnection) urlURL.openConnection();
}
} else {
httpConn = (HttpURLConnection) urlURL.openConnection();
}
httpConn.setDoInput(true);
httpConn.setReadTimeout(READ_TIMEOUT);
httpConn.setConnectTimeout(CONNECTION_TIMEOUT);
} else {
// LogOut.out(this, "No Avaiable Network");
}
} catch (NullPointerException npe) {
npe.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return httpConn;
}


/** 启动链接并将RespondCode值返回。 */
public static int connect(HttpURLConnection httpConn) {
int code = -1;
if (httpConn != null) {
try {
httpConn.connect();
code = httpConn.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
}
}
return code;
}


/**
* 将指定的HTTP链接内容存储到指定的的文件中。<br/>
* 返回值仅当参考。<br/>

* @param httpConn
* @param filePath
*            指定存储的文件路径。
*/
public static boolean download2File(HttpURLConnection httpConn, File file) {
boolean result = true;
FileOutputStream fos = null;
byte[] data = new byte[1024];
int readLength = -1;
InputStream is = null;
try {
fos = new FileOutputStream(file);
is = httpConn.getInputStream();
while ((readLength = is.read(data)) != -1) {
fos.write(data, 0, readLength);
fos.flush();
}
fos.flush();
} catch (IOException ie) {
result = false;
ie.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException ie) {
ie.printStackTrace();
}
}
return result;
}


/**
* 将bean资源下载。<br/>
* 支持断点续传。

*/
public static void download2File(Context context, BeanDownload bean,
DownloadCallable downloadCallable) {
HttpURLConnection httpConn = null;
File file = bean.file;
RandomAccessFile randomFile = null;
FileOutputStream fos = null;
int dataBlockLength = 2048;
byte[] data = new byte[dataBlockLength];
int readLength = -1;
InputStream is = null;
try {
if (file.getParentFile().exists() == false) {
file.getParentFile().mkdirs();
}
if (file.exists() == false) {
file.createNewFile();
}
randomFile = new RandomAccessFile(file, "rw");
bean.loadedSize = (int) randomFile.length();
httpConn = openUrl(context, bean.url);
bean.size = httpConn.getContentLength();
if (bean.loadedSize <= 0) {
System.out.println("普通方式");
// 采用普通的下载方式
int respondCode = connect(httpConn);
fos = new FileOutputStream(file);
if (respondCode == HttpURLConnection.HTTP_OK) {
is = httpConn.getInputStream();
while ((readLength = is.read(data)) != -1) {
fos.write(data, 0, readLength);
bean.loadedSize += readLength;
downloadCallable.downRefresh(bean);
System.out.println("普通刷新");


}
if (bean.loadedSize >= bean.size) {
downloadCallable.downFinish();
}
}
} else if (bean.loadedSize < bean.size) {
// 采用断点续传方式
httpConn = openUrl(context, bean.url);
httpConn.setRequestProperty("Range", "bytes=" + bean.loadedSize
+ "-" + (bean.size - 1));
int respondCode = connect(httpConn);
if (respondCode == HttpURLConnection.HTTP_PARTIAL) {
System.out.println("断点续传");
is = httpConn.getInputStream();
while ((readLength = is.read(data)) != -1) {
randomFile.seek(bean.loadedSize);
randomFile.write(data, 0, readLength);
bean.loadedSize += readLength;
downloadCallable.downRefresh(bean);
}
if (bean.loadedSize == bean.size) {
downloadCallable.downFinish();
}
}
} else {
System.out.println("下载完成");
downloadCallable.downFinish();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (httpConn != null) {
disconnect(httpConn);
}
if (fos != null) {
fos.close();
}
if (randomFile != null) {
randomFile.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

public static void disconnect(HttpURLConnection httpConn) {
if (httpConn != null) {
httpConn.disconnect();
}
}

//此处是我写的一个回调接口,当然你也可以修改接口里方法的声明以满足你的需求
public interface DownloadCallable {

public void downRefresh(BeanDownload bean);
public void downFinish();
public void downFaile();
}

//简单的封装的一个下载类
public static class BeanDownload {
public int size;// 下载的文件大小
public int loadedSize;// 已经下载的大小
public String url;// 下载地址
public File file;// 下载到本地的文件


public BeanDownload(String url, File file) {
this.file = file;
this.url = url;
}
}
}


在更新serivice里开启一个线程,调用这个类里面的下载方法,自己实现相应的回调接口,如果是通知栏提示的话就可以用notification,如果是在activity中进行UI更新,那就用handler。这里我用的是简单的通知的形式,当然更复杂的通知,你可以去写一个layout文件,用远程视图实现效果。

package com.example.yunmiweather.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;


import com.example.yunmiweather.R;
import com.example.yunmiweather.activity.MainActivity;
import com.example.yunmiweather.service.NetWorkTool.BeanDownload;
import com.example.yunmiweather.service.NetWorkTool.DownloadCallable;
import com.example.yunmiweather.util.UpdateVersion;


public class UpdateVersionService extends Service {

public static final int mUpdateNotificationId = 0;
private String appUrl;

private File mUpdateFile;
private File mUpdateDir;

private NetWorkTool.DownloadCallable mDownloadCallable;
private BeanDownload mBeanDown;

private NotificationManager mNotificationManager;
private Notification mNotification;

private PendingIntent mPendingIntent;
private Intent mUpdateIntent;


private Thread mDownLoadThread;


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


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
appUrl = intent.getStringExtra(UpdateVersion.APPDOWNLOADURL);


if (android.os.Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
mUpdateDir = new File(
Environment.getExternalStorageDirectory(),
getPackageName());
mUpdateFile = new File(mUpdateDir.getPath(),
"yunmi_weather.apk");
}


createNotification();


createDownloadThread();

mDownloadCallable = new DownloadCallable() {


@Override
public void downRefresh(BeanDownload bean) {
mNotification.setLatestEventInfo(UpdateVersionService.this,
"正在下载", bean.loadedSize * 100 / bean.size + "%",
mPendingIntent);
mNotificationManager.notify(mUpdateNotificationId,
mNotification);
}


@Override
public void downFinish() {
mNotification.setLatestEventInfo(UpdateVersionService.this,
"yunmi", "下载完成",
mPendingIntent);
mNotificationManager.notify(mUpdateNotificationId,
mNotification);
instartAPK();
stopSelf();
}


@Override
public void downFaile() {
mNotification.setLatestEventInfo(UpdateVersionService.this,
"yunmi", "下载失败", mPendingIntent);
mNotificationManager.notify(mUpdateNotificationId,
mNotification);
stopSelf();
}
};
}
return super.onStartCommand(intent, flags, startId);
}


private void createNotification() {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotification = new Notification();
mNotification.icon = R.drawable.ic_launcher;
mNotification.tickerText = "开始下载";


mUpdateIntent = new Intent(this, MainActivity.class);
mUpdateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mPendingIntent = PendingIntent.getActivity(this, 0, mUpdateIntent, 0);
mNotification.setLatestEventInfo(this, "yunmi", "开始下载", mPendingIntent);


mNotificationManager.notify(mUpdateNotificationId, mNotification);


}


private void createDownloadThread() {
mDownLoadThread = new Thread(new DownLoadRunnable());
mDownLoadThread.start();
}


class DownLoadRunnable implements Runnable {


@Override
public void run() {
mBeanDown = new BeanDownload(appUrl,mUpdateFile);
NetWorkTool.download2File(UpdateVersionService.this, mBeanDown,
mDownloadCallable);
}
}


public void instartAPK() {
Uri uri = Uri.fromFile(mUpdateFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}

}

0 0
原创粉丝点击