【邊做項目邊學Android】手機安全衛士04_02:從服務器下載并安裝新版本安裝包
來源:程序員人生 發布時間:2014-11-09 10:48:46 閱讀次數:3224次
文件下載
1. 下載文件業務類
下載文件的操作也屬于業務方法,所以在com.liuhao.mobilesafe.engine中創建1個DownloadFileTask下載文件的類。
其中的getFile方法,用于從http://www.vxbq.cn/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.vxbq.cn/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.vxbq.cn/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.vxbq.cn/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.vxbq.cn/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);// 默許情況下不顯示進度,這個設置用于顯示進度
效果:

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