【邊做項目邊學(xué)Android】手機(jī)安全衛(wèi)士04_02:從服務(wù)器下載并安裝新版本安裝包
來源:程序員人生 發(fā)布時間:2014-11-09 10:48:46 閱讀次數(shù):3228次
文件下載
1. 下載文件業(yè)務(wù)類
下載文件的操作也屬于業(yè)務(wù)方法,所以在com.liuhao.mobilesafe.engine中創(chuàng)建1個DownloadFileTask下載文件的類。
其中的getFile方法,用于從http://www.jyygyx.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.jyygyx.com/server/文件路徑
* @param filepath
* 本地文件路徑
* @return 本節(jié)文件對象
* @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);
// 讀取數(shù)據(jù)沒有異常
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.使用下載文件類
在用戶點擊“肯定”后,會進(jìn)行下載。
其中定義了1個進(jìn)度條,用來顯示下載進(jìn)程:
private ProgressDialog pd;// 進(jìn)度條
pd = new ProgressDialog(this);
pd.setMessage("正在下載,請耐心等待。o(∩_∩)o");// 設(shè)置進(jìn)度條顯示的內(nèi)容
builder.setPositiveButton("肯定", new OnClickListener() { // 設(shè)置用戶選擇肯定時的按鍵操作
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "下載pak文件:" + info.getApkurl());
// 判斷sd卡是不是可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 調(diào)用子線程進(jìn)行下載
DownloadFileThreadTask task = new DownloadFileThreadTask(
info.getApkurl(), Environment.getExternalStorageDirectory().getPath() + "/aanew.apk");
pd.show();// 顯示下載進(jìn)度條
new Thread(task).start();// 啟動子線程
} else {
Toast.makeText(getApplicationContext(), "sd卡不可用",
Toast.LENGTH_LONG).show();
loadMainUI();
}
}
});
// 子線程,用于下載文件,由于下載文件比較耗時
private class DownloadFileThreadTask implements Runnable {
private String path;// http://www.jyygyx.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.添加權(quán)限
由于下載文件需要對sd卡進(jìn)行讀寫,因襲需要sd卡的權(quán)限:<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
寫外部存儲裝備的權(quán)限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4.配置http://www.jyygyx.com/server/真?zhèn)€apk文件(高版本的)
將當(dāng)前版本號改成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創(chuàng)建Dialog若使用以下的代碼
progressDialog = new ProgressDialog(XXX.this)
創(chuàng)建就會出現(xiàn)以下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對話框的時候,參數(shù)content 指定成了this,即指向當(dāng)前子Activity的content。但子Activity是動態(tài)創(chuàng)建的,不能保證1直存在。其父Activity的content是穩(wěn)定存在的,所以有下面的解決辦法。
若ActivityGroup中嵌套ActivityGroup,嵌套多少就該使用多少個getParent()。
為何要使用getParent我們可以從柯元旦的《Android內(nèi)核剖析》中第10章”Ams內(nèi)部原理“中的ActivityGroup的內(nèi)部機(jī)制來理解:
TabActivity的父類是ActivityGroup,而ActivityGroup的父類是Activity。因此從Ams的角度來看,ActivityGroup與普通的Activity沒有甚么區(qū)分,其生命周期包括標(biāo)準(zhǔn)的start,stop,resume,destroy等,而且系統(tǒng)中只允許同時允許1個ActivityGroup.但ActivityGroup內(nèi)部有1個重要成員變量,其類型為LocalActivityManager,該類的最大特點在于它可以訪問利用進(jìn)程的主類,即ActivityThread類。Ams要啟動某個Activity或贊同某個Activity都是通過ActivityThread類履行的,而LocalActivityManager類就意味著可以通過它來裝載不同的Activity,并控制Activity的不同的狀態(tài)。注意,這里是裝載,而不是啟動,這點很重要。所謂的啟動,1般是指會創(chuàng)建1個進(jìn)程(如果所在的利用常常還不存在)運行該Activity,而裝載僅僅是指把該Activity作為1個普通類進(jìn)行加載,并創(chuàng)建1個該類的對象而已,而該類的任何函數(shù)都沒有被運行。裝載Activity對象的進(jìn)程對AmS來說是完全不可見的,那些嵌入的Activity僅僅貢獻(xiàn)了自己所包括的Window窗口而已。而子Activity的不同狀態(tài)是通過moveToState來處理的。
所以子Activity不是像普通的Activity1樣,它只是提供Window而已,所以在創(chuàng)建Dialog時就應(yīng)當(dāng)使用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();// 終結(jié)當(dāng)前Activity
startActivity(intent);// 激活新的Activity
}

讓當(dāng)前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方法中:
// 讓當(dāng)前Activity延時兩秒鐘,再去檢查更新
new Thread(){
public void run() {
try {
sleep(2000);
handler.sendEmptyMessage(0);// 向主線程發(fā)送1條空消息
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
設(shè)置下載進(jìn)度條顯示下載進(jìn)度(知識點:ProgressDialog)
在下載任務(wù)類DownloadFileTask的getFile()方法中添加1個ProgressDialog作為參數(shù),在下載進(jìn)程中對其進(jìn)行設(shè)置。
/**
* @param path
* http://www.jyygyx.com/server/文件路徑
* @param filepath
* 本地文件路徑
* @param pd
* 進(jìn)度條,用以顯示下載進(jìn)度
* @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);
// 讀取數(shù)據(jù)沒有異常
if (conn.getResponseCode() == 200) {
int total = conn.getContentLength();// 獲得內(nèi)容的總長度
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;// 當(dāng)前進(jìn)度
while ((length = is.read(buffer)) != ⑴) {
fos.write(buffer, 0, length);
process += length;
pd.setProgress(process);// 設(shè)置當(dāng)前進(jìn)度
Thread.sleep(50);
}
fos.flush();
fos.close();
is.close();
return file;
}
return null;
}
由于默許的ProgressDialog是不顯示下載進(jìn)度的,因此需要進(jìn)行設(shè)置。
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 默許情況下不顯示進(jìn)度,這個設(shè)置用于顯示進(jìn)度
效果:

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