天天看點

Android 輕松實作背景搭建+APP版本更新 看完本文,您可以學到:一、大緻思路闡述二、詳細代碼解釋

(本文講解了在Android中實作APP版本更新,文末附有源碼。)

看完本文,您可以學到:

1.版本更新的方法

2.與背景的互動

3.Android中Handler的使用

4.Android中ProgressDialog的使用

話不多說,先來看看效果圖:

Android 輕松實作背景搭建+APP版本更新 看完本文,您可以學到:一、大緻思路闡述二、詳細代碼解釋
Android 輕松實作背景搭建+APP版本更新 看完本文,您可以學到:一、大緻思路闡述二、詳細代碼解釋
Android 輕松實作背景搭建+APP版本更新 看完本文,您可以學到:一、大緻思路闡述二、詳細代碼解釋

一、大緻思路闡述

首先,我們要有一個可以被手機通路的背景。 這裡有 兩種方法,在調試的時候我們可以利用 手機和筆記本連到同一個區域網路的方式,在電腦上開啟個類似PHP或者JAVAEE一樣樣的背景服務。 但是對于沒有相關背景開發經驗的朋友,這裡有一種 更好的方式:利用Github等 免費空間來實作。詳細請戳我的另一篇博文 利用Github建立你的個人網站 。 OK,有了存放資源的背景,我們要放點什麼東西呢?很簡單,一個 包含最新版本資訊的update.txt檔案和一個.apk檔案足矣!

txt檔案裡寫啥?看下我的例子: XXX&1.3&這裡寫點描述&http://192.168.1.100:8080/PersonalHomePage/new.apk

解釋一下:  &是分隔符,用于手機端擷取到資訊後的分割。 1.3代表着最新版本号,之後的是 新版本的描述,最後的是 新版本APK的下載下傳位址(這裡我用了區域網路)。一開始的是啥呢?我當時在試驗的時候,在開頭并沒有加額外資訊,即以1.3開頭,實驗之後,發現手機端擷取到TXT文本資訊後不能正确解析,原因我覺得是因為TXT檔案的開頭包含有一些自帶的字元,手機解析時會有問題。(感興趣的朋友可以去深究,還望不吝賜教!)

OK,有了新版本的資訊,我們要怎麼做? 我們要擷取到最新的版本号,然後與目前APP的版本号進行對比。如果低于最新版本,就到下載下傳位址中去下載下傳。

二、詳細代碼解釋

首先,建立一個UpdateInfo類,用來與update.txt的内容對應,這個很簡單:

package com.example.appupdatedemo;

public class UpdateInfo
{
        private String version;
        private String description;
        private String url;
        
        public String getVersion()
        {
                return version;
        }
        public void setVersion(String version)
        {
                this.version = version;
        }
        public String getDescription()
        {
                return description;
        }
        public void setDescription(String description)
        {
                this.description = description;
        }
        public String getUrl()
        {
                return url;
        }
        public void setUrl(String url)
        {
                this.url = url;
        }
        
}
           

然後,寫一個類去擷取更新的資訊,即我們的update.txt檔案:

UpdateInfoService:

package com.example.appupdatedemo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;

public class UpdateInfoService {
	public UpdateInfoService(Context context) {
	}

