編輯:關於Android編程
提醒一下,更新的操作不要放到Application中,有的人想程序啟動的時候就馬上檢查更新,然後就把更新的操作放在了Application中,Application不是可見界面,所以不會有彈出框提醒,我測試的時候是這樣的,不知道我解釋的對不對,不對了請指正。謝謝
可以優化的地方:
判斷當前網絡是不是數據連接,數據連接下應該彈出對話框讓用戶再次確認,為用戶流量考慮
這個是初級版的,更新條顯示在了前台
項目需要,學習了一下app自動升級,網上查了好多資料,好多都不能直接用。下面我自己寫了一個,下次用到了直接拷貝就行了
加上權限防止忘記
新建布局文件:
updateversion.xml
更新類UpdateVersion.java
package com.example.updateversion;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
public class UpdateVersion {
private static final int DOWNLOAD = 1;
private static final int DOWNLOAD_FINISH = 2;
private static final int CONNECT_FAILED = 0;
private static final int CONNECT_SUCCESS = 1;
HashMap mHashMap;
private String mSavePath;
private int progress;
private boolean cancelUpdate = false;
private Context mContext;
private ProgressBar mProgress;
private Dialog mDownloadDialog;
private String mXmlPath; // 服務器更新xml存放地址
public UpdateVersion(Context context, String xmlPath, String savePath) {
this.mContext = context;
this.mXmlPath = xmlPath;
this.mSavePath = savePath;
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOAD:
mProgress.setProgress(progress);
break;
case DOWNLOAD_FINISH:
installApk();
break;
default:
break;
}
};
};
/**
* 檢查更新
*/
public void checkUpdate() {
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(mXmlPath);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(5*1000);
conn.setRequestMethod("GET");
if(conn.getResponseCode()==200){
Log.i("TAG", "dfdfd");
Log.i("TAG", conn.getResponseCode()+"");
InputStream inStream = conn.getInputStream();
Log.i("TAG", "dfdfd");
mHashMap = parseXml(inStream);
Message msg = new Message();
msg.what = CONNECT_SUCCESS;
handler.sendMessage(msg);
}
} catch (Exception e) {
Message msg = new Message();
msg.what = CONNECT_FAILED;
handler.sendMessage(msg);
}
}
}).start();
}
/**
* 訪問服務器更新XML
*/
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case CONNECT_FAILED:
Toast.makeText(mContext, "訪問服務器失敗!", Toast.LENGTH_SHORT).show();
break;
case CONNECT_SUCCESS:
if (null != mHashMap) {
int serviceCode = Integer.valueOf(mHashMap.get("version"));
if (serviceCode > getVersionCode(mContext)) {
showNoticeDialog();
}
}
break;
}
}
};
/**
* 獲取程序版本號
*/
private int getVersionCode(Context context) {
int versionCode = 0;
try {
versionCode = context.getPackageManager().getPackageInfo(
mContext.getPackageName(), 0).versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}
/**
* 是否更新提示窗口
*/
private void showNoticeDialog() {
AlertDialog.Builder builder = new Builder(mContext);
builder.setTitle("有重要更新");
builder.setMessage(mHashMap.get("updateInfo"));
builder.setPositiveButton("更新",
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
showDownloadDialog();
}
});
builder.setNegativeButton("忽略",
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
Dialog noticeDialog = builder.create();
noticeDialog.show();
}
/**
* 下載等待窗口
*/
private void showDownloadDialog() {
AlertDialog.Builder builder = new Builder(mContext);
builder.setTitle("正在更新");
final LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.updateversion, null);
mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
builder.setView(v);
builder.setNegativeButton("取消下載",
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
cancelUpdate = true;
}
});
mDownloadDialog = builder.create();
mDownloadDialog.show();
downloadApk();
}
/**
* 下載apk
*/
private void downloadApk() {
new downloadApkThread().start();
}
/**
* 下載程序
*/
private class downloadApkThread extends Thread {
@Override
public void run() {
try {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
URL url = new URL(mHashMap.get("url"));
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(mSavePath);
if (!file.exists()) {
file.mkdir();
}
File apkFile = new File(mSavePath, mHashMap.get("name"));
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
byte buf[] = new byte[1024];
do {
int numread = is.read(buf);
count += numread;
progress = (int) (((float) count / length) * 100);
mHandler.sendEmptyMessage(DOWNLOAD);
if (numread <= 0) {
mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
break;
}
fos.write(buf, 0, numread);
} while (!cancelUpdate);
fos.close();
is.close();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mDownloadDialog.dismiss();
}
};
/**
* 安裝apk
*/
private void installApk() {
File apkfile = new File(mSavePath, mHashMap.get("name"));
if (!apkfile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
"application/vnd.android.package-archive");
mContext.startActivity(i);
}
private HashMap parseXml(InputStream inStream)
throws Exception {
HashMap hashMap = new HashMap();
// 實例化一個文檔構建器工廠
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 通過文檔構建器工廠獲取一個文檔構建器
DocumentBuilder builder = factory.newDocumentBuilder();
// 通過文檔通過文檔構建器構建一個文檔實例
Document document = builder.parse(inStream);
// 獲取XML文件根節點
Element root = document.getDocumentElement();
// 獲得所有子節點
NodeList childNodes = root.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
// 遍歷子節點
Node childNode = (Node) childNodes.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element) childNode;
// 版本號
if ("version".equals(childElement.getNodeName())) {
hashMap.put("version", childElement.getFirstChild()
.getNodeValue());
}
// 軟件名稱
else if (("name".equals(childElement.getNodeName()))) {
hashMap.put("name", childElement.getFirstChild()
.getNodeValue());
}
// 下載地址
else if (("url".equals(childElement.getNodeName()))) {
hashMap.put("url", childElement.getFirstChild()
.getNodeValue());
}
else if (("updateInfo".equals(childElement.getNodeName()))) {
hashMap.put("updateInfo", childElement.getFirstChild()
.getNodeValue());
}
}
}
return hashMap;
}
//當不需要的時候,清除之前的下載文件,避免浪費用戶空間
public void deletFile(){
File updateFile = new File(mSavePath,mContext.getResources().getString(R.string.app_name)+".apk");
if(updateFile.exists()){
updateFile.delete();
}
}
}
package com.example.updateversion;
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
update();
}
private void update() {
if(isNetworkAvailable(this)){//判斷網絡是否有效
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
String sdpath = Environment.getExternalStorageDirectory() + "/";
String mSavePath = sdpath + "download/";//文件的下載路徑
UpdateVersion updateManager = new UpdateVersion(this,
"http://192.168.8.227:8080/manyiApp/UpdateVersion.xml", mSavePath);
updateManager.checkUpdate();
}else{
Toast.makeText(this, "SD卡不可用", 1).show();
Log.i("TAG", "11213");
}
}else{
Toast.makeText(this, "網絡沒有連接", 1).show();
}
}
public boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo(); //沒有網絡的時候會返回 null
Log.i("TAG", "INFOddd");
if (info == null || !cm.getBackgroundDataSetting()) {
return false;
}else
return true;
}
}
12 BoilerAndroid_1.1 http://192.168.8.227:8080/manyiApp/AndroidTest.apk 1.增加收藏功能
服務器段工程結構

