前一段时间因为公司项目砍掉,导致了一段时间的失业期,赶在年前这么个时间段,迫于无奈之下接了一个外派的项目合同,为期一个月,削微有些蛋疼。这一阵一直在做一些页面布局之类的东西,感觉时间都有点荒废掉了,不过庆幸的是可以参考人家项目中的一些代码。我做的是下载游戏功能的界面,所以顺便参考了一下实现下载逻辑的代码,由于不是自己实现的,逻辑等方面都有些混乱。在此记录一下,旨为加深一下自己的印象,同时留待以后可能用到的时候做一些参考。
具体的使用情景大概是:
1.判断当前手机中是否安装有相同包名的应用
private boolean isAppInstalled(Context context, String packagename) {
PackageInfo packageInfo;
try {
packageInfo=context.getPackageManager()
.getPackageInfo(packagename, 0);
} catch (NameNotFoundException e) {
packageInfo = null;
}
if (packageInfo == null) {
//没有安装当前包名的应用
return false;
} else {
//已经安装过当前包名的应用
return true;
}
}
2.如果没有安装过该包名的应用,执行以下操作:
if (!isAppInstalled(context, appInfo.getLatest().getPackageName())) {
//没有安装过该包名的应用,将下载链接的地址进行分割,最后一个/之后为应用的名称
String[] strs = appInfo.getLatest().getFid().split("/");
String downName = strs[strs.length - 1];
//不明白这里为什么用do while循环做
do {
//判断下载文件的目录下,此文件是否可以安装,如果可以则直接进行安装
if (PackageInfoUtils.checkApkCanInstalled(context, Environment.getExternalStorageDirectory() + DOWNLOAD_PATH + "/" + downName)) {
installApk(new File(Environment.getExternalStorageDirectory()
+ DOWNLOAD_PATH, downName), (TextView) v);
//跳出循环
break;
}
//目录下的文件不能直接进行安装,新建一个file对象
File file = new File(Environment.getExternalStorageDirectory() + DOWNLOAD_PATH, downName);
//判断当前网络是否可用,如果不可用则弹出吐司提示
if (!NetworkStatusHandler.isNetWorkAvaliable(context)) {
ToastUtils.showAsNoNetwork(context);
return;
}
//判断下载地址是否为空
if (Model.getInstance().isEmpty(appInfo.getLatest().getFid())) {
Toast.makeText(context, "下载地址错误", Toast.LENGTH_SHORT).show();
return;
}
//查询处于下载状态的任务(从数据库中查询处于下载状态的数据,根据数据在下载的辅助线程类中查询任务。。这里表述不清楚。。弄不太清各种标记表示的状态,猜测应该是不让同时下载的任务超过8个吧)
List<DownloadRequest> idleTask = AppDownloadHelper.getInstance().getDownloadTaskIdle(2);
if (idleTask.size() >= 8) {
Toast.makeText(context, "不能添加更多下载任务", Toast.LENGTH_SHORT).show();
return;
}
//所有其他的条件都符合了,开始进行下载了
download(appInfo);
} while (false);
}
第二步中用到的方法:
//判断是否可以安装
public static boolean checkApkCanInstalled(Context context, String filePath) {
PackageInfo info = getUninstallApkInfo(context, filePath);
return info != null ? true : false;
}
public static PackageInfo getUninstallApkInfo(Context context, String filePath) {
File f = new File(filePath);
if (!f.exists()) {
return null;
}
PackageInfo info = null;
try {
PackageManager pm = context.getPackageManager();
info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
} catch (Exception e) {
e.printStackTrace();
}
return info;
}
//安装apk文件
private void installApk(File file, TextView downButton) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
AppStoreInit.getContext().startActivity(i);
}
// 判断是否有可用的网络连接
public static final boolean isNetWorkAvaliable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) {
return false;
} else {
NetworkInfo[] info = connectivityManager.getAllNetworkInfo();
if (info == null) {
return false;
} else {
for (NetworkInfo nf : info) {
if (nf.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
return false;
}
}
}
3.开始执行下载的操作了,具体看代码吧
//括号内的参数表示需要下载的应用的一些信息,这些信息是从后台接口中获取的,包括名称、大小、链接等等。
private void download(final AppInfo info) {
//这里是app的下载地址
final String downloadUrl = info.getLatest().getFid();
//将Appinfo对象中的信息封装到另一个对象downloadInfo中
DownloadInfo downloadInfo = getDownloadInfo(info);
int currentDownType = info.getCurrentDownType();
//根据当前应用的下载状态进行判断
if (currentDownType == AppInfo.DOWNLOAD_START) {
currentDownType = AppInfo.DOWNLOAD_PAUSE;
info.setCurrentDownType(currentDownType);
downloadInfo.setBtnCurrentDownType(info.getCurrentDownType());
//开始下载应用
AppDownloadHelper.getInstance().downApp(downloadInfo);
} else if (currentDownType == AppInfo.DOWNLOAD_PAUSE) {
currentDownType = AppInfo.DOWNLOAD_START;
info.setCurrentDownType(currentDownType);
downloadInfo.setBtnCurrentDownType(info.getCurrentDownType());
//暂停正在下载的应用
AppDownloadHelper.getInstance().pause(downloadInfo);
}
}
//根据AppInfo的信息得到DownloadInfo的对象
private DownloadInfo getDownloadInfo(AppInfo appInfo) {
final String downloadName = appInfo.getName();
final String downloadUrl = appInfo.getLatest().getFid();
final String fileExtensions = appInfo.getFileExtensions();
final int installationDirectory = appInfo.getInstallationDirectory();
final int sizeLong = appInfo.getLatest().getSizeLong();
final int position = appInfo.getPosition();
int currentDownType = appInfo.getCurrentDownType();
final String appId = appInfo.getId();
DownloadInfo downloadInfo = new DownloadInfo();
downloadInfo.setDownloadName(downloadName);
downloadInfo.setDownloadUrl(downloadUrl);
downloadInfo.setFileExtensions(fileExtensions);
downloadInfo.setDownloadFileSize(sizeLong);
downloadInfo.setInstallationDirectory(installationDirectory);
downloadInfo.setPosterfid(appInfo.getIconfid());
downloadInfo.setSubhead(appInfo.getSubhead());
com.dfsj.video.download.beans.AppInfo downAppInfo = new com.dfsj.video.download.beans.AppInfo();
downAppInfo.setName(appInfo.getName());
AppLatestInfo appLatestInfo = new AppLatestInfo();
appLatestInfo.setFid(appInfo.getLatest().getFid());
appLatestInfo.setPackageName(appInfo.getLatest().getPackageName());
appLatestInfo.setSize(appInfo.getLatest().getSize());
appLatestInfo.setVersionCode(appInfo.getLatest().getVersionCode());
appLatestInfo.setVersionName(appInfo.getLatest().getVersionName());
downAppInfo.setLatest(appLatestInfo);
downAppInfo.setScore(appInfo.getScore());
downAppInfo.setOnedescription(appInfo.getOnedescription());
downAppInfo.setGametype(appInfo.getGametype());
downloadInfo.setInfo(downAppInfo);
downloadInfo.setDownloadTpye(2);
downloadInfo.setAppId(Integer.valueOf(appInfo.getId()));
downloadInfo.setDownloadHelperListener(this);
downloadInfo.setDetailDownloadHelperListener(this);
return downloadInfo;
}
4.开始下载。。。。(感觉已经开始过好几次了。。。囧。。。。),还是上代码吧。。。
public void downApp(DownloadInfo downloadInfo) {
if (SystemUtils.getNetType(DownloadInit.getContext()) != 4) {
ToastUtils.showShort(DownloadInit.getContext(), "当前为运营商网络,继续下载会产生流量费用");
}
String downloadUrl = downloadInfo.getDownloadUrl();
String downloadName = downloadInfo.getDownloadName();
View view = downloadInfo.getUpdateView();
//一些下载过程中状态的监听,包括进度条的更新,下载过程中错误的回调等等
downloadHelperListener = downloadInfo.getDownloadHelperListener();
detailDownloadHelperListener = downloadInfo.getDetailDownloadHelperListener();
String[] strs = downloadUrl.split("/");
String downName = strs[strs.length - 1];
File file = new File(DOWNLOAD_PATH, downName);
//这几步应该是得到一个用来下载的请求
DownloadRequest request = queryDownloadInfo(downloadUrl);
if (null == request) {
request = new DownloadRequest(downloadUrl,
file.getAbsolutePath(), 0);
}
if (null != view)
request.setView(view);
request.setExtraValue(downloadInfo.getPosterfid());
request.setFileExtensions(downloadInfo.getFileExtensions());
request.setDownloadFileSize(downloadInfo.getDownloadFileSize());
request.setInstallationDirectory(downloadInfo.getInstallationDirectory());
request.setTitle(downloadName);
request.setInfo(downloadInfo.getInfo());
request.setBtnCurrentDownType(downloadInfo.getBtnCurrentDownType());
request.setDownloadTpye(downloadInfo.getDownloadTpye());
request.setDownloadEpisode(downloadInfo.getSubhead());
request.setAppId(downloadInfo.getAppId());
request.setPackageName(downloadInfo.getInfo().getLatest().getPackageName());
request.setScore(downloadInfo.getInfo().getScore());
request.setOnewordDesc(downloadInfo.getInfo().getOnedescription());
request.setGametype(downloadInfo.getInfo().getGametype());
//这个方法是真正的执行下载任务的
mDownloadManager.enqueue(request);
setClickStatus(request);
}
5.感觉这个代码写的确实是挺啰嗦的,希望有机会的话可以自己精简一下。。。。太蛋疼了。。
public void enqueue(DownloadRequest request) {
VolumeSize compare = new VolumeSize();
if (request.getSrcUri() == null)
return;
int type = request.getmType();
if (type == 1) {
if (null != request.getDestUri())
request.setDestUri(request.getDestUri());
request.setmTimeStamp(System.currentTimeMillis());
request.setDownloadStatus(DownloadColumns.STATUS_IDLE);
//这里是进行开始下载任务。。感觉要吐血了。。
mDownloadThreadPool.enqueue(request);
} else {
boolean has = mDBHelper.isHasFile(request.getmUniquely_id());
if (request.getId() == -1 || has == true) {
long id = mDBHelper.insert(request.toContentValues());
request.setId(id);
request.setDownloadSize(0);
}
request.setmTimeStamp(System.currentTimeMillis());
request.setDownloadStatus(DownloadColumns.STATUS_IDLE);
if (!TextUtils.isEmpty(request.getDestUri())) {
request.setDestUri(request.getDestUri());
} else {
String path = SharePrefUtils.getString("PATH", Environment.getExternalStorageDirectory().getAbsolutePath());
String url = path + DOWNLOAD_PATH + "/" + request.getTitle();
request.setDestUri(url);
}
Log.d(TAG, "enqueue: " + request.getDownloadStatus() + "type" + request.getSrcUri());
mDownloadThreadPool.enqueue(request);
String where = DownloadColumns._ID + "=" + request.getId();
mDBHelper.update(request.toContentValues(), where, null);
}
}
private ExecutorService mThreadPool;
//执行下载任务了。。。。。
void enqueue(DownloadRequest request) {
Log.d(TAG, "enqueue: ");
//这里是一个开启线程池的对象(DownloadTask见下面。。。)
mThreadPool.submit(new DownloadTask(request));
Log.d(TAG, "enqueue: submit");
mDownloadRequests.add(request);
}
class DownloadTask implements Runnable {
private DownloadRequest mDownloadRequest;
DownloadTask(DownloadRequest request) {
mDownloadRequest = request;
Log.d(TAG, "DownloadTask: ");
}
@Override
public void run() {
Log.d(TAG, "run: ");
int statusCode = -1;
if (mDownloadRequest.getDownloadStatus().equals(DownloadColumns.STATUS_IDLE)) {
//开始下载。。。。。
statusCode = mHttpDownloader.doDownload(mDownloadRequest);
}
mDownloadRequests.remove(mDownloadRequest);
}
}
//执行下载操作的代码(应该是包含了断点续传的)
public int doDownload(DownloadRequest request) {
Log.d(TAG, "doDownload: start" + request.getDownloadStatus());
// 不能设置成全局变量,会导致写文件出错
HttpURLConnection conn = null;
InputStream inStream = null;
RandomAccessFile oSavedFile = null;
long breakPoint = 0L;
File destFile = null;
int statusCode = 0;
try {
URL url = new URL(request.getSrcUri());
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setReadTimeout(10 * 1000);
conn.setRequestMethod("GET");
} catch (IOException e) {
saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_ERROR, "HttpURLConnection出错,e:" + e);
notifyError(request);
conn.disconnect();
return statusCode;
}
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Referer", request.getSrcUri());
conn.setRequestProperty("Charset", "UTF-8");
// 在conn.connect();之前new os 不然会导致暂停后无法重新下载
destFile = setupFile(request.getDestUri() + TEMP_SUFFIX);
// 如果下载文件存在
if (destFile.exists() && destFile.isFile() && destFile.length() > 0) {
breakPoint = destFile.length();
request.setDownloadSize(breakPoint);
} else {
request.setDownloadSize(0);
}
conn.setRequestProperty("Range", "bytes=" + breakPoint + "-");
conn.setRequestProperty(
"User-Agent",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("content-type", "text/html");
int responseCode = -1;
try {
conn.connect();
responseCode = conn.getResponseCode();
} catch (IOException e) {
saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_CONNECT_ERROR, "HttpURLConnection connect出错,e:" + e);
notifyError(request);
conn.disconnect();
return statusCode;
}
if (responseCode == 206) {
Log.d(TAG, "doDownload: " + responseCode);
try {
inStream = conn.getInputStream();
} catch (IOException e) {
saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_GET_INPUTSTREAM_ERROR, "HttpURLConnection getInputStream出错,e:" + e + ",responseCode:" + responseCode);
notifyError(request);
closeHttpConnection(inStream, conn, oSavedFile);
return responseCode;
}
try {
oSavedFile = new RandomAccessFile(destFile, "rw");
} catch (FileNotFoundException e) {
saveDownloadRequest(request, ErrorCode.FILE_OUT_PUT_STREAM_WITH_RANGE_ERROR, "RandomAccessFile出错,e:" + e);
notifyError(request);
closeHttpConnection(inStream, conn, oSavedFile);
return statusCode;
}
try {
oSavedFile.seek(breakPoint);
} catch (IOException e) {
saveDownloadRequest(request, ErrorCode.FILE_OUT_PUT_STREAM_WITH_RANGE_ERROR, "RandomAccessFile seek出错,e:" + e);
notifyError(request);
closeHttpConnection(inStream, conn, oSavedFile);
return statusCode;
}
try {
long filesize = conn.getContentLength();
if (request.getDownloadSize() == 0) {
request.setTotalSize(filesize);
}
byte buffer[] = new byte[800096];
int length = 0;
notifyStart(request);
startTime = System.currentTimeMillis();
while (request.getDownloadStatus().equals(
DownloadColumns.STATUS_START)
&& (length = inStream
.read(buffer, 0, buffer.length)) != -1) {
oSavedFile.write(buffer, 0, length);
long downloadSize = request.getDownloadSize();
downloadSize += length;
request.setDownloadSize(downloadSize);
long mdownloadsize = request.getMtemdownsize();// 获取临时下载数量
mdownloadsize += length;
request.setMtemdownsize(mdownloadsize);
curTime = System.currentTimeMillis();
usedTime = (int) ((curTime - startTime) / 1000);
if (usedTime == 0)
usedTime = 1;
downloadSpeed = (int) ((mdownloadsize / usedTime) / 1024);
request.setDownloadSpeed(downloadSpeed);
notifyProgress(request);
// 获取到停止状态跳出循环
if (request.getDownloadStatus().equals(
DownloadColumns.STATUS_PAUSE)) {
break;
}
}
request.setMtemdownsize(0);
request.setDownloadSpeed(0);
if (request.getTotalSize() == request.getDownloadSize()
&& !(request.getDownloadStatus()
.equals(DownloadColumns.STATUS_COMPLETE))) {
destFile.renameTo(new File(request.getDestUri()));
request.setDownloadStatus(DownloadColumns.STATUS_COMPLETE);
request.setMlastTimeStamp(System.currentTimeMillis());
request.setDownloadSize(0L);
notifyComplete(request);
} else {
notifyProgress(request);
}
} catch (IOException e) {
saveDownloadRequest(request, ErrorCode.IO_ERROR, "Os write 错误,e:" + e + "ResponseCode:" + responseCode);
notifyError(request);
} finally {
closeHttpConnection(inStream, conn, oSavedFile);
}
} else {
saveDownloadRequest(request, ErrorCode.HTTP_RESPONSE_CODE_ERROR, "ResponseCode不等于206,ResponseCode:" + responseCode);
notifyError(request);
closeHttpConnection(inStream, conn, oSavedFile);
}
return statusCode;
}
结语,我反正是累的吐血了,感觉代码的逻辑太啰嗦,比想象中复杂了一万倍,后期有时间的话再优化一次,今天就到这。。。