软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很流行使用Splash界面, 正好与自动更新配套在一起;

 

在这个自动更新Splash中, 使用到了 动画设置 ,SharedPerference ,pull解析 ,dialog对话框 ,http网络编程,handler 等.

 

注意一个错误 : 已安装具有该名称和不同签名的数据包 , 早上测试人员报告突然出现这个问题, 在开发的时候我直接将eclipse上编译的版本放到了服务器上, 最后出现了这个问题, 开发的时候明明是好的啊, 怎么测试的时候出问题了呢.

编译环境不同, 产生的签名是不一样的, 在eclipse上编译生成 与 正式版本在linux下编译 所产生的 数字签名 是不一样的.

 

一. 创建Activity

 

1. 创建Activity大概流程

a. 设置全屏显示.

b. 设置布局, 并在布局中显示当前版本号, 为Splash界面添加动画.

c. 获取当前时间.

d. 获取SharedPerence配置文件.

e. 开启检查版本号线程, 后续的操作都在这个线程中执行.

 

2. 设置窗口样式

 

(1) 设置全屏显示

a. 代码实现 : 由于是Splash界面, 这里需要设置成无标题, 并且全屏显示, 注意下面的两行代码需要在setContentView()方法之前调用;

 

1
2
3
4
5
//隐藏标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
//隐藏状态栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);

 

 

b. 配置实现 : 

 

AndroidManifest.xml
<activity 
	android:name="myAcitivty"  
	android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />

 

 

(2) 关于窗口的其它设置

 

1
2
//①设置窗体始终点亮
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

 

 

 

//②设置窗体始终点亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

 

 

设置窗体始终点亮的配置文件实现

 

//③AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.WAKE_LOCK" />



 

//设置窗体背景模糊
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

 

(3) 屏幕方向设置

 

a. 配置文件实现

 

1
2
3
4
5
/设置横屏
<activity android:name="myAcitivty"  android:screenOrientation="landscape" />    
 
//设置竖屏
<activity android:name="myAcitivty"  android:screenOrientation="portrait" />

 

 

b. 代码实现

 

1
2
3
4
5
//设置横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 
//设置竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

 

 

c. 获取屏幕方向

 

1
2
//获取横屏方向
int orientation = this.getResources().getConfiguration().orientation;

其中的orientation方向可以使 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 或者 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE .

 

3. 设置动画

 

为了更好的用户体验, 这里给Splash界面添加一个动画, 这个动画加给整个界面.

 

(1) 创建动画

 

 

1
2
3
AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);<span style="white-space:pre;">   </span>//创建动画
animation.setDuration(2000);<span style="white-space:pre;"> </span>//设置渐变
splash_rl.setAnimation(animation);<span style="white-space:pre;">   </span>//设置动画载体

创建动画吧: 创建的这个动画是透明度渐变动画, 传入浮点型参数, 0代表完全透明, 1代表不透明, 传入参数代表透明度从完全透明到不透明.

 

设置时间 : 设置的duration是动画渐变过程所消耗的时间.

设置动画 : 最后使用setAnimation()方法将穿件的动画设置给Splash界面.

 

(2) 动画常用方法

 

a. 普通设置 

 

 

        alphaAnimation.setRepeatCount(5);//设置重复次数
        alphaAnimation.setFillAfter(true);//动画执行完是否停留在执行完的状态
        alphaAnimation.setStartOffset(1000);//动画执行前等待的时间, 单位是毫秒
        alphaAnimation.start();//开始动画

 

 


b. 设置监听器

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
alphaAnimation.setAnimationListener(new AnimationListener() {
            //动画开始时回调
            @Override
            public void onAnimationStart(Animation animation) {
            }
            //动画重复执行时回调
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
            //动画执行结束时回调
            @Override
            public void onAnimationEnd(Animation animation) {
            }
        });

 

 

4. SharedPerference使用

 

 

1
2
3
4
5
6
7
8
//获取SharedPerference
 SharedPreferences sharedPreferences = getSharedPreferences("sp", Context.MODE_PRIVATE);
  
 Editor editor = sharedPreferences.edit();   //获取Editor对象
 editor.putBoolean("isUpdate"true);        //向sp中写入数据
 editor.commit();                            //提交
      
 sharedPreferences.getBoolean("isUpdate"true);//获取sp中的变量



 