	public UpdateInfo getUpDateInfo() throws Exception {
		String path = GetServerUrl.getUrl() + "/update.txt";
		StringBuffer sb = new StringBuffer();
		String line = null;
		BufferedReader reader = null;
		try {
			// 建立一個url對象
			URL url = new URL(path);
			// 通過url對象,建立一個HttpURLConnection對象(連接配接)
			HttpURLConnection urlConnection = (HttpURLConnection) url
					.openConnection();
			// 通過HttpURLConnection對象,得到InputStream
			reader = new BufferedReader(new InputStreamReader(
					urlConnection.getInputStream()));
			// 使用io流讀取檔案
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (reader != null) {
					reader.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String info = sb.toString();
		UpdateInfo updateInfo = new UpdateInfo();
		updateInfo.setVersion(info.split("&")[1]);
		updateInfo.setDescription(info.split("&")[2]);
		updateInfo.setUrl(info.split("&")[3]);
		return updateInfo;
	}

}
           

這裡擷取檔案的方法是先建立一個HttpURLConnection,再擷取輸入流。細心的朋友可能注意到其中有個類,叫GetServerUrl,這個類是用來存放背景位址資訊的:

package com.example.appupdatedemo;

/**
 * 擷取伺服器IP位址
 */

public class GetServerUrl{
	static String url="http://192.168.1.100:8080/PersonalHomePage";   //沒錯,我這裡用的是本地的JAVAEE工程,各位根據實際情況修改。
			
	public static String getUrl() {
		return url;
	}
}
           

OK,到了這一步, 準備工作都做完了,接下來隻剩一個類了!即我們的MainActicity,一共一百多行,我們分幾部分來講。

第一部分代碼,做的工作是擷取版本更新資訊。

public class MainActivity extends Activity {

	// 更新版本要用到的一些資訊
	private UpdateInfo info;
	private ProgressDialog pBar;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Toast.makeText(MainActivity.this, "正在檢查版本更新..", Toast.LENGTH_SHORT).show();
		// 自動檢查有沒有新版本 如果有新版本就提示更新
		new Thread() {
			public void run() {
				try {
					UpdateInfoService updateInfoService = new UpdateInfoService(
							MainActivity.this);
					info = updateInfoService.getUpDateInfo();
					handler1.sendEmptyMessage(0);
				} catch (Exception e) {
					e.printStackTrace();
				}
			};
		}.start();
	}

	@SuppressLint("HandlerLeak")
	private Handler handler1 = new Handler() {
		public void handleMessage(Message msg) {
			// 如果有更新就提示
			if (isNeedUpdate()) {   //在下面的代碼段
				showUpdateDialog();  //下面的代碼段
			}
		};
	};
           

這裡我們用到了new Thread+ Handler的方式去進行異步加載版本資訊,主要是因為在安卓中要把耗時任務放在非主線程中執行,否則會造成阻塞,抛出無響應異常。還有另外的實作方式是安卓封裝的AsyncTask,具體可以參考這篇博文: Android AsyncTask詳解。

第二部分,判斷是否是最新版本,如果不是,跳出對話框選擇是否更新:

private void showUpdateDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setIcon(android.R.drawable.ic_dialog_info);
		builder.setTitle("請更新APP至版本" + info.getVersion());
		builder.setMessage(info.getDescription());
		builder.setCancelable(false);

		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				if (Environment.getExternalStorageState().equals(
						Environment.MEDIA_MOUNTED)) {
					downFile(info.getUrl());     //在下面的代碼段
				} else {
					Toast.makeText(MainActivity.this, "SD卡不可用,請插入SD卡",
							Toast.LENGTH_SHORT).show();
				}
			}
		});
		builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
			}

		});
		builder.create().show();
	}

	private boolean isNeedUpdate() {
		
		String v = info.getVersion(); // 最新版本的版本号
		Log.i("update",v);
		Toast.makeText(MainActivity.this, v, Toast.LENGTH_SHORT).show();
		if (v.equals(getVersion())) {
			return false;
		} else {
			return true;
		}
	}

	// 擷取目前版本的版本号
	private String getVersion() {
		try {
			PackageManager packageManager = getPackageManager();
			PackageInfo packageInfo = packageManager.getPackageInfo(
					getPackageName(), 0);
			return packageInfo.versionName;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
			return "版本号未知";
		}
	}
           

這段裡面要注意的是怎麼擷取目前版本,方法是使用PackageManager提供的getPackageInfo方法,傳回的是manifest檔案中的版本号。其他的代碼挺簡單,注釋也挺全的。如果有問題,歡迎留言。

接下來是最後一部分,下載下傳檔案。

void downFile(final String url) { 
		pBar = new ProgressDialog(MainActivity.this);    //進度條,在下載下傳的時候實時更新進度,提高使用者友好度
		pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		pBar.setTitle("正在下載下傳");
		pBar.setMessage("請稍候...");
		pBar.setProgress(0);
		pBar.show();
		new Thread() {
			public void run() {        
				HttpClient client = new DefaultHttpClient();
				HttpGet get = new HttpGet(url);
				HttpResponse response;
				try {
					response = client.execute(get);
					HttpEntity entity = response.getEntity();
					int length = (int) entity.getContentLength();   //擷取檔案大小
                                        pBar.setMax(length);                            //設定進度條的總長度
					InputStream is = entity.getContent();
					FileOutputStream fileOutputStream = null;
					if (is != null) {
						File file = new File(
								Environment.getExternalStorageDirectory(),
								"Test.apk");
						fileOutputStream = new FileOutputStream(file);
						byte[] buf = new byte[10];   //這個是緩沖區,即一次讀取10個比特,我弄的小了點,因為在本地,是以數值太大一 下就下載下傳完了,看不出progressbar的效果。
						int ch = -1;
						int process = 0;
						while ((ch = is.read(buf)) != -1) {       
							fileOutputStream.write(buf, 0, ch);
							process += ch;
							pBar.setProgress(process);       //這裡就是關鍵的實時更新進度了!
						}

					}
					fileOutputStream.flush();
					if (fileOutputStream != null) {
						fileOutputStream.close();
					}
					down();
				} catch (ClientProtocolException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}.start();
	}

	void down() {
		handler1.post(new Runnable() {
			public void run() {
				pBar.cancel();
				update();
			}
		});
	}
//安裝檔案,一般固定寫法
	void update() {                    
		Intent intent = new Intent(Intent.ACTION_VIEW);
		intent.setDataAndType(Uri.fromFile(new File(Environment
				.getExternalStorageDirectory(), "Test.apk")),
				"application/vnd.android.package-archive");
		startActivity(intent);
	}
           

這一段主要是利用progressdialog在下載下傳的時候實時更新進度,主要利用的是一個位元組數組的緩沖區。即每次擷取到的内容填滿緩沖區後就寫入到本地本件中。這裡我把緩沖區的大小設定為10個位元組(1024會比較好),理由是因為在同一個區域網路中速度特别快,刷一下就下載下傳完了,看不出進度條效果,緩沖區調小點就OK了。

========================================

寫在後面:

源代碼已上傳到我的Github,或者到CSDN下載下傳區下載下傳。

任何問題,歡迎留言交流!