Android项目 手机安全卫士(代码最全,诠释最详细)之四 自动更新检查的逻辑

Android项目 手机安全卫士(代码最全,注释最详细)之四 自动更新检查的逻辑
------- 源自梦想、永远是你IT事业的好友、只是勇敢地说出我学到! ----------

按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点也都能说出了123来,但是这些孤立的点终究显得太零散了,因此,我想从今天开始,以最经典的手机安全卫士项目为例,自己锻炼一下,也是想和大家交流交流,希望大家都能给出见解,共同进步。


四、自动更新检查的逻辑


3个软件:everything、size、color(GBR需转换成RGB)

版本的检测
会弹出对话框:最新版本的版本号,新版本的描述信息,是(下载路径)、否

1.新版本,在服务器端创建出来(可在Tomcat):
写一个update.xml文件,代码如下:

			<?xml version="1.0" encoding="UTF-8"?>
			<infos>
				<version>2.0</version>
				<description>最新版手机卫士,坚决为您的手机服务,快下载吧,手机杀毒送月饼,下载就开始啦!!</description>
				<apkurl>http://192.168.1.206/phonesafe2.0.apk</apkurl>
			</infos>


开启tomcat服务器,检验xml文件是否能打开。
2.自动更新的逻辑:
1连接服务器去读取服务器的配置文件
2比对客户端和服务器端的版本,看是否相同
若相同,进入应用程序的主UI
若不相同,转3
3升级提醒对话框,看用户是否选择升级?
若否,进入应用程序的主UI
若是,下载新版本替换安装,转1

3.连接服务器,检查更新信息
联网权限:Internet
在values文件夹中单独创建一个config.xml文件,不写死路径,并在其中
增加服务器路径serverurl的String值为http://localhost/Android/update.xml

checkVersionTask()方法(在新线程中检查更新信息)
new Thread(){public void run(){...}}.start();
URL构造函数
连接网络、设置请求方式和超时时间,当响应码为200时,联网成功,否则出错,用Message给出出错信息,使用Handler()获取信息
定义一个Message:
Message msg =Message.obtain();	//Message类

				msg.what = SERVER_ERROR;
				msg.what = URL_ERROR;
				msg.what = NETOWRK_ERROR;

				protected static final int SERVER_ERROR = 0;
				protected static final int URL_ERROR = 1;
				protected static final int NETOWRK_ERROR = 2;




若没有产生异常的话,则走code == 200:
获取服务器中的输入流,也就是xml文件:

解析xml文件:
属于一个业务方法,建立一个包:com.dondong.phonesafe.engine
在这个包中建立一个业务类(UpdateInfoParser),类里面有一个方法:getUpdateInfo(InputStream is),
返回的是UpdateInfo的bean类对象,即返回解析后的更新信息。新建一个UpdateInfo类(bean类),放在domain包下。
类中有version、description、apkurl三个属性.
具体代码:
						public class UpdateInfo {
							private String version;
							private String description;
							private String apkurl;
							public String getVersion() {
								return version;
							}
							public void setVersion(String version) {
								this.verison = version;
							}
							public String getDescription() {
								return description;
							}
							public void setDescription(String description) {
								this.description = description;
							}
							public String getApkurl() {
								return apkurl;
							}
							public void setApkurl(String apkurl) {
								this.apkurl = apkurl;
							}
						}	



业务类(UpdateInfoParser)具体代码:
					public class UpdateInfoParser {
						
						/**
						 * 解析xml文件,返回更新的信息
						 * @param is	代表xml文件的输入流
						 * @return	null 表示解析失败,否则返回UpdateInfo对象
						 */
						public static UpdateInfo getUpdateInfo(InputStream is){		//这个方法没有用到什么类的成员变量,加static,效率更高些
							try {
								XmlPullParser parser = Xml.newPullParser();
								parser.setInput(is, "utf-8");
								
								//getEventType()方法Returns the type of the current event (START_TAG, END_TAG, TEXT, etc.)
								int type = parser.getEventType(); 
								UpdateInfo updateInfo = new UpdateInfo();
								while(type != XmlPullParser.END_DOCUMENT){
									if(type == XmlPullParser.START_TAG){
										if("version".equals(parser.getName())){
											/*
											 * nextText()方法:
											 * If current event is START_TAG then 
											 * if next element is TEXT then element content is returned 
											 * or if next event is END_TAG then empty string is returned, 
											 * otherwise exception is thrown.
											 * After calling this function successfully parser will be positioned on END_TAG. 
											 */
											String version = parser.nextText();
											updateInfo.setVersion(version);
										}else if("description".equals(parser.getName())){
											String description = parser.nextText();
											updateInfo.setDescription(description);
										}else if("apkurl".equals(parser.getName())){
											String apkurl = parser.nextText();
											updateInfo.setApkurl(apkurl);
										}
									}
									type = parser.next();
								}
								is.close();
								return updateInfo;
							} catch (Exception e) {
								e.printStackTrace();
								return null;
							}
						}
					}





那么什么时候发这个msg呢?try...catch一定会走finally,我们就在finally语句中发送信息:
handler.sendmessage(msg);


具体代码:
						private void checkVersionTask() {
							new Thread(){
								@Override
								public void run() {
									Message msg =Message.obtain();
									try {
										URL url = new URL(getString(R.string.serverurl));	//获取服务器链接url
										HttpURLConnection conn = (HttpURLConnection) url.openConnection();	//链接网络
										conn.setRequestMethod("GET");	//设置请求方式
										conn.setConnectTimeout(5000);	//设置连接超时时限
										
										int code = conn.getResponseCode();	//获取响应码,只有在响应码为200时才连接成功
										if(code == 200){
											//请求成功
										}else{
											//请求失败
											msg.what = SERVER_ERROR;
										}
									}catch (MalformedURLException e) {  //因为MalformedURLException继承了IOException
										e.printStackTrace();
										//url错误:This exception is thrown when a program attempts to create an URL from an incorrect specification.
										msg.what = URL_ERROR;
									} catch (IOException e) {	//若IOException在MalformedURLException前,则MalformedURLException读不到
										e.printStackTrace();
										//网络连接错误
										msg.what = NETOWRK_ERROR;
									}finally{
										handler.sendMessage(msg); //发送后handleMessage(Message msg)就会得到msg
									}
								};
								
							}.start();
						}


这时候handleMessage(Message msg)就可以获得msg,然后我们经过switch判断是那种错误,并Toast错误信息。
具体代码:
						private Handler handler = new Handler(){


							@Override
							public void handleMessage(Message msg) {	//得到msg后,就可以做判断了
								switch (msg.what){
								case SERVER_ERROR:
									Toast.makeText(getApplicationContext(), "服务器错误。。。", 0).show();
									break;
								case URL_ERROR:
									Toast.makeText(getApplicationContext(), "更新的URL错误。。。", 0).show();
									break;
								case NETOWRK_ERROR:
									Toast.makeText(getApplicationContext(), "网络错误,请检查连接。。。", 0).show();
									break;
								}
							}
							
						};


若code=200,即请求成功,则
							//解析成功,则检查版本是否一样,在主线程中执行
							msg.what = PARSE_XML_SUCCESS;

并在Hanlder中:
						case PARSE_XML_SUCCESS:
							checkVersion();
							break;

下面建立一个checkVersion()方法,用于检查客户端与服务端的版本是否相同。
具体代码:
						/**
						 * 对比客户端和服务端的版本是否一样
						 */
						protected void checkVersion() {
							//分别得到客户端和服务端的版本
							if(getVersion().equals(updateInfo.getVersion())){	//如果版本号相同,则直接进入主界面
								
							}else{		//否则,给出升级提醒对话框
								AlertDialog.Builder builder = new Builder(this);	//创建对话框
								builder.setTitle("更新提醒:");
								builder.setMessage(updateInfo.getDescription());
								builder.setPositiveButton("立即更新", new OnClickListener(){


									@Override
									public void onClick(DialogInterface dialog, int which) {
										//用户选择更新,则替换安装
										Log.i(TAG, "版本号不同,下载新的apk,替换安装");
									}
								});
								builder.setNegativeButton("下次再说", new OnClickListener(){
									
									@Override
									public void onClick(DialogInterface dialog, int which) {
										//用户选择不更新,则直接进入主界面
										loadMainUI();		
									}
								});
								builder.show();
							}
						}


这里需要做一个演示的主界面(HomeActivity)。

由于上述各种情况都需要进入主界面,所以在这里抽取成一个方法:loadMainUI()
具体代码:
					/**
					 * 进入主界面
					 */
					private void loadMainUI() {
						Intent intent = new Intent(SplashActivity.this,HomeActivity.class);
						startActivity(intent);
						finish();	//关闭当前界面
					}


------- 源自梦想、永远是你IT事业的好友、只是勇敢地说出我学到! ----------