5. onCreate()方法代码 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
     * 创建Activity时调用
     *
     * ① 设置全屏显示, 由于是Splash界面, 因此不能有标题
     * ② 设置布局, 版本号, 执行动画
     * ③ 设置当前时间
     * ④ 获取SharedPerference配置文件
     * ⑤ 开启检查版本号线程, 后续操作都在改线程中操作
     *
     */
    @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.splash);
         
        /*
         *  显示当前软件的版本号
         *  获取布局中的TextView控件, 将版本号设置到这个TextView控件中
         */
        tv_version = (TextView) findViewById(R.id.tv_version);
        version =getString(R.string.current_version) + " " + getVersion();
        tv_version.setText(version);
         
        /*
         *  在界面设置一个动画, 用来表明正在运行
         *  a. 获取布局
         *  b. 创建一个动画对象
         *  c. 将动画设置到布局中
         */
        splash_rl = (RelativeLayout) findViewById(R.id.splash_rl);
        AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setDuration(2000);
        splash_rl.setAnimation(animation);
         
        /*
         * 这个时间值是用来控制Splash界面显示时间的
         * 记录下这个值, 然后执行到下面, 如果时间差在3秒以内,
         * 就执行下面的操作, 如果时间差不足3秒, 就Thread.sleep时间差
         * 等够3秒在执行下面的操作
         */
        time = System.currentTimeMillis();
 
        //从SharedPreference中获取一些配置
        sp = getSharedPreferences("config", Context.MODE_PRIVATE);
         
        //开启检查版本号线程
        new Thread(new CheckVersionTask()).start();
    }



 

 

二. 检查版本号

 

1. 检查版本号线程

流程 : 

a. 保持Splash持续时间 : 获取当前时间与time进行比较, 如果不足3秒, 人为使Splash保持3秒时间;

b. 查看更新设置 : 从sp中获取更新设置, 如果sp中自动更新为true, 那么就执行下面的更新流程, 如果sp中自动更新为false, 那么直接进入主界面.

c. 获取信息 : 从网络中获取更新信息, 根据是否成功获取信息执行不同的操作.

 

源码 : 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
private final class CheckVersionTask implements Runnable{
    public void run() {
        try {
            /*
             * 获取当前时间, 与onCreate方法中获取的时间进行比较
             * 如果不足3秒, 在等待够3秒之后在执行下面的操作
             */
            long temp = System.currentTimeMillis();
            if(temp - time < 3000){
                SystemClock.sleep(temp - time);
            }
             
            /*
             * 检查配置文件中的设置, 是否设置了自动更新;
             * 如果设置了自动更新, 就执行下面的操作,
             * 如果没有设置自动更新, 就直接进入主界面
             */
            boolean is_auto_update = sp.getBoolean("is_auto_update", true);
            if(!is_auto_update){
                loadMainUI();
                return;
            }
             
            /*
             * 获取更新信息
             * 如果信息不为null, 向handler发信息SUCESS_GET_UPDATEINOF, 执行后续操作
             * 如果信息为null, 向handler发信息ERROR_GET_UPDATEINOF, 执行后续操作
             * 如果出现异常, 向handler发信息ERROR_GET_UPDATEINOF, 执行后续操作
             */
            updateInfo = getUpdateInfo(SettingsFactory.readWebLoadUrl(getApplicationContext()) + UPDATE_FOLDER_DIRECTORY + XML_FILE_DIRECTORY);
            if(updateInfo != null){
                Message msg = new Message();
                msg.what = SUCESS_GET_UPDATEINOF;
                mHandler.sendMessage(msg);
            }else{
                Message msg = new Message();
                msg.what = ERROR_GET_UPDATEINOF;
                mHandler.sendMessage(msg);
            }
        catch (Exception e) {
            e.printStackTrace();
            Message msg = new Message();
            msg.what = ERROR_GET_UPDATEINOF;
            mHandler.sendMessage(msg);
        }
    }
}



 

2. 获取版本号方法

 

流程 : 

a. 创URL建对象;

b. 创建HttpURLConnection对象;

c. 设置超时时间;

d. 设置获取方式;

e. 查看链接是否成功;

f. 解析输入流信息;

 

源码 : 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 获取更新信息
 *      ① 根据字符串地址创建URL对象
 *      ② 根据URL对象创建HttpURLConnection链接对象
 *      ③ 设置链接对象5秒超时
 *      ④ 设置链接对象获取的方式为get方式
 *      ⑤ 如果成功连接, conn.getRequestCode值就是200, 此时就可以获取输入流
 *      ⑥ 解析输入流获取更新信息
 *     
 */
private UpdateInfo getUpdateInfo(String path){
    try {
        URL url = new URL(path);    //创建URL对象
        //创建连接对象
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置链接超时
        conn.setConnectTimeout(5000);
        //设置获取方式
        conn.setRequestMethod("GET");
        //如果连接成功, 获取输入流
        if(conn.getResponseCode() == 200){
            InputStream is = conn.getInputStream();
            //解析输入流中的数据, 返回更新信息
            return parserUpdateInfo(is);
        }
    catch (MalformedURLException e) {
        e.printStackTrace();
    catch (ProtocolException e) {
        e.printStackTrace();
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

 

 

3. 更新信息对象

 

 

将从网上获取的更新信息 包括 版本号, apk文件地址, 软件描述等信息封装在一个类中.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class UpdateInfo {
    private String version; //当前软件版本号
    private String url;     //获取到的软件地址
    private String description; //软件描述
     
    public String getVersion() {
        return version;
    }
    public void setVersion(String version) {
        this.version = version;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    @Override
    public String toString() {
        return "UpdateInfo [version=" + version + ", url=" + url
                ", description="