2、更新提示

在进入splash界面的时候后台启动线程,联网检查是否有更新版本可用,如果没有新版本则splash界面显示后进入主界面,否则显示升级对话框让用户选择是否进行更新。

1、权限设置

因为需要联网,所以AndroidManifest.xml文件需要添加访问网络的权限:

<uses-permission android:name="android.permission.INTERNET" />
本人就是由于忘记添加该权限,在后面的运行中出现错误:

12-23 03:24:26.999    1528-1541/com.example.mobilesafe W/System.err﹕ java.net.SocketException: socket failed: EACCES (Permission denied)
12-23 03:24:26.999    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.socket(IoBridge.java:576)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.create(PlainSocketImpl.java:201)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.Socket.checkOpenAndCreate(Socket.java:664)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.Socket.connect(Socket.java:808)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.Platform.connectSocket(Platform.java:131)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:101)
12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
12-23 03:24:27.019    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
12-23 03:24:27.019    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:146)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)
12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ Caused by: libcore.io.ErrnoException: socket failed: EACCES (Permission denied)
12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.Posix.socket(Native Method)
12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:181)
12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.socket(IoBridge.java:561)
12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ ... 13 more

2、服务器更新配置

这里使用wampserver搭建本地服务器,更新配置文件放在X:\wamp\www\app\mobilesafe目录下,配置内容为:

<?xml version="1.0" encoding="utf-8"?>
<info>
    <ver>2.0</ver>
    <desc>亲,有新版本了,赶紧更新吧!</desc>
    <apkurl>http://10.0.2.2/app/mobilesafe/mobilesafe.apk</apkurl>
 </info>


3、设置服务器地址

因为服务器地址属于常量字符串,这里添加到strings.xml中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">mobilesafe</string>
    <string name="serverurl">http://10.0.2.2/app/mobilesafe/update.xml</string>
</resources>

这里是使用本机进行测试的,注意Android访问本机的IP地址是:10.0.2.2,如果使用127.0.0.1会出现如下错误:

12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ java.net.ConnectException: failed to connect to /127.0.0.1 (port 80) after 5000ms: isConnected failed: ECONNREFUSED (Connection refused)
12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.isConnected(IoBridge.java:223)
12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.connectErrno(IoBridge.java:161)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.connect(IoBridge.java:112)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.Socket.connect(Socket.java:843)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.Platform.connectSocket(Platform.java:131)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:101)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:146)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ Caused by: libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.isConnected(IoBridge.java:208)
12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ ... 15 more

相关参考: http://www.myexception.cn/operating-system/754403.html


4、更新信息结构体

按照服务器更新配置,更新信息共有三个字段:版本号,更新提示文本,apk下载地址:

package com.example.mobilesafe;

/**
 * Created by sing on 13-12-23.
 */
public class UpdateInfo {
    //服务器端版本号
    private String version;

    //服务器端升级提示
    private String desc;

    //服务器端apk下载地址
    private String apkurl;

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getApkurl() {
        return apkurl;
    }

    public void setApkurl(String apkurl) {
        this.apkurl = apkurl;
    }

}

5、XML更新配置解析类

注意XmlPullParser解析XML的nextText存在bug:

12-23 03:46:07.439    1729-1748/com.example.mobilesafe W/System.err﹕ org.xmlpull.v1.XmlPullParserException: END_TAG expected (position:START_TAG <version>@3:14 in java.io.InputStreamReader@b2ef2718)
12-23 03:46:07.449    1729-1748/com.example.mobilesafe W/System.err﹕ at org.kxml2.io.KXmlParser.nextText(KXmlParser.java:2077)
12-23 03:46:07.479    1729-1748/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.UpdateInfoParser.getUpdateInfo(UpdateInfoParser.java:33)
12-23 03:46:07.479    1729-1748/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:153)
12-23 03:46:07.499    1729-1748/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)

参考解决:http://blog.csdn.net/nxh_love/article/details/7109762,

这里使用的方法是:当前的位置不是END_TAG时,在调用nextText()之后再调用nextTag(),完整代码:

package com.example.mobilesafe;

import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;

/**
 * Created by sing on 13-12-23.
 */

