文件下载
1. 下载文件业务类
下载文件的操作也属于业务方法,所以在com.liuhao.mobilesafe.engine中创建1个DownloadFileTask下载文件的类。
其中的getFile方法,用于从http://www.wfuyu.com/server/文件路径上下载文件至本地文件目录。
package com.liuhao.mobilesafe.engine;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class DownloadFileTask {
/**
* @param path
* http://www.wfuyu.com/server/文件路径
* @param filepath
* 本地文件路径
* @return 本节文件对象
* @throws Exception
*/
public static File getFile(String path, String filepath) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
// 读取数据没有异常
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();// 获得文件输入流
File file = new File(filepath);// 本地文件对象
FileOutputStream fos = new FileOutputStream(file);//本地文件输出流
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != ⑴) {
fos.write(buffer, 0, length);
}
fos.flush();
fos.close();
is.close();
return file;
}
return null;
}
}
2.使用下载文件类
在用户点击“肯定”后,会进行下载。
其中定义了1个进度条,用来显示下载进程:
private ProgressDialog pd;// 进度条
pd = new ProgressDialog(this);
pd.setMessage("正在下载,请耐心等待。o(∩_∩)o");// 设置进度条显示的内容
builder.setPositiveButton("肯定", new OnClickListener() { // 设置用户选择肯定时的按键操作
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "下载pak文件:" + info.getApkurl());
// 判断sd卡是不是可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 调用子线程进行下载
DownloadFileThreadTask task = new DownloadFileThreadTask(
info.getApkurl(), Environment.getExternalStorageDirectory().getPath() + "/aanew.apk");
pd.show();// 显示下载进度条
new Thread(task).start();// 启动子线程
} else {
Toast.makeText(getApplicationContext(), "sd卡不可用",
Toast.LENGTH_LONG).show();
loadMainUI();
}
}
});
// 子线程,用于下载文件,由于下载文件比较耗时
private class DownloadFileThreadTask implements Runnable {
private String path;// http://www.wfuyu.com/server/路径
private String filepath;// 本地文件路径
public DownloadFileThreadTask(String path, String filepath) {
this.path = path;
this.filepath = filepath;
}
@Override
public void run() {
try {
File file = DownloadFileTask.getFile(path, filepath);
Log.i(TAG, "下载更新apk成功");
pd.dismiss();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "下载文件失败",
Toast.LENGTH_LONG).show();
pd.dismiss();
loadMainUI();
}
}
}
3.添加权限
由于下载文件需要对sd卡进行读写,因袭需要sd卡的权限:<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
写外部存储装备的权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4.配置http://www.wfuyu.com/server/真个apk文件(高版本的)
将当前版本号改成2.0,生成1个apk安装包,放到之前指定的目录(%TOMCAT_HOME%webappsROOT),然后再改回来。
异常处理:
ERROR/AndroidRuntime(1540): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
我们在ActivityGroup或TabActivity中的子Activity创建Dialog若使用以下的代码
progressDialog = new ProgressDialog(XXX.this)
创建就会出现以下Exception:
ERROR/AndroidRuntime(6362): android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@43e5b158 is not valid; is your activity running?
而该使用:
progressDialog = new ProgressDialog(getParent())
缘由分析:
由于new对话框的时候,参数content 指定成了this,即指向当前子Activity的content。但子Activity是动态创建的,不能保证1直存在。其父Activity的content是稳定存在的,所以有下面的解决办法。
若ActivityGroup中嵌套ActivityGroup,嵌套多少就该使用多少个getParent()。
为何要使用getParent我们可以从柯元旦的《Android内核剖析》中第10章”Ams内部原理“中的ActivityGroup的内部机制来理解:
TabActivity的父类是ActivityGroup,而ActivityGroup的父类是Activity。因此从Ams的角度来看,ActivityGroup与普通的Activity没有甚么区分,其生命周期包括标准的start,stop,resume,destroy等,而且系统中只允许同时允许1个ActivityGroup.但ActivityGroup内部有1个重要成员变量,其类型为LocalActivityManager,该类的最大特点在于它可以访问利用进程的主类,即ActivityThread类。Ams要启动某个Activity或赞同某个Activity都是通过ActivityThread类履行的,而LocalActivityManager类就意味着可以通过它来装载不同的Activity,并控制Activity的不同的状态。注意,这里是装载,而不是启动,这点很重要。所谓的启动,1般是指会创建1个进程(如果所在的利用常常还不存在)运行该Activity,而装载仅仅是指把该Activity作为1个普通类进行加载,并创建1个该类的对象而已,而该类的任何函数都没有被运行。装载Activity对象的进程对AmS来说是完全不可见的,那些嵌入的Activity仅仅贡献了自己所包括的Window窗口而已。而子Activity的不同状态是通过moveToState来处理的。
所以子Activity不是像普通的Activity1样,它只是提供Window而已,所以在创建Dialog时就应当使用getParent获得ActivityGroup真实的Activity,才可以加Dialog加入Activity中。
参考:
http://aijiawang⑴26-com.iteye.com/blog/1717368
下载部署终了后,运行效果
文件安装(下载完成后自动安装)(知识点:Intent)
/**
* 安装apk文件
* @param file
*/
private void install(File file){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
finish();// 终结当前Activity
startActivity(intent);// 激活新的Activity
}
让当前Activity延时2秒再判断是不是需要更新(知识点:Handler)
private String versiontext;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (isNeedUpdate(versiontext)) {
Log.i(TAG, "弹出升级对话框");
showUpdateDialog();
}
}
};
onCreate方法中:
// 让当前Activity延时两秒钟,再去检查更新
new Thread(){
public void run() {
try {
sleep(2000);
handler.sendEmptyMessage(0);// 向主线程发送1条空消息
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
设置下载进度条显示下载进度(知识点:ProgressDialog)
在下载任务类DownloadFileTask的getFile()方法中添加1个ProgressDialog作为参数,在下载进程中对其进行设置。
/**
* @param path
* http://www.wfuyu.com/server/文件路径
* @param filepath
* 本地文件路径
* @param pd
* 进度条,用以显示下载进度
* @return 本地文件对象
* @throws Exception
*/
public static File getFile(String path, String filepath, ProgressDialog pd) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
// 读取数据没有异常
if (conn.getResponseCode() == 200) {
int total = conn.getContentLength();// 获得内容的总长度
pd.setMax(total);
InputStream is = conn.getInputStream();// 获得文件输入流
File file = new File(filepath);// 本地文件对象
FileOutputStream fos = new FileOutputStream(file);//本地文件输出流
byte[] buffer = new byte[1024];
int length = 0;
int process = 0;// 当前进度
while ((length = is.read(buffer)) != ⑴) {
fos.write(buffer, 0, length);
process += length;
pd.setProgress(process);// 设置当前进度
Thread.sleep(50);
}
fos.flush();
fos.close();
is.close();
return file;
}
return null;
}
由于默许的ProgressDialog是不显示下载进度的,因此需要进行设置。
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 默许情况下不显示进度,这个设置用于显示进度
效果: