• 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事业的好友、只是勇敢地说出我学到! ----------
    Le王冬冬 博客分享地址: http://www.cnblogs.com/dongdong230/ 每个人都应做一天攻城狮
  • 相关阅读:
    MySQL表行数查询最佳实践
    mysqldump备份表中有大字段失败的排错过程
    μC/OSⅡ在C8051F060上的移植及其应用
    OSSchedLock()函数透析
    32位与64位区别
    【Cesium】Animation显示系统时间
    【Cesium】根据经纬度计算距离
    【Cesium】 鼠标拾取椭球、地形、模型坐标点(经度+纬度+高程)
    【Python学习】Selenium模拟浏览器抓取数据
    【Cesium】polygon中的height和extrudedHeight的区别
  • 原文地址:https://www.cnblogs.com/dongdong230/p/4183100.html
Copyright © 2020-2023  润新知