public class UpdateInfoParser {
    /**
     *解析一个utf-8格式的xml输入流,返回一个UpdateInfo对象
     * XmlPullParser解析bug参考解决:http://blog.csdn.net/nxh_love/article/details/7109762
     * @param is
     * @return UpdateInfo对象
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static UpdateInfo getUpdateInfo(InputStream is) throws XmlPullParserException, IOException {
        UpdateInfo info = new UpdateInfo();

        //获取一个pull解析的实例
        XmlPullParser parser = Xml.newPullParser();

        //解析xml
        parser.setInput(is, "UTF-8");
        parser.nextTag();
        int type = parser.getEventType();
        while (parser.nextTag() == XmlPullParser.START_TAG) {
            String tag = parser.getName();
            String text = parser.nextText();
            if (parser.getEventType() != XmlPullParser.END_TAG) {
                parser.nextTag();
            }
            if (tag.equals("ver")) {
                info.setVersion(text);
            } else if (tag.equals("desc")) {
                info.setDesc(text);
            } else if (tag.equals("apkurl")) {
                info.setApkurl(text);
            }
        }

        return info;
    }
}

6、SplashActivity::OnCreate创建检查更新的线程

        //检查更新
        new Thread(new checkUpdate()) {
        }.start();


    /**
     * 检查更新
     */
    private class checkUpdate implements Runnable {
       public void run() {
           long startTime = System.currentTimeMillis();
           long endTime = startTime;
           Message msg = Message.obtain();
           try {
               //获取服务器更新地址
               String serverurl = getResources().getString(R.string.serverurl);
               URL url = new URL(serverurl);
               HttpURLConnection conn = (HttpURLConnection)url.openConnection();
               conn.setRequestMethod("GET");
               conn.setConnectTimeout(5000);
               int code = conn.getResponseCode();
               if (code == 200) {
                   //success
                   InputStream is = conn.getInputStream();
                    //解析出更新信息
                   updateinfo = UpdateInfoParser.getUpdateInfo(is);
                   endTime = System.currentTimeMillis();
                   long time = endTime - startTime;
                   if (time < 2000) {
                       try {
                           Thread.sleep(2000 - time);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }

                   msg.what = GET_INFO_SUCCESS;
                   handler.sendMessage(msg);
               } else {
                   //服务器错误
                   msg.what = SERVER_ERROR;
                   handler.sendMessage(msg);
                   endTime = System.currentTimeMillis();
                   long time = endTime - startTime;
                   if (time < 2000) {
                       try {
                           Thread.sleep(2000 - time);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }

           } catch (MalformedURLException e) {
               msg.what = SERVER_URL_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (ProtocolException e) {
               msg.what = PROTOCOL_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (IOException e) {
               msg.what = IO_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (XmlPullParserException e) {
               msg.what = XML_PARSER_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (Exception e) {
               msg.what = UNKNOWN_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           }

       }
    }


7、添加消息处理函数,在界面中统一显示

   /**
     * 消息处理器
     */
    private Handler handler = new Handler() {
         public void handleMessage(Message msg) {
            switch (msg.what) {
                case GET_INFO_SUCCESS:
                    String serverVersion = updateinfo.getVersion();
                    String currentVersion = getVersion();
                    if (currentVersion.equals(serverVersion)) {
                        Log.i(TAG, "版本号相同无需升级,直接进入主界面");
                    }else {
                        Log.i(TAG, "版本号不同需升级,显示升级对话框");
                        showUpdateDialog();
                    }
                    break;
                case SERVER_ERROR:
                    Toast.makeText(getApplicationContext(), "服务器内部异常", 1).show();
                    break;
                case SERVER_URL_ERROR:
                    Toast.makeText(getApplicationContext(), "服务器路径错误", 1).show();
                    break;
                case PROTOCOL_ERROR:
                    Toast.makeText(getApplicationContext(), "协议错误", 1).show();
                    break;
                case XML_PARSER_ERROR:
                    Toast.makeText(getApplicationContext(), "XML解析错误", 1).show();
                    break;
                case IO_ERROR:
                    Toast.makeText(getApplicationContext(), "I/O错误", 1).show();
                    break;
                case UNKNOWN_ERROR:
                    Toast.makeText(getApplicationContext(), "未知错误", 1).show();
                    break;
            }
        }
    };

8、当本地版本号与服务器端获取的版本号不同时提示升级对话框

/**
     * 显示升级提示对话框
     */
    protected void showUpdateDialog() {
        //创建对话框构造器
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        //设置对话框图标
        builder.setIcon(getResources().getDrawable(R.drawable.notification));
        //设置对话框标题
        builder.setTitle("升级提示");
        //设置更新信息为对话框提示内容
        builder.setMessage(updateinfo.getDesc());
        //设置升级按钮及响应事件
        builder.setPositiveButton("升级", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        //设置取消按钮及响应事件
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });

        //创建并显示对话框
        builder.create().show();
    }

9、SplashActivity完整代码

package com.example.mobilesafe;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import android.os.Handler;

public class SplashActivity extends Activity {
    //常量定义
    public static final int UNKNOWN_ERROR = 99;
    public static final int GET_INFO_SUCCESS = 100;
    public static final int SERVER_ERROR = 101;
    public static final int SERVER_URL_ERROR = 102;
    public static final int PROTOCOL_ERROR = 103;
    public static final int IO_ERROR = 104;
    public static final int XML_PARSER_ERROR = 105;
    public static final String TAG = "SplashActivity";

    //获取的服务器端的更新信息
    UpdateInfo updateinfo;

    //显示版本号的tv控件
    private TextView tv_splash_version;

    //布局控件
    private RelativeLayout r1_splash;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //设置无标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        //设置全屏模式
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        //设置局部,显示版本号
        setContentView(R.layout.activity_splash);
        r1_splash = (RelativeLayout)findViewById(R.id.r1_splash);
        tv_splash_version = (TextView)findViewById(R.id.tv_splash_version);
        tv_splash_version.setText("版本号:" + getVersion());

        //显示渐进动画
        AlphaAnimation aa = new AlphaAnimation(0.3f, 1.0f);
        aa.setDuration(2000);
        r1_splash.startAnimation(aa);

        //检查更新
        new Thread(new checkUpdate()) {
        }.start();
    }

    //获取当前应用程序的版本号
    private String getVersion() {
        String version = "";

        //获取系统包管理器
        PackageManager pm = this.getPackageManager();
        try {
            PackageInfo info = pm.getPackageInfo(getPackageName(), 0);
            version = info.versionName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return version;
    }

    /**
     * 消息处理器
     */
    private Handler handler = new Handler() {
         public void handleMessage(Message msg) {
            switch (msg.what) {
                case GET_INFO_SUCCESS:
                    String serverVersion = updateinfo.getVersion();
                    String currentVersion = getVersion();
                    if (currentVersion.equals(serverVersion)) {
                        Log.i(TAG, "版本号相同无需升级,直接进入主界面");
                    }else {
                        Log.i(TAG, "版本号不同需升级,显示升级对话框");
                        showUpdateDialog();
                    }
                    break;
                case SERVER_ERROR:
                    Toast.makeText(getApplicationContext(), "服务器内部异常", 1).show();
                    break;
                case SERVER_URL_ERROR:
                    Toast.makeText(getApplicationContext(), "服务器路径错误", 1).show();
                    break;
                case PROTOCOL_ERROR:
                    Toast.makeText(getApplicationContext(), "协议错误", 1).show();
                    break;
                case XML_PARSER_ERROR:
                    Toast.makeText(getApplicationContext(), "XML解析错误", 1).show();
                    break;
                case IO_ERROR:
                    Toast.makeText(getApplicationContext(), "I/O错误", 1).show();
                    break;
                case UNKNOWN_ERROR:
                    Toast.makeText(getApplicationContext(), "未知错误", 1).show();
                    break;
            }
        }
    };

    /**
     * 检查更新
     */
    private class checkUpdate implements Runnable {
       public void run() {
           long startTime = System.currentTimeMillis();
           long endTime = startTime;
           Message msg = Message.obtain();
           try {
               //获取服务器更新地址
               String serverurl = getResources().getString(R.string.serverurl);
               URL url = new URL(serverurl);
               HttpURLConnection conn = (HttpURLConnection)url.openConnection();
               conn.setRequestMethod("GET");
               conn.setConnectTimeout(5000);
               int code = conn.getResponseCode();
               if (code == 200) {
                   //success
                   InputStream is = conn.getInputStream();
                    //解析出更新信息
                   updateinfo = UpdateInfoParser.getUpdateInfo(is);
                   endTime = System.currentTimeMillis();
                   long time = endTime - startTime;
                   if (time < 2000) {
                       try {
                           Thread.sleep(2000 - time);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }

                   msg.what = GET_INFO_SUCCESS;
                   handler.sendMessage(msg);
               } else {
                   //服务器错误
                   msg.what = SERVER_ERROR;
                   handler.sendMessage(msg);
                   endTime = System.currentTimeMillis();
                   long time = endTime - startTime;
                   if (time < 2000) {
                       try {
                           Thread.sleep(2000 - time);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }

           } catch (MalformedURLException e) {
               msg.what = SERVER_URL_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (ProtocolException e) {
               msg.what = PROTOCOL_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (IOException e) {
               msg.what = IO_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (XmlPullParserException e) {
               msg.what = XML_PARSER_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           } catch (Exception e) {
               msg.what = UNKNOWN_ERROR;
               handler.sendMessage(msg);
               e.printStackTrace();
           }

       }
    }

    /**
     * 显示升级提示对话框
     */
    protected void showUpdateDialog() {
        //创建对话框构造器
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        //设置对话框图标
        builder.setIcon(getResources().getDrawable(R.drawable.notification));
        //设置对话框标题
        builder.setTitle("升级提示");
        //设置更新信息为对话框提示内容
        builder.setMessage(updateinfo.getDesc());
        //设置升级按钮及响应事件
        builder.setPositiveButton("升级", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        //设置取消按钮及响应事件
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });

        //创建并显示对话框
        builder.create().show();
    }
}

10、运行效果图

本地版本号与服务器版本号相同时直接进入主界面:

12-23 05:43:33.279    2125-2125/com.example.mobilesafe I/SplashActivity﹕ 版本号相同无需升级,直接进入主界面

本地版本号与服务器版本号不同时显示提示升级对话框:

12-23 05:44:37.349    2125-2125/com.example.mobilesafe I/SplashActivity﹕ 版本号不同需升级,显示升级对话框







  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

asmcvc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值