下載完成後點擊打開新版本
/**
* 安裝APK文件
*/
private void installApk() {
File apkfile = new File(mSavePath,Constant.appFileName);
if (!apkfile.exists()) {
return;
}
// 通過Intent安裝APK文件
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
"application/vnd.android.package-archive");
mContext.startActivity(i);
android.os.Process.killProcess(android.os.Process.myPid());
}
如果沒有android.os.Process.killProcess(android.os.Process.myPid());最後不會提示完成、打開。
Android開發之ListView、GridView 詳解及示例代碼
ListView與GridView是Android開發中的常用控件,它們和Adapter配合使用能夠實現很多界面效果。下面分別以實例
Android Studio--NDK編譯C代碼為.so文件,JNI調用
前言:從Android Studio開始,就支持jni和.so庫調用了。環境:Windows 7+Android Studio2.1.2+NDK版本:android-nd
Android事件分發機制詳解
在開始講述touch事件流程之前,還簡單介紹下TouchEvent,View和ViewGroup。1. MotionEvent 整個事件分發流程中,會
Android自定義控件--下拉刷新的實現
我們在使用ListView的時候,很多情況下需要用到下拉刷新的功能。為了了解下拉刷新的底層實現原理,我采用自定義ListView控件的方式來實現效果。實現的基本原理是:自